08.01_EXTI-上升沿&下降沿均触发中断
测试步骤
使用P0.15作为外部中断引脚,上升沿&下降沿均触发中断。 外部输入高低电平(默认低电平),记录中断发生次数。
实测数据
| t | P0.15Val | count |
|---|---|---|
| 0 | 0 | 0 |
| 1 | 1 | 1 |
| 2 | 0 | 2 |
| 3 | 1 | 3 |
| 4 | 0 | 4 |
| 5 | 1 | 5 |
| 6 | 0 | 6 |
| 7 | 1 | 7 |
| 8 | 0 | 8 |
| 9 | 1 | 9 |
| 10 | 0 | 10 |
| 11 | 1 | 11 |
| 12 | 0 | 12 |
| 13 | 1 | 13 |
| 14 | 0 | 14 |
| 15 | 1 | 15 |
| 16 | 0 | 16 |
| 17 | 1 | 17 |
| 18 | 0 | 18 |
| 19 | 1 | 19 |
测试结果:通过
参考代码
08.01_EXTI_Toggle.c
/**
* @brief EXTI-上升沿&下降沿均触发中断
* @details
* 使用P0.15作为外部中断引脚,上升沿&下降沿均触发中断。
* 外部输入高低电平(默认低电平),记录中断发生次数。
*/
#include "lks32mc09x_exti.h"
#include "lks32mc09x_gpio.h"
#include "lks32mc09x_sys.h"
volatile uint32_t count = 0;
// EXTI中断处理函数
void GPIO_IRQHandler(void)
{
// 检查P0.15引脚的中断标志
if (EXTI_GetIRQFlag(EXTI0, EXTI_IF_P0_15))
{
// 清除中断标志
EXTI_ClearIRQFlag(EXTI0, EXTI_IF_P0_15);
count++;
}
}
/**
* @brief 主函数
*/
int main(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_StructInit(&GPIO_InitStruct);
// 使能GPIO0时钟
SYS_ModuleClockCmd(SYS_MODULE_GPIO, ENABLE);
// 初始化P0.15为输入,并配置为外部中断引脚
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIO0, &GPIO_InitStruct);
// 配置P0.15的上升沿、下降沿均触发外部中断
EXTI_TriggerConfig(EXTI0, EXTI_CR_P0_15, EXTI_Trigger_Edge);
EXTI_EnableIRQFlag(EXTI0, EXTI_IF_P0_15);
// 使能EXTI0中断
NVIC_EnableIRQ(GPIO_IRQn);
__enable_irq();
while (1)
{
}
}
使用到的库函数
库函数部分代码
#define REG_RESET(reg,mask) reg &= ~(mask)
#define REG_SET(reg,mask) reg |= (mask)
#define REG_WRITE(reg,mask) reg = (mask)
#define SYS0 ((SYS_TypeDef *)(SYS_BASE))
#define SYS_MODULE_GPIO BIT11
/**
* @brief GPIO功能配置结构体句柄
*/
typedef struct GPIO_InitTypeDef {
uint32_t GPIO_Pin;
GPIO_Mode_TypeDef GPIO_Mode;
GPIO_PuPd_TypeDef GPIO_PuPd;
uint32_t GPIO_PODEna;
uint32_t GPIO_PFLT;
};
/**
* EXTI触发信号定义
*/
typedef enum EXTI_Mode_TypeDef {
EXTI_Trigger_None = 0,
EXTI_Trigger_Negedge = 1,
EXTI_Trigger_Posedge = 2,
EXTI_Trigger_Edge = 3,
}} {enum_name};
/**
* @brief 使能外部中断标志
*
* @param EXTIx EXTI模块指针
* @param EXTI_IF_x 外部中断源
*/
void EXTI_EnableIRQFlag(EXTI_TypeDef *EXTIx, uint32_t EXTI_IF_x)
{
exti_ie_flg |= EXTI_IF_x;
if (exti_ie_flg & 0x7f)
{
EXTIx->IE |= BIT0;
}
else
{
EXTIx->IE &= ~BIT0;
}
if (exti_ie_flg & 0x80)
{
EXTIx->IE |= BIT1;
}
else
{
EXTIx->IE &= ~BIT1;
}
if (exti_ie_flg & 0xff00)
{
EXTIx->IE |= BIT2;
}
else
{
EXTIx->IE &= ~BIT2;
}
}
/**
* @brief 初始化GPIO
* @param GPIOx GPIO模块指针
* @param GPIO_InitStruct 指向包含初始化参数的GPIO_InitTypeDef结构体
*/
void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
{
// 使能GPIO时钟
SYS_ModuleClockCmd(SYS_MODULE_GPIO, ENABLE);
// 配置引脚模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IN)
{
GPIOx->PIE |= GPIO_InitStruct->GPIO_Pin; // 打开输入使能
GPIOx->POE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输出使能
GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉使能
}
else if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT)
{
GPIOx->PIE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输入使能
GPIOx->POE |= GPIO_InitStruct->GPIO_Pin; // 使能输出
}
else if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IO)
{
GPIOx->PIE |= GPIO_InitStruct->GPIO_Pin; // 使能输入
GPIOx->POE |= GPIO_InitStruct->GPIO_Pin; // 使能输出
}
else // GPIO_Mode_ANA
{
GPIOx->PIE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输入使能
GPIOx->POE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输出使能
GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉使能
}
if (GPIO_InitStruct->GPIO_PuPd == GPIO_PuPd_UP)
{
GPIOx->PUE |= GPIO_InitStruct->GPIO_Pin; // 使能上拉
}
else
{
GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉
}
// 配置开漏使能
if (GPIO_InitStruct->GPIO_PODEna)
{
GPIOx->PODE |= GPIO_InitStruct->GPIO_Pin;
}
else
{
GPIOx->PODE &= ~GPIO_InitStruct->GPIO_Pin;
}
// 配置滤波使能
if (GPIO_InitStruct->GPIO_PFLT)
{
GPIOx->PFLT |= GPIO_InitStruct->GPIO_Pin;
}
else
{
GPIOx->PFLT &= ~GPIO_InitStruct->GPIO_Pin;
}
}
/**
* @brief 初始化GPIO结构体为默认值
* @param GPIO_InitStruct 指向要初始化的GPIO_InitTypeDef结构体
*/
void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
{
for (int i = 0; i < sizeof(GPIO_InitTypeDef); i++)
{
((uint8_t *)GPIO_InitStruct)[i] = 0;
}
}
/**
* @brief 数字模块时钟使能
* @param nModule 模块编号
* @param state 使能或禁用状态
*/
void SYS_ModuleClockCmd(uint32_t nModule, uint8_t state)
{
REG_WRITE(SYS0->PROTECT, 0x7a83);
if (state)
{
REG_SET(SYS0->CLK_FEN, nModule);
}
else
{
REG_RESET(SYS0->CLK_FEN, nModule);
}
REG_WRITE(SYS0->PROTECT, 0);
}
/**
* @brief 清除GPIO引脚的中断标志
*
* @param GPIOx GPIO模块指针
* @param GPIO_PinSource GPIO引脚源
*/
void EXTI_ClearIRQFlag(EXTI_TypeDef *EXTIx, uint32_t EXTI_IF_x)
{
// 清除对应GPIO引脚的中断标志
EXTIx->IF = EXTI_IF_x;
}
/**
* @brief 获取GPIO引脚的中断标志状态
*
* @param GPIOx GPIO模块指针
* @param GPIO_PinSource GPIO引脚源
* @return 中断标志状态
* @retval 0 无中断
* @retval 1 有中断
*/
uint8_t EXTI_GetIRQFlag(EXTI_TypeDef *EXTIx, uint32_t EXTI_IF_x)
{
// 获取对应GPIO引脚的中断标志状态
return EXTIx->IF & EXTI_IF_x;
}
/**
* @brief 配置GPIO引脚的中断触发模式
*
* @param GPIOx GPIO模块指针
* @param GPIO_PinSource GPIO引脚源
* @param EXTI_Trigger 触发模式
*/
void EXTI_TriggerConfig(EXTI_TypeDef *EXTIx, uint8_t EXTI_CR_x, EXTI_Mode_TypeDef EXTI_Trigger)
{
// 根据GPIO引脚源和触发模式配置EXTI触发寄存器
if (EXTI_CR_x < 8) // cr0
{
EXTIx->CR0 &= ~(0x03 << (EXTI_CR_x * 2));
EXTIx->CR0 |= (EXTI_Trigger << (EXTI_CR_x * 2));
}
else // cr1
{
EXTIx->CR1 &= ~(0x03 << ((EXTI_CR_x - 8) * 2));
EXTIx->CR1 |= (EXTI_Trigger << ((EXTI_CR_x - 8) * 2));
}
}