一. freeRTOS操作系统
操作系统(operating system) 本质上是一个帮助用户进行功能管理的软件,操作系统运行在硬件之上,为其他工作的软件执行资源分配等管理工作。一般称呼不使用操作系统的单片机开发方式为“裸机开发”,当进行裸机开发时,需要自己设计循环,中断,定时等功能来控制各个任务的执行顺序。而使用操作系统进行开发时,只需要创建任务,操作系统会自动按照一些特定的机制自动进行任务的运行和切换。除了任务管理之外,操作系统还可以提供许多功能,比如各个任务之间的通信,同步,任务的堆栈管理,控制任务对重要资源的互斥访问等。
在操作系统,每一个要执行的任务,也就是一段程序的运行过程被称为一个进程。进程包含 着动态的概念,它是一个程序的运行过程,而不是一个静态的程序。进程体现在程序中形式 实际上就是一段循环执行的代码,例如,led_green 是一个让绿色 led 灯闪烁的 进程,使用操作系统的任务创建函数创建了这个进程之后,操作系统就自动找到这段代码并 执行。
一段程序执行时,一般划分成三个阶段,开始执行—>执行中—>执行完成。这也恰好对应了 进程的工作状态:就绪态(Ready)—>运行态(Running)—>终止态(Blocked)。如果在 一个进程执行的过程中,调用了将进程挂起的功能函数,或者是进程执行时有更高优先级的 任务就绪了,则进程会进入挂起状态(Suspended)。
操作系统的一个重要工作就是执行各个进程的状态切换,因为实际上单片机每次只能运行一 个进程,而操作系统通过适当的管理,让每一个进程都可以得到及时的响应,让多个进程呈 现出一种同时运行的“并发”感。
操作系统执行任务切换时必须得要遵循一定的调度算法,操作系统会根据能否将正在运行的 进程打断分为抢占式操作系统和合作式操作系统。
合作式操作系统不能够打断正在运行的进程,当多个进程就绪时,必须等待目前正在执行的 进程结束,实现起来更加简单,但是降低了进程执行的实时性。抢占式操作系统可以将正在 运行的进程打断,因此有着更加复杂的调度机制,但是也有更好的实时性。
二. STM32CubeMX 配置
1.开启freeRTOS: 2. 在任务栏添加任务,并对相应的任务栏进行命名:
- 设置任务函数优先级:
按照上述进行配置后便可生成相应的代码,在freertos.c文件中便可看到这里主要使用两个函数:
函数 | osThreadDef(name, thread, priority, instances, stacksz) |
---|
功能 | 对要创建的任务进行设置 | 参数 1 | name,要创建的任务的名称 | 参数 2 | thread,要创建的任务代码的入口名称 | 参数 3 | priority,要创建的任务的优先级 | 参数 4 | instances,任务下可以创建的线程的数量 | 参数 5 | stacksz,任务栈大小 |
函数 | osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument) |
---|
功能 | 创建一个任务 | 返回值 | osThreadId,任务 ID,ID 是一个任务的重要标识,当在创建完任务后需要执行修改这个任务的优先级,或者销毁该任务时,就需要调用任务 ID,需要提前声明一个类型为 osThreadId 的变量在此处存储返回值。 | 参数 1 | const osThreadDef_t *thread_def,我们通过 osThreadDef 所设置的任务参数,采用强制转换+任务名的方式进行输入,比如在 osThreadDef 中设置任务名为 LED_RED,则在此处输入 osThread(LED_RED) | 参数 2 | void *argument,任务需要的初始化参数,一般填为 NULL |
三. 部分代码和注释
直接在main.c初始化过程中中运行freertos,这样所有的函数直接在freertos.c文件中运行,不需要在while循环中重复,从而实现操作系统的并行过程。
main.c
#include "main.h"
#include "cmsis_os.h"
#include "can.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "motor.h"
#include "remoter_uart.h"
void SystemClock_Config(void);
void MX_FREERTOS_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_USART6_UART_Init();
MX_CAN1_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_TIM4_Init();
MX_TIM5_Init();
MX_TIM8_Init();
MX_TIM12_Init();
HAL_TIM_Base_Start(&htim2);
HAL_TIM_Base_Start(&htim3);
HAL_TIM_Base_Start(&htim4);
HAL_TIM_Base_Start(&htim5);
HAL_TIM_Base_Start(&htim8);
HAL_TIM_Base_Start(&htim12);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_4);
HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_4);
HAL_TIM_PWM_Start(&htim12, TIM_CHANNEL_1);
can_filter_init();
dbus_uart_init();
MX_FREERTOS_Init();
osKernelStart();
while (1)
{
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 6;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
void Error_Handler(void)
{
while(1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
freertos.c:
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
#include "pid.h"
#include "motor.h"
#include "servo.h"
#include "sensor.h"
#include "buzzer.h"
#include "remoter_uart.h"
extern rc_info_t rc;
float distance_mm;
uint16_t psc = 0;
uint16_t pwm = MIN_BUZZER_PWM;
uint16_t set_speed;
uint16_t set_speed_x;
uint16_t set_speed_y;
PidTypeDef motor_pid;
PidTypeDef motor_pid_x;
PidTypeDef motor_pid_y;
fp32 PID[3]={3,0.1,0};
motor_measure_t* motor_data;
osThreadId LED_REDHandle;
osThreadId LED_GREENHandle;
osThreadId SONARHandle;
osThreadId CHASSISHandle;
osThreadId SERVOHandle;
osThreadId REMOTERHandle;
osThreadId UPSTAIRHandle;
osThreadId LEDHandle;
osThreadId BUZZERHandle;
void Delay_us(uint16_t time);
void soner_startrange(void);
uint16_t soner_gettime(void);
void joint_first_cw(uint16_t time);
void joint_first_ccw(uint16_t time);
motor_measure_t* get_chassis_motor_measure_point(uint8_t i);
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan);
void CAN_cmd_chassis(int16_t M1, int16_t M2, int16_t M3, int16_t M4);
fp32 PID_Calc(PidTypeDef *pid,fp32 ref,fp32 set);
void led_red_task(void const * argument);
void led_green_task(void const * argument);
void sonar_task(void const * argument);
void chassis_task(void const * argument);
void servo_task(void const * argument);
void remoter_task(void const * argument);
void upstair_task(void const * argument);
void led_task(void const * argument);
void buzzer_task(void const * argument);
void MX_FREERTOS_Init(void);
void MX_FREERTOS_Init(void) {
osThreadDef(LED_RED, led_red_task, osPriorityLow, 0, 128);
LED_REDHandle = osThreadCreate(osThread(LED_RED), NULL);
osThreadDef(LED_GREEN, led_green_task, osPriorityLow, 0, 128);
LED_GREENHandle = osThreadCreate(osThread(LED_GREEN), NULL);
osThreadDef(SONAR, sonar_task, osPriorityHigh, 0, 128);
SONARHandle = osThreadCreate(osThread(SONAR), NULL);
osThreadDef(CHASSIS, chassis_task, osPriorityNormal, 0, 128);
CHASSISHandle = osThreadCreate(osThread(CHASSIS), NULL);
osThreadDef(SERVO, servo_task, osPriorityNormal, 0, 128);
SERVOHandle = osThreadCreate(osThread(SERVO), NULL);
osThreadDef(REMOTER, remoter_task, osPriorityHigh, 0, 128);
REMOTERHandle = osThreadCreate(osThread(REMOTER), NULL);
osThreadDef(UPSTAIR, upstair_task, osPriorityNormal, 0, 128);
UPSTAIRHandle = osThreadCreate(osThread(UPSTAIR), NULL);
osThreadDef(LED, led_task, osPriorityLow, 0, 128);
LEDHandle = osThreadCreate(osThread(LED), NULL);
osThreadDef(BUZZER, buzzer_task, osPriorityLow, 0, 128);
BUZZERHandle = osThreadCreate(osThread(BUZZER), NULL);
}
__weak void led_red_task(void const * argument)
{
for(;;)
{
osDelay(1);
}
}
__weak void led_green_task(void const * argument)
{
for(;;)
{
osDelay(1);
}
}
__weak void sonar_task(void const * argument)
{
for(;;)
{
distance_mm = soner_getdistance();
osDelay(10);
}
}
__weak void chassis_task(void const * argument)
{
PID_init(&motor_pid,PID_POSITION,PID,16000,2000);
motor_data = get_chassis_motor_measure_point(0);
for(;;)
{
for(set_speed = 0; set_speed < 2000; set_speed += 200)
{
PID_Calc(&motor_pid,motor_data->speed_rpm,set_speed);
CAN_cmd_chassis(-motor_pid.out,motor_pid.out,motor_pid.out,motor_pid.out);
osDelay(100);
}
}
}
void servo_task(void const * argument)
{
for(;;)
{
if(distance_mm < 20)
{
joint_first_cw(1000);
HAL_Delay(1000);
joint_first_ccw(1000);
HAL_Delay(1000);
}
osDelay(1);
}
}
void remoter_task(void const * argument)
{
PID_init(&motor_pid,PID_POSITION,PID,16000,2000);
motor_data = get_chassis_motor_measure_point(0);
for(;;)
{
if(rc.sw1 == 1 && rc.sw2 == 1)
{
set_speed_x = rc.ch2;
set_speed_y = rc.ch3;
PID_Calc(&motor_pid_x,motor_data->speed_rpm,set_speed_x);
PID_Calc(&motor_pid_y,motor_data->speed_rpm,set_speed_y);
CAN_cmd_chassis(motor_pid_x.out+motor_pid_y.out,motor_pid.out-motor_pid_y.out,motor_pid.out+motor_pid_y.out,motor_pid.out-motor_pid_y.out);
osDelay(100);
}
else if(rc.sw1 == 3 && rc.sw2 == 3)
{
set_speed_x = rc.ch2;
set_speed_y = rc.ch3;
PID_Calc(&motor_pid_x,motor_data->speed_rpm,set_speed_x);
PID_Calc(&motor_pid_y,motor_data->speed_rpm,set_speed_y);
CAN_cmd_auxiliary(motor_pid_x.out,motor_pid_y.out);
osDelay(100);
}
else if(rc.sw1 == 3 && rc.sw2 == 1)
{
uint16_t angle1 = -rc.ch1;
uint16_t angle2 = rc.ch1;
uint16_t angle3 = -rc.ch3;
uint16_t angle4 = rc.ch3;
HAL_Delay(10);
if(rc.ch1 < 0)
{
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_1, 400);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_2, 1100);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_3, 400);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_4, 1100);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_14, GPIO_PIN_SET);
HAL_Delay(angle1);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_1, 2000);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_2, 2000);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_3, 2000);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_4, 2000);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
}
else
{
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_1, 1100);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_2, 400);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_3, 1100);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_4, 400);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_14, GPIO_PIN_SET);
HAL_Delay(angle2);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_1, 2000);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_2, 2000);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_3, 2000);
__HAL_TIM_SetCompare(&htim5, TIM_CHANNEL_4, 2000);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
}
if(rc.ch3 < 0)
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 400);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 1100);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 400);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4, 1100);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_14, GPIO_PIN_SET);
HAL_Delay(angle3);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 2000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 2000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 2000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4, 2000);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
}
else
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 1100);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 400);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 1100);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4, 400);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_14, GPIO_PIN_SET);
HAL_Delay(angle4);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 2000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 2000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_3, 2000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4, 2000);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
}
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_Delay(100);
}
else
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_Delay(50);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_14, GPIO_PIN_SET);
HAL_Delay(50);
}
}
}
void upstair_task(void const * argument)
{
PID_init(&motor_pid,PID_POSITION,PID,16000,2000);
motor_data = get_chassis_motor_measure_point(0);
for(;;)
{
for(set_speed = 0; set_speed < 2000; set_speed += 200)
{
PID_Calc(&motor_pid,motor_data->speed_rpm,set_speed);
CAN_cmd_auxiliary(motor_pid.out,motor_pid.out);
osDelay(100);
}
}
}
__weak void led_task(void const * argument)
{
for(;;)
{
osDelay(1);
}
}
__weak void buzzer_task(void const * argument)
{
for(;;)
{
psc++;
if(pwm > MAX_BUZZER_PWM)
{
pwm = MIN_BUZZER_PWM;
}
if(psc > MAX_PSC)
{
psc = 0;
}
buzzer_on(psc, pwm);
osDelay(100);
}
}
函数中所引用的.h头文件在之前的博客中都有整理
结语
由于利用系统这一并行功能实现的工程车性能上更加优越,因此之前所写的一些函数的代码可以统一合并到freertos.c这一文件中,更加方便整体系统的操作和管理,代码在条理上也显得更加清晰明了。
至此,对于大疆A型板的基本功能的应用就分享完毕了,利用这些简单的基本功能便可做出一些有意思的东西,或者设计出一些简单的机械产品。由于之前自己做的时候很难查到相关资料,做起来的时候总会出现各种各样的问题,希望这些分享能够提供一些参考价值,对于大疆RM的这些产品更好入手。
如果对于代码有疑问或需求的可以联系我, 也希望博客中有问题的地方可以一起讨论学习。
|