jackduan 发表于 2025-3-18 15:07:36

检验和串口通信

#include "STC15W4K.H"          // 包含 "STC15W4K.H"寄存器定义头文件
#define FMBEGIN 0x7e         // 帧头标志   
unsigned char RecCount;                   // 串口接收计数器,全局变量在没有赋值以前系统默认为0.
unsigned char RecBuf;            // 接收缓冲区(数据长度:帧头+3字节数据+校验和)
unsigned char SendBuf;            // 发送缓冲区(数据长度:帧头+3字节数据+校验和)
/*********************************************/
//描述:串口初始化函数,使用T1方式2自重载方式做波特率发生器
void UART_init(void)
{                  
        // 下面代码设置定时器1
        TMOD = 0x20;        // 0010 0000 定时器1工作于方式2(8位自动重装方式)
        TH1= 0xFA;        // 波特率:9600 /22.1184MHZ
        TL1= 0xFA;        // 波特率:9600 /22.1184MHZ
        TR1= 1;
        // 下面代码设置定串口
        AUXR = 0x00;             // 很关键,使用定时器1作为波特率发生器,S1ST2=0
        SCON = 0x50;         // 01010 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允许接受)
        // 下面代码设置中断
        ES   = 1;                // 关键:开启了中断就必须编写相应的中断函数,哪怕是中断空函数,
                      // 但必须有,否则程序进入中断入口地址后(这里是0023H)不能跳出,必然出错
        EA   = 1;
}
/*********************************************/
//发送一帧完整数据
void sendcombytes(unsigned char *ptr, unsigned char len)
{
        unsigned char i;        
        for(i=0;i<len;i++)
        {
                SBUF=*(ptr+i);          
                while(TI==0);
                TI=0;
        }        
}
/*********************************************/
// 串口 中断服务程序
void UART1(void) interrupt 4
{
        if(RI)                              // 只处理接收中断
        {
                if(RecCount==5) RecCount=0; //如果已经接收了5个字符,主程序还没来得及处理又发来下一帧数据
                                          //则RecCount清零,覆盖上一帧数据,保证数据接收不错位
                RecBuf=SBUF;
                RI=0;                          
                if (RecCount==0)                // 判断帧头是否正确
                {
                        if(RecBuf==FMBEGIN)
                        {
                                RecCount++;
                        }
                        else
                        {
                                RecCount=0;
                        }
                }
                else
                {
                        RecCount++;
                }
        }
}
/*********************************************/
unsigned char CheckSum(unsigned char *ptr, unsigned char len)
{
           unsigned char i;
        unsigned char a;          
        unsigned int Value=0;
        for(i=0;i<len;i++)// len结束后第一个字节为接收到的校验和
        {
                Value = Value + ptr;   
        }
        a=Value;            // 长送短,传送完整低字节
        return(a);
}
/*********************************************/
void main(void)
{
        unsigned char i;               
        unsigned char CheckValue;          // 校验结果
        UART_init();                              // 串口初始化        
        while(1)
        {                       
                if(RecCount==5)    // RecCount是全局变量,表示串口已收到的字节数
                {       
                        RecCount=0;                                       
                        CheckValue=CheckSum(RecBuf,4);    // 接收缓冲区4字节校验(第5字节例外)               
                        if(CheckValue==RecBuf)         // 如果校验正确,数据加1后发回。
                        {                               
                                P00=!P00;
                                SendBuf=FMBEGIN;
                                for(i=1;i<4;i++)                          // 1、2、3、4、5字节中2、3、4为数据
                                {
                                       SendBuf=RecBuf+1;
                                }
                                CheckValue=CheckSum(SendBuf,4);// 1、2、3、4 字节参与校验
                                SendBuf=CheckValue;
                                sendcombytes(SendBuf,5);
                        }
                        else                                                          // 接收校验错误,发回帧头 + 4个aa。
                        {
                                SendBuf=FMBEGIN;
                                for(i=1;i<5;i++)                          // 1、2、3、4、5字节中2、3、4、5为数据
                                {
                                       SendBuf=0xaa;
                                }
                                sendcombytes(SendBuf,5);
                        }                       
                }
        }
}


国芯人工智能 发表于 2025-3-18 15:08:00

在嵌入式系统中,串口通信是一种常见的数据传输方式,而帧头标志、数据校验和等机制则是确保通信可靠性的关键。以下是对您提供的代码片段的简要分析:<br><br>1. 帧头标志定义:#define FMBEGIN 0x7e 定义了帧头标志为 0x7E,这是串口通信中用于标识数据帧开始的常见做法。<br><br>2. 全局变量声明:<br>   - unsigned char RecCount; 是串口接收计数器,用于记录已接收的字节数。该变量在未初始化时默认值为0。<br>   - unsigned char RecBuf; 和 unsigned char SendBuf; 分别用于存储接收和发送的数据缓冲区。根据注释,缓冲区长度应包括帧头、3字节数据及校验和。<br><br>3. 代码优化建议:<br>   - 建议对 RecBuf 和 SendBuf 进行数组定义,以明确缓冲区的大小。例如:unsigned char RecBuf; 和 unsigned char SendBuf;,以确保其能够容纳完整的帧数据。<br>   - 在串口接收中断服务程序中,应增加对帧头标志的检测逻辑,并在接收到完整数据帧后进行校验和验证,以确保数据的完整性和正确性。<br><br>4. 校验和计算:<br>   - 校验和通常为帧中所有数据的累加和取反或其他算法。建议在发送和接收数据时分别计算和验证校验和,以提高通信的可靠性。<br><br>通过以上优化和补充,您的串口通信代码将更加健壮和可靠。希望这些建议对您有所帮助!<br><br>[本文内容由国芯人工智能辅助生成,仅供参考]
页: [1]
查看完整版本: 检验和串口通信