开发环境问题
1. CH340串口识别失败(22.12.17)
- 用数据线连接好,打开设备管理器,检查端口(COM),是否有
CH340
字样的串口。若无,则说明串口未正确识别。 - 检查CH340驱动是否安装或更新。
- 更换数据线再次尝试。有的数据线接口看似有5个pin(如Micro USB),但实际剪开只有两根充电线,没有数据传输功能,没有差分信号,自然无法识别串口。
- 换一个电脑的USB接口进行尝试,有可能是接口质量问题。
- 检查USB转TTL电路是否有虚焊,损坏。(一般不会)
2. Keil5 如何兼容C51和STM32(22.12.17)
- 进入官网,对于51单片机和STM32单片机有两个版本。
- Keil uvision5(MDK-ARM) : Development environment for Cortex and Arm devices. 为Cortex内核和ARM内核设计。
- Keil uvision5(C51) : Development tools for all 8051 devices. 为51内核设计。
- 将两个版本都下载至同一个目录下即可同时使用。
3. 如何创建C51工程模板(22.12.17)
- Keil4:找Atmel公司的AT89C52芯片即可。
- Keil5:找Microchip中的AT89C51/AT89C52即可。
4. 如何修改字体大小(22.12.17)
- 打开Keil,点击最右侧扳手图标,点击Font选项卡,选中C/C++,修改对应字号。
- 若出现"access to xxxx global.prop was denied"的字样,关闭Keil,以管理员身份运行Keil重复上述操作即可。
5. Keil的 “0xFD” Bug(23.03.04)
在一次偶然的串口通讯过程中,汉字"数" 始终无法正确显示,经验证是 Keil 的历史遗留 Bug。
汉字机内码以 0xFD 结尾的部分汉字会被截尾(如数,正,过等),甚至影响到后面汉字的正常显示。应尽量避免使用上述汉字。
6. Keil中文不显示或乱码或显示问号(23.08.23)
在 Edit 选项卡中,选择Configuration,设置 编码方式 Encoding为UTF-8 或GB2312。
实测Keil中ANSI编码与当前系统编码并不一致。实测环境Windows系统,在Keil编辑器中打开GBK编码可以正常显示,但输入汉字会显示问号,实际只接收了单个字节。这应该是Keil的一个Bug。
7. Keil串口传输中文乱码问题(23.09.02)
现象为单字节数据传输或英文字符传输正常,排除串口程序问题。问题定位至文本编码方式不一致问题。
发送汉字 “开”,通过查询,其GBK
编码为0xBF 0xAA
,Unicode
编码为0x5F 0x00
,UTF-8
编码为0xE5 0xBC 0x80
。
串口助手以HEX
方式打印,结果为0xE5 0xBC 0x80
,说明Keil 编码方式为UTF-8
。
常用的串口助手一般不支持UTF-8
编码,而支持GBK
编码。至此问题清晰了,发送端的编码方式和接收端的解码方式不一致,导致解析出来的中文乱码。
解决方案:将Keil的编码方式改成GB2312,并确认源文件的编码方式为ANSI(GBK),可打开为记事本另存为修改。或者找一款支持 UTF-8编码的串口助手。
8. Keil中文字体美化(23.09.02)
在UTF-8
编码格式,可以使用默认的Courier new
等字体。但编码方式改成GB2312后,大部分字体修改失效。
解决方案:
- 下载新字体文件,YaHei-Consolas-Hybrid 。提供
git
命令。git clone https://gitee.com/a42/YaHei-Consolas-Hybrid-1.12.git && sh YaHei-Consolas-Hybrid-1.12/setup.sh && cd - && rm -rf YaHei-Consolas-Hybrid-1.12
- 双击字体库文件
.ttf
,点击下载。字体会下载到系统字体库中。 - 重新打开Keil,设置
Edit
-Configuration
-Color&Fonts
-C/C++ Editor Files
-Font
-YaHei-Consolas-Hybrid
注意,前缀为@
的字体,会使汉字 90°旋转。
9. Keil导入STC选型文件和头文件(23.10.05)
下载并打开STC公司的STC-ISP软件,选择Keil仿真设置选项卡,点击添加型号和头文件到Keil中字样的按钮,选择Keil安装的根目录,即完成头文件的导入和选型数据文件的导入。
- 在新建工程时,我们可以直接选择对应STC型号的芯片,当然也可以继续选择AT89C52。
- 在包含头文件时,我们可以根据芯片选择包含STC提供的头文件,当然也可以继续选择包含
<REG51.H>
或<REG52.H>
。
C51语法细节问题
C51
使用C51优化C编译器(C51 Optimizing C Compiler
),基本完全兼容(ANSI)C语言标准,但对某些方面进行了更改或增强,为8051微处理器生成极其快速和紧凑的代码,具体可参考【51单片机实验笔记】前篇(三)C51语法新扩展总结 。
1. 将浮点数或整数转化为字符串方案(23.03.04)
使用 sprintf 字符串格式化函数,格式为
#include <stdio.h> // 需包含头文件
char strA[10]; // 保证一定长度,用于保存字符串
char strB[10];
char strC[10];
sprintf(strA, "%d", 123); // 整数转换字符串
sprintf(strA, "%u", 65530); // 整数转换字符串,指定按无符号解析
sprintf(strC, "%0.6f, 3.141593"); // 浮点数转换字符串
需要注意:在整数转换时,"%d"指 int 类型,占两字节(Keil编译器中),故传递整数时也应传递两字节的整型。如果误输入常用的 unsigned char 类型(仅占1个字节),会导致转换结果异常。
2. 位运算符优先级问题(23.08.08)
return tempH << 8 + tempL; // 先执行加法,而非左移
return (tempH <<8 ) + tempL; // 先执行左移
事实上
- 左移
<<
、右移>>
运算符优先级均低于加+
、减-
,均高于大于>
、小于<
,列表达式时需要加括号。 - 按位与
&
、按位异或^
、按位或|
优先级逐次降低,均低于关系运算符。
3. 数码管不显示“0”的异常bug(23.08.09)
现象为其他字符均正常显示,但字符0
始终不显示。
原因为字符串结束符'\0'
的ASCII为恰好为0
,因此在数码管显示函数中遇到0
误作字符串结束标志,直接退出,导致字符0
无法正常显示。
解决方案:输入字符0
的ASCII即可。
4. C51中数据类型字节数问题(23.09.03)
C语言中的数据类型所占字节数由硬件平台决定。
C51规定int
类型占2
字节,而在PC端通常占4
字节。
bit数据类型问题(23.09.03)
大小端问题
union w{
int a;
char b;
}c;
c.a = 1;
if(c.b ==1){
Uart_sendString("小端");
}else{
Uart_sendString("大端");
}
常见警告信息
未调用函数警告(22.12.19)
*** WARNING Lxx(行号): UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS SEGMENT: ?PR?xxxx(函数名)?MAIN
如果你定义了一个函数,但并没有调用它,就会产生这个警告。这在标准C编程中一般不会警告。我猜测是单片机的RAM资源相对紧缺,通过该警告可以提示编码人员精简无用代码。
永远无法执行代码警告(23.08.08)
warning C294: unreachable code
指逻辑上永远无法被执行的代码。理论上并不影响程序运行,但偶然发现该警告会导致串口通讯异常。以此记录。
重复定义警告(23.09.01)
xxx.c(4): warning C231: 'xxxx': redefinition
即编译器发现重复定义的同名变量时会发出此警告。一般由以下三种原因引起:
- 函数声明未指定返回值类型。在C51中类型缺省为
int
,当函数实现的类型与之不符时,产生警告。例如func1(void);
- 命名了与C文件中或头文件中同名的变量,但数据类型不同,产生警告。检查自定义的变量名是否有冲突。
- 外部声明时,缺省了数据类型,在C51中产生此警告。例如
extern para1;
因此,先确认是否有变量名冲突,其次检查声明是否明确了数据类型,即可解决此类警告。
常见报错信息
变量定义报错(22.12.19)
main.c(xx): error C141: syntax error near 'int', expected 'sizeof'
-
首先检查有没有犯弱智错误:括号,分号是否漏打。
-
如果语法没有问题,那么一般是编译器的差异导致的。Keil编译器遵循的是比较古老的C标准。在函数定义的内部,必须把所有的局部静态变量和自动变量都声明了之后,然后才能开始后续的代码书写,否则编译器会报错。
-
举个栗子,在标准C中,我们可以变量定义写在for循环里。
for(int i = 0; i < 10; i++){ // 正常运行 }
然而在Keil中,这么写就会报上述错误,导致变量未正确定义,后续只要使用到该变量就会报 undefined identifier 的错误(可能会产生一大堆)。
所以应该更正为
int i; //先定义变量 for(i = 0; i < 10; i++){ //正常运行 }
文件类型导入错误(23.3.13)
FCARM - Output Name not specified, please check ‘Options for Target - Utilities
用户的.c
和.h
文件被导入 keil 时有可能会被识别成 image file 文件(图标与正常C文件不同)。选择对应文件右击选择Options for File
,在File Type
选择正确的文件类型。
地址溢出错误(23.09.03)
*** ERROR Lxxx: ADDRESS SPACE OVERFLOW
51单片机编译时有三个参数
data
:共128字节,片内RAM区xdata
:共128字节,片外RAM区code
:共8KB,ROM区
注意缩减无用代码,以节省内存空间。
变量初始化不明确错误(23.09.03)
error C247: non-address/-constant initializer
定义的变量没有用明确的常量进行初始化。不要把需要计算的宏定义等未决的常量赋值给新定义的变量,否则报错。
重复定义错误(24.02.13)
*** ERROR L104: MULTIPLE PUBLIC DEFINITIONS
此错误一般是在头文件中定义变量造成的。在头文件中一般只做声明,不定义变量。因为头文件可能会被多个源文件引用,从而产生重复定义的错误。
如需将该变量扩展至其他文件,应在头文件中用extern
关键词声明。