環形隊列+DMA空閑中斷+接收串口數據
- 一.序言
- 二.實驗原理
- 三.實戰是檢驗真理的唯一標準
- 3.1 usart1.c
- 3.2 串口中斷
- 三.隊列代碼
- 4.1 fifo.c
- 4.2 fifo.h
- 五.結語
一.序言
本次實驗利用環形隊列+DMA空閑中斷+串口。。通過這個實驗可以非常深入的理解隊列,DMA,串口的知識。如果你能自己實現掌握這個實驗,那么你應該基本掌握了隊列,DMA,串口的知識。
二.實驗原理
本次使用的是用環形隊列當緩沖器區接收串口數據。我們可以先區了解DMA的空閑中斷。本次實驗就是使用DMA空閑中斷。這里就簡單介紹一下,當串口接收到一幀數據后就會產生中斷,那么如何判斷數據是一幀呢?這里的判斷機制就是,如果收到數據后,大概接收一個字節的時間,都沒有接收到數據的話,就判斷已經接收的數據是一幀。接收一幀數據后,串口就會產生空閑中斷。同時DMA會把串口DR移位寄存器的值搬運到環形隊列緩沖區。我們只需要在環形隊列緩沖器拿數據即可。
三.實戰是檢驗真理的唯一標準
僅僅通過理論,只能說你知道有這個東西,但是你可能并不會。下面我通過代碼講解也幫助深入理解理論。
3.1 usart1.c
void Usart1_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;DMA_InitTypeDef DMA_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //USART1_TX GPIOA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure);//3?ê??ˉGPIOA.9//USART1_RX GPIOA.103?ê??ˉGPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);////Usart1 NVIC ????NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=5 ;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //?ù?Y???¨μ?2?êy3?ê??ˉVIC??′??÷USART_InitStructure.USART_BaudRate = 115200USART_InitStructure.USART_WordLength = USART_WordLength_8bUSART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); //使能空閑中斷USART_ITConfig(USART1, USART_IT_IDLE , ENABLE);//使能發送完成中斷--通過串口發送數據USART_ITConfig(USART1, USART_IT_TC , ENABLE);USART_DMACmd(USART1, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);USART_Cmd(USART1, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel5);//外設地址--串口1 的DR寄存器DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart1_Rx_Buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = BSP_UART1_RX_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//串口1的接收引腳為DAM1的通道5DMA_Init(DMA1_Channel5, &DMA_InitStructure);DMA_Cmd (DMA1_Channel5,ENABLE); //初始化環形隊列Fifo_Init(&Uart1_Rx_Fifo,Uart1_Rx_Buffer,BSP_UART1_RX_SIZE);
3.2 串口中斷
void USART1_IRQHandler(void)
{ //加上volatile 關鍵字只是為了防止警告volatile uint32_t temp = 0;BaseType_t xHigherPriorityTaskWoken = pdFALSE;if(USART_GetITStatus(USART1,USART_IT_IDLE)!= RESET)//???D?D??{//根據數據量數據入隊列//DMA_GetCurrDataCounter(DMA1_Channel5); 通道5還剩下多少個數據應該傳輸。//初始化的時候設置的通道5傳輸多少數據。Uart1_Rx_Fifo.in = BSP_UART1_RX_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);//先讀SR 再讀DR 只是為了消除空閑中斷標志位。手冊上有說明temp = USART1->SR; temp = USART1->DR;USART_ClearITPendingBit(USART1,USART_IT_IDLE);}
三.隊列代碼
代碼可能看起來簡單,但是不是那么容易理解。得自己慢慢體會,才能真正掌握,
而不是一昧的copy,不然出了問題也解決不了,自己代碼水平也不能提高。
4.1 fifo.c
#include "sys.h"
#include "app_fifo.h"//初始化
void Fifo_Init(FIFO_Type* fifo, uint8_t* buffer, uint16_t size)
{fifo->buffer = buffer;fifo->in = 0 ;fifo->out = 0;fifo->size = size;
}
//從隊列中拿數據
uint16_t Fifo_Get(FIFO_Type* fifo, uint8_t* buffer, uint16_t len)
{uint16_t lenght;uint16_t in = fifo->in; uint16_t i;lenght = (in + fifo->size - fifo->out)%fifo->size;if(lenght > len)lenght = len;for(i = 0; i < lenght; i++){buffer[i] = fifo->buffer[(fifo->out + i)%fifo->size];}fifo->out = (fifo->out + lenght)%fifo->size;return lenght;
}
4.2 fifo.h
#ifndef FIFO_H
#define FIFO_H
#include "stm32f10x.h"
typedef struct {uint8_t* buffer; uint16_t in; uint16_t out; uint16_t size;
}FIFO_Type;void Fifo_Init(FIFO_Type* fifo, uint8_t* buffer, uint16_t size);uint16_t Fifo_Get(FIFO_Type* fifo, uint8_t* buffer, uint16_t len);#endif
五.結語
代碼放出來的就是以上這些,都放上去也比較麻煩,同時也沒什么意義。寫這篇博客是想讓大家有大致的思路以及參考代碼,從而根據自己的項目或者需求區進行改動。最后,如果真的需要全部代碼的可以私信博主!最好點點關注!!!