首页 > 编程语言 >嵌入式开发常用技巧及编程知识

嵌入式开发常用技巧及编程知识

时间:2022-10-30 10:33:11浏览次数:50  
标签:全局变量 变量 函数 编程 技巧 断言 str 嵌入式 define


嵌入式开发常用技巧及C/C++知识

  • ​​引言​​
  • ​​查询程序占据的内存大​​
  • ​​static 静态变量​​
  • ​​‘##’连接符​​
  • ​​断言函数​​
  • ​​宏定义与条件变量​​
  • ​​#if...#else...#endif​​
  • ​​选择是否使用串口调试​​
  • ​​memcpy函数​​
  • ​​字符串小写转大写​​
  • ​​字符串大写转小写​​
  • ​​字符串命令处理​​
  • ​​将某几位清0,并保留其他位的状态​​
  • ​​其他​​
  • ​​后续​​

引言

我们在日常的嵌入式开发中,经常会遇到各种C/C++的使用问题,并且C/C++纯软件的常用开发技巧有些嵌入式并不常用,而嵌入式开发中使用到的C/C++知识与技巧有些也非常特别,这里我们来具体介绍一下嵌入式开发常用技巧及C/C++知识(未完待续)。

查询程序占据的内存大

双击你的工程文件名

嵌入式开发常用技巧及编程知识_c语言

打开.map文件,拉到最下面就可以看到你的程序会占据开发板的多少内存。

嵌入式开发常用技巧及编程知识_开发语言_02

static 静态变量

静态全局变量:在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。
静态全局变量有以下特点:

  1. 该变量在全局数据区分配内存
  2. 未经初始化的静态全局变量会被程序自动初始化为0(在函数体内声明的自动变量的值是随机的,除非它被显式初始化,而在函数体外被声明的自动变量也会被初始化为0)
  3. 静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的
    静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的分布情况:

代码区

low address

全局数据区堆区栈区

high address

一般程序把新产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。
定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:

  1. 静态全局变量不能被其它文件所用
  2. 其它文件中可以定义相同名字的变量,不会发生冲突

‘##’连接符

##用来连接前后两个参数,把它们变成一个字符串。
例子如下:

#define main(x,y) x##y
int xy=1;
cout < < main(x,y) < < endl;

将会使编译器把
cout < < main(x,y) < < endl;
解释为
cout < < xy < < endl;
理所当然,将会在标准输出处显示’1’。
从此可以看出,x##y的效果就是将x和y连在一起了。
而#define main(x,y) x##y 则相当于把main(x,y)等价于x##y

断言函数

主要作用:是对一个bool型表达式进行检查,一个正确运行的程序必须保证这个bool型表达式的值为true,若表达式的值为false,则说明程序已处于一种不正确的状态下,系统需要提供警告信息并且退出程序。
在实际开发中assert主要用于保证程序的正确性,通常在程序开发和测试时使用。为了提高运行效率,在软件发布后,assert检查默认是关闭的。
使用断言的几个原则:

  1. 使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是必然存在的并且是一定要作出处理的。
  2. 使用断言对函数的参数进行确认。
  3. 一般教科书都鼓励程序员们进行防错性的程序设计,但要记住这种编程风格会隐瞒错误。当进行防错性编程时,如果"不可能发生"的事情的确发生了,则要使用断言进行报警。
    FreeRTOS 中的 configASSERT
    configASSERT是在FreeRTOS中的断言函数。如果断言函数的参数为0时将触发断言函数的执行。
    FreeRTOS的断言功能在调试阶段是非常有用的,可以有效地检查参数错误和运行中的错误,但在正式发布软件时,请将此功能关闭,因为断言功能会增加工程代码大小并降低工程执行效率。关闭断言也比较简单,如果FreeRTOSConfig.h文件中有断言的宏定义,将其注释掉即可,如果没有宏定义,默认在FreeRTOS.h文件中就是关闭的。
#define configASSERT( x )     if( x == 0 ) {taskDISABLE_INTERRUPTS(); for(;;); }

在使用调试器的情况下,一旦出现断言失败,会关闭中断,程序会死在这个for循环中,此时用户可以很容易就锁定函数出错位置。

宏定义与条件变量

#if…#else…#endif

我们在调试程序时,经常会遇到某段功能的实现,写了两种版本的程序,但调试时又不想来回切换。,这时候我们可以使用条件变量。
比如:想测试__set_FAULTMASK(1);和__disable_fault_irq();的区别,就可以使用如下方式,只需要更改#if后面是1还是0就可以选择是使用哪段程序。

#if 1
//
__set_FAULTMASK(1);
NVIC_SystemReset();
#else
__disable_irq();
delay_ms(1000);
__disable_fault_irq();
NVIC_SystemReset();
#endif

选择是否使用串口调试

我们在程序开发过程时,往往使用串口进行程序的调试,但在产品成熟时,为了避免内存开销和其他的一些问题往往会去掉串口调试,这时候应该如何简单的去掉呢,下面我来介绍一下。

#define DEBUG_EN 1 //选择是否打开printf调试(串口一),1代表打开,0代表关闭
#if DEBUG_EN
#define DEBUG(fmt, ...) do{ printf(fmt , ##__VA_ARGS__); }while(0)
#else
#define DEBUG do{ }while(0);
#endif

我们通过上述程序,就可以实现串口调试的全部切换,非常方便。

memcpy函数

memcpy函数的用法,memcpy (void* _Dst,void const* _Src,size_t _Size)
memcpy函数是将后面地址的内容一个数据一个数据放在前面的地址,注意,是先放低位。
_Size是字节数,也就是说如果是32位数组,两个数组值就应该是_Size就应该是4。
例子:

char a[8]={0x12,0x34,0x56,0x78,0x90,0x14,0x52,0x46 };
short b=0;
memcpy(&b,a+1,2);
printf("b=%x", b);
此段代码的作用是把0x34和0x56拼接起来送到b,输出的最终结果是:0x5634。

字符串小写转大写

//将字符串中的小写字母转换为大写
//str:要转换的字符串
//len:字符串长度
void litterTobig(u8 *str,u8 len)
{
u8 i;
for(i=0;i<len;i++)
{
if((96<str[i])&&(str[i]<123)) //小写字母
str[i]=str[i]-32; //转换为大写
}
}

字符串大写转小写

int8_t* CapToLow(int8_t* str)
{
int i;
for (i = 0; i < sizeof(str); i++)
{
if ((64 < str[i]) && (str[i] < 91)) //大写
str[i] = str[i] + 32; //小写
}
return str;
}

字符串命令处理

通常我们在串口收发或者上下位机的控制中,会使用字符串进行命令的下发,但我们的单片机肯定使用数值会更容易控制些,所以我们可以使用一个控制函数和一些宏定义来完成。

  1. 宏定义命令
//用于命令解析用的命令值
#define LED1ON 1
#define LED1OFF 2
#define BEEPON 3
#define BEEPOFF 4
#define COMMANDERR 0XFF
  1. 命令处理函数,将字符串命令转换成命令值
//str:命令
//返回值: 0XFF,命令错误;其他值,命令值
u8 CommandProcess(u8 *str)
{
u8 CommandValue=COMMANDERR;
if(strcmp((char*)str,"LED1ON")==0) CommandValue=LED1ON;
else if(strcmp((char*)str,"LED1OFF")==0) CommandValue=LED1OFF;
else if(strcmp((char*)str,"BEEPON")==0) CommandValue=BEEPON;
else if(strcmp((char*)str,"BEEPOFF")==0) CommandValue=BEEPOFF;
return CommandValue;
}
  1. 使用方式
Value=CommandProcess(CommandStr);   //命令解析

此时Value就是我们转换成的命令数值(1、2、3、4这类)

将某几位清0,并保留其他位的状态

使用”&= ~"进行清零。
我们以下面的程序为例:

uint32_t ultmp;
ultmp=0x12345678;
ultmp&= ~(0XFFFF0000);
printf("ultmp=0x%d\n",ultmp);

上述程序的作用就是将ultmp的高16位 置0,低16位保留.
最后输出的结果是0x00005678。

其他

  1. %*c表示忽略一个字符
  2. C++变量前面加下划线和不加下划线都不会影响对变量的定义,只是风格问题,更喜欢将成员变量或者私有成员变量的前面加上下划线。以表示该变量是某个类的属性。

后续

如果想了解更多物联网、智能家居项目知识,可以关注我的公众号了解更多。


标签:全局变量,变量,函数,编程,技巧,断言,str,嵌入式,define
From: https://blog.51cto.com/u_15260779/5807351

相关文章

  • 05markdown高级技巧
    markdown高级技巧1.支持html元素不在Markdown涵盖范围之内的标签,都可以直接在文档里面用HTML撰写。目前支持的HTML元素有:<kbd><b><i><em><sup><sub><br>等......
  • 满满干货!成人高考各科目答题技巧,必看完!
    成考专升本考试除了公共科目外,还有一些专业科目,比如大学语文、高数、医学综合、教育理论等,你对于这些科目的复习够了解吗?首先答题攻略一定要牢记!答题总体要求:会做的要做......
  • netty高性能编程-第1章 netty介绍和应用场景
    第1章Netty介绍和应用场景1.1Netty介绍Netty是由JBOSS提供的一个Java开源框架,现为Github上的独立项目。Netty是一个异步的、基于事件驱动的网络应用框架,用以快速开......
  • netty高性能编程-第2章Java BIO编程
    2.1IO模型I/O模型简单的理解:就是用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能Java共支持3种网络编程模型/IO模式:BIO、NIO、AIOJavaBIO:同步......
  • 编程开发-面试-数据分析视频教程阿里云盘资源大全
    编程开发-面试-数据分析教程合集6.6T(最全)Python编程教程合集(80套207GB)Java-30套Web-28套C-C++29套Go-15套Spring-29套Linux-10套面试通关人工智能_云计算R......
  • socket编程的常见问题
    英文小册原文地址:​​beej.us/guide/bgnet…​​作者:Beej中文翻译地址:​​www.chanmufeng.com/posts/netwo…​​1.我从哪获取这些头文件资料?如果你的系统中没有自带这些文......
  • 实验一 Java基础与结构化编程
     一、实验目的1.熟悉JDK开发环境。2.掌握JavaApplication的程序结构和开发过程。3.掌握Java语言基础。4.掌握分支语句。5.掌握循环语句。二、实验内容问题描述 掌握JavaApplic......
  • 并发编程
    并发编程并发:多个进程在某个时间,一起运行并行:多个进程在某个时刻,一起运行python中对并发编程的支持多线程:threading模块,利用CPU和IO可以同时执行的原理,让CPU不会干巴巴......
  • jquery 操作表格 jQuery操作表格(table)的常用方法、技巧汇总
    以下列出13个jQuery操作table常用到的功能:1.鼠标移动行变色$('#table1tr').hover(function(){$(this).children('td').addClass('hover')},function(){$(thi......
  • 9.Markdown高级技巧
    #markdown高级技巧##支持的html元素不在markdown涵盖范围之内的标签,都可以直接在文档里使用html来撰写 目前支持的html元素有:```<kbd><b><i><em><sup>......