RTthread再学习记录(二)
创建第一个自己的任务
前言
接着上一篇继续记录RTT学习历程
一、RTT的启动流程
官方给出的RTT启动流程如图,需要注意的是:以MDK工程为例,程序入口函数是
S
u
b
Sub
Sub$main(),它调用rtthread_startup()完成操作系统启动,而CUBEMX生成代码里的main()函数只是一个用户任务入口,对应的任务创建代码在rt_application_init()内实现。另外在系统启动过程中,还会创建定时器任务(需要启用宏:RT_USING_TIMER_SOFT,用于处理实时性要求较高的操作)和空闲任务(用于系统资源回收),如果使能了Finsh组件,还会启用一个tshell任务,用于处理Finsh终端的输出和输入。
二、创建自己的用户任务
因为RTT提供动态和静态2种对象创建方式(和FreeRTOS类似),所以也就有了2种任务创建方式。
1.动态的创建(任务栈使用heap)
代码如下(示例):
rt_thread_t led_thread=rt_thread_create(
"LED_THREAD", //任务名称
LED_task_entry, //任务入口函数
RT_NULL, //入口函数参数
512, //任务栈空间大小
10, //任务优先级
20 //任务时间片轮转tcik周期,同优先级任务调用时起作用
);
RT_ASSERT(led_thread != RT_NULL);//断言语句检查任务是否创建成功,防止动态内存分配失败
rt_thread_startup(led_thread); //启动任务
2.静态的创建
代码如下(以启动代码中空闲任务创建为例):
static rt_uint8_t rt_thread_stack[IDLE_THREAD_STACK_SIZE]; //事先分配任务栈使用的静态内存区
rt_thread_init(&idle, //任务结构体指针
"tidle", //任务名称
rt_thread_idle_entry, //任务入口函数
RT_NULL, //入口函数参数
&rt_thread_stack[0], //任务栈起始地址
sizeof(rt_thread_stack), //任务栈大小
RT_THREAD_PRIORITY_MAX - 1, //任务优先级
32); //任务时间片轮转tcik周期,同优先级任务调用时起作用
rt_thread_startup(&idle); //启动任务
鉴于CUBEMX工程的结构,建议用户任务创建都在main()任务里完成,由main()任务创建其他任务。当然你如果非要在rt_application_init()里面和main()任务并列创建也不是不可以,看个人习惯吧。
三、完成用户代码函数
还是用入门级的点灯,串口打印之类的功能来玩一下用户任务函数,记得要使用rt_thread_mdelay()函数进行任务切换,要不然高优先级的任务会一直占用内核哦,代码如下:
int main(void)
{
/* USER CODE BEGIN 1 */
list_node * P=create(2);
list_node * Pcurrnt=P->next;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
//HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
//SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_CRC_Init();
MX_DMA2D_Init();
MX_FMC_Init();
MX_I2C3_Init();
MX_LTDC_Init();
MX_SPI5_Init();
MX_TIM1_Init();
//MX_USART1_UART_Init();
/* Initialize interrupts */
MX_NVIC_Init();
/* USER CODE BEGIN 2 */
while(Pcurrnt!=NULL)
{
rt_kprintf("%s", Pcurrnt->date);
Pcurrnt=Pcurrnt->next;
}
R32(GPIOG->BSRR,b13)=1; //位域操作
R32(GPIOG->BSRR,b14)=1;
rt_kprintf("\n系统时钟:%d\n",HAL_RCC_GetSysClockFreq());
rt_kprintf("Currnt position is %s,%s,line%d\n",__FUNCTION__,__FILE__,__LINE__);
rt_thread_t led_thread=rt_thread_create(
"LED_THREAD", //任务名称
LED_task_entry, //任务入口函数
RT_NULL, //入口函数参数
512, //任务栈空间大小
10, //任务优先级
20 //任务时间片tcik周期,同优先级任务调用时起作用
);
RT_ASSERT(led_thread != RT_NULL);
rt_thread_startup(led_thread);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_TogglePin(GPIOG,LD4_Pin);
rt_thread_mdelay(1000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
static void LED_task_entry(void * parm){
while(1)
{
HAL_GPIO_TogglePin(GPIOG,LD3_Pin);
rt_kprintf("hello!\n");
rt_thread_mdelay(2000);
}
}
四、测试
总结
RTT任务创建并没有什么特别的,和其他RTOS差不多,只是要注意他的启动过程,以及工程代码结构。