我们已经将工程中加入了一个多线程并发操作系统Dolphin-OS,我们可以使用这个OS来完成多线程程度的并发执行,所谓并发就是在宏观上多个任务好像在同时运行一样。用户实际上也感受不到任务的延时与停顿。而在微观上讲多个任务其实是以分片时间段轮流执行的,也就是说OS会在每隔一小段时间就会切换一次任务并执行,但这个切换的过程非常快,通常每秒种可切换几百或上千次,我们的OS是的调度频率为1000Hz,也就是说它可以在一秒内切换1000次任务。这在宏观上是完全感觉不到的,我们可以认为多个线程之间是同时执行的。也就是我们常常说的并发执行。
为了验证我们的OS工作正常,我们首先需要完成一个LED闪烁的功能,它是一个在OS下可以正常被调度和执行的线程。首先我们可以先完成一个LED驱动程序,这个LED驱动程序对外提供了LED的点亮、熄灭、闪烁等操作,具体源代码实现如下,我们在drivers文件夹中加入一个led的文件夹,在里面完成led.c和led.h两个驱动文件:
#include <led.h>
void led_init(void)
{
}
void led_on(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
}
void led_off(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_SET);
}
void led_blink(void)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_11);
}
可以看到,实际上我们只是完成了几个LED的功能函数,使LED点亮、熄灭和闪烁,就是使用的HAL_GPIO_WritePin()函数和HAL_GPIO_TogglePin()函数来操作的GPIO脚,而我们这所以要把GPIO脚的操作封装成led_on()、led_off()、led_blink()函数,就是想让我们的代码尽可能的脱离对硬件的依赖,而方便移植到其它平台当中去。
接下来,我们还需要在moudles文件夹下创建一个led文件夹,在里面完成我们的LED控制线程:
#include <led.h>
#include <led_task.h>
uint8_t val = 0x05;
void* led_pthread(void* arg)
{
for (uint8_t i = 0;; i++)
{
if ((val >> (i % 8)) & 0x1)
{
led_on();
}
else
{
led_off();
}
sleep_ticks(125);
}
return NULL;
}
void led_task(void)
{
pcb_create(PCB_LED_PRIO, &led_pthread, NULL, PCB_LED_SIZE);
}
我们使用了OS中的pcb_create()函数为我们的LED功能创建了一个可调度的线程,这个线程的入口函数为led_phtread(),它的功能是每间隔1秒就使led双闪一次。
关于这个双闪功能,我们可以再介绍一下。如果我们想让一个LED灯进行双闪,通常的做法是上LED亮一次,然后熄灭,然后再亮一次,然后再熄灭,不过第二次熄灭时需要等待的时间稍微长一点,如此循环。而我们可以采用一种较为优雅的方式来完成,我们使用一个uint8_t val变量来存放一个值为0x05的数,它的二进制表示为:
0000 0101
我们可以在每一个循环中使用位运算判断其某个比特位上是0还是1,如果是0则熄灭,是1则点亮。而每一次循环我们所判断的bit位向右移动一次,这样我们就完成了LED双闪的功能代码,这样我们即省略了每次等待的时间,又简化了功能代码。
最后,我们只需要在main()函数中调用我们的led_task()函数就可以让我们的LED进行双闪了。如下:
#include "led_task.h"
#include <core.h>
#include <sche.h>
int _kernel_startup = 0;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
kernel_startup();
led_task();
_kernel_startup = 1;
while (1)
{
}
}
我们在Makefile目录下执行make命令即可将源代码编译为我们STM32F103C8T6所能使用的程序dolphin-os.bin,最后使用JLink烧录工具将程序烧录到STM32的芯片Flash中即可。
最终我们给出整个LED闪烁的源代码(包含OS),下载地址
Copyright © 2015-2023 问渠网 辽ICP备15013245号