囿于8051单片机的资源,在使用C语言进行编程的时候应当注重变量的使用以及某些特殊编程需求。

变量

与标准C语言开发不同,8051的开发请注意如下几点:

  • 8051内核的位数为8位,而非标准PC机的32位,二者资源的差异导致其在int与double类型上存在区别,如下图:

  • 受限于8051的资源,一般的开发中建议使用unsigned char替代char,unsigned int替代int来记录正值。一般遵守的变量选取原则为:占据最小空间,能完整满足需求。例如,在循环变量的表示中(小于255)一般采用unsigned char来减少资源占用。

  • 当进行多次循环设计(常见于延迟函数)时,注意使用嵌套而非单层循环,由此避免溢出。在下图的错误示例中69630超过了unsigned int类型所能够表达的范围造成溢出。

  • 以我使用的STC15F2K61S2为例,其RAM空间为2K,ROM空间61K。在实际开发中应该避免将大量的固定数据储存于RAM内,否则将会报错:

    1
    main.c(168): error C249: 'DATA': SEGMENT TOO LARGE

    应该将固定数据的定义更改为(关于code与data类型可参考文末):

    1
    uchar code sin_tab[60]={};
  • 应当尽量减少全局变量的定义,避免程序出错时产生严重的后果。

运算符

  • 8051内核执行乘除法的时间远大于加减法,频繁的乘除将会导致大量的资源浪费。
  • 在某些场合下只需要更改单个端口的电平,此时需要使用与或操作。

出于以上两个原因,我们在单片机编程中采用了较多的位运算符。

  • &(按位与):10001 & 10010 = 10000
  • |(按位或):10001 | 10010 = 10011,&与|的巧妙应用可以在一个字节中只改变个别端口电平,如该应用场景
  • ~(按位取反):~10001 = 01110,常用于取反端口电平,如~LED即可做到小灯闪烁。
  • <<(左移):思考如何快速将73乘以8,使用位移运算符73<<3即可。
  • >>(右移):快速将73除以8并取整,使用73>>3即可。

延时

在单片机的简单应用中,常常使用软件上的死循环来做到延迟。在STC-ISP中,配置好参数后可以快速生成延迟函数:

变量

局部与全局

  • 在函数内声明的变量即为局部变量,仅在函数内有效。
  • 在函数外声明的变量,可供所有函数使用。因为任意一个函数均可修改变量,所以应当避免过多使用全局变量,否则将会降低函数之间的独立性与清晰度。同时由于定义在全局,该变量将会一直占用RAM空间,增加内存消耗。

动态与静态

  • 不特殊声明的变量默认为动态变量(auto),调用函数时分配空间,结束时自动销毁。
  • 使用static声明的变量称为静态变量,在程序的生命周期仅初始化一次,当第二次调用时仍然保留上次的值。即能做到全局变量的生命周期(整个程序)而不影响其他函数的调用。

规范开发

  • 函数&变量定义
    定义应当完全避免拼音的使用,或者拼音+英文的使用。

  • 注释与缩进
    注释与缩进的使用均是为了增加程序的可读性,好的注释能够帮助你快速明白程序的结构与流程。
  • 模块化
    尝试将可以重复使用的模块封装为函数或者库,在调用的时候只需要调用函数,传入参数即可。例如常用的延迟函数,将其包装为函数,在需要的时候只需要加入语句delay(200)即可
  • 宏定义
    出于后期维护性与代码可读性,通常应当对某些具有特定意义的数字进行宏定义,从而避免开发到后期忘记了改数字的意义,举例如下:
    1
    2
    3
    4
    5
    6
    #define len 60
    ...
    ...
    ...
    uchar code sin_tab[len]={};
    uchar sin_tab_temp[len]={0};

其他

8051内部Memory类型

8051位操作