嵌入式C语言编程遇到的问题

嵌入式C语言编程遇到的问题

使用mdk5仿真

新建mdk工程,这里我们选择ARMCM3内核,并在Manage Run-time Environment界面勾选CMSIS的core和Dvice的startup。然后在Source Group1Z中添加main.c文件和debugprint.c文件。
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在debugprint.c文件中输入如下代码:

#include <stdio.h>
#define ITM_Port8(n) (*((volatile unsigned char *)(0xE0000000+4*n)))
#define ITM_Port16(n) (*((volatile unsigned short*)(0xE0000000+4*n)))
#define ITM_Port32(n) (*((volatile unsigned long *)(0xE0000000+4*n)))
#define DEMCR (*((volatile unsigned long *)(0xE000EDFC)))
#define TRCENA 0x01000000
struct __FILE { int handle; /* Add whatever you need here */ };
    FILE __stdout;
    FILE __stdin;
int fputc(int ch, FILE *f) 
{
    if (DEMCR & TRCENA) 
    {
        while (ITM_Port32(0) == 0);
        ITM_Port8(0) = ch;
    }
    return(ch);
}

配置工程为仿真模式:点击,选择debug栏选中Use Simulator,选择Target栏下选中
Use MicroLIB。

在这里插入图片描述
在这里插入图片描述

利用仿真分析实际问题

1.在main.c文件中添加下图中代码,按如下步骤进行仿真

在这里插入图片描述

这个程序理论上得到的值是 fun1=2,fun2=3 ;fun2=3,fun1=2 。 但我们可以看到得到的结果跟理论值不同,这是因为我们在两个函数中定义了相同的变量,而printf函数是沿着“右→左”运算的,所以把右边的运算结果被当做变量附给了左边,以第一个函数为例,先执行fun2(),cnt_var=3,再执行fun1(),cnt_var=3+1=4。所以得到如上结果。所以在编辑程序的时候,切忌将函数的结果作为另一个函数的变量。

2.在main.c中输入下图中代码,进行仿真

在这里插入图片描述
仿真结果如下:
在这里插入图片描述
理论上得到的结果是a=1,b=1;因为在条件执行过程中,前一个条件已经能够判断,导致后面函数没有执行,所以出现如上结果,所以在编程时不要把赋值语句用作条件。

3.在main.c中输入下图代码,进行仿真,仿真结果如图

在这里插入图片描述在这里插入图片描述
我们把语句b=*p++改为b=(*p)++,再进行仿真,结果如图

在这里插入图片描述在这里插入图片描述

我们发现两次仿真的结果 * p的值是不一样的,这是因为 * 和++的优先级不同导致,前者是按从右向左先运算p++,再运算 * ,相当于*(p++),就是把指针p指向的地址移位; 后者则相反,是把p地址内的值加一,所以,我们在编程的时候要注意运算符优先级顺序,否则可能导致与我们的预期不符,应适当加圆括号,但不可过多使用括号分散代码。

4.另外,在布尔值表达式中不要使用赋值操作,当需要的时候,赋值操作要在布尔值表达式外进行,可避免“=”与“==”混淆。
5.性能优化—减小运算强度的方法
(1)、查表法,对一些需要用到的运算事先建立一个表格,需要用到的时候使用查表的方式替代运算,能够优化代码的运行效率。
(2)、使用位操作,比如取余:a=a%8可改为a=a&7,位操作只需一个指令周期即可完成,而大部分C编辑器的“%”运算均是调用子程序来完成,代码长、执行速度慢。通常只要是求2的n次方的余数,都可使用位操作。此外还有交换a、b的值可用三次位操作实现a^=b ; b^ =a; a^=b。还有类似的乘除运算,平方运算等,如下举例:

		y=pow(x,2);
		z=y*33;
		for(i=0;i<n;i++)
		{
		h=5*i;
		printf(“%d”,h);
		}

常改为

y=x*x;
z=(y<<5)+y;
for(i=0,h=0;i<n;i++)
{
h+=5
printf(“%d”,h);
}

下边相对上边的运算效率就会提高很多,所以在编程时要注意适当减小运算强度
(3)、使用增量和减量运算符,在使用加一和减一的操作时尽可能地使用增量和减量运算,回避赋值语句快很多(增、减量运算符的前置和后置运算在重载时是不同的)。
如通常使i用i++或i–,而不是i=i+1或i=i-1。
6. 性能优化—优化编译
虽然编译器已经很智能,但对于高级语言的解释优化能力还远远达不到人脑的等级,所以我们需要用到一些优化。
比如循环的优化,我们先看一个例子:

在这里插入图片描述在这里插入图片描述
该程序的作用是将字符串中的大写字母改为小写字母,我们可以看到此程序的第8行有”i<strlen(str)”,该语句是获取字符串长度,由于字符串的长度在运算过程中不变,所以不必要每做一次循环运算一次,我们可以在循环外计算其值,这样就会大大提高运算效率。
7.使用宏定义开关打印
在程序的编写调试过程中,总会使用printf之类的语句,但当程序发布的时候为了某些原因还要删除这些语句,再次编写还要加回去,所以很浪费时间,所以使用宏定义的方式定义调试语句。
代码如下:


#define DEBUG 
//#undef DEBUG 
#ifdef DEBUG  
#define dmsg(format,...) printf(format, ##__VA_ARGS__)  
#else  
#define dmsg(format,...)  
#endif 


int main() 
	{  
    char str[] = "Hello";  
    dmsg(" %s",str);  
    return 0;  	
	} 

当我们需要使用输出语句时打开DEBUG开关(#define DEBUG),所有的dmsg会替换成printf语句,仿真后我们可以看到仿真界面打印出了我们要打印的字符串

在这里插入图片描述
当我们不需要该功能时,只需将#define DEBUG改为#undef DEBUG就可以关闭DEBUG开关了,此时dmsg会被替换成空,因此不被编译。仿真结果如下:

在这里插入图片描述
我们可以看到程序没有执行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值