天天看點

STM32序列槽資料接收 --環形緩沖區 STM32序列槽資料接收 --環形緩沖區

STM32序列槽資料接收 --環形緩沖區

環形緩沖區簡介

  在單片機中序列槽通信是我們使用最頻繁的,使用序列槽通信就會用到序列槽的資料接收與發送,環形緩沖區方式接收資料可以更好的保證資料丢幀率第。

  在通信程式中,經常使用環形緩沖器作為資料結構來存放通信中發送和接收的資料。環形緩沖區是一個先進先出的循環緩沖區,可以向通信程式提供對緩沖區的互斥通路。

  環形緩沖區的一個有用特性是:當一個資料元素被用掉後,其餘資料元素不需要移動其存儲位置。相反,一個非圓形緩沖區(例如一個普通的隊列)在用掉一個資料元素後,其餘資料元素需要向前搬移。換句話說,環形緩沖區适合實作先進先出緩沖區,而非環形緩沖區适合後進先出緩沖區。

STM32序列槽資料接收 --環形緩沖區 STM32序列槽資料接收 --環形緩沖區

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 ,USAT2\USART3 --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_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='\0';//接收到的字元儲存為字元串
    return len;//傳回讀取到的字元個數
}
           
  • 主函數
#include "stm32f10x.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
u8 buff[200];
int main()
{
    u8 stat=0;
	Led_Init();//LED初始化
	Usartx_Init(USART1,115200,72);
	TIMx_Init(TIM2,72,20000);//通過定時器2輔助序列槽接收資料,20ms
	printf("序列槽初始化完成\r\n");
	/*輪詢*/
	while(1)
	{
        stat=Usart1_Annular_txdata(buff);
        if(stat)
        {
            Usartx_SendString(USART1,buff,stat);
        }
	}
}
           
  • 效果展示
    STM32序列槽資料接收 --環形緩沖區 STM32序列槽資料接收 --環形緩沖區

示例工程

  示例工程連結:https://download.csdn.net/download/weixin_44453694/14981774

繼續閱讀