FreeRTOS的启动-基于STM32

1、Reset_Handler

系统上电后第一个执行的汇编函数,系统通过该函数进行初始化

1 Reset_Handler PROC
2 EXPORT Reset_Handler [WEAK]
3 IMPORT __main
4 IMPORT SystemInit
5 LDR R0, =SystemInit
6 BLX R0 
7 LDR R0, =__main
8 BX R0
9 ENDP

2、__main

C库函数,系统初始化后会调用该函数,从而执行C代码


3、main()

main函数是C语言的代码第一个执行的函数,一般操作系统的创建与启动都在main函数中调用。

 int main(void)
 {
 	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
 
 	/* 开发板硬件初始化 */
	 BSP_Init(); 
	 taskENTER_CRITICAL(); //进入临界区
   /* 创建 AppTaskCreate 任务 */ 
 	xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,/* 任务入口函数 */
 						  (const char* )"AppTaskCreate",/* 任务名字 */
 						  (uint16_t )512, /* 任务栈大小 */
 						  (void* )NULL,/* 任务入口函数参数 */
 						  (UBaseType_t )1, /* 任务的优先级 */
 						  (TaskHandle_t*)&AppTaskCreate_Handle);/*任务控制块指针*/
 	taskEXIT_CRITICAL(); //退出临界区
 	/* 启动任务调度 */
	 if (pdPASS == xReturn)
 		vTaskStartScheduler(); /* 启动任务,开启调度 */ (3)
	 else
	 	return -1; 
 
	 while (1); /* 正常不会执行到这里 */
 }


4、创建任务

通过调用FreeRTOS 的任务创建函数创建任务,在任务创建中,FreeRTOS会自动进行一系列的操作系统初始化,比如初始化内存等。

//创建任务函数原型
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
					    const char * const pcName,
					    const uint16_t usStackDepth,
					    void * const pvParameters,
					    UBaseType_t uxPriority,
					    TaskHandle_t * const pxCreatedTask )

5、启动任务

在创建完任务的时候,我们需要开启调度器,因为创建仅仅是把任务添加到系统中,还没真正调度,并且空闲任务也没实现,定时器任务也没实现,这些都是在开启调度函数vTaskStartScheduler()中实现的。

为什么要空闲任务?因为 FreeRTOS 一旦启动,就必须要保证系统中每时每刻都有一个任务处于运行态(Runing),并且空闲任务不可以被挂起与删除,空闲任务的优先级是最低的,以便系统中其他任务能随时抢占空闲任务的 CPU 使用权。

这些都是系统必要的东西,也无需用户自己实现,FreeRTOS 全部帮我们搞定了。处理完这些必要的东西之后,系统才真正开始启动。


参考

野火FreeRTOS内核实现与应用开发实战

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于STM32和FreeRTOS的万年历代码的一个简单示例: ```c #include "stm32f4xx.h" #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include "lcd.h" #include "rtc.h" #include "calendar.h" // 定义任务句柄 xTaskHandle xTaskDisplayHandle, xTaskInputHandle, xTaskRTCUpdateHandle; // 定义信号量句柄 xSemaphoreHandle xSemaphoreInput; // 定义输入缓冲区和指针 char cInputBuffer[32] = {'\0'}; uint8_t ucInputIndex = 0; // 显示任务 void vTaskDisplay(void *pvParameters) { char cBuffer[32] = {'\0'}; for (;;) { // 获取当前时间 RTC_DateTypeDef Date; RTC_TimeTypeDef Time; RTC_GetDate(RTC_Format_BIN, &Date); RTC_GetTime(RTC_Format_BIN, &Time); // 格式化时间字符串 sprintf(cBuffer, "%04d-%02d-%02d %02d:%02d:%02d", Date.RTC_Year + 2000, Date.RTC_Month, Date.RTC_Date, Time.RTC_Hours, Time.RTC_Minutes, Time.RTC_Seconds); // 清屏并显示时间 LCD_Clear(); LCD_DisplayString(0, 0, "STM32F4 Calendar"); LCD_DisplayString(1, 0, cBuffer); // 暂停任务,等待1秒 vTaskDelay(1000 / portTICK_RATE_MS); } } // 输入任务 void vTaskInput(void *pvParameters) { char cBuffer[32] = {'\0'}; uint8_t ucKey = 0; BaseType_t xResult; for (;;) { // 等待信号量 xSemaphoreTake(xSemaphoreInput, portMAX_DELAY); // 获取输入缓冲区和指针 memcpy(cBuffer, cInputBuffer, sizeof(cInputBuffer)); ucInputIndex = 0; // 处理输入 if (strcmp(cBuffer, "date") == 0) { // 获取当前日期并显示 RTC_DateTypeDef Date; RTC_GetDate(RTC_Format_BIN, &Date); sprintf(cBuffer, "%04d-%02d-%02d", Date.RTC_Year + 2000, Date.RTC_Month, Date.RTC_Date); LCD_DisplayString(3, 0, cBuffer); } else if (strcmp(cBuffer, "time") == 0) { // 获取当前时间并显示 RTC_TimeTypeDef Time; RTC_GetTime(RTC_Format_BIN, &Time); sprintf(cBuffer, "%02d:%02d:%02d", Time.RTC_Hours, Time.RTC_Minutes, Time.RTC_Seconds); LCD_DisplayString(3, 0, cBuffer); } else if (strcmp(cBuffer, "set date") == 0) { // 设置日期 xResult = xTaskCreate(vTaskCalendar, "Calendar", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); if (xResult != pdPASS) { LCD_DisplayString(3, 0, "Error: Failed to create calendar task"); } } else if (strcmp(cBuffer, "help") == 0) { // 显示帮助信息 LCD_DisplayString(3, 0, "date - show date"); LCD_DisplayString(4, 0, "time - show time"); LCD_DisplayString(5, 0, "set date - set date"); LCD_DisplayString(6, 0, "help - show help"); } else { // 显示错误信息 LCD_DisplayString(3, 0, "Error: Invalid command"); } // 清空输入缓冲区 memset(cInputBuffer, 0, sizeof(cInputBuffer)); } } // RTC更新任务 void vTaskRTCUpdate(void *pvParameters) { for (;;) { // 等待RTC秒更新 xSemaphoreTake(xSemaphoreRTC, portMAX_DELAY); // 发送信号量以触发输入任务 xSemaphoreGive(xSemaphoreInput); } } int main(void) { BaseType_t xResult; // 初始化硬件 LCD_Init(); RTC_Init(); // 创建信号量 xSemaphoreInput = xSemaphoreCreateBinary(); // 创建任务 xResult = xTaskCreate(vTaskDisplay, "Display", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, &xTaskDisplayHandle); if (xResult != pdPASS) { LCD_DisplayString(0, 0, "Error: Failed to create display task"); while (1); } xResult = xTaskCreate(vTaskInput, "Input", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &xTaskInputHandle); if (xResult != pdPASS) { LCD_DisplayString(0, 0, "Error: Failed to create input task"); while (1); } xResult = xTaskCreate(vTaskRTCUpdate, "RTC Update", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 3, &xTaskRTCUpdateHandle); if (xResult != pdPASS) { LCD_DisplayString(0, 0, "Error: Failed to create RTC update task"); while (1); } // 启动调度器 vTaskStartScheduler(); // 不应该运行到这里 while (1); } ``` 这个示例代码包括三个任务: - 显示任务:每秒钟更新一次LCD显示器上的时间。 - 输入任务:等待用户输入命令,根据命令执行相应的操作。 - RTC更新任务:等待RTC秒更新中断,并发送信号量以触发输入任务。 这个示例代码还包括一个信号量和一个输入缓冲区,以便在输入任务中处理用户输入。用户可以通过按键或串口发送命令,来与万年历进行交互。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值