这里给出两种写法,可以根据需求自行判断需要哪种写法,本文使用华大官方库,软件使用keil5。
方法1
方法1是华大官方库的例程写法。

下面以官方串口例程分析为例程分析
先贴源码
/* Peripheral register WE/WP selection */
#define LL_PERIPH_SEL (LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | \
LL_PERIPH_EFM)
/* USART RX/TX pin definition */
#define USART_RX_PORT (GPIO_PORT_C) /* PC11: USART2_RX */
#define USART_RX_PIN (GPIO_PIN_11)
#define USART_RX_GPIO_FUNC (GPIO_FUNC_37)
#define USART_TX_PORT (GPIO_PORT_C) /* PC10: USART2_TX */
#define USART_TX_PIN (GPIO_PIN_10)
#define USART_TX_GPIO_FUNC (GPIO_FUNC_36)
/* USART unit definition */
#define USART_UNIT (CM_USART2)
#define USART_FCG_ENABLE() (FCG_Fcg3PeriphClockCmd(FCG3_PERIPH_USART2, ENABLE))
/* USART Tx complete flag select: USART_INT_TX_CPLT or USART_INT_TX_END */
#define USART_TX_CPLT_FLAG (USART_INT_TX_CPLT)
/* USART interrupt definition */
#define USART_RX_ERR_IRQn (INT000_IRQn)
#define USART_RX_ERR_INT_SRC (INT_SRC_USART2_EI)
#define USART_RX_FULL_IRQn (INT001_IRQn)
#define USART_RX_FULL_INT_SRC (INT_SRC_USART2_RI)
#define USART_TX_EMPTY_IRQn (INT002_IRQn)
#define USART_TX_EMPTY_INT_SRC (INT_SRC_USART2_TI)
#define USART_TX_CPLT_IRQn (INT003_IRQn)
#if (USART_INT_TX_CPLT == USART_TX_CPLT_FLAG)
#define USART_TX_CPLT_INT_SRC (INT_SRC_USART2_TCI)
#elif (USART_INT_TX_END == USART_TX_CPLT_FLAG)
#define USART_TX_CPLT_INT_SRC (INT_SRC_USART2_TENDI)
#else
#error "USART_TX_CPLT_FLAG defined error"
#endif
/* Ring buffer size */
#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;
/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
* @brief USART transmit data register empty IRQ callback.
* @param None
* @retval None
*/
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 {
#if (USART_INT_TX_CPLT == USART_TX_CPLT_FLAG)
USART_FuncCmd(USART_UNIT, USART_INT_TX_CPLT, ENABLE);
#elif (USART_INT_TX_END == USART_TX_CPLT_FLAG)
USART_FuncCmd(USART_UNIT, USART_INT_TX_END, ENABLE);
#endif
}
}
/**
* @brief USART transmit complete IRQ callback.
* @param None
* @retval None
*/
static void USART_TxComplete_IrqCallback(void)
{
m_enTxCompleteFlag = SET;
#if (USART_INT_TX_CPLT == USART_TX_CPLT_FLAG)
USART_FuncCmd(USART_UNIT, (USART_TX | USART_INT_TX_CPLT | USART_INT_TX_EMPTY), DISABLE);
#elif (USART_INT_TX_END == USART_TX_CPLT_FLAG)
USART_ClearStatus(USART_UNIT, USART_FLAG_TX_END);
USART_FuncCmd(USART_UNIT, (USART_TX | USART_INT_TX_EMPTY), DISABLE);
#endif
}
/**
* @brief USART RX IRQ callback
* @param None
* @retval None
*/
static void USART_RxFull_IrqCallback(void)
{
uint8_t u8Data = (uint8_t)USART_ReadData(USART_UNIT);
(void)BUF_Write(&m_stcRingBuf, &u8Data, 1UL);
}
/**
* @brief USART error IRQ callback.
* @param None
* @retval None
*/
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));
}
/**
* @brief Instal IRQ handler.
* @param [in] pstcConfig Pointer to struct @ref stc_irq_signin_config_t
* @param [in] u32Priority Interrupt priority
* @retval None
*/
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);
}
}
/**
* @brief Main function of UART interrupt project
* @param None
* @retval int32_t return value, if needed
*/
int32_t main(void)
{
stc_usart_uart_init_t stcUartInit;
stc_irq_signin_config_t stcIrqSigninConfig;
/* MCU Peripheral registers write unprotected */
LL_PERIPH_WE(LL_PERIPH_SEL);
/* Initialize BSP system clock. */
BSP_CLK_Init();
/* Initialize BSP expand IO. */
BSP_IO_Init();
/* Initialize BSP LED. */
BSP_LED_Init();
/* Configure USART RX/TX pin. */
GPIO_SetFunc(USART_RX_PORT, USART_RX_PIN, USART_RX_GPIO_FUNC);
GPIO_SetFunc(USART_TX_PORT, USART_TX_PIN, USART_TX_GPIO_FUNC);
/* Enable peripheral clock */
USART_FCG_ENABLE();
/* Initialize ring buffer function. */
(void)BUF_Init(&m_stcRingBuf, m_au8DataBuf, sizeof(m_au8DataBuf));
/* Initialize UART. */
(void)USART_UART_StructInit(&stcUartInit);
stcUartInit.u32ClockDiv = USART_CLK_DIV64;
stcUartInit.u32Baudrate = 115200UL;
stcUartInit.u32OverSampleBit = USART_OVER_SAMPLE_8BIT;
if (LL_OK != USART_UART_Init(USART_UNIT, &stcUartInit, NULL)) {
BSP_LED_On(LED_RED);
for (;;) {
}
}
/* Register RX error IRQ handler && configure NVIC. */
stcIrqSigninConfig.enIRQn = USART_RX_ERR_IRQn;
stcIrqSigninConfig.enIntSrc = USART_RX_ERR_INT_SRC;
stcIrqSigninConfig.pfnCallback = &USART_RxError_IrqCallback;
INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_DEFAULT);
/* Register RX full IRQ handler && configure NVIC. */
stcIrqSigninConfig.enIRQn = USART_RX_FULL_IRQn;
stcIrqSigninConfig.enIntSrc = USART_RX_FULL_INT_SRC;
stcIrqSigninConfig.pfnCallback = &USART_RxFull_IrqCallback;
INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_DEFAULT);
/* Register TX empty IRQ handler && configure NVIC. */
stcIrqSigninConfig.enIRQn = USART_TX_EMPTY_IRQn;
stcIrqSigninConfig.enIntSrc = USART_TX_EMPTY_INT_SRC;
stcIrqSigninConfig.pfnCallback = &USART_TxEmpty_IrqCallback;
INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_DEFAULT);
/* Register TX complete IRQ handler && configure NVIC. */
stcIrqSigninConfig.enIRQn = USART_TX_CPLT_IRQn;
stcIrqSigninConfig.enIntSrc = USART_TX_CPLT_INT_SRC;
stcIrqSigninConfig.pfnCallback = &USART_TxComplete_IrqCallback;
INTC_IrqInstalHandler(&stcIrqSigninConfig, DDL_IRQ_PRIO_DEFAULT);
/* MCU Peripheral registers write protected */
LL_PERIPH_WP(LL_PERIPH_SEL);
/* Enable RX function */
USART_FuncCmd(USART_UNIT, (USART_RX | USART_INT_RX), ENABLE);
for (;;) {
if ((SET == m_enTxCompleteFlag) && !BUF_Empty(&m_stcRingBuf)) {
m_enTxCompleteFlag = RESET;
#if (USART_INT_TX_END == USART_TX_CPLT_FLAG)
USART_FuncCmd(USART_UNIT, USART_INT_TX_END, DISABLE);
#endif
USART_FuncCmd(USART_UNIT, (USART_TX | USART_INT_TX_EMPTY), ENABLE);
}
}
}
由源码可知,该例程为串口申请了四个中断,每个中断都有一个自己的对应的回调函数,也就是四个中断号,四个回调函数。

中断初始化部分,申请了四个中断类型,分别对应了四个中断号以及中断回调函数。其中这四个中断号分别是INT000_IRQn、INT001_IRQn、INT002_IRQn、INT003_IRQn。从官方文档的下表可知,官方例程用的是类型A,写入的中断请求编号映射,但是这个中断号资源有限只有16个,且不能重复,也就是说用这个方法申请中断只能申请16个中断编号,对于小项目可以这么写,但是稍微大一点的项目这样写就中断号就有点不够用了。下面引出第二种方法。

方法2
由上表可知,中断请求编号映射有两种方法,方法A是16个可编程的中断号,比如我串口1空闲中断可以用INT000_IRQn,串口2空闲中断INT001_IRQn,定时器溢出中断可以用INT002_IRQn,...
INT000_IRQn~NT015_IRQn这16个中断号可以随意分配给你想用的中断申请(同一个项目申请的中断号不能重复申请,比如我串口1空闲中断用INT000_IRQn,但是我串口2空闲中断也用INT000_IRQn。这是不可行的),但是资源有限,只有16个,遇到稍微大一点的项目就有点力不从心了。
我们再来观察此表类型B,我们以USART_2_EI这个中断举例。我们想用类型B的方法申请中断,就只用固定的就只能用IRQ[95]这个编号申请。
通过这个表查官方库95编号,对应的定义为USART2_IRQn

接下来我们通过代码进行整体中断实验。先贴代码
//中断服务函数
void USART2_Handler(void)
{
if(USART_GetStatus(CM_USART2,(USART_FLAG_PARITY_ERR | USART_FLAG_FRAME_ERR | USART_FLAG_OVERRUN)))
{
(void)USART_ReadData(CM_USART2);
USART_ClearStatus(CM_USART2, (USART_FLAG_PARITY_ERR | USART_FLAG_FRAME_ERR | USART_FLAG_OVERRUN));
return;
}
if(USART_GetStatus(CM_USART2,USART_FLAG_RX_TIMEOUT))
{
//.....
USART_ClearStatus(CM_USART2, USART_FLAG_RX_TIMEOUT);
return;
}
NBRecevieMessageHadle(&nbATMessage,(uint8_t)USART_ReadData(CM_USART2));
}
//c串口二初始化函数
void Usart02ConfingFunction(void)
{
stc_usart_uart_init_t stcUartInit;
stc_irq_signin_config_t stcIrqSigninConfig;
GPIO_SetDebugPort(GPIO_PIN_TRST, DISABLE);
GPIO_SetDebugPort(GPIO_PIN_SWO, DISABLE);
GPIO_SetFunc(GPIO_PORT_A,GPIO_PIN_08,GPIO_FUNC_37);
GPIO_SetFunc(GPIO_PORT_C,GPIO_PIN_09,GPIO_FUNC_36);
FCG_Fcg3PeriphClockCmd(FCG3_PERIPH_USART2, ENABLE);
USART_DeInit(CM_USART2);
(void)USART_UART_StructInit(&stcUartInit);
stcUartInit.u32ClockDiv = USART_CLK_DIV64;
stcUartInit.u32Baudrate = 115200UL;
stcUartInit.u32OverSampleBit = USART_OVER_SAMPLE_8BIT;
USART_UART_Init(CM_USART2, &stcUartInit, NULL);
/* Enable USART_TX | USART_RX | USART_INT_RX function */
/* Register RX error IRQ handler. */
stcIrqSigninConfig.enIRQn = USART2_IRQn;
stcIrqSigninConfig.enIntSrc = INT_SRC_USART1_EI;
stcIrqSigninConfig.pfnCallback = NULL;
(void)INTC_IrqSignIn(&stcIrqSigninConfig);
NVIC_ClearPendingIRQ(stcIrqSigninConfig.enIRQn);
NVIC_SetPriority(stcIrqSigninConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
NVIC_EnableIRQ(stcIrqSigninConfig.enIRQn);
/* Register RX timeout IRQ handler. */
stcIrqSigninConfig.enIRQn = USART2_IRQn;
stcIrqSigninConfig.enIntSrc = INT_SRC_USART1_RTO;
stcIrqSigninConfig.pfnCallback = NULL;
(void)INTC_IrqSignIn(&stcIrqSigninConfig);
NVIC_ClearPendingIRQ(stcIrqSigninConfig.enIRQn);
NVIC_SetPriority(stcIrqSigninConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
NVIC_EnableIRQ(stcIrqSigninConfig.enIRQn);
/* Register RX error IRQ handler. */
stcIrqSigninConfig.enIRQn = USART2_IRQn;
stcIrqSigninConfig.enIntSrc = INT_SRC_USART1_RI;
stcIrqSigninConfig.pfnCallback = NULL;
(void)INTC_IrqSignIn(&stcIrqSigninConfig);
NVIC_ClearPendingIRQ(stcIrqSigninConfig.enIRQn);
NVIC_SetPriority(stcIrqSigninConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
NVIC_EnableIRQ(stcIrqSigninConfig.enIRQn);
USART_FuncCmd(CM_USART2, (USART_RX|USART_TX| USART_INT_RX|USART_RX_TIMEOUT|USART_INT_RX_TIMEOUT), ENABLE);
}
我们这次实验用的依旧是USART2,申请了USART1_R2,USART2_RTO,USART2_EI,这三个中断,观察程序可知,这三个中断全都是用的一个中断编号。因为观察表可知,这三个中断事件全都是用的95这一个中断编号。中断回调函数这一项我全添NULL,这三个中断只要一发生就会直接跳到USART2_Handler这个中断服务函数,然后再根据if获取中断标志位,做出相应的动作即可。

这就是我分享的内容,如果有不对的地方欢迎大佬指出。
2548

被折叠的 条评论
为什么被折叠?



