STM32 串口DMA方式接收(转)

STM32 是一款基于ARM Cortex-M3内核的32位MCU,主频最高可达72M。最近因为要在车机上集成TPMS功能, 便开始着手STM32的开发工作,STM32F10x系列共有5个串口(USART1~USART5),支持DMA方式通信,DMA方式由于不需要CPU的参与,而是直接由DMA控制器完成串口数据的读写,因而可以很大程度的提高CPU的利用率。在使用STM32串口之前需要做一系列的初始化工作:

1.RCC(复位和时钟控制寄存器)初始化,启用GPIO、DMA、USART时钟。

2.NVIC(嵌套向量中断控制寄存器)初始化,完成各个硬件中断的配置。

3.USART初始话,配置串口,设置DMA通道等。

4.DMA初始化,完成DMA的配置。

最后是使能USART和DMA。下面是通过DMA的方式从串口USART1接收数据,STM32工作后串口数据由DMA控制器接收存到指定buffer,读取数据直接从DMA buffer中读取即可。发送数据采用非DMA方式,首先将待发送的数据存入到发送队列,然后在任务循环中将队列中的数据发送给USART1。实例代码如下:

  1 //**********************************************************************************************
  2 //  STM32F10x USART Test
  3 //  compiler: Keil UV3
  4 //  2011-03-28 , By friehood
  5 //**********************************************************************************************
  6 static int8u rDMABuffer[64];   // DMA buffer
  7 static int16u rDMARear = sizeof(rDMABuffer); 
  8 
  9 static int8u USART_RevBuf[64]; // 串口接收buffer
 10 static int8u USART_SndBuf[64]; // 串口发送buffer
 11 static int8u Head=0,Tail=0;    // 发送buffer的头尾
 12 
 13 
 14 // 串口任务
 15 void Task_USART(void)
 16 {
 17     int16u end;
 18     if (USART1->SR & (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE))
 19     {
 20         USART_ReceiveData(USART1);
 21     }
 22 
 23     // DMA接收
 24     end = DMA_GetCurrDataCounter(DMA1_Channel5);
 25     /*if((sizeof(rDMABuffer)-end)>0)
 26         dbgprt("DMA available datalen=%d/n",sizeof(rDMABuffer)-end); */
 27     while(rDMARear != end)
 28     {
 29         USART_receive(rDMABuffer[sizeof(rDMABuffer)-rDMARear]);
 30         if (!(--rDMARear))
 31         {
 32             rDMARear = sizeof(rDMABuffer);
 33         }
 34     }
 35 
 36     //发送
 37     if(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == SET)
 38     {
 39         int8u chr;
 40         // 从发送队列取出一个字符
 41         if(PopFront(&chr))
 42         {
 43             USART_SendData(USART1, chr);
 44             dbgprt("USART_SendData:0x%02x/n",chr);
 45             while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
 46               {
 47               }
 48         }
 49     }
 50 }
 51 
 52 
 53 // USART串口初始化
 54 void dev_USART_init(void)
 55 {
 56     USART_InitTypeDef USART_InitStructure;
 57     GPIO_InitTypeDef  GPIO_InitStructure;
 58     DMA_InitTypeDef   DMA_InitStructure;
 59 
 60     /* DMA1 Channel5 (triggered by USART1 Rx event) Config */        //参见 STM32 datasheet
 61     DMA_DeInit(DMA1_Channel5);  
 62     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
 63     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)rDMABuffer;
 64     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
 65     DMA_InitStructure.DMA_BufferSize = sizeof(rDMABuffer);
 66     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
 67     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
 68     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
 69     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
 70     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
 71     DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
 72     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
 73     DMA_Init(DMA1_Channel5, &DMA_InitStructure);
 74 
 75     USART_InitStructure.USART_BaudRate = 9600;
 76     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
 77     USART_InitStructure.USART_StopBits = USART_StopBits_1;
 78     USART_InitStructure.USART_Parity = USART_Parity_No;
 79     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
 80     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
 81 
 82     //配置IO: GPIOA9和GPIOA10分别作为串口TX、RX端。  见STM32 datasheet
 83     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 84     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 85     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
 86     GPIO_Init(GPIOA,&GPIO_InitStructure);
 87 
 88     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
 89     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
 90     GPIO_Init(GPIOA,&GPIO_InitStructure);
 91 
 92     /* Configure USART1 */
 93     USART_Init(USART1, &USART_InitStructure);
 94     /* Enable USART1 DMA Rxrequest */
 95     USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
 96     /* Enable DMA1 Channel5 */
 97       DMA_Cmd(DMA1_Channel5, ENABLE);
 98     /* Enable the USART1 */
 99     USART_Cmd(USART1, ENABLE);
100 }
101 
102 // 向串口发送数据
103 void USART_send(const int8u *pBuf, int8u len)
104 {
105     int i;
106     if(pBuf == NULL)
107     {
108         return;
109     }
110        // 将数据压入到发送队列
111     dbgprt("USART_PushBack:");
112     for(i=0;i<len;i++)
113     {
114            PushBack(*pBuf);
115         dbgprt("0x%02x ",*pBuf);
116         pBuf++;
117     }
118     dbgprt("/n");
119 }
120 
121 // 向发送队列尾部插入一个字节
122 void PushBack(int8u byte)
123 {
124     USART_SndBuf[Tail++]= byte;
125     if(Tail >= ARRAYSIZE(USART_SndBuf))
126         Tail = 0;
127     if(Tail == Head)
128         Head = Tail+1;      
129 }
130 
131 // 从发送队列头部取出一个字节
132 bool PopFront(int8u *byte)
133 {
134     if(Head >= ARRAYSIZE(USART_SndBuf))
135         Head = 0;
136     if(Head == Tail)
137         return FALSE;
138     *byte = USART_SndBuf[Head++];
139     return TRUE;
140 }
141 
142 // 处理接收到的串口数据
143 void USART_receive(int8u byte)
144 {
145     // Treate received data
146     // Place Code here
147         // ...
148 }
149 
150 // CRC校验
151 bool CheckCRC(const int8u *str, int8u len, const int8u *crcstr)
152 {
153     int8u checkSum;
154     if(str == NULL || crcstr== NULL)
155         return FALSE;
156     GetCRC(str,len,&checkSum);
157     if(checkSum != *crcstr)
158         return FALSE;
159     else
160         return TRUE;
161 }
162 
163 // 获取CRC
164 bool GetCRC(const int8u *str, int8u len, int8u *crcstr)
165 {
166     int8u i;
167     int8u checkSum;
168     if(str == NULL || crcstr== NULL)
169         return FALSE;
170     checkSum = *str;
171     for(i=1; i<len; i++)
172     {
173         checkSum ^= *(str+i);
174     }
175     *crcstr = checkSum;
176     return TRUE;
177 }
原文地址:https://www.cnblogs.com/skl374199080/p/3524596.html