FreeRTOS-03中断测试
根据正点原子FreeRTOS视频整理
单片机:STM32F207VC
FreeRTOS源码版本:v10.0.1
portDISABLE_INTERRUPTS(); /*关中断*/
portENABLE_INTERRUPTS(); /*开中断*/
工程列表:
实验说明:
1. 定时器3控制一个灯闪烁,抢占优先级为4;定时器5控制一个灯闪烁,抢占优先级为5.
2. InterruptTask()函数,一段时间后关闭中断,过一段时间再开启中断,如此反复。
3. 实验现象应该是,关闭中断后,优先级为4的灯继续闪烁,优先级为5的灯停止闪烁;
开启中断后,2个灯都在闪烁。
1. main.c
1 /* 2 * 实验说明: 3 * 1. 定时器3控制一个灯闪烁,抢占优先级为4;定时器4控制1个灯闪烁,抢占优先级为5. 4 * 2. InterruptTask()函数,一段时间后关闭中断,过一段时间再开启中断,如此反复。 5 * 备注: 6 * 1. portDISABLE_INTERRUPTS();关中断 7 * 2. portENABLE_INTERRUPTS();开中断 8 * 3. 关中断后,优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的任务,会被关掉。 9 * 4. 数值越大,优先级越低。 10 */ 11 #include "main.h" 12 #include "gpio.h" 13 #include "delay.h" 14 #include "sys.h" 15 #include "timer.h" 16 17 #include "stm32f2xx_gpio.h" 18 19 #include "FreeRTOS.h" 20 #include "task.h" 21 22 #define START_TASK_PRIO 1 /*任务优先级*/ 23 #define START_STK_SIZE 128 /*任务堆栈大小*/ 24 TaskHandle_t StartTask_Handle; /*任务句柄*/ 25 void StartTask(void *pvParameters); /*任务函数*/ 26 27 #define INTERRUPT_TASK_PRIO 2 28 #define INTERRUPT_STK_SIZE 256 29 TaskHandle_t InterruptTask_Handle; 30 void InterruptTask(void *pvParameters); 31 32 33 34 /***** 声明 *****/ 35 static void SystemInitial(void); 36 37 38 void StartTask(void *pvParameters) 39 { 40 taskENTER_CRITICAL(); /*进入临界区*/ 41 42 xTaskCreate((TaskFunction_t )InterruptTask, /*任务函数*/ 43 (const char * )"InterruptTask", /*任务名称*/ 44 (uint16_t )INTERRUPT_STK_SIZE, /*任务堆栈大小*/ 45 (void * )NULL, /*传递给任务函数的参数*/ 46 (UBaseType_t )INTERRUPT_TASK_PRIO, /*任务优先级*/ 47 (TaskHandle_t )&InterruptTask_Handle); /*任务句柄*/ 48 49 vTaskDelete(StartTask_Handle); /*删除开始任务*/ 50 taskEXIT_CRITICAL(); /*推出临界区*/ 51 } 52 53 void InterruptTask(void *pvParameters) 54 { 55 static uint8_t i = 0; 56 57 while (1) 58 { 59 i++; 60 if (5==i) 61 { 62 portDISABLE_INTERRUPTS(); 63 } 64 else if (10 == i) 65 { 66 i = 0; 67 portENABLE_INTERRUPTS(); 68 } 69 else 70 ; 71 72 DelayXms(1000); 73 } 74 } 75 76 static void SystemInitial(void) 77 { 78 /*组4,16级抢占优先级,无响应优先级*/ 79 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); 80 81 DelayInitial(); 82 GPIO_Initial(); 83 TimerInitial(); 84 } 85 86 int main(void) 87 { 88 SystemInitial(); 89 90 91 /*创建开始任务*/ 92 xTaskCreate((TaskFunction_t )StartTask, /*任务函数*/ 93 (const char * )"StartTask", /*任务名称*/ 94 (uint16_t )START_STK_SIZE, /*任务堆栈大小*/ 95 (void * )NULL, /*传递给任务函数的参数*/ 96 (UBaseType_t )START_TASK_PRIO, /*任务优先级*/ 97 (TaskHandle_t )&StartTask_Handle); /*任务句柄*/ 98 99 /*开启任务调度*/ 100 vTaskStartScheduler(); 101 } 102 103 /***************************END OF FILE***************************/
2. main.h
1 /**/ 2 #ifndef __MAIN_H__ 3 #define __MAIN_H__ 4 5 6 7 8 #endif /*__MAIN_H__*/ 9 10 /***************************END OF FILE***************************/
3. sys.c
1 /**/ 2 #include "sys.h" 3 #include "stdio.h" 4 5 #pragma import(__use_no_semihosting) 6 //标准库需要的支持函数 7 struct __FILE 8 { 9 int handle; 10 11 }; 12 13 FILE __stdout; 14 //定义_sys_exit()以避免使用半主机模式 15 void _sys_exit(int x) 16 { 17 x = x; 18 } 19 //重定义fputc函数 20 int fputc(int ch, FILE *f) 21 { 22 // while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 23 // USART1->DR = (u8) ch; 24 return ch; 25 } 26 27 28 /***************************END OF FILE***************************/
4. sys.h
1 /**/ 2 #ifndef __SYS_H__ 3 #define __SYS_H__ 4 5 /*0不支持OS,1支持OS*/ 6 #define SYSTEM_SUPPORT_OS 1 /*定义系统文件夹是否支持OS*/ 7 8 #endif /*__SYS_H__*/ 9 10 /***************************END OF FILE***************************/
5. delay.c
1 /**/ 2 #include "delay.h" 3 #include "sys.h" 4 /*如果需要使用OS,则包括下面的头文件即可*/ 5 #if SYSTEM_SUPPORT_OS 6 #include "FreeRTOS.h" 7 #include "task.h" 8 #endif 9 10 __IO uint32_t TimingDelay; 11 12 ////////////////////////// 13 static uint8_t fac_us = 0; 14 ////////////////////////// 15 16 /***** 声明 *****/ 17 extern void xPortSysTickHandler(void); 18 19 /*systick中断服务函数,使用FreeRTOS时用到*/ 20 void SysTick_Handler(void) 21 { 22 TimingDelayDecrement(); 23 24 if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) /*系统已运行*/ 25 { 26 xPortSysTickHandler(); 27 } 28 } 29 30 31 void DelayInitial(void) 32 { 33 /* 34 * SystemCoreClock / 1000 1ms中断一次 35 * SystemCoreClock / 100000 10us中断一次 36 * SystemCoreClock / 1000000 1us中断一次 37 */ 38 if (SysTick_Config(SystemCoreClock / 1000)) 39 { 40 while (1); 41 } 42 /*关闭systick timer定时器*/ 43 /* SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;*/ 44 45 /*使能滴答定时器*/ 46 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; 47 } 48 49 void DelayNus(uint32_t nus) 50 { 51 uint32_t ticks; 52 uint32_t told, tnow, tcnt = 0; 53 uint32_t reload = SysTick->LOAD; 54 55 fac_us = SystemCoreClock / 1000000; 56 ticks = nus * fac_us; 57 told = SysTick->VAL; 58 59 while (1) 60 { 61 tnow = SysTick->VAL; 62 if (tnow != told) 63 { 64 if (tnow < told) 65 { 66 tcnt += told - tnow; 67 } 68 else 69 { 70 tcnt += reload - tnow + told; 71 } 72 told = tnow; 73 if (tcnt >= ticks) break; 74 } 75 } 76 } 77 78 /*不会引起调度*/ 79 void DelayXms(uint32_t nms) 80 { 81 uint32_t i; 82 83 for (i=0;i<nms;++i) 84 { 85 DelayNus(1000); 86 } 87 } 88 89 /* 90 * 本函数在中断函数中调用,滴答定时器中断一次调用一次。 91 */ 92 void TimingDelayDecrement(void) 93 { 94 if (TimingDelay != 0x00) 95 { 96 TimingDelay--; 97 } 98 } 99 100 /* 101 * TimingDelay值在TimingDelayDecrement函数中递减 102 */ 103 void DelayNms(uint32_t nTimes) 104 { 105 TimingDelay = nTimes; 106 107 while (TimingDelay!=0); //等待计数停止 108 } 109 110 /***************************END OF FILE***************************/
6. delay.h
1 /**/ 2 #ifndef __DELAY_H__ 3 #define __DELAY_H__ 4 5 #include "stm32f2xx.h" 6 7 #include <stdint.h> 8 9 extern void DelayInitial(void); 10 extern void TimingDelayDecrement(void); 11 extern void DelayNms(uint32_t nTimes); 12 13 ///////////////////////// 14 extern void DelayXms(uint32_t nms); 15 ///////////////////////// 16 17 #endif /*__DELAY_H__*/ 18 /***************************END OF FILE***************************/
7. gpio.c
1 /**/ 2 #include "gpio.h" 3 4 /***** 声明 *****/ 5 static void GPIO_LED_Configuration(void); 6 7 8 void GPIO_Initial(void) 9 { 10 GPIO_LED_Configuration(); 11 } 12 13 14 static void GPIO_LED_Configuration(void) 15 { 16 GPIO_InitTypeDef GPIO_InitStructure; 17 18 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); 19 20 GPIO_InitStructure.GPIO_Pin = LED_POWER | LED_RUN | LED_ALARM; 21 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 22 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 23 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 24 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 25 GPIO_Init(GPIOE, &GPIO_InitStructure); 26 27 LED_Power_On(); 28 LED_Run_Off(); 29 LED_Alarm_Off(); 30 } 31 32 /***************************END OF FILE***************************/
8. gpio.h
1 /**/ 2 #ifndef __GPIO_H__ 3 #define __GPIO_H__ 4 5 #include "stm32f2xx_gpio.h" 6 7 #define LED_POWER GPIO_Pin_2 /*PE2*/ 8 #define LED_RUN GPIO_Pin_3 /*PE3*/ 9 #define LED_ALARM GPIO_Pin_4 /*PE4*/ 10 11 #define LED_Power_On() GPIO_ResetBits(GPIOE, LED_POWER) 12 #define LED_Power_Off() GPIO_SetBits(GPIOE, LED_POWER) 13 #define LED_Run_On() GPIO_ResetBits(GPIOE, LED_RUN) 14 #define LED_Run_Off() GPIO_SetBits(GPIOE, LED_RUN) 15 #define LED_Alarm_On() GPIO_ResetBits(GPIOE, LED_ALARM) 16 #define LED_Alarm_Off() GPIO_SetBits(GPIOE, LED_ALARM) 17 18 19 extern void GPIO_Initial(void); 20 21 #endif /*__GPIO_H__*/ 22 /***************************END OF FILE***************************/
9. timer.c
1 /**/ 2 #include "timer.h" 3 #include "gpio.h" 4 #include "stm32f2xx_tim.h" 5 6 /***** 声明 *****/ 7 static void Timer3Init(void); 8 static void Timer4Init(void); 9 10 void TimerInitial(void) 11 { 12 Timer3Init(); 13 Timer4Init(); 14 } 15 16 /*timer3:APB1 30MHz*/ 17 static void Timer3Init(void) 18 { 19 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 20 NVIC_InitTypeDef NVIC_InitStructure; 21 22 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 23 24 TIM_TimeBaseStructure.TIM_Prescaler = 30000-1; /*预分频系数,30MHz/30000=1KHz*/ 25 TIM_TimeBaseStructure.TIM_Period = 1000-1; /*计数值,每计1000个数,产生一次中断. 1000*(1/1KHz) = 1s */ 26 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; /*设置计数器模式为向上计数模式*/ 27 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; /*设置时钟分频系数,TIM_CKD_DIV1不分频*/ 28 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /*初始化*/ 29 30 TIM_Cmd(TIM3, ENABLE); /*使能TIM4外设。在使用外设时,不仅要使能其时钟,还要调用此函数使能外设才可以正常使用*/ 31 32 TIM_ClearFlag(TIM3, TIM_FLAG_Update); /*清除溢出中断标志*/ 33 34 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); /*开启中断*/ 35 36 37 /*4级抢占优先级,0级响应优先级*/ 38 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; 39 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4; 40 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 41 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 42 43 NVIC_Init(&NVIC_InitStructure); 44 } 45 46 47 /*timer4:APB1 30MHz*/ 48 static void Timer4Init(void) 49 { 50 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 51 NVIC_InitTypeDef NVIC_InitStructure; 52 53 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); 54 55 TIM_TimeBaseStructure.TIM_Prescaler = 30000-1; /*预分频系数,30MHz/30000=1KHz*/ 56 TIM_TimeBaseStructure.TIM_Period = 1000-1; /*计数值,每计1000个数,产生一次中断. 1000*(1/1KHz) = 1s */ 57 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; /*设置计数器模式为向上计数模式*/ 58 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; /*设置时钟分频系数,TIM_CKD_DIV1不分频*/ 59 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); /*初始化*/ 60 61 TIM_Cmd(TIM4, ENABLE); /*使能TIM4外设。在使用外设时,不仅要使能其时钟,还要调用此函数使能外设才可以正常使用*/ 62 63 TIM_ClearFlag(TIM4, TIM_FLAG_Update); /*清除溢出中断标志*/ 64 65 TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); /*开启中断*/ 66 67 68 /*5级抢占优先级,0级响应优先级*/ 69 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; 70 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; 71 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 72 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 73 74 NVIC_Init(&NVIC_InitStructure); 75 } 76 77 /*Timer3中断服务函数*/ 78 void TIM3_IRQHandler(void) 79 { 80 if (TIM_GetITStatus(TIM3, TIM_IT_Update)==SET) /*溢出中断*/ 81 { 82 GPIOE->ODR ^= LED_RUN; 83 } 84 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); 85 } 86 87 88 /*Timer4中断服务函数*/ 89 void TIM4_IRQHandler(void) 90 { 91 if (TIM_GetITStatus(TIM4, TIM_IT_Update)==SET) /*溢出中断*/ 92 { 93 GPIOE->ODR ^= LED_ALARM; 94 } 95 TIM_ClearITPendingBit(TIM4, TIM_IT_Update); 96 // TIM_ClearFlag(TIM4, TIM_FLAG_Update); /*清除溢出中断标志*/ 97 } 98 99 100 /***************************END OF FILE***************************/
10. timer.h
1 /**/ 2 #ifndef __TIMER_H__ 3 #define __TIMER_H__ 4 5 extern void TimerInitial(void); 6 7 #endif /*__TIMER_H__*/ 8 9 /***************************END OF FILE***************************/
说明:
main.c文件InterruptTask()函数中,如果延时用DelayNms()函数, 在执行portDISABLE_INTERRUPTS()函数后,会无法进入到滴答定时器, 导致portENABLE_INTERRUPTS()函数无法执行。