基于UC/COSII系统的STM32F103系列单片机外部中断按键的一种使用方法
记录学习过程遇到的问题及解决方法,与大家一起分享:
外部中断按键大家都不陌生,在裸奔时只需配置几个寄存器就可以完成操作,初学单片机时都会将外部中断按键放到前几章学习中,那么当我们嵌入了UCOSII操作系统时,也需要外部按键中断来触发一个事件,比如按下按键打开蜂鸣器播放音乐,下面介绍一种在UCOSII操作系统下的使用方法:
参考如下代码:
- 初始化按键GPIO、中断。
- 写中断函数,按键触发进入中断函数,判断是按键按下,发送一个信号量给任务。
- 任务一直等待信号量,一旦有按键信号量,就会执行任务。处理按键按下需要处理的函数。
//按键端口初始化
void BSP_KeyInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = KEY_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//推挽输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口速度为50MHz
GPIO_Init(KEY_PORT, &GPIO_InitStructure);//根据设定参数初始化GPIOB.5
}
void BSP_KeyExtiInit(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 按键端口初始化
BSP_KeyInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能复用功能时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
EXTI_InitStructure.EXTI_Line=EXTI_Line1;//外部中断线1
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;//子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
//目的就是发送一个信号量给任务函数。
extern OS_EVENT*g_tKeyExtiSem;
void HDD_KeyIsr(void)
{
//发送信号量,并不会引起系统调度,中断服务函数一定要简洁
OSSemPost(g_tKeyExtiSem);
return;
}
//该函数放到库函数中断函数中
void EXTI1_IRQHandler(void)
{
//进入处理函数
OSIntEnter();
//判断按键是否按下,发送信号量给任务函数
if (KEY_VALUE == 0)
{
HDD_KeyIsr();
}
EXTI_ClearITPendingBit(EXTI_Line1); //清除LINE4上的中断标志位
OSIntExit();
//在出中断的时候会引起系统调度,然后最高优先级的任务会先执行,保证了 系统的实时性
}
//任务函数如下
void USERAPP_KeyScanTask(void *pData)
{
// OS_CPU_SR cpu_sr=0;
(void)pData;
g_tKeyExtiSem = OSSemCreate( 0 ); //定义处置为0的信号量
while(1)
{
OSSemPend( g_tKeyExtiSem,0,&g_ucErr);//等待按键触发中断信号
OSTimeDlyHMSM(0,0,0,1);
if (KEY_VALUE == 0)
{
//要完成的代码区
//也就是相当于不带操作系统中的中断处理函数内的内容。
}
}
}
在这前面需要定义两个全局变量,
//信号量及邮箱的定义
OS_EVENT *g_tKeyExtiSem;//按键中断信号量
//错误类型全局变量
INT8U g_ucErr;
可以添加更为复杂的长按、短按、多按键的按键队列等。