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.
Previous article:STM32 HAL library timed interrupts and encoding input
Next article:STM32F429HAL library timer study notes
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- 10-channel logic analyzer based on VGA display.pdf
- TFTP network burning system
- Introduction to the estimation method of the remaining capacity SOC of lithium batteries
- Advances in radar technology and the development of in-cockpit sensing technology
- Is it so difficult to post a message?
- [RVB2601 Creative Application Development] Ultrasonic pressure-sensitive buttons based on RISC-V processor
- First of all, the 9 boards sent by National Technology have arrived. It's so fast.
- There is no year-end bonus this year.
- Pingtou Ge RRVB2601 Review: Unboxing, Hardware Analysis and Environment Setup
- OrangePi Zero GPIO Control