Use of STM32L0xx_HAL_Driver library——UART

Publisher:小九分析仪Latest update time:2018-12-29 Keywords:STM32L0xx  HAL  UART Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

MCU model: STM32L051C8T6


Development environment MDK5.12


Library version: STM32L0xx_HAL_Driver V1.1.0


Host environment: Windows XP


I used to use the STM32F030C8T6 microcontroller for development. Due to changes in requirements, I replaced it with a new model STM32L051C8T6, mainly because of its low power consumption. I thought I could just copy the code and use it. It turned out to be too naive. The library used by STM32F030C8T6 is STM32F0_StdPeriph_Lib and the library used by STM32L051C8T6 is STM32L0xx_HAL_Driver. The difference between the two is still very large, and the official also recommends the latter. There is no way, I have to learn it again... Referring to its routine, I can barely write a project, and here I will write about UART debugging.


The reference program is the UART_TwoBoards_ComIT project in the STM32L053R8-Nucleo example, which uses interrupts to communicate between two microcontrollers. The layering of the STM32L0xx_HAL_Driver library is more obvious, and the board initialization code is as follows



void HAL_UART_MspInit(UART_HandleTypeDef *huart)

{  

  GPIO_InitTypeDef  GPIO_InitStruct;

  

  /*##-1- Enable peripherals and GPIO Clocks #################################*/

  /* Enable GPIO TX/RX clock */

  USARTx_TX_GPIO_CLK_ENABLE();

  USARTx_RX_GPIO_CLK_ENABLE();

  /* Enable USART1 clock */

  USARTx_CLK_ENABLE(); 

  

  /*##-2- Configure peripheral GPIO ##########################################*/  

  /* UART TX GPIO pin configuration  */

  GPIO_InitStruct.Pin = USARTx_TX_PIN;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull      = GPIO_NOPULL;

  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;

  GPIO_InitStruct.Alternate = USARTx_TX_AF;

  

  HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);

    

  /* UART RX GPIO pin configuration  */

  GPIO_InitStruct.Pin = USARTx_RX_PIN;

  GPIO_InitStruct.Alternate = USARTx_RX_AF;

    

  HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);

    

  /*##-3- Configure the NVIC for UART ########################################*/

  /* NVIC for USART1 */

  HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1);

  HAL_NVIC_EnableIRQ(USARTx_IRQn);

}

 

/**

  * @brief UART MSP De-Initialization 

  *        This function frees the hardware resources used in this example:

  *          - Disable the Peripheral's clock

  *          - Revert GPIO and NVIC configuration to their default state

  * @param huart: UART handle pointer

  * @retval None

  */

void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)

{

  /*##-1- Reset peripherals ##################################################*/

  USARTx_FORCE_RESET();

  USARTx_RELEASE_RESET();

 

  /*##-2- Disable peripherals and GPIO Clocks #################################*/

  /* Configure UART Tx as alternate function  */

  HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN);

  /* Configure UART Rx as alternate function  */

  HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN);

  

  /*##-3- Disable the NVIC for UART ##########################################*/

  HAL_NVIC_DisableIRQ(USARTx_IRQn);

}


There is nothing much to say about these two functions. Just modify them according to the development board. This makes the serial port initialization more concise and only requires logical initialization.


/**********************************************************************

Function: uart_init()

Function: Serial port initialization

parameter:

uint32_t BaudRate==========================Serial port baud rate

Return value: None

Previous version: None

Current version: 1.0

author:

Last modified:2015-04-02

illustrate: 

**********************************************************************/

void uart_init(uint32_t BaudRate)

{

    

    UartHandle.Instance        = USARTx;

    UartHandle.Init.BaudRate   = BaudRate;

    UartHandle.Init.WordLength = UART_WORDLENGTH_8B;

    UartHandle.Init.StopBits   = UART_STOPBITS_1;

    UartHandle.Init.Parity     = UART_PARITY_NONE;

    UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;

    UartHandle.Init.Mode       = UART_MODE_TX_RX;

    

    if(HAL_UART_Init(&UartHandle) != HAL_OK)

    {

        Error_Handler();

    }

__HAL_UART_ENABLE(&UartHandle);

 

NVIC_SetPriority(USARTx_IRQn,0);

NVIC_EnableIRQ(USARTx_IRQn);

uart_rev.front = aRxBuffer;

uart_rev.rear = aRxBuffer; //The two pointers point to the same address space

if(HAL_UART_Receive_IT(&UartHandle,(uint8_t*)aRxBuffer,1) != HAL_OK)

{

Error_Handler();

}

}


Here, a 500-byte buffer aRxBuffer is opened for serial port reception. The head and tail pointers are used to receive and access data, that is, a single buffer mechanism.


struct uart

{

uint8_t *rear; //Change in interrupt function

uint8_t *front; //Change in the main loop

};


Since the STM32L0xx_Hal_Driver library uses three types of serial ports: query mode, interrupt mode, and DMA mode, all of which are implemented using HAL functions. Therefore, we cannot automatically open the interrupt mode reception. We must use the function HAL_UART_Receive_IT to open the receive interrupt. Here, we enter the interrupt every time we receive a byte. The use of the STM32L0xx_Hal_Driver library makes the interrupt function very concise and can be done in one sentence. The callback function mechanism is used to handle interrupts.


void USARTx_IRQHandler(void)

{

  HAL_UART_IRQHandler(& UartHandle);

}

The callback function of the serial port receive interrupt will be automatically called in HAL_UART_IRQHandler()


/**

  * @brief  Rx Transfer completed callback

  * @param  UartHandle: UART handle

  * @note   This example shows a simple way to report end of IT Rx transfer, and 

  *         you can add your own implementation.

  * @retval None

  */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)

{

uint8_t right = HAL_OK;

/* Set transmission flag: trasfer complete*/

uart_rev.rear++; //Update rear pointer

if(uart_rev.rear >= (aRxBuffer + BUFFSIZE))

uart_rev.rear = aRxBuffer;

do

{

ret = HAL_UART_Receive_IT(UartHandle,uart_rev.rear,1);

}while(ret != HAL_OK);

}


Each time the received data is stored in the address space pointed to by rear, storing data only updates the rear pointer and starts requesting the arrival of the next data. In the main function, call the uart_read function to retrieve the data


/**********************************************************************

Function: uart_read()

Function: Read data from the receive buffer

parameter:

uint8_t *fmt--------------------------------Received data

uint16_t time_out---------------------------Timeout

Return value: 0: data is read - 1: no data is read

Previous version: None

Current version: 1.0

author:

Last modified:2015-04-08

illustrate: 

**********************************************************************/

int8_t uart_read(uint8_t *fmt, uint16_t time_out)

{

while(time_out)

{

if(uart_rev.front != uart_rev.rear)

{

//If the head pointer and tail pointer are different, it means that there is data in the buffer that has not been received

*fmt=*uart_rev.front;


uart_rev.front++;

 

if (uart_rev.front >= (aRxBuffer+BUFFSIZE))

uart_rev.front = aRxBuffer;

 

return 0;

}

time_out--;

}

return (int8_t)-1;

}


Fetching data only updates the front pointer. There is a shortcoming here. If you don't fetch data or fetch data slowly, and receive a lot of data, it will cause data overwriting, that is, data loss. However, this rarely happens (for me, I keep reading in the main loop, so it's okay). The whole file is as follows


#include "UART.h"

#include "stm32l0xx_hal_def.h"

#include "utils.h"

 

UART_HandleTypeDef UartHandle;

uint8_t aRxBuffer[BUFFSIZE];

struct uart uart_rev;

 

void HAL_UART_MspInit(UART_HandleTypeDef *huart)

{  

  GPIO_InitTypeDef  GPIO_InitStruct;

  

  /*##-1- Enable peripherals and GPIO Clocks #################################*/

  /* Enable GPIO TX/RX clock */

  USARTx_TX_GPIO_CLK_ENABLE();

  USARTx_RX_GPIO_CLK_ENABLE();

  /* Enable USART1 clock */

  USARTx_CLK_ENABLE(); 

  

  /*##-2- Configure peripheral GPIO ##########################################*/  

  /* UART TX GPIO pin configuration  */

  GPIO_InitStruct.Pin = USARTx_TX_PIN;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull      = GPIO_NOPULL;

  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;

  GPIO_InitStruct.Alternate = USARTx_TX_AF;

  

  HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);

    

  /* UART RX GPIO pin configuration  */

  GPIO_InitStruct.Pin = USARTx_RX_PIN;

  GPIO_InitStruct.Alternate = USARTx_RX_AF;

    

  HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);

    

  /*##-3- Configure the NVIC for UART ########################################*/

  /* NVIC for USART1 */

  HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1);

  HAL_NVIC_EnableIRQ(USARTx_IRQn);

}

 

/**

  * @brief UART MSP De-Initialization 

  *        This function frees the hardware resources used in this example:

  *          - Disable the Peripheral's clock

  *          - Revert GPIO and NVIC configuration to their default state

  * @param huart: UART handle pointer

  * @retval None

  */

void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)

{

  /*##-1- Reset peripherals ##################################################*/

  USARTx_FORCE_RESET();

  USARTx_RELEASE_RESET();

 

  /*##-2- Disable peripherals and GPIO Clocks #################################*/

  /* Configure UART Tx as alternate function  */

  HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN);

  /* Configure UART Rx as alternate function  */

  HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN);

  

  /*##-3- Disable the NVIC for UART ##########################################*/

  HAL_NVIC_DisableIRQ(USARTx_IRQn);

}

 

/**********************************************************************

Function: uart_init()

Function: Serial port initialization

parameter:

uint32_t BaudRate==========================Serial port baud rate

Return value: None

Previous version: None

Current version: 1.0

author:

Last modified:2015-04-02

illustrate: 

**********************************************************************/

void uart_init(uint32_t BaudRate)

{

    

    UartHandle.Instance        = USARTx;

    UartHandle.Init.BaudRate   = BaudRate;

    UartHandle.Init.WordLength = UART_WORDLENGTH_8B;

    UartHandle.Init.StopBits   = UART_STOPBITS_1;

    UartHandle.Init.Parity     = UART_PARITY_NONE;

    UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;

    UartHandle.Init.Mode       = UART_MODE_TX_RX;

    

    if(HAL_UART_Init(&UartHandle) != HAL_OK)

    {

        Error_Handler();

    }

__HAL_UART_ENABLE(&UartHandle);

 

NVIC_SetPriority(USARTx_IRQn,0);

NVIC_EnableIRQ(USARTx_IRQn);

uart_rev.front = aRxBuffer;

uart_rev.rear = aRxBuffer; //The two pointers point to the same address space

if(HAL_UART_Receive_IT(&UartHandle,(uint8_t*)aRxBuffer,1) != HAL_OK)

{

Error_Handler();

}

}

void Error_Handler(void)

{

    while(1)

    {

        

    }

}

 

/**********************************************************************

Function: uart_read()

Function: Read data from the receive buffer

parameter:

uint8_t *fmt--------------------------------Received data

uint16_t time_out---------------------------Timeout

Return value: 0: data is read - 1: no data is read

Previous version: None

Current version: 1.0

author:

Last modified:2015-04-08

illustrate: 

**********************************************************************/

int8_t uart_read(uint8_t *fmt, uint16_t time_out)

{

while(time_out)

{

if(uart_rev.front != uart_rev.rear)

{

//If the head pointer and tail pointer are different, it means that there is data in the buffer that has not been received

*fmt=*uart_rev.front;


uart_rev.front++;

 

if (uart_rev.front >= (aRxBuffer+BUFFSIZE))

uart_rev.front = aRxBuffer;

 

return 0;

}

time_out--;

}

return (int8_t)-1;

}

 

int8_t uart_send(uint8_t *fmt, uint8_t len)

{

while(len)

{

printf("%c",*fmt);

fmt++;

only--;

}

 

return 0;

}

 

#ifdef UART_DEBUG

int fputc(int ch, FILE *f)

{

    USART1->TDR = ch;

    while(!(USART1->ISR & USART_ISR_TXE));

    return(ch);

}

#endif

 

/**

  * @brief  Tx Transfer completed callback

  * @param  UartHandle: UART handle. 

  * @note   This example shows a simple way to report end of IT Tx transfer, and 

  *         you can add your own implementation. 

  * @retval None

  */

void HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart)

{

uint8_t right = HAL_OK;

UartReady = SET;

#if 1

uart_snd.front++; //Update rear pointer

if(uart_snd.front >= (aTxBuffer + BUFFSIZE))

uart_snd.front = aTxBuffer;

if(uart_snd.front != uart_snd.rear)

{

//If the head pointer and tail pointer are different, it means that there is data in the buffer that has not been sent

do

{

ret = HAL_UART_Transmit_IT(&UartHandle,uart_snd.front,1);//Request to send the next data

}while(ret != HAL_OK);

}

#endif

}

/**

  * @brief  Rx Transfer completed callback

  * @param  UartHandle: UART handle

  * @note   This example shows a simple way to report end of IT Rx transfer, and 

  *         you can add your own implementation.

  * @retval None

  */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)

{

uint8_t right = HAL_OK;

/* Set transmission flag: trasfer complete*/

uart_rev.rear++; //Update rear pointer

if(uart_rev.rear >= (aRxBuffer + BUFFSIZE))

uart_rev.rear = aRxBuffer;

do

{

ret = HAL_UART_Receive_IT(UartHandle,uart_rev.rear,1);

}while(ret != HAL_OK);

}

/******************************************************************************/

/*                 STM32L0xx Peripherals Interrupt Handlers                   */

/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */

/*  available peripheral interrupt handler's name please refer to the startup */

/*  file (startup_stm32l0xx.s).                                               */

/******************************************************************************/

/**

  * @brief  This function handles UART interrupt request.  

  * @param  None

  * @retval None

  * @Note   This function is redefined in "main.h" and related to DMA stream 

  *         used for USART data transmission     

  */

void USARTx_IRQHandler(void)

{

  HAL_UART_IRQHandler(& UartHandle);

}


There is no problem in the actual test. When the single buffer mechanism is available, we will consider using the double buffer mechanism, that is, to open a buffer for serial port transmission. I will analyze it next time.


Keywords:STM32L0xx  HAL  UART Reference address:Use of STM32L0xx_HAL_Driver library——UART

Previous article:STM32 HAL library timed interrupts and encoding input
Next article:STM32F429HAL library timer study notes

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号