STM32F429串口(HAL)学习之发送篇

串口初始化

void MX_USART3_UART_Init(void)
{
    UART3_Handler.Instance             = USART3;
    UART3_Handler.Init.BaudRate     = 2400;
    UART3_Handler.Init.WordLength     = UART_WORDLENGTH_9B;      //发送8位和9位是一样的道理  
    UART3_Handler.Init.StopBits     = UART_STOPBITS_1;
    UART3_Handler.Init.Parity         = UART_PARITY_NONE;
    UART3_Handler.Init.Mode         = UART_MODE_TX_RX;
    UART3_Handler.Init.HwFlowCtl     = UART_HWCONTROL_NONE;
    UART3_Handler.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&UART3_Handler) != HAL_OK)     //这个函数中会调用下面这个函数//HAL_UART_MspInit(UART_HandleTypeDef *huart)
    {
        //Error_Handler();  //我的实验工程中没有实现这个函数
    }
}

UART底层初始化,时钟使能,引脚配置,中断配置,使用的是MX主动生成的函数,其实道理一样就是初始化串口,将相关的数据填入对应的寄存器,我试过自己直接操作寄存器(像操作单片机一样),实现也使用一样,为了方便

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{

    //如果是串口3,进行串口3 MSP初始化
      if(huart->Instance==USART3)
      {
      /* USER CODE BEGIN USART3_MspInit 0 */

      /* USER CODE END USART3_MspInit 0 */
        /* USART3 clock enable */
        __HAL_RCC_USART3_CLK_ENABLE();
      
        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**USART3 GPIO Configuration    
        PB10     ------> USART3_TX
        PB11     ------> USART3_RX 
        */
        GPIO_InitStruct.Pin         = GPIO_PIN_10|GPIO_PIN_11;
        GPIO_InitStruct.Mode         = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull         = GPIO_NOPULL;
        GPIO_InitStruct.Speed         = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate     = GPIO_AF7_USART3;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        /* USART3 interrupt Init */
        HAL_NVIC_EnableIRQ(USART3_IRQn);
        HAL_NVIC_SetPriority(USART3_IRQn, 3, 3);
        
      /* USER CODE BEGIN USART3_MspInit 1 */

      /* USER CODE END USART3_MspInit 1 */
      }    

}

/*************************************************************************
*串口3:中断服务程序
*************************************************************************/
void USART3_IRQHandler(void)                    

    HAL_UART_IRQHandler(&UART3_Handler);    //调用HAL库中断处理公用函数
}

/*************************************************************************
*工程中只要调用这个函数即可以发生数据
*************************************************************************/
void    modules_common_total(void)
{
    if(modules_commt_send.commt_send_state)
    {
        if(modules_commt_send.commt_send_second_dat_signl == 0)
        {
            modules_commt_send.commt_send_second_dat_signl = 1;
            HAL_UART_Transmit(&UART3_Handler,(uint8_t *)modules_commt_send.commt_send_dat_buf,modules_commt_send.commt_send_dat_count,0xffff);            
        }
    }
    if(modules_commt_send.commt_send_state == 0)
    {
        .......
    }
}

这里要说明的是,串口监视软件的使用,我使用的是9位数据发送,一般的串口监控只有8位,那么需要使用的是将校验位设置为“0校验”(STC下载程序的软件里有个串口助手具备这个功能),这样就能监控到传输的前八位是否正常)最高位没有办法,若有能监控到9位的软件,望朋友告知

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint16_t* tmp;
  uint32_t tmp1 = 0;
 
  tmp1 = huart->State;//串口状态
  if((tmp1 == HAL_UART_STATE_READY) || (tmp1 == HAL_UART_STATE_BUSY_RX))//准备就绪,正在接收状态,反正发送不忙
  {
    if((pData == NULL ) || (Size == 0)) 
    {
      return  HAL_ERROR;
    }
    
    /* Process Locked */
    __HAL_LOCK(huart);
    
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    /* Check if a non-blocking receive process is ongoing or not */
    if(huart->State == HAL_UART_STATE_BUSY_RX) 
    {
      huart->State = HAL_UART_STATE_BUSY_TX_RX;
    }
    else
    {
      huart->State = HAL_UART_STATE_BUSY_TX;
    }

    huart->TxXferSize = Size;
    huart->TxXferCount = Size;            //剩余发送数量
    while(huart->TxXferCount > 0)
    {
      huart->TxXferCount--;
       /*

       //实验时自己在这里添加的几句

       if(huart->TxXferCount == 0)
        {
            modules_commt_send.commt_send_state = 0;
        }

*/
      if(huart->Init.WordLength == UART_WORDLENGTH_9B)  //9位数据模式
      {
        if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, Timeout) != HAL_OK)
        { //上面这里是检测SR中是否为TXE=1,为1表示DR中可以接受新的数据,上个数据已经开始发送
          return HAL_TIMEOUT;
        }
        tmp = (uint16_t*) pData;        
        huart->Instance->DR = (*tmp & (uint16_t)0x01FF);      //写入数据后会自动启动发送
        if(huart->Init.Parity == UART_PARITY_NONE)        //#define  UART_PARITY_NONE     ((uint32_t)0x00000000)
        {    //在初始化串口的时候会有这句 UART3_Handler.Init.Parity         = UART_PARITY_NONE;
          pData +=2;  
        }
        else
        { 
          pData +=1;
        }
      } 
      else
      {
        if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, Timeout) != HAL_OK)
        {
          return HAL_TIMEOUT;
        }
        huart->Instance->DR = (*pData++ & (uint8_t)0xFF);        
      } 
    }
    
    if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, Timeout) != HAL_OK)
    { 
      return HAL_TIMEOUT;
    }
    
    /* Check if a non-blocking receive process is ongoing or not */
    if(huart->State == HAL_UART_STATE_BUSY_TX_RX) 
    {
      huart->State = HAL_UART_STATE_BUSY_RX;
    }
    else
    {
      huart->State = HAL_UART_STATE_READY;
    }
    
    /* Process Unlocked */
    __HAL_UNLOCK(huart);
    
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;   
  }
}

从上面这个函数看出,这里是个死循环,一直会等到发送完成,但是要注意了,这个函数调用后并不能进入发送中断回调函数HAL_UART_TxCpltCallback(),这是因为没有置位TXEIE,不会产生中断,而UART_Transmit_IT(huart);函数中有会程序如下

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t tmp = 0;
  
  tmp = huart->State;
  if((tmp == HAL_UART_STATE_READY) || (tmp == HAL_UART_STATE_BUSY_RX))
  {
    if((pData == NULL ) || (Size == 0)) 
    {
      return HAL_ERROR;
    }
    
    /* Process Locked */
    __HAL_LOCK(huart);
    
    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    /* Check if a receive process is ongoing or not */
    if(huart->State == HAL_UART_STATE_BUSY_RX) 
    {
      huart->State = HAL_UART_STATE_BUSY_TX_RX;
    }
    else
    {
      huart->State = HAL_UART_STATE_BUSY_TX;
    }

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    /* Enable the UART Transmit data register empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_TXE);          
    
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;   
  }
}

__HAL_UART_ENABLE_IT(huart, UART_IT_TXE);     这一句很重要,

它是这样的

#define UART_IT_TXE                      ((uint32_t)(UART_CR1_REG_INDEX << 28 | USART_CR1_TXEIE))

这就能形成中断,我尝试在HAL_StatusTypeDef HAL_UART_Transmit()中合适的位置添加这样一句__HAL_UART_ENABLE_IT(huart, UART_IT_TXE); 也将产生中断,

遗憾的是 HAL_UART_Transmit_IT()不支持9位数据发送,需要直接进行修改,接下来我只能自己改了

中断程序如下

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t tmp1 = 0, tmp2 = 0;

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  
  /* UART parity error interrupt occurred ------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_PEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_PE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART frame error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_FEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_FE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART noise error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_NEFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_NE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART Over-Run interrupt occurred ----------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_OREFLAG(huart);
    
    huart->ErrorCode |= HAL_UART_ERROR_ORE;
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
  /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    UART_Receive_IT(huart);
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);
  /* UART in mode Transmitter ------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_Transmit_IT(huart);
  }
  
  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC);
  /* UART in mode Transmitter end --------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_EndTransmit_IT(huart);
  }

  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
    
    HAL_UART_ErrorCallback(huart);
  }  
}

中断与这几个函数有关UART_Receive_IT(huart); UART_Transmit_IT(huart);UART_EndTransmit_IT(huart);但是与HAL_UART_Transmit();无关,

你可能感兴趣的:(STM32F429串口(HAL)学习之发送篇)