华大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

  1. 定义相关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 缓存区大小

  1. 接收数据错误中断、接收数据寄存器满中断、发送数据寄存器空中断、发送完成中断回调函数。

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); 将接收到的数据写入到串口。

  1. 中断使能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);
    }
}
  1. 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)
 ******************************************************************************/

以上就是全部内容,有什么疑问可以私信我,有空会解答~~

物联沃分享整理
物联沃-IOTWORD物联网 » 华大HC32F460 USART串口中断代码详解及应用指南

发表评论