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接送一帧数据(不定长)的主要内容,如果未能解决你的问题,请参考以下文章

MM32F3277空闲中断+DMA接收不定长数据

DMA+USART+stm32

RA生态之USART通过定时器中断接收不定长数据

RA生态之USART通过定时器中断接收不定长数据

RA生态之USART通过定时器中断接收不定长数据

STM32F103VET6基于STM32CubeMX创建串口中断+ DMA 不定长数据接收