前言
上一篇我们进行了串口的收发测试,要方便使用,需要给应用层提供好用的串口收发接口。这里通过环形缓冲区的方式实现串口的接收。
过程
临界段处理
由于缓冲区的基本数据流是串口接收中断中写缓冲区,读接口函数读缓冲区,存在多方使用缓冲区资源,所以对缓冲区资源访问时必须做临界段处理。这里简单的使用开关中断处理。
__disable_irq(); __enable_irq();
由于写缓冲区只在串口接收中断中进行,所以uart_rx_handler写缓冲区就不需要再做临界段处理了,只有uart_read读缓冲区时需要进行临界段处理。
‘
环形缓冲区结构
通过以下结构体实现
分别设计了读写指针,当前有效数据个数,缓冲区大小。
写缓冲区时in_u32写指针递增,到末尾后绕到最开始,如果缓冲区满则丢失。
读缓冲区时out_u32读指针递增,到末尾后绕到最开始。
typedefstruct{uint32_tdatalen_u32;uint32_tmaxlen_u32;uint32_tin_u32;uint32_tout_u32;uint8_t* buffer_pu8; }ring_buffer_t;
代码
添加文件LPUART0_TXRXIRQ\Src\uart.c,内容如下
#include#include"fm33lg0xx_fl.h"#include"core_cmFunc.h"uint8_tuart_buffer[64];uint8_tuart_ring_buffer[128];typedefstruct{uint32_tdatalen_u32;uint32_tmaxlen_u32;uint32_tin_u32;uint32_tout_u32;uint8_t* buffer_pu8; }ring_buffer_t;ring_buffer_ts_ring_buffer_t= { .datalen_u32 =0, .maxlen_u32 =sizeof(uart_ring_buffer), .in_u32 =0, .out_u32 =0, .buffer_pu8 = uart_ring_buffer, };voiduart_rx_handler(constuint8_t*buffer,uint32_tlength){for(uint32_ti=0;iif(s_ring_buffer_t.datalen_u32 <s_ring_buffer_t.maxlen_u32) {s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.in_u32] = buffer[i];s_ring_buffer_t.datalen_u32++;s_ring_buffer_t.in_u32++;s_ring_buffer_t.in_u32 %=s_ring_buffer_t.maxlen_u32; }else{break; } } }intuart_read(uint8_t*buff,uint32_tlen){uint32_treadlen =0;uint32_tmask;if(s_ring_buffer_t.datalen_u32 ==0) {return0; } __disable_irq();for(uint32_ti=0;iif(s_ring_buffer_t.datalen_u32 >0) { buff[i] =s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.out_u32];s_ring_buffer_t.datalen_u32--;s_ring_buffer_t.out_u32++;s_ring_buffer_t.out_u32 %=s_ring_buffer_t.maxlen_u32; readlen++; }else{break; } } __enable_irq();returnreadlen; }intuart_write(uint8_t*buff,uint32_tlen){for(uint32_ti=0; iFL_LPUART_WriteTXBuff(LPUART0, buff[i]);while(FL_LPUART_IsActiveFlag_TXBuffEmpty(LPUART0)==0); }return0; }
LPUART0_TXRXIRQ\Src\uart.h中提供三个接口
#ifndefUART_H#defineUART_H#includevoiduart_rx_handler(constuint8_t*buffer,uint32_tlength);intuart_read(uint8_t*buff,uint32_tlen);intuart_write(uint8_t*buff,uint32_tlen);#endif
串口中断函数中调用uart_rx_handler
LPUART0_TXRXIRQ\Src\demo_lpuart.c中
#include"uart.h"voidLPUARTx_IRQHandler(void){if((FL_ENABLE ==FL_LPUART_IsEnabledIT_RXBuffFull(LPUART0)) && (FL_SET ==FL_LPUART_IsActiveFlag_RXBuffFull(LPUART0))){ temp =FL_LPUART_ReadRXBuff(LPUART0);uart_rx_handler(&temp,1); }
而int uart_read(uint8_t *buff, uint32_t len);
int uart_write(uint8_t *buff, uint32_t len);
供应用层调用。
测试
LPUART0_TXRXIRQ\Src\main.c中
#include"uart.h"uint8_tbuffer[128];while(1) {intlen=0;if((len =uart_read(buffer,sizeof(buffer))) >0) {uart_write(buffer, len); } }
上位机持续发送,测试发送的内容是否和接收到的内容完全一样,测试稳定性。
同时也可以测试发送效率。
总结
- 通过实现环形缓冲区,实现串口收发的接口给应用使用。当然以上实现还可以优化,比如发送现在是查询方式,效率低,可以类似改为环形缓冲区中断发送。实际根据接收和处理速度调整缓冲区的大小,来满足生产和消费平均速率协调。
- 实际临界段处理不需要完全关中断,可以只关指定优先级中断,处理完再恢复到之前的优先级中断。