完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
环形缓冲区简介 在单片机中串口通信是我们使用最频繁的,使用串口通信就会用到串口的数据接收与发送,环形缓冲区方式接收数据可以更好的保证数据丢帧率第。 在通信程序中,经常使用环形缓冲器作为数据结构来存放通信中发送和接收的数据。环形缓冲区是一个先进先出的循环缓冲区,可以向通信程序提供对缓冲区的互斥访问。 环形缓冲区的一个有用特性是:当一个数据元素被用掉后,其余数据元素不需要移动其存储位置。相反,一个非圆形缓冲区(例如一个普通的队列)在用掉一个数据元素后,其余数据元素需要向前搬移。换句话说,环形缓冲区适合实现先进先出缓冲区,而非环形缓冲区适合后进先出缓冲区。 STM32环形缓冲区示例
#include "usart.h" /********************串口初始化函数封装********************* ****硬件接口:USART1_TX -- PA9(发送) ** USART1-RX --PA10(接收) ** USART2_TX -- PA2(发送) ** USART2-RX --PA3(接收) ** USART3_TX -- PB10(发送) ** USART3_RX -- PB11(接收) 形参:USART_TypeDef *USARTx -- 要配置的哪个串口 ** u32 baud --波特率 ** u32 sysclk --时钟频率(USART1 --72MHZ ,USAT2USART3 --36MHZ) ** ***********************************************************/ void Usartx_Init(USART_TypeDef *USARTx,u32 baud,u32 sysclk) { if(USART1 == USARTx) { /*1.开时钟*/ RCC->APB2ENR|=1<<2;//PA时钟 RCC->APB2ENR|=1<<14;//串口时钟 RCC->APB2RSTR|=1<<14;//串口复位 RCC->APB2RSTR&=~(1<<14);//取消复位 /*2.配置GPIO口*/ GPIOA->CRH&=0xFFFFF00F; GPIOA->CRH|=0x000008B0;//上下拉输入,复用推挽输出 #ifdef USART1_IQR USART1->CR1|=1<<5;//开启串口接收中断 STM32_NVIC_SetPriority(USART1_IRQn,0,1);//设置优先级 #endif } else if(USART2 == USARTx) { /*1.开时钟*/ RCC->APB2ENR|=1<<2;//PA时钟 RCC->APB1ENR|=1<<17;//USART2时钟 RCC->APB1RSTR|=1<<17;//开复位时钟 RCC->APB1RSTR&=~(1<<17);//取消复位 /*2.配置GPIO口*/ GPIOA->CRL&=0xFFFF00FF;//清除原来寄存器中的值 GPIOA->CRL|=0x00008B00; #ifdef USART2_IRQ USART2->CR1|=1<<5;//串口2接收中断 STM32_NVIC_SetPriority(USART2_IRQn,1,2);//设置优先级 #endif } else if(USART3 == USARTx) { /*1.开时钟*/ RCC->APB2ENR|=1<<3;//PB时钟 RCC->APB1ENR|=1<<18;//USART3时钟 RCC->APB1RSTR|=1<<18;//开复位时钟 RCC->APB1RSTR&=~(1<<18);//取消复位 /*2.配置GPIO口*/ GPIOB->CRH&=0xFFFF00FF; GPIOB->CRH|=0x00008B00; #ifdef USART3_IRQ USART3->CR1|=1<<5;//开启接收中断 STM32_NVIC_SetPriority(USART3_IRQn,0,0);//设置优先级 #endif } else return; /*3.配置串口核心寄存器*/ USARTx->BRR=sysclk*1000000/baud;//设置波特率 USARTx->CR1|=1<<2;//接收使能 USARTx->CR1|=1<<3;//发送使能 USARTx->CR1|=1<<13;//使能串口3 } /************************串口发送字符************************/ void Usartx_SendString(USART_TypeDef *USARTx,u8 *str,u8 len) { while(len--) { USARTx->DR=*str; while((USARTx->SR&1<<7)==0){}//等待数据发送完成 str++; } } /***************printf重定向**************/ int fputc(int c,FILE *stream) { USART1->DR=c; while(!(USART1->SR&1<<7)){} return c; }
/********************串口接收数据结构体********************/ #define USART1_LEN 200 //缓冲区大小 typedef struct { char buff[USART1_LEN];//缓冲区 u8 usart1_rx_len;//保存的数据长度 u8 usart1_flag;//数据接收完成标志 u8 w;//写 u8 r;//读 }USART1_RX; USART1_RX USART1_rx={{0},0,0,0,0};//串口接收数据缓冲区初始化 void USART1_IRQHandler(void) { u8 c; if(USART1->SR&1<<5) { c=USART1->DR; //当写入的数据长度==缓冲区长度,表示缓冲区满 if(USART1_rx.usart1_rx_len //写入数据到缓冲区 USART1_rx.buff[USART1_rx.w]=c; USART1_rx.w=(USART1_rx.w+1)%USART1_LEN;//防止地址越界 USART1_rx.usart1_rx_len++; TIM2->CNT=0;//清空计数器值 TIM2->CR1|=1<<0; } else USART1_rx.usart1_flag=1;//缓冲区满 } USART1->SR=0;//清除标志位 }
/**********************从缓冲区读取数据****************** ** **形参:u8 *tx_data -- 读取数据保存地址 ** *********************************************************/ u8 Usart1_Annular_txdata(u8 *tx_data) { u8 len=0; //缓冲区为空 或者 USART1_rx.usart1_flag 数据接收完成标志(为了兼容字符串接收处理) if(USART1_rx.usart1_rx_len==0 || USART1_rx.usart1_flag==0)return 0; while(USART1_rx.usart1_rx_len) { *tx_data=USART1_rx.buff[USART1_rx.r];//读取缓冲区数据 USART1_rx.r= (USART1_rx.r+1)%USART1_LEN; USART1_rx.usart1_rx_len--;//缓冲区长度-1 tx_data++; len++; } USART1_rx.usart1_flag=0;//清除标志位 *tx_data=' |