USART DMA接送一帧数据(不定长)
Posted better-day
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了USART DMA接送一帧数据(不定长)相关的知识,希望对你有一定的参考价值。
内容来源于:http://blog.sina.com.cn/s/blog_777668c30102x4hz.html
1、DMA做所周知这个是好的东西,对于跑裸机的开发者来说是一个福音。但是很多工程师还是按照以前的方式来设计串口,本人看到了真的急的不行。多么好的东西就这样子暴遣天物!可能很多开发者会说DMA是定长的我收发的数据都是不定长的有什么用?如果听到这句话我保证该位同事没有好好研究过DMA。今天把自己DMA不定长发送接收程序贴上来。希望大家在开发的过程少受罪。
2、在大家要开始学习的过程中,说一个STM32串口中断的秘密。在以前用51设计MODBUS的朋友中,很多都知道,MODBUS协议栈中,有一个帧间隔判断。很多人为了设计这个帧判断脑袋都炸了,又要加一个定时器判断,这标志那标志的,一句话吐血,本人也吃过哭。其实MODBUS帧间隔判断只是他协议的一条,其实还有一条字节判断,什么是字节判断?就是一个字节一个字节发送过来的间隔时间。虽然我们都是屌丝,但是我们也是很有大脑的,帧判断都这么麻烦了,你还敢叫我们字节判断!我们这群屌丝不干了,直接把这个标准协议的这个字节判断省略了,对!没有看错就是活生生的省略了!程序跑起来OK。呵呵,皆大欢喜。谁也看不出来。呵呵,搞过MODBUS的朋友都知道。除了哪些新手第一次看协议自己设计MODBUS协议栈,他才会去设计这个字节间隔,然后设计不出来,就开始怀疑自己的能力。其实并不是,你敢去设计很厉害了,老手只是为了回避。
说了这么多有什么鬼用?当然了,主要是让大家理解什么是帧间隔,对STM32这个目前全球风靡的单片机居然有帧间隔判断中断,这个多么好的东西!这样子从此以后设计MODBUS的朋友们你可以随随便便写一个MODBUS协议栈了,在也不用担心,什么乱七八糟的帧间隔了。
好了,现在我们说STM32帧间隔。STM32帧间隔就是在串口收到一帧数据的时候我们硬件会自动去判断该帧是否结束,如果结束会产生空闲判断IDLE。我们只要在中断中设置一个标志,我们的应用程序就知道,哦,一帧结束了,好了我可以去处理数据了。
3、串口1驱动 DMA驱动 IDLE中断。
以下是.c文件
1 void Usart1RccEnable( void ) 2 { 3 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); //使能串口1时钟 4 RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE); //使能串口1时钟 5 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启DMA时钟 6 } 7 8 void Usart1GpioConfig( void ) 9 { 10 GPIO_InitTypeDef GPIO_InitStructure; 11 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //USART1 TX 12 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 13 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 14 GPIO_Init(GPIOA, &GPIO_InitStructure); //A端口 15 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1 RX 16 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //复用开漏输入 17 GPIO_Init(GPIOA, &GPIO_InitStructure); //A端口 18 } 19 20 void Usart1DmaConfig( void ) 21 { 22 DMA_InitTypeDef DMA_InitStructure; 23 DMA_DeInit(DMA1_Channel5); 24 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; 25 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Usart1_Module_Struct.S_usart_dma_rx_buffer;//这是初始化时候配置,可以根据程序运行重新设置。 26 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 27 DMA_InitStructure.DMA_BufferSize = UART1_TX_RX_MAX_SIZE; 28 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 29 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 30 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 31 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 32 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; 33 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 34 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 35 DMA_Init(DMA1_Channel5, &DMA_InitStructure); 36 DMA_Cmd(DMA1_Channel5, ENABLE); 37 USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); 38 } 39 40 void Usart1Config(void) 41 { 42 USART_InitTypeDef USART_InitStructure; 43 USART_InitStructure.USART_BaudRate = BAUD_RATE; //速率115200bps 44 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位8位 45 USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位1位 46 USART_InitStructure.USART_Parity = USART_Parity_No; //无校验位 47 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控 48 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 49 USART_Init(USART1, &USART_InitStructure); //配置串口参数函数 50 USART_ITConfig(USART1,USART_IT_TC,DISABLE); //串口中断使能 51 USART_ITConfig(USART1,USART_IT_RXNE,DISABLE); //串口接收中断使能 52 USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //串口空闲中断使能 53 USART_Cmd(USART1, ENABLE); 54 USART_ClearFlag(USART1,USART_FLAG_TC); 55 } 56 57 void Usart1NvicConfig( void ) 58 { 59 NVIC_InitTypeDef NVIC_InitStructure; 60 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 61 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 串口中断配置 62 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 63 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 64 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 65 NVIC_Init(&NVIC_InitStructure); 66 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 67 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn; // 串口中断配置 68 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 69 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 70 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 71 NVIC_Init(&NVIC_InitStructure); 72 } 73 74 void Usart1DmaStructInit( void ) 75 { 76 Usart1_Module_Struct.S_rx_idle_flag = DISABLE; //初始化IDLE为0,没有数据发来 77 Usart1_Module_Struct.S_dma_send_usart_flag = ENABLE; //初始化DMA状态设置位1,才能启动第一次发送。 78 } 79 80 void Usart1Init( void ) 81 { 82 Usart1RccEnable(); 83 Usart1GpioConfig(); 84 Usart1Config(); 85 Usart1NvicConfig(); 86 Usart1DmaConfig(); 87 Usart1DmaStructInit(); 88 } 89 90 void Usart1SendData(uint8_t *Usart_TxBuffer, uint32_t Length) 91 { 92 DMA_InitTypeDef DMA_InitStructure; 93 while(Usart1_Module_Struct.S_dma_send_usart_flag == DISABLE); 94 Usart1_Module_Struct.S_dma_send_usart_flag = DISABLE; 95 DMA_DeInit(DMA1_Channel4); 96 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 97 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; 98 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Usart_TxBuffer; 99 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; 100 DMA_InitStructure.DMA_BufferSize = Length; 101 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 102 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 103 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 104 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 105 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; 106 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 107 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 108 DMA_Init(DMA1_Channel4, &DMA_InitStructure); 109 DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE); 110 DMA_Cmd(DMA1_Channel4, ENABLE); 111 USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); 112 } 113 114 void USART1_IRQHandler(void) 115 { 116 if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) 117 { 118 Usart1_Module_Struct.S_dma_rx_usart_size = USART1->SR; 119 Usart1_Module_Struct.S_dma_rx_usart_size = USART1->DR; 120 DMA_Cmd(DMA1_Channel5,DISABLE); 121 Usart1_Module_Struct.S_dma_rx_usart_size = UART1_TX_RX_MAX_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5); 122 DMA_SetCurrDataCounter(DMA1_Channel5,UART1_TX_RX_MAX_SIZE); 123 DMA_Cmd(DMA1_Channel5,ENABLE); 124 Usart1_Module_Struct.S_rx_idle_flag = 1; 125 } 126 } 127 128 129 130 131 void DMA1_Channel4_IRQHandler(void) 132 { 133 if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET) 134 { 135 DMA_ClearFlag(DMA1_FLAG_TC4); 136 DMA_Cmd(DMA1_Channel4,DISABLE); 137 Usart1_Module_Struct.S_dma_send_usart_flag = ENABLE; 138 } 139 } 140 141 unsigned char GetUsart1DmaTxFlag( void ) 142 { 143 return Usart1_Module_Struct.S_dma_send_usart_flag; 144 } 145 146 unsigned char GetUsart1DmaRxFlag( void ) 147 { 148 return Usart1_Module_Struct.S_rx_idle_flag; 149 } 150 151 void SetUsart1DmaTxFlag( unsigned char status ) 152 { 153 Usart1_Module_Struct.S_dma_send_usart_flag = status; 154 } 155 156 void SetUsart1DmaRxFlag( unsigned char status ) 157 { 158 Usart1_Module_Struct.S_rx_idle_flag = status; 159 } 160 161 unsigned int GetUsart1DmaRxSize( void ) 162 { 163 return Usart1_Module_Struct.S_dma_rx_usart_size; 164 } 165 166 void SetUsart1DmaRxSize( void ) 167 { 168 Usart1_Module_Struct.S_dma_rx_usart_size = 0; 169 }
以下是.h文件
1 #ifndef _usart1_h 2 #define _usart1_h 3 #include "public.h" 4 #ifdef _usart1_C 5 #define _usart1_ext 6 #else 7 #define _usart1_ext extern 8 #endif 9 10 #define BAUD_RATE 115200 11 #define UART1_TX_RX_MAX_SIZE 1460 12 13 typedef struct 14 { 15 unsigned char __IO S_dma_send_usart_flag; //该状态表示DMA发送结束标志,如果该标志为否DMA资源占用用请勿使用。 16 unsigned int __IO S_dma_rx_usart_size; //接收到一帧数据结束,获取该帧长度 17 unsigned char __IO S_rx_idle_flag; //接收一帧结束标志位 18 unsigned char S_usart_dma_tx_buffer[UART1_TX_RX_MAX_SIZE];//发送缓冲Buffer 19 unsigned char S_usart_dma_rx_buffer[UART1_TX_RX_MAX_SIZE];//接收缓冲Buffer 20 } Usart_p; 21 22 _usart1_ext Usart_p Usart1_Module_Struct; 23 24 _usart1_ext void Usart1Init( void ); 25 _usart1_ext void Usart1SendData(uint8_t *Usart_TxBuffer, uint32_t Length); 26 _usart1_ext unsigned char GetUsart1DmaTxFlag( void ); 27 _usart1_ext unsigned char GetUsart1DmaRxFlag( void ); 28 _usart1_ext void SetUsart1DmaTxFlag( unsigned char status ); 29 _usart1_ext void SetUsart1DmaRxFlag( unsigned char status ); 30 _usart1_ext unsigned int GetUsart1DmaRxSize( void ); 31 _usart1_ext void SetUsart1DmaRxSize( void ); 32 33 #endif 34 35 36 //用户应用: 37 int main( void ) 38 { 39 SystemInit(); 40 Usart1Init(); 41 while(1) 42 { 43 if(GetUsart1DmaRxFlag()==TRUE) 44 { 45 SetUsart1DmaRxFlag(FALSE); 46 Usart1SendData(Usart1_Module_Struct.S_usart_dma_rx_buffer,GetUsart1DmaRxSize()); 47 } 48 } 49 }
以上是关于USART DMA接送一帧数据(不定长)的主要内容,如果未能解决你的问题,请参考以下文章