本帖最后由 通宵敲代码 于 2017-1-4 15:25 编辑
原文链接:http://bbs.mydigit.cn/read.php?tid=1249525
这个命题最开始诞生于前段时间玩SIM900A的时候,接收AT指令的反馈时需要串口接收字符串,根据官方文档,上位机或MCU发送AT指令的格式为“AT+指令+CRLF(换行符)”,返回的字符串也以CRLF结尾。但是实际使用时发现,如果开启回显,模块的返回为“AT指令+CRLF+反馈+CRLF”,如果关闭回显,则返回为“CRLF+返回+CRLF”,头尾各一个CRLF叫我很是头疼,最后,我写了这样一个小函数解决问题。
以下使用51单片机为例。
首先,定义全局标记变量:
BOOL UART1RING = FALSE;
然后是串口接收的缓冲池与指针:
BYTE UART1RBUFF[64] = {0};
BYTE *UART1RBUFFP = UART1RBUFF;
然后在串口中断服务函数中的接收部分编程如下:
void UART1INTERRUPT() interrupt 4 using 1
{
if (RI)
{
RI = 0;
*UART1RBUFFP++ = SBUF;
*UART1RBUFFP = 0x00;
UART1RING = TRUE;
}
if (TI)
{
TI = 0;
UART1SING = 0;
}
}
然后编写如下函数:
void UART1ReceiveString()
{
UART1RBUFFP = UART1RBUFF;
*UART1RBUFFP = 0x00;
UART1RING = FALSE;
while(!UART1RING);
while(!UART1RING)
{
UART1RING = FALSE;
DelayXms(2); //延时,等待重新检测标志位
}
}
上面的程序,如果有细心的朋友应该已经看懂了,原理就是设定一个标志位,在每次串口因接收触发中断时,将标志位设定为TRUE,然后检查函数每隔一段时间会检查该变量并重新置为FALSE并延时等待下一次检查,直到检测到这个标记变量为FALSE,则视为接受结束。延时的长度根据波特率而定,实验程序以9600波特率计,9600bps即每秒9600个二进制位,程序设定为八个数据位,一个停止位,无校验位,所以每个字节8位,加上起始位和停止位共10位,也就是每秒960字节。每字节间隔理论值约1.042ms(1000/960),也就是说,延时的长度应该高于每字节传输时间间隔的理论值,串行中断是每接收一字节触发一次而不是每接收一位触发一次。
指导思想:接收超时,即指定时间内未接受到下一个有效字节,则视为本次接收结束。
本算法经实际验证可用,每次向SIM900A发送AT指令后,随即执行此函数,然后将返回的字符串开头的非字符字节和结尾的非字符字节移除,再判断内容并作出相应动作。但是本算法的一个致命缺陷在于,无法随机接收,每次必须执行接收函数,在程序准备好后才能做出有效的接收,如果想处理随机的串口事件,这个算法就显得力不从心了。
|