基于串口的简单通信协议
2013-11-04 23:32
645 查看
发一个基于串口的简单通信协议(在TMS320F2812上实现)
可变帧长
可选的CRC校验
基于状态机的接收机制
这个简单的通信协议可以选择加入计时器后,设置超时时间,然后让状态机到0状态。
可变帧长
可选的CRC校验
基于状态机的接收机制
/* * ==== SciA模块实现串口 ==== * * 使用函数Sci_puts()函数发送unsigned char[] 数组 * 设置回调函数set_RXAHook()接收串口数据 * * Author: hexingshi * Date: 2012-2-25 */ #include "lib/DSP28_Device.h" void Init_Gpio_Sci(); void Init_SciDevice(long baud); interrupt void SciRXA_ISR(void); interrupt void SciTXA_ISR(void); void Sci_puts(unsigned char * str, unsigned char num); /* * == 初始化SciA模块 == * 使用前必须使能SciA时钟 SysCtrlRegs.PCLKCR.bit.SCIENCLKA = 1; * LSPCLK时钟必须为37.5MHz SysCtrlRegs.LOSPCP.all = 0x0002; */ void Init_Sci(long baud) { Init_Gpio_Sci(); Init_SciDevice(baud); EALLOW; PieVectTable.TXAINT = &SciTXA_ISR; PieVectTable.RXAINT = &SciRXA_ISR; EDIS; PieCtrlRegs.PIEIER9.bit.INTx1=1; //使能PIE模块中的SCI接收中断 PieCtrlRegs.PIEIER9.bit.INTx2=1; //使能PIE模块中的SCI发送中断 IER|=M_INT9; //开CPU中断 } /* * == 设置SciA模块功能引脚 == * SCITXDA_GPIOF4 SCIA的发送引脚 * SCIRXDA_GPIOF5 SCIA的接收引脚 */ void Init_Gpio_Sci() { EALLOW; GpioMuxRegs.GPFMUX.bit.SCITXDA_GPIOF4=1; //设置SCIA的发送引脚 GpioMuxRegs.GPFMUX.bit.SCIRXDA_GPIOF5=1; //设置SCIA的接收引脚 EDIS; } /* * == 配置SciA模块为串口 == * 配置SciA波特率 * LSPCLK时钟必须为37.5MHz SysCtrlRegs.LOSPCP.all = 0x0002; */ void Init_SciDevice(long baud) { long brr = 0; SciaRegs.SCICCR.bit.STOPBITS=0; //1位停止位 SciaRegs.SCICCR.bit.PARITYENA=0; //禁止极性功能 SciaRegs.SCICCR.bit.LOOPBKENA=0; //禁止回送测试模式功能 SciaRegs.SCICCR.bit.ADDRIDLE_MODE=0; //空闲线模式 SciaRegs.SCICCR.bit.SCICHAR=7; //8位数据位 SciaRegs.SCICTL1.bit.TXENA=1; //SCIA模块的发送使能 SciaRegs.SCICTL1.bit.RXENA=1; //SCIA模块的接收使能 brr = 4687500/baud -1 ; SciaRegs.SCIHBAUD=brr>>8; SciaRegs.SCILBAUD=brr%0x100; //波特率为19200 SciaRegs.SCICTL2.bit.RXBKINTENA=1; //SCIA模块接收中断使能 SciaRegs.SCICTL2.bit.TXINTENA=1; //SCIA模块发送中断使能 SciaRegs.SCICTL1.bit.SWRESET=1; //重启SCI } static unsigned char TxNum = 0; static volatile char TxBusy = 0; //表示缓冲区中的数据状态,1=正在发送数据,0=数据已经发送完成 static unsigned char * TxStr; /* * == 串口数据发送函数 == * 以中断的方式自动发送str数组 * 函数立即返回 * 如果上一次发送未完成,函数将阻塞,直到上一次发送完成 */ void Sci_puts(unsigned char * str, unsigned char num) { while(TxBusy != 0) NOP; //等待数据发送完 TxBusy = 1; TxNum = num-1; SciaRegs.SCITXBUF= *str; str++; TxStr = str; } interrupt void SciTXA_ISR(void) // SCI-A发送中断函数 { if(TxNum > 0) { SciaRegs.SCITXBUF= *TxStr; //发送数据 TxStr++; TxNum--; }else TxBusy = 0; PieCtrlRegs.PIEACK.all=0x0100; //使得同组其他中断能够得到响应 } static void (*RXA_hook)(unsigned char val) = 0; interrupt void SciRXA_ISR(void) // SCI-A接收中断函数 { RXA_hook((unsigned char)SciaRegs.SCIRXBUF.bit.RXDT); PieCtrlRegs.PIEACK.all=0x0100; //使得同组其他中断能够得到响应 } /* * == 串口数据接收函数 == * 使用串口接收中断,通过回调函数进行接收 * 必须设置回调函数RXA_hook */ void set_RXAHook(void (*f)(unsigned char val)) { RXA_hook = f; } /* * ==== 基于串口的简单通信协议 ==== * * 帧格式: 起始位 | 数据长度 | 数据... | 校验 | * 起始位 0xAA * 校验方式 CRC16循环校验 低8位在前,高8位在后 * * 串口提供: 发送数据函数,以unsigned char[]数组格式 * 接收数据回调函数 * * 通过使用宏TxBufferMaxNum 定义发送缓冲区大小 * 通过使用宏RxBufferMaxNum 定义接收缓冲区大小 * 数据长度最长为255 * 使用前必须调用初始化函数ComPro_Init() * * Author: hexingshi * Date: 2012-4-25 */ unsigned int CRC16_Cal(unsigned char * data, unsigned char len); void Sci_puts(unsigned char * str, unsigned char num); void set_RXAHook(void (*f)(unsigned char val)); static void ComPro_Rx(unsigned char val); void ComPro_Received(); #define TxBufferMaxNum 56 #define RxBufferMaxNum 56 static unsigned char TxBuffer[TxBufferMaxNum]; //发送缓冲区 static unsigned char RxBuffer[RxBufferMaxNum]; //接收缓冲区 static unsigned char RxNum = 0; //接收缓冲区中的数据个数 static unsigned int RxCRC = 0; //接收到的数据帧中的校验位 /* * == 发送数据 == * 将数据打包,并通过串口发送 * 函数立即返回 * 如果Sci_puts上一次调用未完成,会产生阻塞 */ void ComPro_put(unsigned char * data, unsigned char num) { unsigned char i; unsigned int crc; TxBuffer[0] = 0xAA; //设置起始位 TxBuffer[1] = num; //设置数据长度位 for (i = 0; i < num; ++i) { TxBuffer[i+2] = data[i]; } crc = CRC16_Cal(data, num); TxBuffer[num+2] = (unsigned char)(crc&0x00FF); //crc的低8位 TxBuffer[num+3] = (unsigned char)(crc>>8); //crc的高8位 Sci_puts(TxBuffer, num+4); } /* * == 通信协议初始化 == * 设置底层串口接收数据的回调函数 */ void ComPro_Init() { set_RXAHook(ComPro_Rx); } /* * == 串口的回调函数 == * 当串口收到数据后回调此函数 * 使用前必须设置串口hook函数 * 通过状态机获取数据帧 */ static void ComPro_Rx(unsigned char val) { static unsigned char RxState = 0; static unsigned char RxBufferIndex = 0; switch (RxState) { case 0: if(val == 0xAA) RxState = 1; break; case 1: if(val > RxBufferMaxNum) { RxState = 0; } else { RxState = 2; RxNum = val; RxBufferIndex = 0; } break; case 2: RxBuffer[RxBufferIndex] = val; RxBufferIndex++; if (RxBufferIndex >= RxNum) RxState = 3; break; case 3: RxCRC = val; RxState = 4; break; case 4: RxCRC = ((unsigned int)val)*256 + RxCRC; RxState = 0; ComPro_Received(); break; } } /* * == 数据接收完成hook == * 数据接收完成后,可以在此函数中添加处理 * CRC16校验:调用CRC16_Cal()与接收的校验位RxCRC比较 */ void ComPro_Received() { //添加对数据的处理语句 ComPro_put(RxBuffer, RxNum); //测试 :回传数据 }
这个简单的通信协议可以选择加入计时器后,设置超时时间,然后让状态机到0状态。
printf
相关文章推荐
- 简单而强大的多线程串口编程工具CserialPort类(附VC基于MFC单文档协议通讯源程序及详细编程步骤)
- 基于COMPAC协议的.NET框架实现的串口通信程序
- 基于socket简单通信协议实现
- 基于socket简单通信协议实现(c/c++)
- 基于socket简单通信协议实现(c/c++)
- 实现采用客户/服务器通信模式,基于TCP网络通信协议的多客户端简单应用之案例分析
- 基于socket简单通信协议实现
- 基于VC6.0 MFC的简单串口通信软件编程
- 基于Tcp&UDP协议的简单Socket通信实例(JAVA)
- 基于socket简单通信协议实现
- 实现采用客户/服务器通信模式,基于TCP网络通信协议的多客户端简单应用
- 简单而强大的多线程串口编程工具CserialPort类(附VC基于MFC单文档协议通讯源程序及详细编程步骤)
- vs2015基于UDP协议的简单通信例程
- 简单而强大的多线程串口编程工具CserialPort类(附VC基于MFC单文档协议通讯源程序及详细编程步骤)
- 基于socket简单通信协议实现(c/c++)
- 基于状态机State Machine的程序设计技巧②状态转移图和简单通信协议
- 基于socket简单通信协议实现
- 基于UDP协议的简单聊天程序
- 一个简单的自定义通信协议(socket)
- Android Service和Activity基于串口蓝牙模块的双向通信