张飞实战电子

  论坛   硬件电路   单片机 C51 编程要点总结
返回列表
查看: 4557|回复: 0
收起左侧

单片机 C51 编程要点总结

[复制链接]

78

主题

81

帖子

403

积分

版主

Rank: 7Rank: 7Rank: 7

积分
403
发表于 2018-8-1 19:32:59 | 显示全部楼层 |阅读模式
1、头文件:#include (我用的是 STC 89C54RD+)
2、预定义:sbit LED = P1^0  // 定义 P1 口的 0 位为 LED  
注:“P1^0”这个写法,与 A51 不同(A51 是 P1.0),P1 是一组端口,端口号范围 0~7
注2:sbit 用于定义 SFR(特殊功能寄存器)的位变量,上例中 LED 作为“全局变量”进行定义
注3:以下写法是错误的:

sbit code table[ ] = {P1^0, P1^1, P1^2, P1^3};  // 想用 table 指定不同的引脚,但这么做会报错

sbit table[ ] = {P1^0, P1^1, P1^2, P1^3};            // 考虑到上面可能是 code 关键字使用错误,使用标准 C 数组写法,但这同样是错的

3、主函数写法:void main (void)
4、数值的表示:

P1 = 1111 1111       // 二进制
P1 = 0xff 或者 P1 = 0xFF   // 十六进制,0x 开头,且数值不分大小写
P1 = 255          // 十进制

5、定义小数值时,可以使用 unsigned char i,这样 i 的范围为 0~255,作为循环变量比较好用
6、左右移位:

P1 <<= 2 等价于 P1 = P1 << 2  // P1 左移 2 位,左移一位相当于乘以 2
P1 >>= 3 等价于 P1 = P1 >> 3  // P1 右移 3 位,右移一位相当于除以 2

注:左右移位默认为“逻辑移位”,即无论左移还是右移,空位都补 0

7、按位与或:
P1 = P1 & 0x01
P1 = P1 | 0x01
8、定义 ROM 表格(就是数据为常量的数组):

unsigned char code table[ ] = {0xff, 0xff, 0xff, 0xff};

使用:P1 = table

注:table[ ] 定义为“全局变量”,上例中 i 的范围为 0~3

注2:code 定义的常量存于“代码区”,即 ROM 区,可以节省 RAM 空间

9、在使用数码管编程时,假如你正在使用 temp 代表某一个显示字符,突然想显示小数点,可以使用 temp | 0x80,通过“或”运算实现加上小数点……

10、如果你用 Keil C51 进行编译,记住一点:它不区分大小写!!!卧槽,今天编程序那个调错啊,就因为一个数组名和一个变量名完全一样,只是大小写不一样罢了,标准 C 我怎么记得这样可以啊……上网一查,卧槽,Keil C51 不区分大小写,准确的说是“连接的时候不区分大小写”,更准确一点就是“具有外部连接的变量区分大小写,内部连接 static 区分大小写”……至少 Keil uVision2 是这样,不知道别的版本是不是,待验证……

11、没有 unsigned float x !float 型变量从来没有前边加 unsigned 的语法!

12、Keil 编译的程序,main 函数执行完不会停止,会循环执行 main 函数,何解?

结论 1:如果主程序中没有 while(1) 这个无限循环,程序走到最后会再次从头开始执行。
结论 2:如果主程序有 while(1) 这个无限循环,程序走到最后会一直在这个死循环中运行,不会出现再从头执行的情况。

这应该属于 Keil 编译器的 bug,有网友做过实验,表示 Keil 编译后期产生的汇编代码中,结尾有一条 LJMP main,意思就是跳到 main 函数重复执行……还有一种说法是 PC 指针溢出,溢出后的地址指向开头,造成继续执行的效果……(博主觉得还是 Keil 的问题,要是 Keil 编译器不产生 LJMP main 这种语句,也不会产生循环效应……)

不管怎么说,在程序结尾加上 while(1) 能够解决循环执行 main 函数的 bug……

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

收藏:3 | 帖子:240

有图有真相