找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 11952|回复: 0
打印 上一主题 下一主题
收起左侧

MCU串口异步通讯过程中的奇偶校验和停止位深入研究

[复制链接]
跳转到指定楼层
楼主
ID:91442 发表于 2015-10-29 12:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在连续的高速异步通讯中,如果没有作为握手用的信号位,那么如何辨识一个字符帧的开始变成了难题。从一串连续的数字中找出字节的帧头,然后正确的识别出要传输的信息,除非做多次尝试,并且通讯双方约定好起始信息,方可正确传输信息。此时,为了让信号有较为明显的辨识信息,增加奇偶校验位,以及加长停止位的长度,都是一个提高帧起始判定的一种方法。

在波特率为115200的设置下,如果采用N,8,1的标准设置,可以从下面的波形图中看出,如果连续发送字符0x55,则停止位到下一个起始位之间的脉宽是11.12us, 而标准的数字位的脉宽是8.83us。如果在两个数据的发送之间没有其他延时信号,则可能无法分辨出那一个位是一个字符帧的起始位,从而导致后续其它字符的帧错误。这样在使用软件方法做串行数据接收时,就会出错。


图1,在波特率115200时,标准位脉冲宽度为8.83us


图2,在波特率115200时,停止位到下一个起始位的宽度可能更小,这里是11.12us。


图3,出现帧判别错误的情形(这里是奇偶校验设置不正确导致)。

为了解决这个异常,可以通过加长停止位的方法,提高软件对起始位的识别几率。因此上可以将常用的1个停止位,增加到1.5个或2个位长度。对于长线传输,为了检查传输过程中信号是否受其他干扰而导致的翻转,又在停止位之前,插入奇偶校验位的方式,协议商定传输的1的个数是奇数个或者偶数个,然后通过插补的方式确定每帧的情况相同。这样,如果在接收端发现帧错误,可以及时检查出来。

使用C51的发送程序:
sbit TXB = P3^1;
sbit RXB = P3^0;
bit bUartBusy; //串口正在使用的标志
unsigned char bEven; //用来计算偶校验的和
#define ON 1
#define OFF 0

// #define EVENPARITY
//#define STOP2BITS

void SendChar(unsigned char c)
{
    unsigned char nCnt;
   
    TXB=0; //串口起始位开始
    TR0 = 1; //定时器0开始计时
    ET0 = 1; //使能定时器0中断
    bUartBusy = ON;      
    //bUartBusy 在Timer0的服务程序中设置为OFF
    while(bUartBusy == ON); //维持当前TXB的电平,直到下一次中断到来。输出一个位宽的数据。
    //由低位开始,将数据通过串口输出
   #ifdef EVENPARITY    //如果定义偶校验
   bEven=0;           //偶校验的初值为0.
   #endif
    for (nCnt = 0; nCnt < 8; nCnt++) {
        TXB =c & 0x01;  //输出最低位
#ifdef EVENPARITY
        bEven = bEven + (c & 0x01); //偶校验计算,把所有的1加起来
#endif

        c >>= 1;  //右移一位,准备在下个周期中输出
        bUartBusy = ON;
       while(bUartBusy == ON);
    }
#ifdef EVENPARITY
    TXB=bEven & 0x1;   //取1的个数和作为偶校验结果位发送。
    bUartBusy = ON;
    while(bUartBusy == ON);
#endif
    TXB = 1; // 发送第一个串口停止位  
    bUartBusy = ON;
    while(bUartBusy == ON);
#ifdef STOP2BITS    //如果定义2位停止位
    bUartBusy = ON;         //发送第2个停止位
    while(bUartBusy == ON);
#endif
    TR0 = 0; //定时器0结束计时
    ET0 = 0; //禁能定时器0中断   
}
定时器Timer0的中断服务中,仅仅完成标志设置,确保每个数据位发送的延迟时间准确。
void Timer0ISR(void) interrupt 1 using 1
{
    EA=0;
    bUartBusy=OFF;
    EA=1;
}
关于定时器的工作模式和时间间隔设置如下:
void uartInit(void)
{
    AUXR |= 0x80; //Timer0为1T模式
    TMOD &= 0xF0; //设置Timer0为模式0(16位自动重装载)
    //设置Timer0的计数器初值
    TL0 = (0xFFFF - MCUFREQ / UARTBAUD) & 0xFF;
    TH0 = ((0xFFFF - MCUFREQ / UARTBAUD) >> 8) & 0xFF;
    TR0 = 0;
    ET0 = 0;
    EA = 1;
}

其中:AUXR 为特殊功能寄存器,地址为0x8e。
sfr AUXR=0x8E;
#define MCUFREQ   11059200  //系统主频为11.0592MHz
#define UARTBAUD 115200      //串口通讯的波特率

此时,数据的波形变化如下:

取其中的一个字符分析如下:完整的字符帧包括8位数据位,1个起始位,1个偶校验位,2个停止位。示意图如下所示。


在数据接收时,在双方的发送接收参数都协商好以后,通过对重复的停止位,校验位进行确认,就可由大量数据中判定出数据的起始位等信息。否则,需要定义握手信息来确认是否通讯正常。

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表