使用HAL库开发铁头山羊平衡车,裸机多任务系统理解及电源指示灯
裸机多任务系统:不是freertos类系统,是将任务切片放到一个while循环里去执行,把任务的执行时间切片得足够小,然后在一个while循环里去执行,以达到像是“多个while循环一起”的多线程操作。

我们如果执行闪灯代码,传统上是这样的,亮-delay-灭-delay-亮
但是delay函数会大大阻塞我们的运行时间,由于要适配逻辑多任务模型切片时间短的需求,这里就不能使用delay函数了

羊哥的delay函数可以保证吧时间切片到几us,适用于逻辑多任务模型,由于羊哥的delay函数是自己编写的且为标准库,这里用HAL库不太方便,于是我自己写了一个方便大家复制(其实主要是AI的功劳)
---------------------------------------------------------------------------------------------------------------------------------
.c:
#include "delay.h"
// 用于微秒延时的校准值,根据实际时钟频率调整
static uint32_t us_ticks_per_us = 0;
/**
* @brief 初始化延迟函数。
* @param None
* @retval None
*/
void Delay_Init(void)
{
// 启用DWT单元
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
// 清空CYCCNT计数器
DWT->CYCCNT = 0;
// 启用CYCCNT计数器
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
// 计算每个微秒对应的CYCCNT计数值
// SystemCoreClock 是HAL库定义的系统核心时钟频率,对于STM32F103C8T6通常是72000000
us_ticks_per_us = SystemCoreClock / 1000000;
}
/**
* @brief 毫秒级延迟函数。
* @param ms: 延迟的毫秒数。
* @retval None
*/
void Delay(uint32_t ms)
{
// 直接调用HAL库的毫秒延迟函数
HAL_Delay(ms);
}
/**
* @brief 获取当前系统运行时间(毫秒)。
* @param None
* @retval 当前时间(毫秒)。
*/
uint32_t GetTick(void)
{
// 直接调用HAL库的获取时间函数
return HAL_GetTick();
}
/**
* @brief 获取当前高精度时间(微秒)。
* @param None
* @retval 当前时间(微秒)。
*/
uint64_t GetUs(void)
{
uint32_t ms = HAL_GetTick();
uint32_t us = DWT->CYCCNT / us_ticks_per_us;
// 处理在读取ms和us之间,HAL_GetTick()刚好溢出(+1)的情况
// 如果当前CYCCNT的计数值很小,但ms却比上次大很多,说明发生了溢出
if ((DWT->CYCCNT < (SystemCoreClock / 2)) && (ms > GetTick()))
{
ms--;
}
return ((uint64_t)ms * 1000) + us;
}
/**
* @brief 微秒级延迟函数。
* @param us: 延迟的微秒数。
* @retval None
*/
void DelayUs(uint32_t us)
{
uint64_t start_time = GetUs();
while ((GetUs() - start_time) < us);
}
---------------------------------------------------------------------------------------------------------------------------------
.h:
#ifndef __DELAY_H
#define __DELAY_H
#include "stm32f1xx_hal.h"
void Delay_Init(void);
void Delay(uint32_t ms);
uint32_t GetTick(void);
uint64_t GetUs(void);
void DelayUs(uint32_t us);
#endif
---------------------------------------------------------------------------------------------------------------------------------
Keil代码编写部分:
这里我们新建两个文件,新建文件的方法在上一节已经提到这里就不再多说了
代码也很简单这里不再过多解释,具体可以看山哥标准库的视频

接着放到main.c里作为切片

更多推荐

所有评论(0)