华大HC32F460 USART串口中断代码详解及应用指南
声明:以下内容只是本人学习心得,分享给同样是小白入嵌入式软件的人。
一、基础知识
USART1基地址为:0x4001_D000
USART2基地址为:0x4001_D400
USART3基地址为:0x4002_1000
USART4基地址为:0x4002_1400
引脚映射:华大HC32F460与STM32F10x的区别在于:HC32F460有64个引脚支持Fun32~63功能选择,即我们说的重映射,Fun32~63主要为串行通信功能(包含USART,SPI, I2C, I2S, CAN);分为了Fun_Grp1、Fun_Grp2。具体可看<数据手册-引脚功能表>。而STM32F10x的GPIO引脚重映射是有规定的,所以华大的用起来比较灵活。
本样例使用的是PB9、PE6重映射到Fun_Grp2中Func36、Func37的USART4_TX、USART4_RX。
二、代码详解
本样例主要展示USART外设配置为USART模式时通过中断方式收发数据。
串口助手软件配置端口参数:
波特率:115200
数据位:8
校验位:None
停止位:1
main.c
-
定义相关IO口
#define LL_PERIPH_SEL (LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | \
LL_PERIPH_EFM | LL_PERIPH_SRAM)
/* USART RX/TX pin definition */
#define USART_RX_PORT (GPIO_PORT_B) /* PB9: USART4_RX */
#define USART_RX_PIN (GPIO_PIN_09)
#define USART_RX_GPIO_FUNC (GPIO_FUNC_37)
#define USART_TX_PORT (GPIO_PORT_E) /* PE6: USART4_TX */
#define USART_TX_PIN (GPIO_PIN_06)
#define USART_TX_GPIO_FUNC (GPIO_FUNC_36)
/* USART unit definition */
#define USART_UNIT (CM_USART4)
#define USART_FCG_ENABLE() (FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USART4, ENABLE))
/* USART interrupt definition */
#define USART_RX_ERR_IRQn (INT000_IRQn)
#define USART_RX_ERR_INT_SRC (INT_SRC_USART4_EI)
#define USART_RX_FULL_IRQn (INT001_IRQn)
#define USART_RX_FULL_INT_SRC (INT_SRC_USART4_RI)
#define USART_TX_EMPTY_IRQn (INT002_IRQn)
#define USART_TX_EMPTY_INT_SRC (INT_SRC_USART4_TI)
#define USART_TX_CPLT_IRQn (INT003_IRQn)
#define USART_TX_CPLT_INT_SRC (INT_SRC_USART4_TCI)
#define LL_PERIPH_SEL 作用:关闭相关寄存器的写保护
#define USART_RX_GPIO_FUNC 作用:将PB9映射到USART4_RX。
#define USART_UNIT 定义USART4的基地址
#define USART_FCG_ENABLE() 使能USART4时钟
#define USART_RX_ERR_IRQn 接收数据错误中断
#define USART_RX_ERR_INT_SRC 接收数据错误中断标志位
#define USART_RX_FULL_IRQn 接收数据满中断
#define USART_RX_FULL_INT_SRC 接收数据满中断标志位
#define USART_TX_EMPTY_IRQn 发送数据空中断
#define USART_TX_EMPTY_INT_SRC 发送数据空中断标志位
#define USART_TX_CPLT_IRQn 发送完成中断
#define USART_TX_CPLT_INT_SRC 发送完成中断标志位
#define RING_BUF_SIZE (500UL)
static uint8_t m_au8DataBuf[RING_BUF_SIZE];//缓存区
static stc_ring_buf_t m_stcRingBuf;//创建一个缓存区结构体
static __IO en_flag_status_t m_enTxCompleteFlag = SET;//发送数据完成标志位
#define RING_BUF_SIZE 缓存区大小
-
接收数据错误中断、接收数据寄存器满中断、发送数据寄存器空中断、发送完成中断回调函数。
static void USART_TxEmpty_IrqCallback(void)
{
uint8_t u8Data;
if (!BUF_Empty(&m_stcRingBuf)) {
(void)BUF_Read(&m_stcRingBuf, &u8Data, 1UL);
USART_WriteData(USART_UNIT, (uint16_t)u8Data);
} else {
USART_FuncCmd(USART_UNIT, USART_INT_TX_CPLT, ENABLE);
}
}
static void USART_TxComplete_IrqCallback(void)
{
m_enTxCompleteFlag = SET;
USART_FuncCmd(USART_UNIT, (USART_TX | USART_INT_TX_CPLT | USART_INT_TX_EMPTY), DISABLE);
}
static void USART_RxFull_IrqCallback(void)
{
uint8_t u8Data = (uint8_t)USART_ReadData(USART_UNIT);
(void)BUF_Write(&m_stcRingBuf, &u8Data, 1UL);
}
static void USART_RxError_IrqCallback(void)
{
(void)USART_ReadData(USART_UNIT);
USART_ClearStatus(USART_UNIT, (USART_FLAG_PARITY_ERR | USART_FLAG_FRAME_ERR | USART_FLAG_OVERRUN));
}
数据的传输都是这样的过程:数据发送->ring_buf->数据接收。
以发送数据寄存器满中断回调函数为例,USART_TxEmpty_IrqCallback。
首先if (!BUF_Empty(&m_stcRingBuf)) 判断ring_buf缓存区是否有数据,不为空就调用ring_buf.c中的BUF_Read(&m_stcRingBuf, &u8Data, 1UL)函数来接收数据。
BUF_Read(&m_stcRingBuf, &u8Data, 1UL) 三个参数说明:
m_stcRingBuf :ring_buf缓存区内的数据
u8Data:用于接收数据
1UL:接收数据的长度。
最后USART_WriteData(USART_UNIT, (uint16_t)u8Data); 将接收到的数据写入到串口。
-
中断使能NVIC
使用任何中断,都得配置NVIC使能相应的中断源。代码具体含义可参考本人前面所发的文章
static void INTC_IrqInstalHandler(const stc_irq_signin_config_t *pstcConfig, uint32_t u32Priority)
{
if (NULL != pstcConfig) {
(void)INTC_IrqSignIn(pstcConfig);
NVIC_ClearPendingIRQ(pstcConfig->enIRQn);
NVIC_SetPriority(pstcConfig->enIRQn, u32Priority);
NVIC_EnableIRQ(pstcConfig->enIRQn);
}
}
-
ring_buf.c
/**
*******************************************************************************
* @file usart/usart_uart_int/source/ring_buf.c
* @brief This file provides firmware functions to manage the ring buffer.
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022-2023, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
/*******************************************************************************
* Include files
******************************************************************************/
#include <string.h>
#include "ring_buf.h"
#include "hc32_ll_utility.h"
/**
* @addtogroup USART_UART_Interrupt
* @{
*/
/**
* @defgroup Ring_Buffer Ring Buffer
* @{
*/
/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/*******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/
/*******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
/*******************************************************************************
* Local variable definitions ('static')
******************************************************************************/
/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
* @defgroup Ring_Buffer_Global_Functions Ring Buffer Global Functions
* @{
*/
/**
* @brief Initialize ring buffer.
* @param [in] pstcBuf Pointer to a @ref stc_ring_buf_t structure
* @param [in] pu8Data Data buffer
* @param [in] u32Size Data buffer size
* @retval int32_t:
* - LL_OK: Initialize successfully.
* - LL_ERR_INVD_PARAM: If one of following cases matches:
* - The pointer pstcBuf value is NULL.
* - The pointer pu8Data value is NULL.
* - The u32Size value is 0.
*/
int32_t BUF_Init(stc_ring_buf_t *pstcBuf, uint8_t *pu8Data, uint32_t u32Size)
{
int32_t i32Ret = LL_ERR_INVD_PARAM;
if ((pstcBuf != NULL) && (pu8Data != NULL) && (u32Size != 0UL)) {
pstcBuf->pu8Data = pu8Data;
pstcBuf->u32In = 0;
pstcBuf->u32Out = 0;
pstcBuf->u32Size = u32Size;
pstcBuf->u32FreeSize = u32Size;
i32Ret = LL_OK;
}
return i32Ret;
}
/**
* @brief Ring buffer free size.
* @param [in] pstcBuf Pointer to a @ref stc_ring_buf_t structure
* @retval Ring buffer free size
*/
uint32_t BUF_FreeSize(const stc_ring_buf_t *pstcBuf)
{
return pstcBuf->u32FreeSize;
}
/**
* @brief Ring buffer used size.
* @param [in] pstcBuf Pointer to a @ref stc_ring_buf_t structure
* @retval Ring buffer used size
*/
uint32_t BUF_UsedSize(const stc_ring_buf_t *pstcBuf)
{
return (pstcBuf->u32Size - pstcBuf->u32FreeSize);
}
/**
* @brief Ring buffer full.
* @param [in] pstcBuf Pointer to a @ref stc_ring_buf_t structure
* @retval Ring buffer status
*/
bool BUF_Full(const stc_ring_buf_t *pstcBuf)
{
return (0UL == pstcBuf->u32FreeSize);
}
/**
* @brief Check ring buffer empty.
* @param [in] pstcBuf Pointer to a @ref stc_ring_buf_t structure
* @retval Ring buffer status
*/
bool BUF_Empty(const stc_ring_buf_t *pstcBuf)
{
return (pstcBuf->u32Size == pstcBuf->u32FreeSize);
}
/**
* @brief Read ring buffer.
* @param [in] pstcBuf Pointer to a @ref stc_ring_buf_t structure
* @param [in] au8Data Pointer to data buffer to read
* @param [in] u32Len Data length
* @retval Read length
*/
uint32_t BUF_Read(stc_ring_buf_t *pstcBuf, uint8_t au8Data[], uint32_t u32Len)
{
uint32_t u32CopyLen;
uint32_t u32ReadLen = 0UL;
if ((pstcBuf != NULL) && (au8Data != NULL) && (u32Len != 0UL)) {
u32ReadLen = BUF_UsedSize(pstcBuf);
if (u32ReadLen >= u32Len) {
u32ReadLen = u32Len;
}
if (pstcBuf->u32Out + u32ReadLen <= pstcBuf->u32Size) {
(void)memcpy(au8Data, &pstcBuf->pu8Data[pstcBuf->u32Out], u32ReadLen);
} else {
u32CopyLen = pstcBuf->u32Size - pstcBuf->u32Out;
(void)memcpy(&au8Data[0], &pstcBuf->pu8Data[pstcBuf->u32Out], u32CopyLen);
(void)memcpy(&au8Data[u32CopyLen], &pstcBuf->pu8Data[0], u32ReadLen - u32CopyLen);
}
__disable_irq();
pstcBuf->u32FreeSize += u32ReadLen;
pstcBuf->u32Out += u32ReadLen;
if (pstcBuf->u32Out >= pstcBuf->u32Size) {
pstcBuf->u32Out %= pstcBuf->u32Size;
}
__enable_irq();
}
return u32ReadLen;
}
/**
* @brief Write ring buffer.
* @param [in] pstcBuf Pointer to a @ref stc_ring_buf_t structure
* @param [in] au8Data Pointer to data buffer to write
* @param [in] u32Len Data length
* @retval Write length
*/
uint32_t BUF_Write(stc_ring_buf_t *pstcBuf, uint8_t au8Data[], uint32_t u32Len)
{
uint32_t u32CopyLen;
uint32_t u32WriteLen = 0UL;
if ((pstcBuf != NULL) && (au8Data != NULL) && (u32Len != 0UL)) {
u32WriteLen = BUF_FreeSize(pstcBuf);
if (u32Len <= u32WriteLen) {
u32WriteLen = u32Len;
}
if (pstcBuf->u32In + u32WriteLen <= pstcBuf->u32Size) {
(void)memcpy(&pstcBuf->pu8Data[pstcBuf->u32In], au8Data, u32WriteLen);
} else {
u32CopyLen = pstcBuf->u32Size - pstcBuf->u32In;
(void)memcpy(&pstcBuf->pu8Data[pstcBuf->u32In], &au8Data[0], u32CopyLen);
(void)memcpy(&pstcBuf->pu8Data[0], &au8Data[u32CopyLen], u32WriteLen - u32CopyLen);
}
__disable_irq();
pstcBuf->u32FreeSize -= u32WriteLen;
pstcBuf->u32In += u32WriteLen;
if (pstcBuf->u32In >= pstcBuf->u32Size) {
pstcBuf->u32In %= pstcBuf->u32Size;
}
__enable_irq();
}
return u32WriteLen;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/*******************************************************************************
* EOF (not truncated)
******************************************************************************/
以上就是全部内容,有什么疑问可以私信我,有空会解答~~