【FreeRTOS】创建第一个多任务程序

创建第1个多任务程序

韦东山 Freertos学习 第一个多任务程序创建

1. 目标

创建两个任务,任务A运行Led_Test,任务B运行LCD_Test。

硬件平台:DShanMCU-F103开发板

2. 接口函数

创建任务的API函数

不同操作系统有不同的创建API函数

FreeRTOS: xTaskCreate

RT-Thread: rt_thread_create

统一:osThreadNew

在cmsis_os2.c里面定义了

参考《FreeRTOS入门与工程实践(基于DshanMCU-103)》里《9.2.2 创建任务》,关键信息如下:

c 复制代码
	BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
							const char * const pcName,		
							const configSTACK_DEPTH_TYPE usStackDepth,
							void * const pvParameters,
							UBaseType_t uxPriority,
							TaskHandle_t * const pxCreatedTask );
  • ASK_CODE pvTaskCode :是一个指向任务的实现函数的指针,任务只是一个不会退出的子函数,通常我们会写一个死循环来实现;
  • const signed portCHAR * const pcName:任务名,用于辅助调试FreeRTOS并不会使用他;
  • unsigned portSHORT usStackDepth:当任务创建时,内核会分为每个任务分配属于任务自己的唯一状态,该值用于指定分配多大的栈空间,传入的值表示的是栈空间可以保存多少个字(word),而不是多少个字节(byte)。比如说,如果是 32 位宽的栈空间,传入的
  • usStackDepth值为 100,则将会分配 400 字节的栈空间(100 * 4bytes)。栈深度乘以栈宽度的结果千万不能超过一个 size_t 类型变量所能表达的最大值,大部分时间用户赋予较合理的数值即可(小了就调大,大了就调小尽量保证空间的不浪费)
  • void *pvParameters:传入我们任务函数中的值,一般为NULL
  • unsigned portBASE_TYPE uxPriority:指定任务执行的优先级。优先级的取值范围可以从最低优先级 0 到最高优先级(configMAX_PRIORITIES -- 1)
  • xTaskHandle *pxCreatedTask:传入任务句柄,如果该任务不会被应用程序用到也可以设置为NULL;
  • 该函数有两个可能的返回值:
    pdTRUE: 表明任务创建成功。
    errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:由于内存堆空间不足,FreeRTOS 无法分配足够的空间来保存任务结构数据和任务栈,因此无法创建任务

当我们创建完成一个任务,我们的任务状态还是处于就绪状态,还未开启任务调度器,也没创建空闲任务与定时器任务任务调度器只启动一次,之后就不会再次执行了,FreeRTOS 中启动任务调度器的函数是 vTaskStartScheduler(),并且启动任务调度器的时候就不会返回,从此任务管理都由 FreeRTOS管理,如果这里我们卸载vTaskStartScheduler后面的语句执行了也就说明我们的任务启动失败这时候我们需要根据情况特殊处理(这里需要注意在实时操作系统中我们的任务看似是可以共同执行,但实际过程中他们也是有一个切换过程的,在任何时刻只可能有一个任务处于运行态。所以一个任务进入运行态后(切入)另一个任务就会进入非运行态(切出),更多理论上的就不多赘述了网上有很多大神写过,或者查看官方文档了解freertos的任务调度算法;


                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_43581670/article/details/127655121

3. 编程

用FreeRTOS原生代码创建任务

先写一个自己的函数MyTask, 在这个任务里执行Led_Test();函数

c 复制代码
void MyTask(void *argumment) // 自己创建的任务的函数
{
	while (1)
	{
		Led_Test();
	}
}

创建这个任务

freertos的所有任务都是一个while循环

c 复制代码
void MX_FREERTOS_Init(void)
{
	/* USER CODE BEGIN Init */

	/* USER CODE END Init */

	/* USER CODE BEGIN RTOS_MUTEX */
	/* add mutexes, ... */
	/* USER CODE END RTOS_MUTEX */

	/* USER CODE BEGIN RTOS_SEMAPHORES */
	/* add semaphores, ... */
	/* USER CODE END RTOS_SEMAPHORES */

	/* USER CODE BEGIN RTOS_TIMERS */
	/* start timers, add new ones, ... */
	/* USER CODE END RTOS_TIMERS */

	/* USER CODE BEGIN RTOS_QUEUES */
	/* add queues, ... */
	/* USER CODE END RTOS_QUEUES */

	/* Create the thread(s) */
	/* creation of defaultTask */
	defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

	/* USER CODE BEGIN RTOS_THREADS */
	/* add threads, ... */
    
	xTaskCreate(MyTask,             //用MyTask函数来创建一个任务
                "MyFirstTask",      //任务的名字:我的第一个任务MyFirstTask
                128,                //栈的深度 128
                NULL,               //不需要什么参数 NULL
                osPriorityNormal,   //优先级 osPriorityNormal
                NULL);              //最后一个参数先不用 NULL

	/* USER CODE END RTOS_THREADS */

	/* USER CODE BEGIN RTOS_EVENTS */
	/* add events, ... */
	/* USER CODE END RTOS_EVENTS */
}

CubeMX创建的默认任务,执行LCD_Test();函数

c 复制代码
/**
 * @brief  Function implementing the defaultTask thread.
 * @param  argument: Not used
 * @retval None
 */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
	/* USER CODE BEGIN StartDefaultTask */
	/* Infinite loop */
	LCD_Init();
	LCD_Clear();

	for (;;)
	{
		// Led_Test();
		LCD_Test();
		// MPU6050_Test();
		// DS18B20_Test();
		// DHT11_Test();
		// ActiveBuzzer_Test();
		// PassiveBuzzer_Test();
		// ColorLED_Test();
		// IRReceiver_Test();
		// IRSender_Test();
		// LightSensor_Test();
		// IRObstacle_Test();
		// SR04_Test();
		// W25Q64_Test();
		// RotaryEncoder_Test();
		// Motor_Test();
		// Key_Test();
		// UART_Test();
	}
	/* USER CODE END StartDefaultTask */
}

修改LCD_Test();的内容,LCD_Test();函数里是OLED_Test(); 只修改OLED_Test函数即可

c 复制代码
void OLED_Test(void)
{
    int OLED_Count = 0;
    OLED_Init();
    // 清屏
    OLED_Clear();

    while (1)
    {
        // 在(0, 0)打印'A'
        OLED_PutChar(0, 0, 'A');
        // 在(1, 0)打印'Y'
        OLED_PutChar(1, 0, 'Y');
        // 在第0列第2页打印一个字符串"Hello World!"
        OLED_PrintString(0, 2, "Hello World!");
        OLED_PrintSignedVal(6, 4, OLED_Count++);
    }
}

4. 测试

编译程序,下载测试~

开发板使用

1. 硬件接线

DshanMCU-103上有4个插针,它们分别是GND、SWCLK、SWDIO、3.3V。ST-Link上有10个插针,它们的功能在外壳上有标注。接线方法如下图所示:

连接好的实物图如下(ST-Link的USB口要插到电脑上):

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/3ead43300b704f8e8ea90feefcee09bc.png## 2. 打开工程

解压如下程序,放入无中文字符的目录里:

使用Keil打开工程。

3. 修改代码

4. 注意事项

有些模块的引脚是共用的,所以它们要么不能同时接,要么不能同时使用。

打开底板原理图,里面有说明:

列表如下:

模块1 模块2 备注
M2(DS18B20) M10(DHT11温湿度模块) 不能同时接
M4(红外发射模块) M9(蜂鸣器) 不能同时接
M6(超声波模块) M12(Flash模块) 可以同时接,但是要互斥访问

参考文章:

http://t.csdnimg.cn/a6WMU

http://t.csdnimg.cn/nuOz1

http://t.csdnimg.cn/yr2Ms

http://t.csdnimg.cn/SO6iz

我们下文再见~

相关推荐
qq_459730032 小时前
4-3 MCU中ARM存储器的作用
arm开发·单片机·嵌入式硬件
嵌入式科普5 小时前
嵌入式科普(24)从SPI和CAN通信重新理解“全双工”
c语言·stm32·can·spi·全双工·ra6m5
重生之我是数学王子5 小时前
点亮核心板小灯 STM32U575
stm32·单片机·嵌入式硬件
end_SJ5 小时前
初学stm32 --- 定时器中断
stm32·单片机·嵌入式硬件
南城花随雪。5 小时前
单片机:实现数码管动态显示(0~99999999)74hc138驱动(附带源码)
单片机·嵌入式硬件
南城花随雪。8 小时前
单片机:实现信号发生器(附带源码)
单片机·嵌入式硬件
三月七(爱看动漫的程序员)10 小时前
HiQA: A Hierarchical Contextual Augmentation RAG for Multi-Documents QA---附录
人工智能·单片机·嵌入式硬件·物联网·机器学习·语言模型·自然语言处理
新晨单片机设计10 小时前
【087】基于51单片机智能宠物喂食器【Proteus仿真+Keil程序+报告+原理图】
嵌入式硬件·51单片机·proteus·宠物·ad原理图
大风起兮1211 小时前
STM32HAL库中RTC闹钟设置时分秒,年月日
stm32·嵌入式硬件
超能力MAX12 小时前
IIC驱动EEPROM
单片机·嵌入式硬件·fpga开发