使用HAL库开发STM32:系统时间基础及进阶使用

您所在的位置:网站首页 hal库怎么念 使用HAL库开发STM32:系统时间基础及进阶使用

使用HAL库开发STM32:系统时间基础及进阶使用

#使用HAL库开发STM32:系统时间基础及进阶使用| 来源: 网络整理| 查看: 265

文章目录 目的基础使用进阶使用总结

目的

HAL库默认提供了系统时间,系统时间默认情况下由SysTick定时器计数产生。系统时间一方面用于HAL库自身调用,另一方面用户也可以使用,为开发带来便利。(本文提到的相关使用主要应用于未使用OS(操作系统)的情况下。)

基础使用

一般的系统时间使用方面常用到两个函数:

__weak uint32_t HAL_GetTick(void) 返回从系统运行开始经过的时间,默认情况下单位为ms;__weak void HAL_Delay(uint32_t Delay) 延时,该延时是阻塞的,默认情况下延时单位为ms,该函数不能在等于或高于系统时钟源优先级(默认情况下为0)的中断程序中使用,不然程序就阻塞在这里不动了;

对于上面两个函数本身来说没什么特别可以多说的,需要注意的点也在上面说明了。上面的延时函数是阻塞型的,当然我们也有方式实现非阻塞的延时。

int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); while (1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); HAL_Delay(1000); } }

上面方式使用HAL_Delay()进行延时,可以实现GPIOA0口每秒反转一次电平。如果只有一个任务这样就没问题,但是如果有多个对延时时间有不同需求的任务这样就不太合适了,这时候可以使用下面方式:

uint32_t previousMillisA0 = 0; uint32_t previousMillisA1 = 0; int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); while (1) { uint32_t currentMillis = HAL_GetTick(); //获取当前系统时间 if (currentMillis - previousMillisA0 >= 1000) //当前时间刻减去前次执行的时间刻 { previousMillisA0 = currentMillis; //更新执行时间刻 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); } if (currentMillis - previousMillisA1 >= 500) //当前时间刻减去前次执行的时间刻 { previousMillisA1 = currentMillis; //更新执行时间刻 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1); } } }

上面的代码实现了GPIOA0口每秒反转一次电平,同时GPIOA1口每500毫秒反转一次电平。可以使用这种方式处理更多的任务。

进阶使用

HAL的系统时间由定时器在中断中累加计数:

/** * @brief This function is called to increment a global variable "uwTick" * used as application time base. * @note In the default implementation, this variable is incremented each 1ms * in SysTick ISR. * @note This function is declared as __weak to be overwritten in case of other * implementations in user file. * @retval None */ __weak void HAL_IncTick(void) { uwTick += uwTickFreq; }

因为这个回调函数是由 __weak 符号修饰的,所以可以自己重新写同名函数来实现更复杂的功能,比如可以用来实现调度器功能。先看下面演示: 在这里插入图片描述 上图例子中声明了两个任务,分别设置运行参数并运行。通过图中可以看到两个任务都按期望的方式执行了。

以下是Ticker部分代码:

#ifndef LIB_TICKER_H_ #define LIB_TICKER_H_ #include "main.h" #define LIB_TICKER_MAX_SIZE 16 // 最大Ticker可绑定数 class LibTicker { public: LibTicker(void); ~LibTicker(void); typedef void (*callback_t)(void); typedef void (*callback_with_arg_t)(void*); // 设置Ticker定期执行,输入参数分别是时间(毫秒)、回调函数 bool attach(size_t milliseconds, callback_t callback) { if (!milliseconds) { return false; } return _attach(milliseconds, milliseconds, reinterpret_cast(callback), 0); } // 设置Ticker定期执行,输入参数分别是时间(毫秒)、回调函数、不大于32位变量 template bool attach(size_t milliseconds, void (*callback)(T), T arg) { if (!milliseconds) { return false; } if (sizeof(T) > sizeof(size_t)) { return false; } uint32_t arg32 = (uint32_t) arg; return _attach(milliseconds, milliseconds, reinterpret_cast(callback), arg32); } // 设置Ticker执行一次,输入参数分别是时间(毫秒)、回调函数 bool once(size_t milliseconds, callback_t callback) { return _attach(0, milliseconds, reinterpret_cast(callback), 0); } // 设置Ticker执行一次,输入参数分别是时间(毫秒)、回调函数、不大于32位变量 template bool once(size_t milliseconds, void (*callback)(T), T arg) { if (sizeof(T) > sizeof(size_t)) { return false; } uint32_t arg32 = (uint32_t) arg; return _attach(0, milliseconds, reinterpret_cast(callback), arg32); } void detach(void); // 停止已绑定运行的Ticker bool active(void); // 返回Ticker当前是否已绑定 static void handle(void); // 执行已就绪的任务,该函数可以设置成main(){while(1){LibTicker::handle();}} static void schedule(void); private: bool _active; size_t _index; bool _ready; size_t _period; size_t _count; callback_with_arg_t _callback; size_t _arg; bool _attach(size_t period, size_t count, callback_with_arg_t callback, size_t arg); static LibTicker *_ticker[LIB_TICKER_MAX_SIZE]; }; #endif /* LIB_TICKER_H_ */ #include "lib_ticker.h" typedef void (*LibTickerCallBack)(size_t arg); LibTicker::LibTicker(void) : _active(false), _ready(false), _period(0), _count(0), _callback(nullptr), _arg(0) { } LibTicker::~LibTicker(void) { detach(); } void LibTicker::detach(void) { if (_active) { // 如果Ticker当前已绑定运行 __disable_irq(); _active = false; _ready = false; _period = 0; _callback = nullptr; _arg = 0; _ticker[_index] = nullptr; __enable_irq(); } } bool LibTicker::active(void) { return _active; } bool LibTicker::_attach(size_t period, size_t count, callback_with_arg_t callback, size_t arg) { if (callback == nullptr) { return false; } if (_active) { // 如果Ticker当前已绑定运行 _ready = false; _period = period; _count = count; _callback = callback; _arg = arg; return true; } else { for (size_t i = 0; i __disable_irq(); _active = true; _index = i; _ready = false; _period = period; _count = count; _callback = callback; _arg = arg; _ticker[i] = this; if (_count == 0) { _ready = true; } __enable_irq(); return true; } } } return false; } void LibTicker::handle(void) { for (size_t i = 0; i continue; } if (!_ticker[i]->_active) { continue; } if (_ticker[i]->_ready) { // 当前Ticker已就绪 _ticker[i]->_ready = false; _ticker[i]->_callback(reinterpret_cast(_ticker[i]->_arg)); if ((_ticker[i]->_period == 0) && (_ticker[i]->_count == 0)) { // 该任务只运行一次 _ticker[i]->detach(); } } } } void LibTicker::schedule(void) { for (size_t i = 0; i continue; } if (!_ticker[i]->_active) { continue; } if (_ticker[i]->_count) { _ticker[i]->_count--; } if (_ticker[i]->_count == 0) { _ticker[i]->_ready = true; _ticker[i]->_count = _ticker[i]->_period; } } } LibTicker * LibTicker::_ticker[LIB_TICKER_MAX_SIZE] = { nullptr }; extern __IO uint32_t uwTick; extern HAL_TickFreqTypeDef uwTickFreq; void HAL_IncTick(void) { // 重写系统时间计数函数 uwTick += uwTickFreq; // 保留系统时间计数功能 LibTicker::schedule(); // 进行Ticker调度处理 }

上面的例子打包下载: 《基于STM32 HAL库的定时任务调度器例程 stm32f405ticker.zip》 https://download.csdn.net/download/naisu_kun/11913140 另外也可以参考GitHub上项目,命名稍有调整,功能并没有改动: https://github.com/NaisuXu/STM32-tool-library-based-on-HAL-and-LL

总结

系统时间在开发过程中还是比较有用的,上面只是列举了部分常见用法。如果对时间有更精密的需求的话推荐使用定时器。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3