最近在学校用
单片机做一个小项目,在涉及到串口
通信这部分是遇到了一些问题,希望
论坛的前辈们可以给我一些指点。 单片机串口通信分为接收与发送两种情况,其数据单位都是1个字节。也就是说,每接收/发送一个字节,单片机的RI/
ti位会置1从而选择是否进入中断。以最基本的使用“串口助手”实现PC与单片机的串口通信为例:
如图是PC从串口助手发送一个字符到单片机,再由单片机返回该字符的例程结果。该字符'1'的数据流图应该是从PC端进入到单片机的SBUF寄存器中去,当单片机接收到该字符的结束位时,单片机将RI置1,表示接收完毕。同理,在发送到该字符的结束位时,单片机将TI置1,表示发送完毕。
但当发送多个字符的情况时,我对串口通信的数据传输过程有了疑惑:
如图,当从PC发送多个字符时(
问题1:这里是否可以理解为字符串的串口通信),仍然可以完美的实现PC与单片机之间的数据互通。而程序仍然与之前一样没有改动(总程序见下)。这时我产生了疑惑,就单片机而言,无论接收还是发送,都是以一个字符为单位进行操作,当面对多个字符的传输时,它是先将所有字符依次接收到SBUF中去,然后将接收到的多个字符再依次发送出去?还是每接收一个字符,就立马发送一个字符?(
问题2:是实时传输单个字符还是缓存所有数据后再进行处理),比如在处理“1a!”时,当单片机SBUF接收到'1',立刻就将'1'从SBUF中发送出去,然后再对'a'进行接收......
我认为是后者的情况,因此我想利用LCD1602进行验证。我的思路是:既然单片机是每接收一个字符,就发送一个字符,那我可以定义一个数组,在单片机的接收中断中(由RI==1触发的中断)存储每次SBUF接收的数据,为了验证方便,我假设每次传输的都是3个字符。中断程序如下:
#define DATA_LENGTH 3
uchar Receivedata[];
uchar ReData,Flag1,Flag2;
uint i,j;
void ser_int (void) interrupt 4
{
if(RI == 1)
{
RI = 0;
ReData = SBUF;
Receivedata
=ReData;
i++;
if(i==DATA_LENGTH)
{
i=0;
Flag1=1; //代表3个字符接收完毕
}
Flag2=1; //代表当前字符接收完毕
}
}
如果说单片机是每接收到一个字符就发送它,按照这个中断,最后Receivedata[]应该是一个存储了“1a!”长度为3的字符类型的数组。
接下来我们只要将数组中的字符元素依次显示在LCD1602上就可以证明猜想,以下为主程序:
void main (void)
{
init_time(); //初始化定时器中断
init_1602(); //初始化LCD1602
write_com(0x80); //选定开始显示的位置是第一行第一列
while(1)
{
if(Flag2==1)
{
SBUF = ReData;
while(TI==0);
TI=0;
Flag2=0;
if(Flag1==1)
{
for(j=0;j<3;j++)
{
write_dat(Receivedata[j]);
}
Flag1=0;
}
}
}
}
但最后程序烧录后结果并不理想,当从PC送入三个字符时,LCD并不能正常显示这三个字符,而且串口助手接收也出现了问题。
验证行动就此夭折,出现这种情况,首先说明数组Receivedata中并没有正确的存储SBUF中的字符。另外在增加LCD显示模块的过程中,影响了串口通信的准确度。
在此,我希望仔细看过该问答的前辈们指出我的错误,或者回答上面红字标出的问题。另外,新的问题也从验证的过程中产生(问题3,如何将多个字符或者字符串完整的存储下来或进一步显示在1602上?)
在我编程的过程中一定忽视了一些致命的问题,恳请赐教!
您回复中的“处理”我是否可以认为成这里我想将接受到的几个字符显示在LCD上?
我对您提到的第二种实现方式很感兴趣。您的意思是否可以通过下面的做法实现:可以再接受串口终端(RI==1)中加一个判断语句,if(SBUF接收到的数据为' '),则关闭串口中断(ES==0;),然后在主程序中对之前在串口中接收到的缓冲区数据(Receivedata[])显示在LCD上,显示完毕后再将ES打开。
至于我在文中的验证,实际上我程序中已经加上下标了,但仍然是文中图片的症状。
感谢您的回复!
一周热门 更多>