AT32F415 USART1、2、3,DMA 用结构体统一配置收发
生活随笔
收集整理的這篇文章主要介紹了
AT32F415 USART1、2、3,DMA 用结构体统一配置收发
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
AT32F415 USART1、2、3,DMA收發
1、串口1,2,3的收發原理都是一樣的, 所以配置上都可以一起來,不同的地方再用指針引用。
2、程序基本流程串口配置,DMA配置,接收時用空閑中斷,發送時用發送中斷來關閉DMA.
(打開DMA后,串口的收發完成中斷會對接到DMA的傳輸完成中斷)
3、串口緩存和DMA緩存用兩個獨立,防止接收時有沖突。
4、接收時看空閑中斷信號,有信號說明接收完了,把數據拿出來,DMA讀數清零來重新接收,狀態改為接收完成
5、發送時要手動開啟DMA傳輸,傳輸完成后會產生串口中斷,有中斷后就關閉DMA
配置
串口配置
//串口編號 typedef enum {serial=0,Bluetooth,IrDA,serialCount, }serialNum_e; //統一緩沖格式:狀態,收發大小,收發緩沖區大小 #define USART_MAX_BUFFER_SIZE 512 typedef struct usartRT {uint8_t status;uint16_t rxBufferSize;uint16_t txBufferSize;uint8_t txBuffer[USART_MAX_BUFFER_SIZE];uint8_t rxBuffer[USART_MAX_BUFFER_SIZE]; }usartPacket_s; //統一串口接口:串口編號,串口的DMA通道,串口收發緩沖,DMA收發緩沖 typedef struct serialHandle {USART_Type* USARTx;DMA_Channel_Type* rxChannel;DMA_Channel_Type* txChannel;usartPacket_s packet;usartPacket_s DMApacket; }SerialHandle_s; //串口接口初始化配置 SerialHandle_s serialHandle[serialCount] = {[serial] = {//主要調試串口.USARTx = USART1,.rxChannel = DMA1_Channel5,.txChannel = DMA1_Channel4,},[Bluetooth] = {//串口2接到藍牙模塊.USARTx = USART2,.rxChannel = DMA1_Channel6,.txChannel = DMA1_Channel7,},[IrDA] = {//串口3接到紅外收發模塊.USARTx = USART3,.rxChannel = DMA1_Channel3,.txChannel = DMA1_Channel2,}, }; //串口初始化配置:串口接口,波特率,字節長度,停止位,校驗位,收發模式,流控 //DMA配置 //開空閑中斷,用來接收 //開發送中斷,用來發送 //開啟串口 void Serial_Setup(SerialHandle_s* serialx, uint32_t baudrate, uint16_t Wordlength, uint16_t Stopbits, uint16_t Parity, uint16_t Mode, uint16_t HardwareFlowControl) {USART_Reset(serialx->USARTx);USART_InitType USARTx_InitStructure;USARTx_InitStructure.USART_BaudRate = baudrate;USARTx_InitStructure.USART_WordLength = Wordlength;USARTx_InitStructure.USART_StopBits = Stopbits;USARTx_InitStructure.USART_Parity = Parity;USARTx_InitStructure.USART_Mode = Mode;USARTx_InitStructure.USART_HardwareFlowControl = HardwareFlowControl;USART_Init(serialx->USARTx, &USARTx_InitStructure);USART_DMA_SETUP(serialx);USART_INTConfig(serialx->USARTx, USART_INT_IDLEF, ENABLE);USART_INTConfig(serialx->USARTx, USART_INT_TRAC, ENABLE);USART_Cmd(serialx->USARTx, ENABLE); }DMA配置
//DMA通道配置: 通道,發送的地址,設備地址,緩沖地址,緩沖大小,傳送方向 void USART_DMA_INIT(DMA_Channel_Type* DMAchannelx, uint32_t periphAddr, uint32_t bufferAddr, uint16_t bufferSize, uint32_t Direction) {DMA_InitType DMA_InitStructure;DMA_Reset(DMAchannelx);DMA_DefaultInitParaConfig(&DMA_InitStructure);DMA_InitStructure.DMA_PeripheralBaseAddr = periphAddr;DMA_InitStructure.DMA_MemoryBaseAddr = bufferAddr;DMA_InitStructure.DMA_Direction = Direction;DMA_InitStructure.DMA_BufferSize = bufferSize;DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_BYTE;DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE;DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;DMA_InitStructure.DMA_Priority = DMA_PRIORITY_LOW;DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;DMA_Init(DMAchannelx, &DMA_InitStructure); } //用人話重定義傳送方向 /*memory to periph */ #define UART_TX DMA_DIR_PERIPHERALDST /*periph to memory*/ #define UART_RX DMA_DIR_PERIPHERALSRC //DMA初始化:發送通道,接收通道,開啟通道,開啟串口通道請求 void USART_DMA_SETUP(SerialHandle_s* serialx) {USART_DMA_INIT(serialx->txChannel, (uint32_t) &(serialx->USARTx->DT), (uint32_t)(serialx->DMApacket.txBuffer), USART_MAX_BUFFER_SIZE, UART_TX);USART_DMA_INIT(serialx->rxChannel, (uint32_t) &(serialx->USARTx->DT), (uint32_t)(serialx->DMApacket.rxBuffer), USART_MAX_BUFFER_SIZE, UART_RX);//DMA_ChannelEnable(serialx->txChannel, ENABLE);DMA_ChannelEnable(serialx->rxChannel, ENABLE);/* Enable USARTx DMA Rx and TX request */USART_DMACmd(serialx->USARTx, USART_DMAReq_Rx, ENABLE);USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, ENABLE); }串口中斷處理
// 緩沖準狀態 typedef enum {rxDone=1,txDone=1<<1,rxBusy=1<<2,txBusy=1<<3, }SerialStatus_e;void Serial_IRQHandler(SerialHandle_s* serialx) {uint16_t bufferCount = 0;//接收處理if (USART_GetITStatus(serialx->USARTx, USART_INT_IDLEF)){USART_ClearITPendingBit(serialx->USARTx, USART_INT_IDLEF);(void)(serialx->USARTx->DT);//讀一次接收寄存器來清除接收中斷DMA_ChannelEnable(serialx->rxChannel, DISABLE);//關閉通道serialx->DMApacket.status |= rxDone;//緩沖狀態:接收完成bufferCount = DMA_GetCurrDataCounter(serialx->rxChannel);//緩沖計數serialx->DMApacket.rxBufferSize = USART_MAX_BUFFER_SIZE - bufferCount;//緩沖數serialx->packet.rxBufferSize = 0;//memcpy(serialx->packet.rxBuffer, serialx->DMApacket.rxBuffer, serialx->DMApacket.rxBufferSize);//復制DMA緩沖到USART緩沖//重新準備接收DMA_SetCurrDataCounter(serialx->rxChannel, USART_MAX_BUFFER_SIZE);DMA_ChannelEnable(serialx->rxChannel, ENABLE);USART_DMACmd(serialx->USARTx, USART_DMAReq_Rx, ENABLE);}//發送處理if (USART_GetITStatus(serialx->USARTx, USART_INT_TRAC)){USART_ClearITPendingBit(serialx->USARTx, USART_INT_TRAC);DMA_ChannelEnable(serialx->txChannel, DISABLE);serialx->DMApacket.status |= txDone;serialx->DMApacket.status &= (~txBusy);serialx->DMApacket.txBufferSize = 0;} }void USART1_IRQHandler(void) {Serial_IRQHandler(&serialHandle[serial]); } void USART2_IRQHandler(void) {Serial_IRQHandler(&serialHandle[Bluetooth]); } void USART3_IRQHandler(void) {Serial_IRQHandler(&serialHandle[IrDA]); }數據收發
發送數據
//把數據寫入到發送緩存里 //常量指針能避免修改指針指向的數據 void Serial_putc(SerialHandle_s* serialx, const char b) {serialx->packet.txBuffer[serialx->packet.txBufferSize] = b;serialx->packet.txBufferSize++; } void Serial_puts(SerialHandle_s* serialx, const char* b) {while (*b){serialx->packet.txBuffer[serialx->packet.txBufferSize] = *b;serialx->packet.txBufferSize++; b++;if (serialx->packet.txBufferSize == USART_MAX_BUFFER_SIZE) Serial_flush(serialx);} } //把緩存里的數據發送出去 void dmaChannelFlush(SerialHandle_s* serialx) {if (!serialx->packet.txBufferSize)return;/*wait for transmition complete*/uint16_t tryCount = 0;//delay_ms(10);while (serialx->DMApacket.status & txBusy){if (tryCount++ > SystemCoreClock/10000)return;}/*close dma channel and USART_DMAReq_Tx*/DMA_ChannelEnable(serialx->txChannel, DISABLE);USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, DISABLE);/*copy data from packet.txBuffer to DMApacket.txBuffer*/memcpy(serialx->DMApacket.txBuffer, serialx->packet.txBuffer, serialx->packet.txBufferSize);serialx->DMApacket.txBufferSize = serialx->packet.txBufferSize;/*reset packet.txBufferSize to 0*/serialx->packet.txBufferSize = 0;/*reset dma current data counter to DMApacket.txBufferSize*/DMA_SetCurrDataCounter(serialx->txChannel, serialx->DMApacket.txBufferSize);/*reopen USART_DMAReq_Tx*/USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, ENABLE);/*reopen dma channel*/DMA_ChannelEnable(serialx->txChannel, ENABLE);/*tx busy*/serialx->DMApacket.status |= txBusy; } void Serial_flush(SerialHandle_s* serialx) {dmaChannelFlush(serialx); }接收數據
uint16_t IsSerialRxHasData(SerialHandle_s* serialx) {if (serialx->DMApacket.status & rxDone){return serialx->DMApacket.rxBufferSize;}elsereturn 0; } /* *Input: SerialHandle *output: 1 byte of read */ const char Serial_getc(SerialHandle_s* serialx) {return serialx->packet.rxBuffer[serialx->packet.rxBufferSize++]; } /* Input: SerialHandle, rxBuffer pointer, bytesOfread pointer ouput: pointer of rxBuffer */ const char* Serial_gets(SerialHandle_s* serialx) {return (serialx->packet.rxBuffer); } /* Input: SerialHandle, rxBuffer pointer, bytesOfread pointer, bytes to read ouput: pointer of rxBuffer */ const char Serial_get(SerialHandle_s* serialx, uint16_t byteIndex) {if (byteIndex >= USART_MAX_BUFFER_SIZE) return 0;return serialx->packet.rxBuffer[byteIndex-1]; } //清空接收緩沖 void Serial_Pruge(SerialHandle_s* serialx) {serialx->DMApacket.status &= ~rxDone;serialx->DMApacket.rxBufferSize = 0;memset(serialx->packet.rxBuffer, 0, USART_MAX_BUFFER_SIZE); }總結
以上是生活随笔為你收集整理的AT32F415 USART1、2、3,DMA 用结构体统一配置收发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 杭州:久摇不中72次及以上 可申请领取车
- 下一篇: 亚马逊 CEO 发内部信:公司将再裁员