说在前面
码代码的应该学数据结构都学过队列。环形队列是队列的一种特殊形式,应用挺广泛的。因为有太多文章关于这方面的内容,理论知识可以看别人的,下面写得挺好的:STM32进阶之串口环形缓冲区实现
代码实现
环形队列数据结构
typedef?struct?ringBuff{ ????unsigned?int?in;???????????????//写入的位置 ????unsigned?int?out;??????????????//读出的位置 ????unsigned?char?buffer[RING_BUFF_SIZE];?????//数据域 }stRingBuff;
写一字节数据到队列
/** ?-?@brief:?????????寫一字節的數據到環形隊列 ?-?@param[in]:?????None ?-?@retval[out]:???None ?-?@note:???????????? ?-?@author:???????AresXu ?-?@version:??????v1.0.0 */ char?WriteOneByteToRingBuffer(stRingBuff?*ringBuf,char?data) { ?if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ???? ????if(IsRingBufferFull(ringBuf))???//写之前先判断队列是否写满 ????{ ????????return?FALSE; ????} ????ringBuf->buffer[ringBuf->in]?=?data; ????ringBuf->in?=?(++ringBuf->in)?%?RING_BUFF_SIZE;????//防止越界 ?return?TRUE; }
写入数据时要判断队列是否满,满了肯定就不能写入。
判断队列是否写满
/** ?-?@brief:?????????判斷環形隊列是否满 ?-?@param[in]:?????None ?-?@retval[out]:???None ?-?@note:???????????? ?-?@author:???????AresXu ?-?@version:??????v1.0.0 */ bool?IsRingBufferFull(stRingBuff?*ringBuf) { ??if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ???? ????if(((ringBuf->in+1)?%?RING_BUFF_SIZE)?==?ringBuf->out) ????{ //??printf("Ring?buffer?is?Full "); ????????return?TRUE; ????} ????return?FALSE; }
当写满时,读写位置也是相等,无法判断是否写满。这种情况有两种办法解决:
数据结构增加一个变量来计数写入数据的个数
像这种((ringBuf->in+1) % RING_BUFF_SIZE) == ringBuf->out,空出一个字节来不写数据
读一字节的数据
/** ?-?@brief:?????????从環形隊列中读一字节数据 ?-?@param[in]:?????None ?-?@retval[out]:???None ?-?@note:???????????? ?-?@author:???????AresXu ?-?@version:??????v1.0.0 */ char?ReadOneByteFromRingBuffer(stRingBuff?*ringBuf,char?*data) { ?if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ???? ????if(IsRingBufferEmpty(ringBuf))????//读之前判断队列是否为空 ????{ ????????return?FALSE; ????} ????*data?=?ringBuf->buffer[ringBuf->out]; ????ringBuf->out?=?(++ringBuf->out)?%?RING_BUFF_SIZE;????//防止越界 ????return?TRUE; }?
判断队列是否为空写入位置和读出位置相等时为空
/** ?-?@brief:????????判斷環形隊列是否空 ?-?@param[in]:?????None ?-?@retval[out]:???None ?-?@author:???????AresXu ?-?@version:??????v1.0.0 */ bool?IsRingBufferEmpty(stRingBuff?*ringBuf) {? ?if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ???? ????if(ringBuf->in?==?ringBuf->out)???//写入位置和读出位置相等时为空 ????{ //??printf("Ring?buffer?is?Empty "); ????????return?TRUE; ????} ????return?FALSE; }
写多个字节到队列
/** ?*?@brief:?????????寫len個字節數據到環形隊列 ?*?@param[in]:?????None ?*?@retval[out]:???None ?*?@note:???????????? ?*?@author:????????AresXu ?*?@version:???????v1.0.0 */ void?WriteRingBuffer(stRingBuff?*ringBuf,char?*writeBuf,unsigned?int?len) { ????unsigned?int?i; ? ?if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ???? ????for(i?=?0;?i?从队列中读出多个字节
/** ?*?@brief:?????????從環形隊列讀出len個字節的數據 ?*?@param[in]:?????None ?*?@retval[out]:???None ?*?@note:???????????? ?*?@author:???????AresXu ?*?@version:??????v1.0.0 */ void?ReadRingBuffer(stRingBuff?*ringBuf,char?*readBuf,unsigned?int?len) { ????unsigned?int?i; ???? ?if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ???? ????for(i?=?0;?i?获取已经写入队列的数据长度有这个方便知道接收完了要从队列中读出多少个数据。
/** ??*?@brief:?????????獲取已經寫入的長度 ??*?@param[in]:?????None ??*?@retval[out]:???None ??*?@note:???????????? ??*?@author:????????AresXu ??*?@version:???????v1.0.0 */ int?GetRingBufferLength(stRingBuff?*ringBuf) { ????if?(ringBuf?==?NULL) ????{ ????????printf("pointer?is?null "); ????????return; ????} ????return?(ringBuf->in?-?ringBuf->out?+?RING_BUFF_SIZE)?%?RING_BUFF_SIZE; }画个图,画画就可以知道为什么这样可以判断写入的长度。
到STM32上测试
串口接收部分:
static?stRingBuff?g_stRingBuffer?=?{0,0,0}; static?u8?g_recvFinshFlag?=?0; stRingBuff?*GetRingBufferStruct(void) { ?return?&g_stRingBuffer; } u8?*IsUsart1RecvFinsh(void) { ?return?&g_recvFinshFlag; } void?USART1_IRQHandler(void)?????????????????//串口1中断服务程序 { ?u8?res; ?if(USART_GetITStatus(USART1,?USART_IT_RXNE)?!=?RESET)??//接收中断(接收到的数据必须是0x0d?0x0a结尾) ?{ ??res?=?USART_ReceiveData(USART1);?//读取接收到的数据 ??WriteOneByteToRingBuffer(GetRingBufferStruct(),res);? ????} ?if(USART_GetITStatus(USART1,?USART_IT_IDLE)?!=?RESET)????????//空闲中断 ?{ ??USART_ReceiveData(USART1);???????????//清除空闲中断 ??g_recvFinshFlag?=?1;??????????????????//接收完成 ?} }?主函数:
int?main(void) {?? ?char?readBuffer[100]; ?u16?t;?? ?u16?len;? ?u16?times?=?0; ?delay_init();???????//延时函数初始化??? ?NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);?//设置NVIC中断分组2:2位抢占优先级,2位响应优先级 ?uart_init(115200);??//串口初始化为115200 ?LED_Init();????????//LED端口初始化 ?KEY_Init();??????????//初始化与按键连接的硬件接口 ? ?while(1) ?{ ??times++; ??if(*IsUsart1RecvFinsh()) ??{ ???ReadRingBuffer(GetRingBufferStruct(),readBuffer,GetRingBufferLength(GetRingBufferStruct())); ???printf("%s",readBuffer); ???memset(readBuffer,0,100); ???*IsUsart1RecvFinsh()?=?0; ??} ??if(times%500==0) ???LED0=!LED0; ??delay_ms(1);??? ?}?? } 串口收发测试
编辑:黄飞
评论