FreeRTOS之中断管理
学习/总结/工具
FreeRTOS
字数统计: 1.3k(字)
阅读时长: 5(分)
FreeRTOS学习记录第五天
一、延迟中断处理
主函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| static void AppTaskCreate (void) { /*信号量在使用前必须先创建。本例中创建了一个二值信号量*/ vSemaphoreCreateBinary(xBinarySemaphore); /*检测信号量是否成功创建*/ if(xBinarySemaphore!=NULL) { /*创建延迟处理任务。此任务将与中断同步。延迟处理任务在创建时用了一个较高的 优先级,以保证中断退出后立即执行。(在本例中由于只有一个任务所以没有必要)*/ xTaskCreate(vHandlerTask,"Handler",1000,NULL,3,NULL); /*启动调度器*/ vTaskStartScheduler(); } }
|
中断回调函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { static portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken=pdFALSE; /*给出信号量来解除任务阻塞*/ xSemaphoreGiveFromISR(xBinarySemaphore,&xHigherPriorityTaskWoken); if(xHigherPriorityTaskWoken==pdTRUE) { /*给出信号量以使得等待此信号量的任务接触阻塞。如果解除阻塞的任务的 优先级高于当前任务的优先级-强制进行上下文切换,以确保中断直接返回到 解除阻塞的任务(优先级更高)*/ portYIELD_FROM_ISR(); } }
|
同步任务:
1 2 3 4 5 6 7 8 9 10 11 12 13
| static void vHandlerTask( void *pvParameters ) {
for( ;; ) { /*使用信号量等待一个事件。信号量在调度器启动之前,也即此任务之前就已被创建。 任务无超时阻塞,所以此函数调用也只有会在成功获取信号量之后才会返回。此处也 没有必要检测返回值*/ xSemaphoreTake(xBinarySemaphore,portMAX_DELAY); /*程序运行到这里,事件必然已经发生*/ printf("Handler task-Processing event\r\n"); } }
|
FreeRTOS学习记录第六天
写队列任务实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| static void vIntegerGenerator(void *pvParameters) { portTickType xLastExecutionTime; unsigned portLONG u1ValueToSend=0; int i; /*初始化变量,用于调用vTaskDelayUntil(),用于准确延时*/ xLastExecutionTime=xTaskGetTickCount(); for(;;) { /*这是个周期性任务。进入阻塞态直到再次运行的时刻。此任务每200毫秒执行一次*/ vTaskDelayUntil(&xLastExecutionTime,200/portTICK_RATE_MS); /*连续五次发送递增数值到队列。此数值将在中断服务程序中读出。中断服务例程会 将队列读空,所以此任务可以确保将所有的数值都发送到队列。因此不需要设置阻塞 时间*/ for(i=0;i<5;i++) { xQueueSendToBack(xIntegerQueue,&u1ValueToSend,0); u1ValueToSend++; } /*产生中断,以让中断服务例程读取队列*/ printf("About to generate an interrupt\r\n"); __asm{int 0x82} printf("Interrupt generated\r\n"); } }
|
中断服务例程实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| static void __interrupt__far vExampleInterruptHandle(void) { static portBASE_TYPE xHigherPriorityTaskWoken; static unsigned long u1ReceivedNumber; /*这些字符串被声明为static const,以保证它们不会被定位到ISR的栈空间中,即使ISR 没有运行它们也是存在的*/ static const char *pcStrings[]= { "String 0\r\n", "String 1\r\n", "String 2\r\n", "String 3\r\n" }; xHigherPriorityTaskWoken=pdFALSE; /*重复执行,直到队列为空*/ while(xQueueReceiveFromISR(xIntegerQueue,&u1ReceivedNumber,&xHigherPriorityTaskWoken)!=errQUEUE_EMPTY) { /*截取收到的数据,保留低两位(数值范围0到3),然后将索引到的字符串指针发送到另一个队列*/ u1ReceivedNumber&=0x03; xQueueSendToBackFromISR(xStringQueue,&pcStrings[u1ReceivedNumber],&xHigherPriorityTaskWoken); } /*被队列读写操作解除阻塞的任务,其优先级是否高于当前任务?如果是,则进行上下文切换*/ if(xHigherPriorityTaskWoken==pdTRUE) { /*给出信号量以使得等待此信号量的任务接触阻塞。如果解除阻塞的任务的 优先级高于当前任务的优先级-强制进行上下文切换,以确保中断直接返回到 解除阻塞的任务(优先级更高)*/ portYIELD_FROM_ISR(); } }
|
字符串接收任务实现,其接收来自中断服务例程的字符串,并打印输出:
1 2 3 4 5 6 7 8 9 10
| static void vStringPrinter(void *pvParameters) { char *pcString; for(;;) { /*读队列阻塞,直到有消息到来,并将接收的字符串打印输出*/ xQueueReceive(xStringQueue,&pcString,portMAX_DELAY); printf("%s",pcString); } }
|
main()函数实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| int main(void) { /*队列使用前必须先创建。本例中创建了两个队列。一个队列用于保存类型为unsigned long 的变量,另一个队列用于保存类型为char*的变量。两个队列的深度都为10。在实际应用中应 检测返回值以确保队列创建成功*/ xIntegerQueue=xQueueCreate(10,sizeof(unsigned long)); xStringQueue=xQueueCreate(10,sizeof(char*)); /*安装中断服务例程*/ _dos_setvect(0x82,vExampleInterruptHandle); /*创建任务用于往中断服务例程中发送数值。此优先级为1*/ xTaskCreate(vIntegerGenerator,"IntGen",1000,NULL,1,NULL); /*创建任务用于从中断服务例程中接收字符串,并打印输出。此任务的优先级为2*/ xTaskCreate(vStringPrinter,"String",1000,NULL,2,NULL); /*开启调度器*/ vTaskStartScheduler(); /* 如果一切正常, main()函数不应该会执行到这里。但如果执行到这里,很可能是内存堆空间不足导致空闲 任务无法创建。*/ for(;;); }
|
运行输出如下:
1 2 3 4 5 6 7 8 9 10 11 12
| String 3 String 0 String 1 Interrupt generated
About to generate an interrupt String 2 String 3 String 0 String 1 String 2 Interrupt generated
|
注:因为这几次的实验不太方便演示,这里只是做个学习记录和理解,并没有实际运行。
本文链接 : https://www.aye.ink/posts/9519ae2e/
本博客所有文章除特别声明外均为原创,采用 CC BY 4.0 CN协议 许可协议。转载请注明出处