uCOSII下的STM32外部中断
2014-09-25 10:21
225 查看
在进行uCOSII的程序之前先来复习下,裸机平台下stm32的外部中断的操作。
大概可以分作4个步骤:1-配置相应管脚为浮空输入;2-配置相应管脚为外部中断口并设定其中断属性及参数;3-配置NVIC相关寄存器,设定中断优先级;4-编写中断服务函数。废话不说直接上代码:
第一步:配置相应管脚为浮空输入,来自文件Key.c
voidKey_Port_Configuration(void)
{
GPIO_InitTypeDefGPIO_InitStructure_EXTI_KEY_PORTE;
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Pin=GPIO_Pin_4;
//
端口4
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Mode=GPIO_Mode_IN_FLOATING;
// 浮空输入
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Speed=GPIO_Speed_50MHz;
// 口线翻转速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure_EXTI_KEY_PORTE);//
端口初始化
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Pin=GPIO_Pin_3;
// 端口3
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Mode=GPIO_Mode_IN_FLOATING;
// 浮空输入
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Speed=GPIO_Speed_50MHz;
// 口线翻转速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure_EXTI_KEY_PORTE);//
端口初始化
}
第二步:配置相应管脚为外部中断口并且设定其中断属性及参数,来自文件EXTIG.c
voidEXTI_PORTE_Configuration(void)
{
EXTI_InitTypeDefEXTI_InitStructure_EXTI_LINE4;
EXTI_InitTypeDefEXTI_InitStructure_EXTI_LINE3;
/* Connect EXTI Line4,3 to PE4,PE3 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); //
配置管脚PE4用作外部中断线路
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3); //
配置管脚PE3用作外部中断线路
/* Configure EXTI Line4 to generate aninterrupt on falling edge */
EXTI_InitStructure_EXTI_LINE4.EXTI_Line=EXTI_Line4;
//配置使能或失能的外部线路
EXTI_InitStructure_EXTI_LINE4.EXTI_Mode=EXTI_Mode_Interrupt;
//配置 EXTI线路为中断请求(或者是事件请求)
EXTI_InitStructure_EXTI_LINE4.EXTI_Trigger=EXTI_Trigger_Falling;
//配置使能线路的触发边沿 --
下降沿触发中断
EXTI_InitStructure_EXTI_LINE4.EXTI_LineCmd=ENABLE;
//配置状态为使能
EXTI_Init(&EXTI_InitStructure_EXTI_LINE4);//
初始化外部中断线路4
/* Configure EXTI Line3 to generate aninterrupt on falling edge */
EXTI_InitStructure_EXTI_LINE3.EXTI_Line=EXTI_Line3;
//配置使能或失能的外部线路
EXTI_InitStructure_EXTI_LINE3.EXTI_Mode=EXTI_Mode_Interrupt;
//配置 EXTI线路为中断请求(或者是事件请求)
EXTI_InitStructure_EXTI_LINE3.EXTI_Trigger=EXTI_Trigger_Falling;
//配置使能线路的触发边沿 --
下降沿触发中断
EXTI_InitStructure_EXTI_LINE3.EXTI_LineCmd=ENABLE;
//配置状态为使能
EXTI_Init(&EXTI_InitStructure_EXTI_LINE3);//
初始化外部中断线路3
/* Generate software interrupt: simulate afalling edge applied on EXTI line 13 */
EXTI_GenerateSWInterrupt(EXTI_Line4); //线路4产生一个软件中断
EXTI_GenerateSWInterrupt(EXTI_Line3); //线路3产生一个软件中断
}
第三步:配置NVIC相关寄存器,设定中断优先级,来自文件SysInit.c
voidNVIC_Configuration(void)
{
NVIC_InitTypeDefNVIC_InitStructure_EXTI_LINE;
/* ================ NVIC-EXTI-PORTE================= */
/* Configure one bit for preemption priority*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //
配置优先级分组长度
/* Enable the EXTI15_10 Interrupt */
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannel=EXTI4_IRQn;
// 配置使能指定的IRQ(Interrupt ReQuest中断请求)通道
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelPreemptionPriority=0;
// 配置IRQ的组优先级
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelSubPriority=0;
// 配置IRQ的从优先级
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelCmd=ENABLE;
// 配置IRQ
使能
NVIC_Init(&NVIC_InitStructure_EXTI_LINE);//
初始化 IRQ
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannel=EXTI3_IRQn;
// 配置使能指定的IRQ(Interrupt ReQuest中断请求)通道
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelPreemptionPriority=0;
// 配置IRQ的组优先级
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelSubPriority=0;
// 配置IRQ的从优先级
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelCmd=ENABLE;
// 配置IRQ
使能
NVIC_Init(&NVIC_InitStructure_EXTI_LINE);//
初始化 IRQ
}
第四步:编写中断服务程序,来自文件stm32f10x_it.c
voidEXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3)
== SET)
// 读取中断状态
{
LED1_LOW;
EXTI_ClearITPendingBit(EXTI_Line3); //
清除标志位
}
}
voidEXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4)
== SET)
// 读取中断状态
{
LED1_HIGH;
EXTI_ClearITPendingBit(EXTI_Line4); //
清除标志位
}
}
下面就要说说在uCOSII里的时候了。
首先把上面所述步骤1,步骤2和步骤4的代码放到KEY.C文件内,然后把步骤3的代码加入SysInit.C文件内的
NVIC_Configuration()函数。步骤1,步骤2,和步骤3与没有操作系统的代码一致,都是最底层的东西。步骤4需要符合ucos的代码规范,也要用到ucos的系统函数,如下面代码:
/*******************************************************************************
* Function Name : Interrupt_Handle_KEY2
* Description :
按键2中断服务函数
* Input : None
* Output : None
* Return : None
*******************************************************************************/
voidInterrupt_Handle_KEY2(void)
{
OSIntEnter();
OSSemPost(Sem_Task_LED2);
// 发送信号量,这个函数并不会引起系统调度,所以中断服务函数一定要简洁。
EXTI_ClearITPendingBit(EXTI_Line4); //
清除标志位
OSIntExit();
}
如代码所示黄色高亮部分就是进入中断和出中断的ucos部分的代码,在出中断的时候会引起系统调度,然后最高优先级的任务会先执行,保证了系统的实时性。
步骤1~3的代码和上面类似就不一一列举,系统运行过程如下:
首先系统建立一个起始任务START,这个任务的优先级最低为10,他主要是做系统心跳的显示,另外把其他需要的任务初始化。在例程里有另外两个任务,分别是KEY1任务(优先级为9)和LED2任务(优先级为5)。先初始化KEY1任务,初始化函数结束后就跳到KEY1任务代码处执行,当遇到OSTimeDlyHMSM()函数时,会引发系统调度,此时就两个任务,所以肯定会回到起始任务START,然后初始化LED2任务,初始化函数结束后就跳到LED2任务代码处执行,在这个任务中有等待信号量的函数,所以系统会自己挂起任务,系统再进行调度的时候也会执行这个挂起任务里的代码。这时候如果按下按键,就会触发中断,在中断函数里会有信号量发出来,在结束中断的时候会有系统调度,此时系统会跳到请求信号量的断点处去执行代码,这一点体现了ucos的抢占性的特点,就是中断的优先级都是凌驾与非中断任务的,所以中断里发出的信号量一定是要先相应的。然后系统就会遵循优先级高低进行系统调度。
在这个例程里还有一个新的知识点就是计数信号量的使用。
使用时分为4个步骤:
1 定义信号量指针
void *Sem_Task_LED2;
2 创建信号量
Sem_Task_LED2 = OSSemCreate(0);
// 函数里参数是指信号量的初始值
3 设置等待信号量
OSSemPend(Sem_Task_LED2,0,&err);
4 设置发送信号量
OSSemPost(Sem_Task_LED2);
这里创建信号量和设置等待信号量都是在任务LED2里,设置发送信号量在中断服务函数里。见代码:
/*******************************************************************************
* Function Name : Task_LED2
* Description : LED2任务
* Input : None
* Output : None
* Return : None
*******************************************************************************/
voidTask_LED2(void*
p_arg)
{
(void) p_arg ;
Sem_Task_LED2 = OSSemCreate(0);
while(1)
{
OSSemPend(Sem_Task_LED2,0,&err);//
等待信号量
LED2_HIGH;
OSTimeDlyHMSM(0,0,1,0);
LED2_LOW;
OSTimeDlyHMSM(0,0,1,0);
// 延时,用来给其他任务留有运行的时间
}
}
这里要说一下注意点,首先定义的信号量指针是一个全局变量,需要在相应的头文件里进行extern声明,在这里是把他放在task.c文件里的。另外创建信号量和设置等待信号量函数都放在具体的任务中,因为在逻辑上,创建信号量和等待信号量函数肯定要早与发送信号量函数执行,因此在设置等待信号量之前去创建信号量是完全合适的,并且把创建信号量函数放在具体任务的while(1)上面,在创建函数的时候信号量就已经被创建了,然后代码执行到等待信号量的时候任务就会被挂起,除非时间到或者有信号量来的话才会被执行。最后设置发送信号量,在这里发送信号量函数是放在中断服务程序里的,因为发送信号量函数的执行并不会引起系统调度,只有在中断服务函数执行完毕,出中断函数的执行才会引发系统调度,所以中断服务函数里的内容一定要精简,否则就会影响系统的实时性。
大概可以分作4个步骤:1-配置相应管脚为浮空输入;2-配置相应管脚为外部中断口并设定其中断属性及参数;3-配置NVIC相关寄存器,设定中断优先级;4-编写中断服务函数。废话不说直接上代码:
第一步:配置相应管脚为浮空输入,来自文件Key.c
voidKey_Port_Configuration(void)
{
GPIO_InitTypeDefGPIO_InitStructure_EXTI_KEY_PORTE;
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Pin=GPIO_Pin_4;
//
端口4
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Mode=GPIO_Mode_IN_FLOATING;
// 浮空输入
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Speed=GPIO_Speed_50MHz;
// 口线翻转速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure_EXTI_KEY_PORTE);//
端口初始化
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Pin=GPIO_Pin_3;
// 端口3
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Mode=GPIO_Mode_IN_FLOATING;
// 浮空输入
GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Speed=GPIO_Speed_50MHz;
// 口线翻转速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure_EXTI_KEY_PORTE);//
端口初始化
}
第二步:配置相应管脚为外部中断口并且设定其中断属性及参数,来自文件EXTIG.c
voidEXTI_PORTE_Configuration(void)
{
EXTI_InitTypeDefEXTI_InitStructure_EXTI_LINE4;
EXTI_InitTypeDefEXTI_InitStructure_EXTI_LINE3;
/* Connect EXTI Line4,3 to PE4,PE3 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); //
配置管脚PE4用作外部中断线路
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3); //
配置管脚PE3用作外部中断线路
/* Configure EXTI Line4 to generate aninterrupt on falling edge */
EXTI_InitStructure_EXTI_LINE4.EXTI_Line=EXTI_Line4;
//配置使能或失能的外部线路
EXTI_InitStructure_EXTI_LINE4.EXTI_Mode=EXTI_Mode_Interrupt;
//配置 EXTI线路为中断请求(或者是事件请求)
EXTI_InitStructure_EXTI_LINE4.EXTI_Trigger=EXTI_Trigger_Falling;
//配置使能线路的触发边沿 --
下降沿触发中断
EXTI_InitStructure_EXTI_LINE4.EXTI_LineCmd=ENABLE;
//配置状态为使能
EXTI_Init(&EXTI_InitStructure_EXTI_LINE4);//
初始化外部中断线路4
/* Configure EXTI Line3 to generate aninterrupt on falling edge */
EXTI_InitStructure_EXTI_LINE3.EXTI_Line=EXTI_Line3;
//配置使能或失能的外部线路
EXTI_InitStructure_EXTI_LINE3.EXTI_Mode=EXTI_Mode_Interrupt;
//配置 EXTI线路为中断请求(或者是事件请求)
EXTI_InitStructure_EXTI_LINE3.EXTI_Trigger=EXTI_Trigger_Falling;
//配置使能线路的触发边沿 --
下降沿触发中断
EXTI_InitStructure_EXTI_LINE3.EXTI_LineCmd=ENABLE;
//配置状态为使能
EXTI_Init(&EXTI_InitStructure_EXTI_LINE3);//
初始化外部中断线路3
/* Generate software interrupt: simulate afalling edge applied on EXTI line 13 */
EXTI_GenerateSWInterrupt(EXTI_Line4); //线路4产生一个软件中断
EXTI_GenerateSWInterrupt(EXTI_Line3); //线路3产生一个软件中断
}
第三步:配置NVIC相关寄存器,设定中断优先级,来自文件SysInit.c
voidNVIC_Configuration(void)
{
NVIC_InitTypeDefNVIC_InitStructure_EXTI_LINE;
/* ================ NVIC-EXTI-PORTE================= */
/* Configure one bit for preemption priority*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //
配置优先级分组长度
/* Enable the EXTI15_10 Interrupt */
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannel=EXTI4_IRQn;
// 配置使能指定的IRQ(Interrupt ReQuest中断请求)通道
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelPreemptionPriority=0;
// 配置IRQ的组优先级
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelSubPriority=0;
// 配置IRQ的从优先级
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelCmd=ENABLE;
// 配置IRQ
使能
NVIC_Init(&NVIC_InitStructure_EXTI_LINE);//
初始化 IRQ
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannel=EXTI3_IRQn;
// 配置使能指定的IRQ(Interrupt ReQuest中断请求)通道
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelPreemptionPriority=0;
// 配置IRQ的组优先级
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelSubPriority=0;
// 配置IRQ的从优先级
NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelCmd=ENABLE;
// 配置IRQ
使能
NVIC_Init(&NVIC_InitStructure_EXTI_LINE);//
初始化 IRQ
}
第四步:编写中断服务程序,来自文件stm32f10x_it.c
voidEXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3)
== SET)
// 读取中断状态
{
LED1_LOW;
EXTI_ClearITPendingBit(EXTI_Line3); //
清除标志位
}
}
voidEXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4)
== SET)
// 读取中断状态
{
LED1_HIGH;
EXTI_ClearITPendingBit(EXTI_Line4); //
清除标志位
}
}
下面就要说说在uCOSII里的时候了。
首先把上面所述步骤1,步骤2和步骤4的代码放到KEY.C文件内,然后把步骤3的代码加入SysInit.C文件内的
NVIC_Configuration()函数。步骤1,步骤2,和步骤3与没有操作系统的代码一致,都是最底层的东西。步骤4需要符合ucos的代码规范,也要用到ucos的系统函数,如下面代码:
/*******************************************************************************
* Function Name : Interrupt_Handle_KEY2
* Description :
按键2中断服务函数
* Input : None
* Output : None
* Return : None
*******************************************************************************/
voidInterrupt_Handle_KEY2(void)
{
OSIntEnter();
OSSemPost(Sem_Task_LED2);
// 发送信号量,这个函数并不会引起系统调度,所以中断服务函数一定要简洁。
EXTI_ClearITPendingBit(EXTI_Line4); //
清除标志位
OSIntExit();
}
如代码所示黄色高亮部分就是进入中断和出中断的ucos部分的代码,在出中断的时候会引起系统调度,然后最高优先级的任务会先执行,保证了系统的实时性。
步骤1~3的代码和上面类似就不一一列举,系统运行过程如下:
首先系统建立一个起始任务START,这个任务的优先级最低为10,他主要是做系统心跳的显示,另外把其他需要的任务初始化。在例程里有另外两个任务,分别是KEY1任务(优先级为9)和LED2任务(优先级为5)。先初始化KEY1任务,初始化函数结束后就跳到KEY1任务代码处执行,当遇到OSTimeDlyHMSM()函数时,会引发系统调度,此时就两个任务,所以肯定会回到起始任务START,然后初始化LED2任务,初始化函数结束后就跳到LED2任务代码处执行,在这个任务中有等待信号量的函数,所以系统会自己挂起任务,系统再进行调度的时候也会执行这个挂起任务里的代码。这时候如果按下按键,就会触发中断,在中断函数里会有信号量发出来,在结束中断的时候会有系统调度,此时系统会跳到请求信号量的断点处去执行代码,这一点体现了ucos的抢占性的特点,就是中断的优先级都是凌驾与非中断任务的,所以中断里发出的信号量一定是要先相应的。然后系统就会遵循优先级高低进行系统调度。
在这个例程里还有一个新的知识点就是计数信号量的使用。
使用时分为4个步骤:
1 定义信号量指针
void *Sem_Task_LED2;
2 创建信号量
Sem_Task_LED2 = OSSemCreate(0);
// 函数里参数是指信号量的初始值
3 设置等待信号量
OSSemPend(Sem_Task_LED2,0,&err);
4 设置发送信号量
OSSemPost(Sem_Task_LED2);
这里创建信号量和设置等待信号量都是在任务LED2里,设置发送信号量在中断服务函数里。见代码:
/*******************************************************************************
* Function Name : Task_LED2
* Description : LED2任务
* Input : None
* Output : None
* Return : None
*******************************************************************************/
voidTask_LED2(void*
p_arg)
{
(void) p_arg ;
Sem_Task_LED2 = OSSemCreate(0);
while(1)
{
OSSemPend(Sem_Task_LED2,0,&err);//
等待信号量
LED2_HIGH;
OSTimeDlyHMSM(0,0,1,0);
LED2_LOW;
OSTimeDlyHMSM(0,0,1,0);
// 延时,用来给其他任务留有运行的时间
}
}
这里要说一下注意点,首先定义的信号量指针是一个全局变量,需要在相应的头文件里进行extern声明,在这里是把他放在task.c文件里的。另外创建信号量和设置等待信号量函数都放在具体的任务中,因为在逻辑上,创建信号量和等待信号量函数肯定要早与发送信号量函数执行,因此在设置等待信号量之前去创建信号量是完全合适的,并且把创建信号量函数放在具体任务的while(1)上面,在创建函数的时候信号量就已经被创建了,然后代码执行到等待信号量的时候任务就会被挂起,除非时间到或者有信号量来的话才会被执行。最后设置发送信号量,在这里发送信号量函数是放在中断服务程序里的,因为发送信号量函数的执行并不会引起系统调度,只有在中断服务函数执行完毕,出中断函数的执行才会引发系统调度,所以中断服务函数里的内容一定要精简,否则就会影响系统的实时性。
相关文章推荐
- stm32 外部中断学习
- STM32外部中断笔记(一)
- STM32_外部中断_笔记
- STM32外部中断及定时器编程示例
- STM32 外部中断的使用(按键中断点亮LED)
- STM32单片机学习(2) 外部中断
- STM32外部中断
- stm32NVIC与外部中断
- STM32之外部中断例程
- stm32 外部中断的使用(含实例)
- stm32 EXTI中断BUG,无法进入外部中断的问题
- STM32外部中断
- stm32中断学习篇(2)——以外部中断为例与多个中断的使用
- STM32学习笔记整理之(2)——外部中断
- STM32学习笔记之外部中断实验
- STM32-外部中断学习笔记
- STM32 外部中断
- stm32 外部中断
- 第17章 EXTI—外部中断/事件控制器—零死角玩转STM32-F429系列
- 关于STM32的外部中断服务程序