五、中断管理
5.1、什么是中断?
概念:让CPU打断正常运行的程序,转而去处理紧急的事件(程序),就叫中断。
中断执行机制一般有三步:
1、中断请求:外设产生中断请求(GPIO外部中断、定时器中断等)。
2、响应中断:CPU停止执行当前程序,转而去执行中断处理程序(ISR)。
3、退出中断:执行完毕,返回被打断的程序处,继续往下执行。
5.2、中断优先级分组设置
ARM Cortex-M 使用了8位宽(256既0~255)的寄存器来配置中断的优先等级,这个寄存器就是中断优先级配置寄存器。
5.3、中断相关寄存器
注意,在freertos优先级中,0到4不会被freertos禁止,因为通过configfreertos.h文件我们可以观察到freertos优先级处于5到16。
5.4、FreeRTOS中断管理实验
#####FreeRTOSConfig.h
####定时器的c文件,其中Serial.h和.c代码可以使用江科大的代码。
//——————————TIM.c————————————//
#include "stm32f10x.h" // Device header
#include "LED.h"
#include "Serial.h"
static uint32_t num1 = 0;
static uint32_t num2 = 0;
void Timer_Init(void)
{
//RCC打开时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//选择时基单元的时钟,内部时钟一般默认初始化可以写可以不写
TIM_InternalClockConfig(TIM2);
TIM_InternalClockConfig(TIM3);
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
//TIM_CKD_DIV1代表1分屏
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//代表向上计数
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
//72MHZ分频7200,就是10k,10k计10000个数就是1s
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
//高级定时器才有,现在是通用定时器给0
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
//如果不加入这一句,会导致复位之后从1开始计数
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
//TIM_IT_Update代表更新中断,中断控制,用来控制某个中断能不能通往NIVC
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);
//启动定时器
TIM_Cmd(TIM2, ENABLE);
TIM_Cmd(TIM3, ENABLE);
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
Serial_Printf("优先级4\r\n");
// if(num1 == 0)
// {
// LED1_ON();
// num1 = 1;
// }
// else if(num1 == 1)
// {
// LED1_OFF();
// num1 = 0;
// }
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
Serial_Printf("优先级15\r\n");
// if(num2 == 0)
// {
// LED2_ON();
// num2 = 1;
// }
// else if(num2 == 1)
// {
// LED2_OFF();
// num2 = 0;
// }
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
####task_demo.c
//————————task_demo.c————————//
#include "stm32f10x.h" // Device header
#include "freertos.h"
#include "task.h"
#include "LED.h"
#include "Serial.h"
#include "Delay.h"
uint16_t num=0;
uint8_t KNum=0;
static TaskHandle_t myTaskHandler0 ;
static TaskHandle_t myTaskHandler1 ;
void task_begin(void *arg);
void myTask1(void *arg );
void freertos_demo(void)
{
xTaskCreate(task_begin,"task_begin",128,NULL,1,&myTaskHandler0);
vTaskStartScheduler();
}
void task_begin(void *arg)
{
taskENTER_CRITICAL();//进入临界区
xTaskCreate(myTask1,"myTask1",128,NULL,2,&myTaskHandler1);
vTaskDelete(NULL);
taskEXIT_CRITICAL();//退出临界区
}
/*
注意:因为我的FreeRTOS宏定义将开中断关中断定义为porDISABLE_INTERRUPTS();
porENABLE_INTERRUPTS();是不能直接使用的,所以如果使用这个的话,现象是实现不了的,所以我们需要使用原始的vPortRaiseBASEPRI()和vPortSetBASEPRI(0);;
vPortSetBASEPRI(0);进行关中断和开中断。
*/
void myTask1(void *arg )
{
while(1)
{
if(++num ==5)
{
num=0;
Serial_Printf("关中断\r\n");
vPortRaiseBASEPRI();
//porDISABLE_INTERRUPTS();
Delay_ms(5000);
vPortSetBASEPRI(0);
//porENABLE_INTERRUPTS();
Serial_Printf("开中断\r\n");
}
vTaskDelay(1000);
}
}
####main.c
//——————main.c——————//
#include "stm32f10x.h" // Device header
#include "freertos.h"
#include "task.h"
#include "LED.h"
#include "Key.h"
#include "Serial.h"
#include "OLED.h"
#include "TIM.h"
#include "task_demo.h"
int main(void)
{
LED_Init();
Key_Init();
Serial_Init();
Timer_Init();
freertos_demo();
}