打印
[STM32L0]

基于STM32L073的USART+DMA实现串口通信

[复制链接]
5452|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
昨天有幸获得21小跑堂送的STML073开发板,今天先开个贴,晒晒照片。


后续补充上程序。
沙发
mmuuss586| | 2016-3-5 08:09 | 只看该作者

不错,支持下;

使用特权

评论回复
板凳
yklstudent|  楼主 | 2016-3-6 15:05 | 只看该作者
STM32L073+USART_DMA范例讲解
由于以前学习、开发STM32程序时,都是利用STM32的标准库来开发程序的。得到STM32L073学习板后,就去STM32官网查找STM32L0系列的库文件;找了半天发现STML0系列没有标准库而只要HAL库来,所以今天就利用HAL库来写篇基于STML073利用USART1+DMAUSART4+DMA串口通信(实现MODBUS协议和串口控制LED).
1、  平台:
程序库版本:STM32L0系列1.4.0版本HAL库;
软件平台:KEIL 5.14
调试工具:JLINK V9
2、  新建工程如下图所示:
                              
3、移植代码
参考stm32cubel0\STM32Cube_FW_L0_V1.4.0\Projects\STM32L073RZ-Nucleo下的UART串口通信范例移植代码如下所示:
externDMA_HandleTypeDef lusHdma_Uart1_tx;
externDMA_HandleTypeDef lusHdma_Uart1_rx;
externDMA_HandleTypeDef lusHdma_Uart4_tx;
externDMA_HandleTypeDef lusHdma_Uart4_rx;
voidHAL_UART_MspInit(UART_HandleTypeDef *huart)
{
         GPIO_InitTypeDef  GPIO_InitStruct;
  
         if(huart->Instance == USART1)
         {
                   /*##-2- Configure peripheralGPIO ##########################################*/  
                   /* UART TX and RX GPIO pinconfiguration  */
                   GPIO_InitStruct.Pin       = GPIO_PIN_9;
                   GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
                   GPIO_InitStruct.Pull      = GPIO_PULLUP;
                   GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
                   GPIO_InitStruct.Alternate =GPIO_AF4_USART1;
                   HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
                   /* UART RX GPIO pinconfiguration  */
                   GPIO_InitStruct.Pin =GPIO_PIN_10;
                   GPIO_InitStruct.Alternate =GPIO_AF4_USART1;
                   HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
                   /*##-3- Configure the DMA##################################################*/
                   /* Configure the DMA handlerfor Transmission process */
                   lusHdma_Uart1_tx.Instance                 = DMA1_Channel4;
                   lusHdma_Uart1_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
                   lusHdma_Uart1_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
                   lusHdma_Uart1_tx.Init.MemInc              = DMA_MINC_ENABLE;
                   lusHdma_Uart1_tx.Init.PeriphDataAlignment= DMA_PDATAALIGN_BYTE;
                   lusHdma_Uart1_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
                   lusHdma_Uart1_tx.Init.Mode                = DMA_NORMAL;
                   lusHdma_Uart1_tx.Init.Priority            = DMA_PRIORITY_LOW;
                   lusHdma_Uart1_tx.Init.Request             = DMA_REQUEST_3;
                  HAL_DMA_Init(&lusHdma_Uart1_tx);
                   /* Associate the initializedDMA handle to the UART handle */
                   __HAL_LINKDMA(huart, hdmatx,lusHdma_Uart1_tx);
                  
                   /* Configure the DMA handlerfor reception process */
                   lusHdma_Uart1_rx.Instance                 = DMA1_Channel5;
                   lusHdma_Uart1_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
                   lusHdma_Uart1_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
                   lusHdma_Uart1_rx.Init.MemInc              = DMA_MINC_ENABLE;
                   lusHdma_Uart1_rx.Init.PeriphDataAlignment= DMA_PDATAALIGN_BYTE;
                   lusHdma_Uart1_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
                   lusHdma_Uart1_rx.Init.Mode                = DMA_NORMAL;
                   lusHdma_Uart1_rx.Init.Priority            = DMA_PRIORITY_HIGH;
                   lusHdma_Uart1_rx.Init.Request             = DMA_REQUEST_3;
                   HAL_DMA_Init(&lusHdma_Uart1_rx);
                   /* Associate the initializedDMA handle to the the UART handle */
                   __HAL_LINKDMA(huart, hdmarx,lusHdma_Uart1_rx);
         }
         else if(huart->Instance == USART4)
         {
                   /*##-2- Configure peripheralGPIO ##########################################*/  
                   /* UART TX and RX GPIO pinconfiguration  */
                   GPIO_InitStruct.Pin       = GPIO_PIN_10|GPIO_PIN_11;
                   GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
                   GPIO_InitStruct.Pull      =GPIO_PULLUP;
                   GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
                   GPIO_InitStruct.Alternate =GPIO_AF6_USART4;
                   HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);
                   /*##-3- Configure the DMA##################################################*/
                   /* Configure the DMA handlerfor Transmission process */
                   lusHdma_Uart4_tx.Instance                 = DMA1_Channel7;
                   lusHdma_Uart4_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
                   lusHdma_Uart4_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
                   lusHdma_Uart4_tx.Init.MemInc              = DMA_MINC_ENABLE;
                   lusHdma_Uart4_tx.Init.PeriphDataAlignment= DMA_PDATAALIGN_BYTE;
                   lusHdma_Uart4_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
                   lusHdma_Uart4_tx.Init.Mode                = DMA_NORMAL;
                   lusHdma_Uart4_tx.Init.Priority            = DMA_PRIORITY_LOW;
                   lusHdma_Uart4_tx.Init.Request             = DMA_REQUEST_12;
                   HAL_DMA_Init(&lusHdma_Uart4_tx);
                   /* Associate the initializedDMA handle to the UART handle */
                   __HAL_LINKDMA(huart, hdmatx, lusHdma_Uart4_tx);
                  
                   /* Configure the DMA handlerfor reception process */
                   lusHdma_Uart4_rx.Instance                 = DMA1_Channel6;
                   lusHdma_Uart4_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
                   lusHdma_Uart4_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
                   lusHdma_Uart4_rx.Init.MemInc              = DMA_MINC_ENABLE;
                   lusHdma_Uart4_rx.Init.PeriphDataAlignment= DMA_PDATAALIGN_BYTE;
                   lusHdma_Uart4_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
                   lusHdma_Uart4_rx.Init.Mode                = DMA_NORMAL;
                   lusHdma_Uart4_rx.Init.Priority            = DMA_PRIORITY_HIGH;
                   lusHdma_Uart4_rx.Init.Request             = DMA_REQUEST_12;
                   HAL_DMA_Init(&lusHdma_Uart4_rx);
                   /* Associate the initializedDMA handle to the the UART handle */
                   __HAL_LINKDMA(huart, hdmarx,lusHdma_Uart4_rx);
         }
}
voidHAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
         if(huart->Instance == USART1)
         {
                   /*##-1- Reset peripherals##################################################*/
                   __HAL_RCC_USART1_FORCE_RESET();
                   __HAL_RCC_USART1_RELEASE_RESET();
                   /*##-2- Disable peripheralsand GPIO Clocks #################################*/
                   /* Configure USARTx Tx asalternate function  */
                   HAL_GPIO_DeInit(GPIOA,GPIO_PIN_9);
                   /* Configure USARTx Rx asalternate function  */
                   HAL_GPIO_DeInit(GPIOA,GPIO_PIN_10);
           
                   /*##-3- Disable the DMA#####################################################*/
                   /* De-Initialize the DMAchannel associated to reception process */
                   if(huart->hdmarx != 0)
                   {
                            HAL_DMA_DeInit(huart->hdmarx);
                   }
                   /* De-Initialize the DMAchannel associated to transmission process */
                   if(huart->hdmatx != 0)
                   {
                            HAL_DMA_DeInit(huart->hdmatx);
                   }  
         }
         else if(huart->Instance == USART4)
         {
                   /*##-1- Reset peripherals##################################################*/
                   __HAL_RCC_USART4_FORCE_RESET();
                   __HAL_RCC_USART4_RELEASE_RESET();
                   /*##-2- Disable peripheralsand GPIO Clocks #################################*/
                   /* Configure USARTx Tx asalternate function  */
                   HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10);
                   /* Configure USARTx Rx asalternate function  */
                   HAL_GPIO_DeInit(GPIOC,GPIO_PIN_11);
           
                   /*##-3- Disable the DMA#####################################################*/
                   /* De-Initialize the DMAchannel associated to reception process */
                   if(huart->hdmarx != 0)
                   {
                            HAL_DMA_DeInit(huart->hdmarx);
                   }
                   /* De-Initialize the DMAchannel associated to transmission process */
                   if(huart->hdmatx != 0)
                   {
                            HAL_DMA_DeInit(huart->hdmatx);
                   }
         }
}
其中
AUSART1引脚为GPIOAGPIO_PIN_9GPIO_PIN_10DMADMA1_Channle4DMA1_Channel5通道;
BUSART2引脚为GPIOCGPIO_PIN_10GPIO_PIN_11DMADMA1_Channel6DMA1_Channel7通道;
4、  串口配置初始化
A、 使能GPIOA和GPIOC时钟;
B、 使能DMA1、USART1和USART2时钟;
C、 设置DMA1、USART1和USART2中断;
D、 配置USART1和USART2串口;
5、  配置DMA+USART1和DMA+USART2串口接收
HAL_UART_Receive_DMA(&lusUart1Handle,(uint8_t *)aRxBuffer, MAX_BUF_SIZE);
HAL_UART_Receive_DMA(&lusUart4Handle,(uint8_t *)bRxBuffer, MAX_BUF_SIZE);
6、  测试此函数功能时,发现DMA必须接收到MAX_BUF_SIZE数据后,才能触发调用HAL_UART_RxCpltCallback函数;为了实现发送任意长度的串口数据都能触发调用HAL_UART_RxCpltCallback函数,需要修改stm32l0xx_hal_usart.c库文件,
7、修改内容如下所示:
A、添加USART的IDLE空闲中断
在stm32l0xx_hal_usart.c文件内查找到HAL_UART_Receive_DMA函数,添加开启串口UART_IT_IDLE空闲中断,如下所示
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart,uint8_t *pData, uint16_t Size)
{
  uint32_t *tmp;
  
  if((huart->State ==HAL_UART_STATE_READY) || (huart->State == HAL_UART_STATE_BUSY_TX))
  {
    if((pData == NULL ) ||(Size == 0))
    {
      return HAL_ERROR;
    }
   
    /* Process Locked */
    __HAL_LOCK(huart);
   
    huart->pRxBuffPtr =pData;
    huart->RxXferSize =Size;
   
    huart->ErrorCode =HAL_UART_ERROR_NONE;
    /* Check if a transmitprocess is ongoing or not */
    if(huart->State ==HAL_UART_STATE_BUSY_TX)
    {
      huart->State =HAL_UART_STATE_BUSY_TX_RX;
    }
    else
    {
      huart->State =HAL_UART_STATE_BUSY_RX;
    }
   
    /* Set the UART DMAtransfert complete callback */
   huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;
   
    /* Set the UART DMA Halftransfer complete callback */
   huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;
   
    /* Set the DMA errorcallback */
   huart->hdmarx->XferErrorCallback = UART_DMAError;
    /* Enable the DMA Stream*/
    tmp =(uint32_t*)&pData;
   HAL_DMA_Start_IT(huart->hdmarx,(uint32_t)&huart->Instance->RDR, *(uint32_t*)tmp, Size);
    /* Enable the DMA transferfor the receiver request by setting the DMAR bit
       in the UART CR3register */
    huart->Instance->CR3 |= USART_CR3_DMAR;
   
     /* Process Unlocked */
     __HAL_UNLOCK(huart);
//modify by kl.yao 2016/03/04
/* Enable the UART IDLEInterrupt */
__HAL_UART_ENABLE_IT(huart,UART_IT_IDLE);
     
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}
B、添加串口IDLE空闲中断处理
在stm32l0xx_hal_usart.c文件内查找到HAL_UART_IRQHandler函数,添加串口IDLE空闲中断处理,如下所示:
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  /* UART parity errorinterrupt occurred ------------------------------------*/
  if((__HAL_UART_GET_IT(huart,UART_IT_PE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE)!= RESET))
  {
    __HAL_UART_CLEAR_IT(huart,UART_CLEAR_PEF);
   
    huart->ErrorCode |=HAL_UART_ERROR_PE;
    /* Set the UART stateready to be able to start again the process */
    huart->State =HAL_UART_STATE_READY;
  }
  
  /* UART frame errorinterrupt occured --------------------------------------*/
  if((__HAL_UART_GET_IT(huart,UART_IT_FE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR)!= RESET))
  {
    __HAL_UART_CLEAR_IT(huart,UART_CLEAR_FEF);
   
    huart->ErrorCode |=HAL_UART_ERROR_FE;
    /* Set the UART stateready to be able to start again the process */
    huart->State =HAL_UART_STATE_READY;
  }
  
  /* UART noise errorinterrupt occured --------------------------------------*/
  if((__HAL_UART_GET_IT(huart,UART_IT_NE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR)!= RESET))
  {
    __HAL_UART_CLEAR_IT(huart,UART_CLEAR_NEF);
   
    huart->ErrorCode |=HAL_UART_ERROR_NE;
    /* Set the UART stateready to be able to start again the process */
    huart->State =HAL_UART_STATE_READY;
  }
  
  /* UART Over-Run interruptoccured -----------------------------------------*/
  if((__HAL_UART_GET_IT(huart,UART_IT_ORE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR)!= RESET))
  {
    __HAL_UART_CLEAR_IT(huart,UART_CLEAR_OREF);
   
    huart->ErrorCode |=HAL_UART_ERROR_ORE;
    /* Set the UART stateready to be able to start again the process */
    huart->State =HAL_UART_STATE_READY;
  }
   /* Call UART Error Callback function if need be --------------------------*/
  if(huart->ErrorCode !=HAL_UART_ERROR_NONE)
  {
   HAL_UART_ErrorCallback(huart);
  }
  /* UART Wake Up interruptoccured ------------------------------------------*/
  if((__HAL_UART_GET_IT(huart,UART_IT_WUF) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_WUF)!= RESET))
  {
    __HAL_UART_CLEAR_IT(huart,UART_CLEAR_WUF);
    /* Set the UART stateready to be able to start again the process */
    huart->State =HAL_UART_STATE_READY;
   HAL_UARTEx_WakeupCallback(huart);
  }
  
  /* UART in mode Receiver---------------------------------------------------*/
  if((__HAL_UART_GET_IT(huart,UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart,UART_IT_RXNE) != RESET))
  {
    UART_Receive_IT(huart);
  }
  
  /* UART in mode Transmitter------------------------------------------------*/
  if((__HAL_UART_GET_IT(huart,UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE)!= RESET))
  {
    UART_Transmit_IT(huart);
  }
  /* UART in mode Transmitter-- TC ------------------------------------------*/
if((__HAL_UART_GET_IT(huart,UART_IT_TC) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC) !=RESET))
  {
   UART_EndTransmit_IT(huart);
  }   
  /* UART in mode IDLE-------------------------------------------------------*/
if((__HAL_UART_GET_IT(huart,UART_IT_IDLE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart,UART_IT_IDLE) != RESET))
  {
/* Disable the UART TransmitComplete Interrupt */   
__HAL_UART_CLEAR_IT(huart,UART_CLEAR_IDLEF);
    UART_EndReceive_IT(huart);
  }  
}
8、  串口通信处理任务描述
voidapp_usart_task(void)
{
         /*USART1*/
         if(Inverter1_Slave_QueueStack.QueueIsEmpty(&Inverter1_Slave_QueueStack.Queue)== 0)
         {
                   Inverter1_Slave_QueueStack.QueueOut(&Inverter1_Slave_QueueStack.Queue,lubRx1Buf, &luwRx1Len);        //从缓存区读取数据
                   //接收判断与处理
                   Inverter_recv_data_analysis(lubRx1Buf,&luwRx1Len);
                   //数据发送
                   usart_tran_data_inverter(&lusUart1Handle,lubRx1Buf, luwRx1Len);
         }
         /*USART4*/
         if(Inverter2_Slave_QueueStack.QueueIsEmpty(&Inverter2_Slave_QueueStack.Queue)== 0)
         {
                   Inverter2_Slave_QueueStack.QueueOut(&Inverter2_Slave_QueueStack.Queue,lubRx4Buf, &luwRx4Len);        //从缓存区读取数据
                   //解析数据包
                   sAnalyProtocal(lubRx4Buf);
                   memset(lubRx4Buf, 0x00,sizeof(lubRx4Buf));
         }
}
voidHAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
         if(UartHandle->Instance == USART1)
         {
                   usart_recv_data_inverter(UartHandle,aRxBuffer, UartHandle->RxXferSize -UartHandle->hdmarx->Instance->CNDTR);
                   UartHandle->hdmarx->Lock= HAL_UNLOCKED;
                   HAL_UART_Receive_DMA(UartHandle,(uint8_t *)aRxBuffer, MAX_BUF_SIZE);
         }
         else if(UartHandle->Instance ==USART4)
         {
                   usart_recv_data_inverter(UartHandle,bRxBuffer, UartHandle->RxXferSize -UartHandle->hdmarx->Instance->CNDTR);
                   UartHandle->hdmarx->Lock= HAL_UNLOCKED;
                   HAL_UART_Receive_DMA(UartHandle,(uint8_t *)bRxBuffer, MAX_BUF_SIZE);
         }
}
描述:
A、 串口进入IDLE空闲中断后,触发调用HAL_UART_RxCpltCallback函数,然后根据串口号进行数据保存(数据保存到FIFO);
B、 通信任务函数时刻检测判断FIFO内是否有数据,然后读取FIFO内数据进行处理;
C、 USART1+DMA用来进行MODBUS通信;
D、 USART2+DMA用来通信控制LED亮灭;
9、最后上整个工程文件(包含全部源代码)
STM32L073RZ_RTT_Example.rar (1.26 MB)

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:本人熟悉STM32、PIC、AVR等嵌入式软件开发;联系方式:524716771.

39

主题

3256

帖子

22

粉丝