前言
说到一款单片机,要发挥更高的性能使用操作系统是必然,最近我也是对其操作系统的移植进行了了解,这边官方给了FreeRTOS的例程,但是使用和CAN总线通信协议绑定,难免有些复杂,我也在移植过程也遇到了一些问题和报错,本文来对其进行讲解并且帮助读者更好入门STC32单片机的操作系统和修改一些之前使用的延时函数,使其适用FreeRTOS。
移植过程
这边我们可以直接搜索STC的官网,这边我们打开官方给的例程,查看路径找到FreeRTOS和的文件User之中的FreeRTOSConfig(用户自定义使用)头文件
然后我们在自己的工程文件创建一个FreeRTOS的文件夹来放置FreeRTOS的源文件(.c)和头文件(.h)和User的FreeRTOSConfig.h(我们用户自己定义使用),接着我们将这些要移植的头文件和源文件(包括include 和 portable之中的)全部添加到我们自己创建的文件夹之中。
随后我们就将FreeRTOS文件全部都移植到我们的文件之中了,我们就可以点开工程了
接着我们创建一个组命名为FreeRTOS,然后将源文件(.c)全部添加到里面,然后再将FreeRTOSConfig.h添加到User(存放main.c)的分组之中,然后在点魔术棒再选C251添加头文件路径就可以了,但是我们做完这些再编译工程会出现报错,这时我们还要修改一些东西
(1)右键(port.c)接口文件选择Option修改打上这两个勾(粗体黑)
(2)再次点开魔术棒修改Target和C251的配置为这样
这样我们再编译就不会报错了,但是还有一些警告,这边我们可以忽视不用管他哈
这样我们的移植就完成了
验证操作系统代码
#include <STC32G.H>
#include "Delay.h"
#include "GPIO.h"
#include "FreeRTOS.h"
#include "task.h"
//设置优先级,栈内存,任务句柄,任务函数
#define START_TASK_PRIO 1
#define START_TASK_STK 128
TaskHandle_t Start_Handler;
void Start_Task(void*pvParameters);
#define LED1_TASK_PRIO 2
#define LED1_TASK_STK 128
TaskHandle_t LED1_Handler;
void LED1_Task(void*pvParameters);
#define LED2_TASK_PRIO 3
#define LED2_TASK_STK 128
TaskHandle_t LED2_Handler;
void LED2_Task(void*pvParameters);
#define LED3_TASK_PRIO 4
#define LED3_TASK_STK 128
TaskHandle_t LED3_Handler;
void LED3_Task(void*pvParameters);
void main(void)
{
//设置为推挽输出
GPIO_Init(4,0,GPIO_Mode_Out_PP,GPIO_NoPull);
GPIO_Init(4,1,GPIO_Mode_Out_PP,GPIO_NoPull);
GPIO_Init(4,2,GPIO_Mode_Out_PP,GPIO_NoPull);
//创建开始任务 xTaskCreate(Start_Task,"Start_Task",START_TASK_STK,NULL,START_TASK_PRIO,&Start_Handler);
vTaskStartScheduler();//进入任务调度
while(1);
}
void Start_Task(void*pvParameters)
{
taskENTER_CRITICAL();//进入临界保护区
//创建任务
xTaskCreate(LED1_Task,"LED1_Task",LED1_TASK_STK,NULL,LED1_TASK_PRIO,&LED1_Handler);
xTaskCreate(LED2_Task,"LED2_Task",LED2_TASK_STK,NULL,LED2_TASK_PRIO,&LED2_Handler);
xTaskCreate(LED3_Task,"LED3_Task",LED3_TASK_STK,NULL,LED3_TASK_PRIO,&LED3_Handler);
vTaskDelete(Start_Handler);//删除开始任务
taskEXIT_CRITICAL();//退出临界保护区
}
void LED1_Task(void*pvParameters)
{
while(1)
{
P41=~P41;
vTaskDelay(300);
}
}
void LED2_Task(void*pvParameters)
{
while(1)
{
P40=~P40;
vTaskDelay(400);
}
}
void LED3_Task(void*pvParameters)
{
while(1)
{
P42=~P42;
vTaskDelay(500);
}
}
实验现象
我们可以看到三个灯在以不同频率在闪烁
延时函数修改
之前我们用到的Timer0用于延时函数,这边我们使用到了操作系统就最好不要去使用Timer0了哈,但是如果在资源紧张的情况下,我们要实现一些us的延时比如I2C总线的通信协议,我们又要如何去实现使用定时器延时呢,这边我们可以对之前的延时函数进行一定的修改来使用
思路:因为操作系统的任务调度和时间计数是用定时器中断去实现的,所以我们在要使用延时时,关闭中断即可,延时完了再次打开就行哈,但是进行us延时一定要记得出来修改重装值为1ms的状态,我们FreeRTOS系统默认为1ms的重装值,要是不改回来,也是有大问题的哈
定时器修改代码
void Delay_us(uint16_t xus)//24MHz
{
TR0=0;//关闭定时器设置重装值
ET0=0;
TH0=0xFF;//设置1us的重装值
TL0=0xE8;
TR0=1;
while(xus--)
{
TF0=0;
while(!TF0);
}
TR0=0;//关闭定时器,停止计数并且可以设置重载值
TH0=0xA2;
TL0=0x40;
ET0=1;//再次使能定时器中断
TR0=1;//开启定时器
}
void Delay_ms(uint16_t xms)//24MHz
{
TR0=0;//开启定时器,才可以设置重载值
ET0=0;//关闭定时器中断
TH0=0xA2;
TL0=0x40;
TR0=1;//开启定时器
while(xms--)
{
TF0=0;//清除定时器标志位
while(!TF0);//
}
TR0=0;//关闭定时器,停止计数并且可以设置重载值
//此时可以设置重载值但是本来就是1ms的重装值所以不必设置
ET0=1;//再次使能定时器中断
TR0=1;//开启定时器
}
最后
有什么错误的地方请大家指出,一起交流学习哈^--^