一个自己写的UART双数据缓冲(buffer)乒乓中断读取程序(原创)
0赞一个自己写的UART双数据缓冲(buffer)乒乓中断读取程序(原创)
首先介绍一下,背景:在本次UDC大赛中,我们队的作品需要将现场采样的实时环境数据和智能小车运行状态通过无线方式传输至PC上位机软件(C++编写)显示和绘图,另一方面,我们还要实现上位机对现场智能蔽障小车的控制。由于数据量大,并且要保证实时可靠的接收数据和发送控制命令,对PC机一端UART通信及无线通信的可靠性和实时性提出了严格的要求,无线由于采用的是nRF24L01模块,其具有自动应答,片上完整的CRC校验功能,再加上我们精心设计的(数据和命令)通信帧,以及两端的中断接收,保证了无线数传的可靠性和实时性。
这里主要谈一下UART与PC之间的通信,之前采用惯用的一个数据缓存,加中断标志控制的方式实现,在数据量不大的情况下,可以正常无误的通信,但是当增大收发的数据量是,出现错误数据和数据丢失现象。
我们配置的UART设置为:
波特率:9600bitps;8比特数据;1位停止位,无奇偶校验位,接收端RX buffer为32 Bytes;接收RX中断使能;
当然,提高通信波特率可以增大安全数据通信速率,但是总是治标不治本。经过一番思考,我们编写了如下的UART双数据缓冲(buffer)乒乓中断读取程序,保证任何波特率下的可靠实时通信。实测结果令人满意(在单片机循环发送大量数据至PC机的情况下,上位机软件每间隔1ms向下发送100字节数据,测试五数据丢失和错误)。
最后,附上源代码并简单解释一下原理:
所谓双数据缓存即:rx_buffer1[RX_BUFFER_SIZE]和rx_buffer2[RX_BUFFER_SIZE],BufferUsed,作为全局变量,用于记录并传递两个buffer操作顺序;所谓乒乓中断读取,即在UART中断服务程序中轮流交替使用上述两个数据缓存接收PC发来的数据。
其中main.C的语句if(BufferUsed!=LastBuffer){….LastBuffer = BufferUsed;….}用于完成两个buffer乒乓操作的检测与切换,具体代码如下:
- 中断服务程序代码:
#define RX_BUFFER_SIZE128
uint8BufferUsed = 0;//
uint8rx_buffer1[RX_BUFFER_SIZE]={0};
uint8rx_buffer2[RX_BUFFER_SIZE]={0};
CY_ISR(isr_UartRX_Interrupt)
{
/* Place your Interrupt code here. */
/* `#START isr_UartRX_Interrupt` */
uint8rec_status = 0u;
staticuint8pointerRX = 0u;
staticuint8buffer = 0;
uint8ReceiveChar = 0;
rec_status = UART_ReadRxStatus();//read the RX state
while(rec_status & UART_RX_STS_FIFO_NOTEMPTY)//there are data in the FIFO
{
if(pointerRX if(buffer%2==0) rx_buffer1[pointerRX++] = UART_RXDATA_REG; else rx_buffer2[pointerRX++] = UART_RXDATA_REG; else { pointerRX = 0; buffer++; BufferUsed = buffer; } rec_status = UART_ReadRxStatus(); } /* `#END` */ /* PSoC3 ES1, ES2 RTC ISR PATCH */ #if(CYDEV_CHIP_FAMILY_USED == CYDEV_CHIP_FAMILY_PSOC3) #if((CYDEV_CHIP_REVISION_USED <= CYDEV_CHIP_REVISION_3A_ES2) && (isr_UartRX__ES2_PATCH )) isr_UartRX_ISR_PATCH(); #endif #endif } //UART to PC communication externuint8BufferUsed; externuint8rx_buffer1[RX_BUFFER_SIZE]; externuint8rx_buffer2[RX_BUFFER_SIZE]; voidmain() { uint8LastBuffer = 0; While(1) { UART_PutArray(MutiInfo,32);//send large information to PC if(BufferUsed!=LastBuffer)//if there is one buffer data ready { if(BufferUsed%2) { //just send the buffer back to PC for verify UART_PutArray(rx_buffer1,RX_BUFFER_SIZE); //clean the buffer for next data receive for(i=0;i } else { //just send the buffer back to PC for verify UART_PutArray(rx_buffer2,RX_BUFFER_SIZE); //clean the buffer for next data receive for(i=0;i } LastBuffer = BufferUsed;//record current operate state LCD_Char_1602_Position(1,0); LCD_Char_1602_PrintString("UART Get data!"); } } } 胡恩伟 2011年9月7日星期三 于重大A区主教2601实验室