diff --git a/book/07:FreeRTOS/01.md b/book/07:FreeRTOS/01.md index 9279e3b..aaa504f 100644 --- a/book/07:FreeRTOS/01.md +++ b/book/07:FreeRTOS/01.md @@ -74,6 +74,14 @@ - [代码](#代码) - [运行效果和代码分析](#运行效果和代码分析) - [3.6. 软件定时器](#36-软件定时器) + - [函数接口](#函数接口) + - [软件定时器创建函数(osTimerNew)](#软件定时器创建函数ostimernew) + - [软件定时器启动函数(osTimerStart)](#软件定时器启动函数ostimerstart) + - [软件定时器停止函数(osTimerStop)](#软件定时器停止函数ostimerstop) + - [应用示例](#应用示例) + - [配置](#配置-1) + - [代码编写](#代码编写) + - [代码分析](#代码分析) # 1. 概述 @@ -655,6 +663,15 @@ FreeRTOS提供了事件标志组的功能,每一个事件标志组最多具有 #### 3.2.2.2. 代码编写 +在 USER CODE BEGIN 4 部分加入以下代码: + +```c +/* USER CODE BEGIN 4 */ +#define EVENT1 0x01 +#define EVENT2 0x02 +/* USER CODE END 4 */ +``` + 补充 StartEventTask 代码: ```c @@ -969,3 +986,118 @@ osMessageQueuePut(ComQueueHandle, RxBuffer, 0, 0); 为什么?无解。 ## 3.6. 软件定时器 + +在嵌入式系统设计中,常常有这样的功能需求:一个任务周期性地运行或者在将来某个时刻运行,以实现定时或者延时控制,这个功能可以利用定时器实现。 + +从定时器的实现角度来看,可以分为硬件定时器和软件定时器。硬件定时器数量有限,往往可以实现除了简单定时而外的其他功能;作为简单的定时而言,软件定时器可能更适合。 + +软件定时器的工作方式和硬件定时器类似:设置一个定时时间后,启动定时器运行预设的定时时间到达后,可以调用一个回调函数来执行相应的操作。 + +软件定时器可以配置为单次触发或者周期触发:单次触发定时器执行一次回调函数后将不再运行;周期触发定时器则重复执行回调函数,直到用户停止或删除该定时器为止。所有软件定时器都可以启动、停止或重新启动。 + +### 函数接口 + +#### 软件定时器创建函数(osTimerNew) + +![image-20241013111906257](./img/image-20241013111906257.png) + +![image-20241013111929339](./img/image-20241013111929339.png) + +#### 软件定时器启动函数(osTimerStart) + +![image-20241013112018017](./img/image-20241013112018017.png) + +#### 软件定时器停止函数(osTimerStop) + +![image-20241013112103440](./img/image-20241013112103440.png) + +### 应用示例 + +建立两个软件定时器:一个是周期触发定时器,每隔100ms通过串口向PC发送数据;一个是单次触发定时器,控制指示灯在系统启动5s后再开启。 + +#### 配置 + +1. 新建一个工程,取名OsTimer;注意:需要设置SYS中的Debug为 Serial Wire;另外固件版本可能需要调整,1.8.6的有问题; +2. 同样在 SYS 中,配置Timebase Source 为一个没有使用的定时器,如TIM4; +3. 设置PA7为输出,并设置Label为LED; +4. 打开串口2,不用打开中断; +5. 配置中间件,打开FREERTOS,Interface设置成 CMSIS_V2; +6. FreeRTOS 的 Advanced settings 中打开 NEWLIB 的选项,否则要提示警告; +7. 建立一个任务 + +![image-20241013115709382](./img/image-20241013115709382.png) + + + +#### 代码编写 + +在 USER CODE BEGIN Includes 代码段补充以下代码: + +```c +/* USER CODE BEGIN Includes */ +#include +/* USER CODE END Includes */ +``` + +在 USER CODE BEGIN 0 补充以下代码 + +```c +/* USER CODE BEGIN 0 */ +osTimerId_t ComTimerHandle; +osTimerId_t LedTimerHandle; + +char *MSG = "Periodic Virtual Timer:run every 1s.\n"; +void ComCallback(void *argument) { + HAL_UART_Transmit(&huart2, (uint8_t*) MSG, strlen(MSG), 100); // 发送接收到的数据 +} +void LedCallback(void *argument) { + HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); + osDelay(200); + HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); +} +/* USER CODE END 0 */ +``` + +完善 StartInitTimer 任务函数 + +```c +/* USER CODE END Header_StartInitTimer */ +void StartInitTimer(void *argument) { + /* USER CODE BEGIN 5 */ + ComTimerHandle = osTimerNew(ComCallback, osTimerPeriodic, NULL, NULL); + LedTimerHandle = osTimerNew(LedCallback, osTimerOnce, NULL, NULL); + osTimerStart(ComTimerHandle, 1000); + osTimerStart(LedTimerHandle, 5000); + for (;;) { + osDelay(1000); + } + /* USER CODE END 5 */ +} +``` + +#### 代码分析 + +按照书上的方法,启动定时器不能简单的在main 函数中完成。首先分析一下main函数的流程: + +```c +int main(void) { + HAL_Init(); // 1. 硬件代码初始化 + SystemClock_Config(); // 2. 系统时钟配置 + MX_GPIO_Init(); // 3. GPIO初始化 + MX_USART2_UART_Init(); // 4. 串口初始化 + osKernelInitialize(); // 5. 操作系统初始化 + InitTimerHandle = osThreadNew(StartInitTimer, NULL, &InitTimer_attributes); // 6. 建立一个任务 + osKernelStart(); // 7. 操作系统正式运行 + while (1) { + // 8. 非操作系统的循环代码 + } +} +``` + +1. 正常情况下,当运行到7的位置时,操作系统进行自己的任务调度循环,这时,7之后的代码永远不能运行; +2. 在7之前的代码都是初始化的代码,操作系统也没有运行; +3. 因此启动定时器的代码放在7之前是不合适的,因为操作系统还没有运行,无法启动定时器; +4. 启动定时器的代码放在7之后也是不合适的,因为7之后的代码正常情况下永远不会运行; +5. 因此,我们需要一个独立的任务,在操作系统运行后对定时器进行启动,因此有了 StartInitTimer 这个任务;这个任务的目的就是在操作系统运行的时候启动定时器; +6. 按理说,这个任务可以是一次性任务,不需要后面的死循环;但是删除后面的死循环后,代码无法正常运行; +7. 有猜测操作系统至少应该有一个周期性任务,因此另外添加一个任务(保留该任务中的死循环);并删除 StartInitTimer 任务中的死循环,让 StartInitTimer 成为一次性任务,依旧不能正常运行。具体原因还需要进一步分析。 diff --git a/book/07:FreeRTOS/img/image-20241013111906257.png b/book/07:FreeRTOS/img/image-20241013111906257.png new file mode 100644 index 0000000..6f30411 Binary files /dev/null and b/book/07:FreeRTOS/img/image-20241013111906257.png differ diff --git a/book/07:FreeRTOS/img/image-20241013111929339.png b/book/07:FreeRTOS/img/image-20241013111929339.png new file mode 100644 index 0000000..a5cfb7b Binary files /dev/null and b/book/07:FreeRTOS/img/image-20241013111929339.png differ diff --git a/book/07:FreeRTOS/img/image-20241013112018017.png b/book/07:FreeRTOS/img/image-20241013112018017.png new file mode 100644 index 0000000..476cb2f Binary files /dev/null and b/book/07:FreeRTOS/img/image-20241013112018017.png differ diff --git a/book/07:FreeRTOS/img/image-20241013112103440.png b/book/07:FreeRTOS/img/image-20241013112103440.png new file mode 100644 index 0000000..a76c229 Binary files /dev/null and b/book/07:FreeRTOS/img/image-20241013112103440.png differ diff --git a/book/07:FreeRTOS/img/image-20241013112927781.png b/book/07:FreeRTOS/img/image-20241013112927781.png new file mode 100644 index 0000000..ab04fc7 Binary files /dev/null and b/book/07:FreeRTOS/img/image-20241013112927781.png differ diff --git a/book/07:FreeRTOS/img/image-20241013112943747.png b/book/07:FreeRTOS/img/image-20241013112943747.png new file mode 100644 index 0000000..f5bbac6 Binary files /dev/null and b/book/07:FreeRTOS/img/image-20241013112943747.png differ diff --git a/book/07:FreeRTOS/img/image-20241013115709382.png b/book/07:FreeRTOS/img/image-20241013115709382.png new file mode 100644 index 0000000..f929e27 Binary files /dev/null and b/book/07:FreeRTOS/img/image-20241013115709382.png differ diff --git a/book/07:FreeRTOS/img/os_init.drawio.png b/book/07:FreeRTOS/img/os_init.drawio.png new file mode 100644 index 0000000..eb5647c Binary files /dev/null and b/book/07:FreeRTOS/img/os_init.drawio.png differ