51单片机串口通信异常的调试一例
- 格式:doc
- 大小:2.39 MB
- 文档页数:3
51单片机串口通信异常的调试一例
单片机与DSP在硬件结构和程序编写方面存在很多共同之处,所以最近几周试着用了一下51单片机开发板,希望进一步熟悉中断的概念、串口通信、I2C协议、存储扩展等常用的知识。
在进行串口通信的实验时,预期功能不能实现。实验的设计方案是:通过上位机给单片机发送一个16bit的字符串,单片机对字符串进行接收并立刻回显给上位机,接收并回显完毕后依次将这些字符(只能是0-9,a-f这几个字符,可以重复)在数码管上进行显示。
程序编写完成后,通过上位机发送字符串9876543210abcdef,单片机串口接收并回显9876543210abcde,然后数码管依次显示f9876543210abcde,数码管显示完成后,单片机串口回显的字符串中的e后面又多了一个f。
对实验现象进行分析不难发现,串口的接收和回显功能正常,但是存在2个问题:1.串口接收并回显和数码管显示的时序有点混乱;2.数码管的显示出现异常,本应该依次显示9876543210abcdef,实际上显示的却是f9876543210abcde。
对源代码进行分析发现,时序混乱的原因是中断响应及中断返回的执行时序出现问题,修改代码后问题1被解决。
问题2的解决思路:源代码中,通过串口接收到的字符串被存储在一个一维数组array[16]中,该数组有16个元素,每个元素都是unsigned char型。在源代码中,先注释掉数码管显示的那一段代码,然后添加串口打印代码,串口打印实现的功能是依次显示array[0]到array[15]这16个元素的值。编译通过后,将程序烧写到单片机。使用串口调试助手,以十六进制的形式观察array[0]到array[15]的取值,结果如下:
也就是说array[0]存储的值用十六进制显示是0xff,
array[1]=9
array[2]=8
……
array[14]=d
array[15]=e
很明显可以看出array[0]没有按照预期的那样存储字符9。也可以理解为本应存储的字符串9876543210abcdef在存储时发生了1个字节的偏移,在字符串首部插入了一个0xff。
检查代码发现串口初始化时,串口控制寄存器SCON的设置有点问题:
正确的顺序应该是:
通过SM1和SM0来设置串口的工作方式,通过REN置1来设置允许串口接收。单片机上电复位的时候,SCON清零,REN=0标明禁止串口接收,原来的代码中,先用REN=1
允许串口接收(此时SM1=0;SM0=0串口在工作方式0,是同步移位寄存器),然后设置串口工作方式1(SM1=1;SM0=0)。也就是说,在串口按照预期方式进行接收数据之前,已经开始作为同步移位寄存器对数据进行接收了,接收到的数据0xff就是单片机串口接收SBUF的初值,开发板上使用的单片机型号是STC89C52RC,查阅该芯片的datasheet发现,SBUF的初值是不确定的,规定为xxxx,xxxx(x既可以是0也可以是1)。多次实验经验表明,STC89C52RC型号的单片机在上电复位后,接收SBUF里面的初值通常是11111111。
将源代码中对SCON进行设置的那一部分做个调整,调整为先设置SM1和SM0,再将REN置1,编译通过后将程序烧写到单片机,运行,问题解决。
正常运行时,串口回显的数据如下图所示:
串口调试总结:
1.编写程序之前,先画程序流程图;
2.串口初始化的每一步过程都必须很清楚,串口的4个工作方式都要熟悉;
3.在程序运行结果出现异常时,首先要对异常现象进行仔细分析,进行异常定位;
然后逐一解决。对照着源程序进行功能模块划分,查找与异常相关的模块并对其
进行单独调试。