ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

STM32+FreeRTOS+RTC时钟实验笔记

STM32+FreeRTOS+RTC时钟实验笔记 实验目标在STM32f103C8T6上配置RTC时钟并通过FreeFTOS调用时钟任务实现RTC时钟的使用。实验使用RTC.c/.h代码原文件来自原子哥标准库例程。分析例程中包含的函数共如上八个。除去RTC闹钟一共七个。先来理清RTC时钟需要的七个函数。在初始化阶段需要做的事如上。要从裸机改为FreeRTOS实现RTC时钟大多数函数都不需要改变可以复用。我们需要修改的主要是中断服务函数和新增的任务函数。因为裸机使用单循环的方式执行任务而RTOS则使用时间片轮转的方式出于实时性要求我们不能和原来一样在中断函数中执行耗时较多的事比如这里的RTC_Get();和printf();FreeRTOS运行过程在中断服务函数中一般只做两件事发送信号和清标志位。这里也很好理解使用一个二值信号量进中断了发送信号xSemaphoreGiveFromISR()让RTC_task来执行然后清除标志位。void RTC_IRQHandler(void) { if (RTC_GetITStatus(RTC_IT_SEC) ! RESET)//秒钟中断 { RTC_Get();//更新时间 } if(RTC_GetITStatus(RTC_IT_ALR)! RESET)//闹钟中断 { RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断 RTC_Get(); //更新时间 printf(Alarm Time:%d-%d-%d %d:%d:%d\n,calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间 } RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //清闹钟中断 RTC_WaitForLastTask(); }下面是一个大概的逻辑示意图。RTC硬件每秒触发中断中断服务函数发送xSemaphoreGiveFromISR()信号并清标志位。下方的RTC_task一直在循环等待信号的到来一旦接收到信号执行任务命令。void RTC_IRQHandler(void) { BaseType_t xHigherPriorityTaskWoken pdFALSE; if (RTC_GetITStatus(RTC_IT_SEC) ! RESET)//秒钟中断 { xSemaphoreGiveFromISR(rtcSemaphore, xHigherPriorityTaskWoken); // 在中断服务程序中释放信号量 RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //清秒钟中断标志 } if(RTC_GetITStatus(RTC_IT_ALR)! RESET)//闹钟中断 { xSemaphoreGiveFromISR(rtcSemaphore, xHigherPriorityTaskWoken); // 在中断服务程序中释放信号量,可以再加闹钟信号来处理闹钟逻辑 RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断 } RTC_WaitForLastTask(); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void RTC_task(void *pvParameters) { while(1) { // 阻塞等待信号量ISR 每秒 give 一次 if (xSemaphoreTake(rtcSemaphore, portMAX_DELAY) pdTRUE) { RTC_Get(); // 更新时间 RTC_PrintTime(); // 打印时间 } } }需要注意的是原来的抢占优先级为0不符合FreeRTOS的要求这里改成configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY这个宏来自FreeRTOS可以理解为FreeRTOS下可以设的合理最高优先级。static void RTC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel RTC_IRQn; //RTC全局中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY; //configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY这是一个“人类可读”的逻辑值专为 NVIC_SetPriority 这类库函数准备数值通常比较小比如 5 NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; //先占优先级0位,从优先级4位 NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //使能该通道中断 NVIC_Init(NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 }实验结果如下所示。总结在设置任务前先理清要做的事的调用关系这样修改任务和中断函数就会快很多。没有来得及实现OLED显示功能可以加强一下。
返回列表