之前分享了一個關于gd32的fifo框架,這次就用stm32仿照寫一個,其實幾乎一樣,這次說的更詳細點,我全文都寫上了注釋,大家直接cv模仿我的調用方式即可
uasrt.c
#include "stm32f10x.h" // Device header
#include "queue.h"void myDMA_init(void);
void myNVIC_Config(void);queue_t uart1_queue_in,uart1_queue_out ; //定義2個結構體變量,分別是入、出棧
uint8_t recv_buf[256] = {0}; //接收緩沖區大小256 byte
static uint8_t send_buf[256] = {0}; //發送緩沖區大小256 byte
static uint8_t usart1_tx_buf[64];
static uint8_t uart1_send_ready = 1;void uart1_queue_init(void)
{queue_init(&uart1_queue_in,recv_buf,sizeof(recv_buf));//初始化壓棧的緩沖區queue_init(&uart1_queue_out,send_buf,256); //初始化出棧的緩沖區
}
/* **************************************************************************************
* 函 數 名: uart_get_queue_data
* 功能說明: 拿取uart in隊列的數據
* 形 參: p_buf : 數據存儲地址
* size : 拿取個數
* 返 回 值: 無
* 備 注: 無
*****************************************************************************************/
uint16_t uart1_get_queue_data(uint8_t * p_buf,uint16_t size)
{return queue_out_data(&uart1_queue_in,p_buf,size);
}/* **************************************************************************************
* 函 數 名: uart_get_data_len
* 功能說明: 返回uart in 隊列的儲存數據長度
* 形 參: 無
*
* 返 回 值: 數據長度
* 備 注: 無
*****************************************************************************************/
uint16_t uart1_get_data_len(void)
{return queue_get_num(&uart1_queue_in);
}/* **************************************************************************************
* 函 數 名: uart_put_queue_data
* 功能說明: 把數據壓進uart out隊列
* 形 參: p_buf : 數據存儲地址
* size : 壓的個數
* 返 回 值: 無
* 備 注: 無
*****************************************************************************************/
uint16_t uart1_put_queue_data(uint8_t * p_buf,uint16_t size)
{return queue_in_data(&uart1_queue_out,p_buf,size);
}/* **************************************************************************************
* 函 數 名: uart_send_poll
* 功能說明: 輪詢uart out 隊列并通過dma發送
* 形 參:
*
* 返 回 值: 發送數據個數
* 備 注: 無
*****************************************************************************************/
uint8_t uart0_send_poll(void)
{uint8_t n = 0; if(uart1_send_ready)//串口tx緩沖區是否有數據并傳輸完成?{n = queue_out_data(&uart1_queue_out,usart1_tx_buf,sizeof(usart1_tx_buf)); //計算大小if(n){uart1_send_ready=0;DMA_Cmd(DMA1_Channel4,DISABLE);DMA_SetCurrDataCounter(DMA1_Channel4,n);DMA_Cmd(DMA1_Channel4,ENABLE);return n;}}return 0;
}void USART1_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_Init(USART1, &USART_InitStructure);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStructure);USART_Cmd(USART1, ENABLE);USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 使能USART1的DMA發送請求(關鍵!)myDMA_init();myNVIC_Config();uart1_queue_init();
}void myDMA_init(void)
{ DMA_InitTypeDef DMA_InitStructure;// 使能DMA1時鐘RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 配置DMA1通道4(USART1_TX)DMA_DeInit(DMA1_Channel4); // 復位DMA通道4到默認值DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; // 外設基址:USART1數據寄存器DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart1_tx_buf; // 內存基址:發送緩沖區DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 傳輸方向:內存到外設DMA_InitStructure.DMA_BufferSize = 1; // 傳輸數據量DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外設地址不遞增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 內存地址遞增(因為發送多個字節)DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外設數據寬度8位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 內存數據寬度8位DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 普通模式(非循環)DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 中等優先級DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 非內存到內存模式DMA_Init(DMA1_Channel4, &DMA_InitStructure);// 使能DMA1通道4傳輸完成中斷DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);
}void myNVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStructure;// 配置DMA1_Channel4_IRQn的中斷優先級NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 搶占優先級1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子優先級1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}void USART1_IRQHandler(void)
{uint8_t Res;if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){Res = USART_ReceiveData(USART1);//接收到的數據進行入棧,壓棧queue_in_data(&uart1_queue_in,&Res,1);USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}
void DMA1_Channel4_IRQHandler(void)
{if (DMA_GetITStatus(DMA1_IT_TC4) != RESET) // 檢查DMA1通道4傳輸完成中斷標志{ uart1_send_ready = 1;DMA_ClearITPendingBit(DMA1_IT_TC4); // 清除中斷標志}
}
queue.c
#include "queue.h"/*** @brief Initialize the circular queue* @param queue: Queue* @param buffer: Queue's buffer* @param size: buff size* @retval None*/
void queue_init(queue_t *queue,uint8_t *buffer, uint16_t size)
{queue->buffer = buffer;queue->size = size;queue->head = 0;queue->tail = 0;queue->length = 0;queue->GetLen = 0;queue->PutLen = 0;
}/*** @brief Insert element into the circular queue* @param queue: Queue* @param buffer: Queue's buffer* @param count: element length* @retval Number of elements inserted successfully*/
uint16_t queue_in_data(queue_t *queue, const uint8_t *buffer, uint16_t count) //Zhixing Change 250430
{uint16_t i = 0;for(i=0; i<count; i++){if(queue->GetLen == 0){if(queue->PutLen == (queue->size - 1)) return i; }else{if(queue->PutLen == (queue->GetLen - 1)) return i; }queue->buffer[queue->PutLen++] = *buffer++;queue->PutLen %= queue->size;}return i;
}/*** @brief Delete element from the circular queue* @param queue: Queue* @param buffer: Queue's buffer* @param count: element length* @retval Number of elements deleted successfully*/
uint16_t queue_out_data(queue_t *queue,uint8_t *buffer, uint16_t count) //Zhixing Change 250430
{uint16_t i = 0;//__disable_irq();for(i=0; i<count; i++){/*if(queue->length == 0)//empty{__enable_irq();return i;}*/if(queue->PutLen == queue->GetLen) return i;*buffer++ = queue->buffer[queue->GetLen++];if(queue->GetLen == queue->size) queue->GetLen = 0;}//__enable_irq();return i;
}/*** @brief Get the remaining amount of data length from queue* @param queue: Queue* @retval data length*/
uint16_t queue_get_num(queue_t *queue)
{return queue->length;
}/******************** (C)Copyright MidiPlus Software ********************/