FREERTOS系统移植+任务创建
前言
关于5V电压驱动四个轮子驱动力不够的问题,换了一个9V的电池已经能够得到很好的解决。
本篇主要介绍一下FREERTOS在STM32上的移植以及两个TASK的创建
因为STM32控制不是重点,所以这里就简单移植一下
FREERTOS移植
1、下载FREERTOS源码,在原有工程基础上创建一个FREERTOS文件夹,把源码放进去。
然后把portable这个文件夹中无关平台的代码删除,只留下这三个文件夹
2、把新添加的文件添加到工程中去
这里创建了两个文件夹,FREERTOS_CORE放置内核文件,FREERTOS_PORTABLE放置适配文件。
这里适配文件根据硬件的平台以及自己需要的内存分配方法来选,因为我的芯片是M3的,且我选择的内存分配方法是heap4。
这里介绍一下heap4的内存管理方式:
heap4方式会把已经释放的相邻的内存碎片合并成一块整体的区域,有助于减少内存碎片化问题,heap1只能申请无法释放,heap2方式无法进行合并相邻碎片。
3、添加对应头文件路径
4、在FREERTOS源码的demo中找到对应平台,把里面的FreeRTOSConfig.h文件拷出来放到include里面,这个文件是一些条件编译的宏和一些配置信息,没有这个文件编译会报错。
5、修改之前的一些文件以便兼容FREERTOS系统,因为这个之前直接拿的正点原子的例程,这个例程是兼容UCOS的,所以现在要稍微修改一下:
(1)首先修改sys.h中,把SYSTEM_SUPPORT_OS宏置1,表示支持OS系统。
(2)在usart.c文件中,引用头文件FreeRTOS.h和task.h,然后把关于UCOS的OSIntEnter()和 OSIntExit()删掉。
(3)修改delay.c文件,删除UCOS对应函数,并且把滴答定时器中断频率设置为FREERTOS的主时钟频率
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
}
SysTick_Handler是systick的中断服务函数,其意思是在系统已经运行的情况下,把systick中端当成FREERTOS系统运行的系统时钟节拍,相当于用systick来当FREERTOS的心脏。
然后设置systick的中断时间:
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//不设置这个那systick默认就是HCLK/8分频也就是AHB/8分频,这里设置为HCLK也就是AHB分频
reload=SystemCoreClock/1000000;
reload*=1000000/configTICK_RATE_HZ;
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启 SYSTICK 中断
SysTick->LOAD=reload; //每 1/configTICK_RATE_HZ 秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启 SYSTICK
fac_us=SystemCoreClock/1000000;
fac_ms=1000/configTICK_RATE_HZ;
}
这里介绍一下systick,SysTick 是一个 24 位的倒计数定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
默认systick的频率是HCLK/8,一般就是72M/8 = 9M ,这里调用SysTick_CLKSourceConfig函数设置systick时钟来源为HCLK也就是72M,所以RELOAD减少1的时间为1/72M。
这几行代码的意思就是设置systick中断一次的时间为1/configTICK_RATE_HZ(s),这个宏是在FreeRTOSConfig.h中配的,这里配的是1000,也就是FREERTOS系统的时钟节拍为1ms。
适配工作主要是设置这个FREERTOS的系统时钟节拍,其他的都没什么。
创建TASK
这里先创建一个start task,然后后面再在这个task里面创建一个motor_task用来控制电机,然后把start_task关掉。后续如果有什么别的task再作调整。main.c代码如下:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "motor.h"
#include "string.h"
#define START_TASK_PRIO 1 //任务优先级
#define START_STK_SIZE 128 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void start_task(void *pvParameters); //任务函数
#define MOTOR_TASK_PRIO 6 //任务优先级
#define MOTOR_STK_SIZE 50 //任务堆栈大小
TaskHandle_t MotorTask_Handler; //任务句柄
void MOTOR_task(void *p_arg); //任务函数
#define DIRECTION_MAX_LEN 10
char stop[DIRECTION_MAX_LEN] = "0";
char top[DIRECTION_MAX_LEN] = "1";
char botton[DIRECTION_MAX_LEN] = "2";
char left[DIRECTION_MAX_LEN] = "3";
char right[DIRECTION_MAX_LEN] = "4";
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
delay_init();
LED_Init();
uart_init(9600);
MOTOR_Init();
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
vTaskStartScheduler(); //开启任务调度
}
void start_task(void *p_arg)
{
taskENTER_CRITICAL(); //临界区,关中断
xTaskCreate((TaskFunction_t )MOTOR_task,
(const char* )"MOTOR_task",
(uint16_t )MOTOR_STK_SIZE,
(void* )NULL,
(UBaseType_t )MOTOR_TASK_PRIO,
(TaskHandle_t* )&MotorTask_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED0 任务函数
void MOTOR_task(void *pvParameters)
{
MOTORA_Pin1 = 0;
MOTORA_Pin2 = 0;
MOTORB_Pin1 = 0;
MOTORB_Pin2 = 0;
MOTORC_Pin1 = 0;
MOTORC_Pin2 = 0;
MOTORD_Pin1 = 0;
MOTORD_Pin2 = 0;
for(;;)
{
if(USART_RX_STA&0x8000)
{
LED0 = !LED0;
if (!strncmp((char *)USART_RX_BUF, top, DIRECTION_MAX_LEN))
{
MOTORA_Pin1 = 0;
MOTORA_Pin2 = 1;
MOTORB_Pin1 = 0;
MOTORB_Pin2 = 1;
MOTORC_Pin1 = 0;
MOTORC_Pin2 = 1;
MOTORD_Pin1 = 0;
MOTORD_Pin2 = 1;
vTaskDelay(500);
MOTORA_Pin1 = 0;
MOTORA_Pin2 = 0;
MOTORB_Pin1 = 0;
MOTORB_Pin2 = 0;
MOTORC_Pin1 = 0;
MOTORC_Pin2 = 0;
MOTORD_Pin1 = 0;
MOTORD_Pin2 = 0;
}
else if (!strncmp((char *)USART_RX_BUF, botton, DIRECTION_MAX_LEN))
{
MOTORA_Pin1 = 1;
MOTORA_Pin2 = 0;
MOTORB_Pin1 = 1;
MOTORB_Pin2 = 0;
MOTORC_Pin1 = 1;
MOTORC_Pin2 = 0;
MOTORD_Pin1 = 1;
MOTORD_Pin2 = 0;
vTaskDelay(500);
MOTORA_Pin1 = 0;
MOTORA_Pin2 = 0;
MOTORB_Pin1 = 0;
MOTORB_Pin2 = 0;
MOTORC_Pin1 = 0;
MOTORC_Pin2 = 0;
MOTORD_Pin1 = 0;
MOTORD_Pin2 = 0;
}
else if (!strncmp((char *)USART_RX_BUF, stop, DIRECTION_MAX_LEN))
{
MOTORA_Pin1 = 0;
MOTORA_Pin2 = 0;
MOTORB_Pin1 = 0;
MOTORB_Pin2 = 0;
MOTORC_Pin1 = 0;
MOTORC_Pin2 = 0;
MOTORD_Pin1 = 0;
MOTORD_Pin2 = 0;
}
else if (!strncmp((char *)USART_RX_BUF, left, DIRECTION_MAX_LEN))
{
MOTORA_Pin1 = 1;
MOTORA_Pin2 = 0;
MOTORB_Pin1 = 1;
MOTORB_Pin2 = 0;
MOTORC_Pin1 = 0;
MOTORC_Pin2 = 1;
MOTORD_Pin1 = 0;
MOTORD_Pin2 = 1;
vTaskDelay(500);
MOTORA_Pin1 = 0;
MOTORA_Pin2 = 0;
MOTORB_Pin1 = 0;
MOTORB_Pin2 = 0;
MOTORC_Pin1 = 0;
MOTORC_Pin2 = 0;
MOTORD_Pin1 = 0;
MOTORD_Pin2 = 0;
}
else if (!strncmp((char *)USART_RX_BUF, right, DIRECTION_MAX_LEN))
{
MOTORA_Pin1 = 0;
MOTORA_Pin2 = 1;
MOTORB_Pin1 = 0;
MOTORB_Pin2 = 1;
MOTORC_Pin1 = 1;
MOTORC_Pin2 = 0;
MOTORD_Pin1 = 1;
MOTORD_Pin2 = 0;
vTaskDelay(500);
MOTORA_Pin1 = 0;
MOTORA_Pin2 = 0;
MOTORB_Pin1 = 0;
MOTORB_Pin2 = 0;
MOTORC_Pin1 = 0;
MOTORC_Pin2 = 0;
MOTORD_Pin1 = 0;
MOTORD_Pin2 = 0;
}
memset(USART_RX_BUF,0,USART_REC_LEN);
USART_RX_STA=0;
}
}
}
这个和之前裸机的控制逻辑是一样的,不做赘述。主要是用xTaskCreate这个函数动态创建一个task,里面跑电机控制程序。
上STM32测试,没什么问题。
总结
下一章开始基于蓝牙3.0的安卓控制APP开发,就涉及到上下左右的控制就行,用的是Android Studio进行开发。