完成操作系统部分

master
高宏宇 11 months ago
parent 8d433a497d
commit 35f57df8f0

@ -74,6 +74,14 @@
- [代码](#代码) - [代码](#代码)
- [运行效果和代码分析](#运行效果和代码分析) - [运行效果和代码分析](#运行效果和代码分析)
- [3.6. 软件定时器](#36-软件定时器) - [3.6. 软件定时器](#36-软件定时器)
- [函数接口](#函数接口)
- [软件定时器创建函数(osTimerNew)](#软件定时器创建函数ostimernew)
- [软件定时器启动函数(osTimerStart)](#软件定时器启动函数ostimerstart)
- [软件定时器停止函数(osTimerStop)](#软件定时器停止函数ostimerstop)
- [应用示例](#应用示例)
- [配置](#配置-1)
- [代码编写](#代码编写)
- [代码分析](#代码分析)
# 1. 概述 # 1. 概述
@ -655,6 +663,15 @@ FreeRTOS提供了事件标志组的功能每一个事件标志组最多具有
#### 3.2.2.2. 代码编写 #### 3.2.2.2. 代码编写
在 USER CODE BEGIN 4 部分加入以下代码:
```c
/* USER CODE BEGIN 4 */
#define EVENT1 0x01
#define EVENT2 0x02
/* USER CODE END 4 */
```
补充 StartEventTask 代码: 补充 StartEventTask 代码:
```c ```c
@ -969,3 +986,118 @@ osMessageQueuePut(ComQueueHandle, RxBuffer, 0, 0);
为什么?无解。 为什么?无解。
## 3.6. 软件定时器 ## 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. 配置中间件打开FREERTOSInterface设置成 CMSIS_V2
6. FreeRTOS 的 Advanced settings 中打开 NEWLIB 的选项,否则要提示警告;
7. 建立一个任务
![image-20241013115709382](./img/image-20241013115709382.png)
#### 代码编写
在 USER CODE BEGIN Includes 代码段补充以下代码:
```c
/* USER CODE BEGIN Includes */
#include <string.h>
/* 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 成为一次性任务,依旧不能正常运行。具体原因还需要进一步分析。

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

Loading…
Cancel
Save