一、线程的理解
裸机和操作系统最大的区别就是实时性和CPU的利用率。使用RTOS可以让你能够及时的响应,但是它是单一进程的,只不过不停地在切换线程,线程是可以多个的。CPU利用率的提高,在外看就好像是同时进行的。其实线程就是任务,都是一个说法。动态线程比较灵活,可以动态创建和释放,静态线程创建的时候就已经分配好内存空间了,后期不能释放。此系列是rtthread搭载STM32标准库来实现,芯片是STM32F103C8T6,一步一步来学习。
二、线程创建与点灯
下面LED初始化是不是很熟悉,就是PC13的常规LED初始化,推挽输出,默认低电平,看原理图就知道低电平就能点灯。
rt_thread_t被重命名过了,实际撒上它是typedef struct rt_thread *rt_thread_t;就是一个结构体指针。
rtthread接口rt_thread_create()就是创建动态线程,返回值也是rt_thread_t,所以我们要用rt_thread_t类型去定义一个结构体指针接收rt_thread_create()的返回值,这样我们就可以通过这个指针去访问线程了。
rt_thread_create()五个参数,也很好理解。第一个是线程名,你要用人家,总得给人家起个名吧;第二个是线程入口函数,填自定义函数的名字即可,因为函数名是地址,这是一个回调,线程创建成功就出触发回调函数执行。第三个是入口函数的形参,这里没用到,填空就行。第四个是创建线程要用的空间,就是栈空间。一般给512就够用了。第四个是优先级,STM32有32个优先级,从0开始到31,这里点灯随便给个值3就行。最后一个是时间片,就是允许你这个线程可以执行的最大时间。注意main()也是一个线程,因为函数总要有个入口,所以都是从main()开始的。 在入口函数中加延时rt_thread_delay(500); /*500tick */的作用就是延时时把CPU使用权给别的线程,不然你就一直循环执行在这,别的线程就不能执行了,这是我们不允许的。现成创建成功,就会返回个地址,失败就是默认RT_NULL。延时500tick它其实去执行主线程了就是main(),执行完就返回线程继续执行。所以出来的效果就是LED交替闪烁。
#include "board.h" //头文件合集
static rt_thread_t led1_thread = RT_NULL;
void LED_GPIO_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
}
static void led1_thread_entry(void* parameter)
{
while (1)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
rt_thread_delay(500); /* ??500?tick */
GPIO_SetBits(GPIOC, GPIO_Pin_13);
rt_thread_delay(500); /* ??500?tick */
}
}int main( void )
{
/*LED初始化*/
LED_GPIO_Config();
led1_thread =
rt_thread_create( "thread1", /*线程名*/
led1_thread_entry, /*线程入口函数*/
RT_NULL, /*给入口函数传递参数*/
512, /*栈的大小*/
3, /*优先级*/
20); /*时间片*/
if (led1_thread != RT_NULL)
{
rt_thread_startup(led1_thread);
}
else
{
return -1;
}
}