stm32 在其他中断中使用 HAL_Delay

需求 因为 485 总线控制的时候,需要考虑在收发转换的时候,不能直接切换,应该让状态再保持一段时间,比如 2ms ,然后再进行切换,这样通讯会更加稳定。这就需要再收发中断里面使用延时,而最简单的延时就是 systick 的延时。但是实际上使用起来,这个延时工作不正常。 解决 出问题的原因也很简单,因为 st 默认让 systick 的中断优先级是最低,所以导致在其他中断中,使用 HAL_Delay, 内部的数值不变,所以一直困在中断里面。解决的方法也很简单,就是重新配置中断优先级,把 systick 的优先级提高到高于通信中断的优先级即可。 参考

<span title='2023-05-24 17:13:00 +0800 CST'>2023-05-24</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;19 words&nbsp;·&nbsp;RamLife

stm32 HAL_SYSTICK_Callback 生效

需求 今天调试的时候,发现通过 systick 的 callback 并没有被调用到,这个有问题。 解决 整体的调用流程是: SysTick_Handler -> HAL_SYSTICK_IRQHandler -> HAL_SYSTICK_Callback, 但是在最新生成的库函数中, SysTick_Handler 中没有默认调用 HAL_SYSTICK_IRQHandler, 所以需要手动在 HAL_IncTick 后添加。 void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); /* USER CODE BEGIN SysTick_IRQn 1 */ HAL_SYSTICK_IRQHandler(); /* USER CODE END SysTick_IRQn 1 */ } 参考 STM32 HAL_SYSTICK_Callback() 失效 无效

<span title='2023-05-21 17:13:00 +0800 CST'>2023-05-21</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;59 words&nbsp;·&nbsp;RamLife

stm32 systick 计时不准确

需求 今天调试的时候,重新配置了 systick 的周期,结果发现通过 systick 进行的延时,怎么都不准,检查了时钟配置,也是很正常。 解决 其实这个问题很简单,有两种可能,一个是配置的位置不对,一个是配置的数据不对。 重新配置位置不对 重新配置 systick 正常使用 HAL_SetTickFreq 这个函数,但是注意,这个函数必须在 main.c 中的 SystemClock_Config 之后调用才可以,否则无效。 因为 SystemClock_Config -> HAL_RCC_ClockConfig -> HAL_InitTick 这个 HAL_InitTick 使用了 uwTickFreq. 但是 uwTickFreq 已经设置了默认值。所以如果 HAL_SetTickFreq 这个函数调用的位置不对,就会导致配置之后,又被重新配置为默认值。 typedef enum { HAL_TICK_FREQ_10HZ = 100U, HAL_TICK_FREQ_100HZ = 10U, HAL_TICK_FREQ_1KHZ = 1U, HAL_TICK_FREQ_DEFAULT = HAL_TICK_FREQ_1KHZ } HAL_TickFreqTypeDef; HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT; /* 1KHz */ 配置数据不对 在 HAL_InitTick 中有如下配置: /* Configure the SysTick to have interrupt in 1ms time basis*/ if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U) { return HAL_ERROR; } 而 systick 的 reload 寄存器只有 24 位,如果是 168M 频率,systick 为 1k,那么必然会超出寄存器的范围,导致出错,重新配置失败。所以,需要考虑系统主频和 systick 的频率,然后带入计算,保证在 24 位之内,才可以。...

<span title='2023-05-21 17:13:00 +0800 CST'>2023-05-21</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;121 words&nbsp;·&nbsp;RamLife

c++ 17 inline 单例模式

需求 在写硬件驱动的时候,有些串口之类的硬件,适合独占访问,适合用单例模式去实现,那么 c++ 中如何实现单例呢? 解决 c++ 17 中拓展了 inline 变量,可以在类内部直接初始化静态变量,这样就方便实现单例模式。如果是需要在多线程情况下使用,那么还可以使用 std::once_flag, std::call_once() 之类的来确保只初始化一次,使用 once 之类的需要引入头文件 <mutex . /* * 多线程条件下只执行一次 * once_flag的生命周期。它必需要比使用它的线程的生命周期要长。所以通常定义成全局变量比較好。 */ static std::once_flag init_flag; // 单例模式 class singleton_pattern { private: inline static singleton_pattern* _instance_ptr{nullptr};// C++ 17 inline static 直接初始化 private: singleton_pattern() { cout << "constructor called" << endl; } singleton_pattern(singleton_pattern&) = delete; singleton_pattern& operator=(const singleton_pattern&) = delete; public: ~singleton_pattern() { cout << "destructor called" << endl; } static singleton_pattern* get_instance() { std::call_once(init_flag, []() { if (_instance_ptr == nullptr) _instance_ptr = new singleton_pattern; }); return _instance_ptr; } void print_addr() { cout << std::format("address: {} \n", (void*)_instance_ptr); } }; 参考 C++ 17 inline static 实现单例模式...

<span title='2023-05-19 10:30:00 +0800 CST'>2023-05-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;118 words&nbsp;·&nbsp;RamLife

c++ 类内初始化非常量静态成员

需求 在类内直接初始化非常量静态成员,编译时给了报错: error: ISO C++ forbids in-class initialization of non-const static member 解决 解决也非常简单,使用 C++17, 然后增加 inline 标识,就可以了。 class A { virtual void fun1(){}; int a; public: static inline int b=0; } 参考 C++:错误:ISO C++ forbids in-class initialization of non-const static member ‘A::b’

<span title='2023-05-19 10:30:00 +0800 CST'>2023-05-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;43 words&nbsp;·&nbsp;RamLife

成员变量是数组,通过初始化列表来初始化

需求 今天编译是报错: warning: list-initializer for non-class type must not be parenthesized, 报错的地方是对类中包含的成员变量是一个数组,然后使用了列表初始化。 解决 其实这个报错提示已经说的很清楚了,对非类使用了列表初始化并且加了括号。所以解决的方法也很简单,这种数组成员变量初始化使用列表初始化时,不要加括号就 ok 了。 class Sn74cbtlv3253 { //using FuncVoidVoid = void (*)(void); using FuncVoidBool = void (*)(bool); public: enum Index { kIndex1 = 0, kIndex2, kIndex3, kIndex4, }; public: Sn74cbtlv3253(FuncVoidBool s0, FuncVoidBool s1, FuncVoidBool oe) : s0_(s0), s1_(s1), oe_(oe) {}; void Switch(Index index); void Disconnect(); private: FuncVoidBool s0_; FuncVoidBool s1_; FuncVoidBool oe_; }; class Channel { public: enum ChannelIndex { kChannel1 = 0, kChannel2, kChannel3, kChannel4, kChannel5, kChannel6, kChannel7, kChannel8, kChannel9, kChannel10, kChannel11, kChannel12, }; public: Channel(); void Switch(ChannelIndex index); void Disconnect(); private: Sn74cbtlv3253 sn74cbtlv3253_[6][2]; }; Channel::Channel() : sn74cbtlv3253_{ {{Chip1S0PinControl, Chip1S1PinControl, Chip1En1PinControl}, {Chip1S0PinControl, Chip1S1PinControl, Chip1En2PinControl}}, {{Chip2S0PinControl, Chip2S1PinControl, Chip2En1PinControl}, {Chip2S0PinControl, Chip2S1PinControl, Chip2En2PinControl}}, {{Chip3S0PinControl, Chip3S1PinControl, Chip3En1PinControl}, {Chip3S0PinControl, Chip3S1PinControl, Chip3En2PinControl}}, {{Chip4S0PinControl, Chip4S1PinControl, Chip4En1PinControl}, {Chip4S0PinControl, Chip4S1PinControl, Chip4En2PinControl}}, {{Chip5S0PinControl, Chip5S1PinControl, Chip5En1PinControl}, {Chip5S0PinControl, Chip5S1PinControl, Chip5En2PinControl}}, {{Chip6S0PinControl, Chip6S1PinControl, Chip6En1PinControl}, {Chip6S0PinControl, Chip6S1PinControl, Chip6En2PinControl}}, } { Disconnect(); } 参考 list initializer for non class type must not be parenthesized werror...

<span title='2023-05-19 10:30:00 +0800 CST'>2023-05-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;155 words&nbsp;·&nbsp;RamLife

结构体位域字节对齐

需求 有些时候,一些数据只占用几个 bit,而且是紧密排列的,所以就会考虑使用结构体位域,最好能再带上 union,使用起来会更加方便,但是位域是否字节对齐? 解决 经过测试,如果每一段的位域都在单个字节内,没有跨字节,那么就可以直接使用,字节是对齐的。否则每个跨字节的位域会多占用一个字节,会造成整体的数据错位。 参考 结构体(Struct)、联合体(Union)和位域 union联合体与内存对齐 C语言位域(位段)详解 UNION和位域的使用

<span title='2023-05-18 18:04:00 +0800 CST'>2023-05-18</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;11 words&nbsp;·&nbsp;RamLife

成员变量是类的对象,通过初始化列表来初始化

需求 类中包含的成员变量是另外一个类的对象,如何对这种成员变量进行初始化? 解决 这种类对象成员变量初始化可以使用初始化列表。 class Hc595 { using FuncVoidVoid = void (*)(void); using FuncVoidBool = void (*)(bool); public: Hc595(FuncVoidVoid sck, FuncVoidVoid rck, FuncVoidBool bit, FuncVoidBool oe, FuncVoidVoid bit_delay) : sck_(sck), rck_(rck), bit_(bit), oe_(oe), bit_delay_(bit_delay) {}; void ShiftByte(uint8_t b); void Store(); void Display(bool en); private: FuncVoidVoid sck_; FuncVoidVoid rck_; FuncVoidBool bit_; FuncVoidBool oe_; FuncVoidVoid bit_delay_; }; class Led { public: enum LedIndex { kLed1 = 0, kLed2, kLed3, kLed4, kLed5, kLed6, kLed7, kLed8, kLed9, kLed10, kLed11, kLed12, }; public: Led(); void Set(LedIndex index, bool g, bool r, bool b); void Refresh(); void ClearData(); private: static const uint8_t kDataLength = 12; static const uint8_t kBufLength = 5; std::array<uint8_t, kDataLength> data_ {}; std::array<uint8_t, kBufLength> buf_ {}; Hc595 hc_; }; Led::Led() : hc_({SckRiseEdge, RckRiseEdge, DataBitPinControl, nullptr, nullptr}) { //hc_ = {SckRiseEdge, RckRiseEdge, DataBitPinControl, nullptr, nullptr}; hc_....

<span title='2023-05-18 10:30:00 +0800 CST'>2023-05-18</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;138 words&nbsp;·&nbsp;RamLife

stm32 cube ide 使用 c 和 c++ 混合开发

需求 在使用 stm32 cube ide 开发的时候,希望通过 c++ 开发,但是自动生成的一些文件是 c 语言的,所以需要解决混合开发的问题。 解决 项目使用 cpp 在新建项目的时候,targeted language 选择 C++ 即可。 混合开发 所有 cpp 需要用到的 c 的头文件,都需要包含 extern "C" 这个标识,需要把相关代码如下包含起来: // may be main.h #ifdef __cplusplus extern "C" { #endif // something #ifdef __cplusplus } #endif 参考 STM32CubeIDE实现nRF24L01通信(C和C++混合编程) STM32CubeMX快速创建工程 点亮LED灯 设置C/C++混合编译 让你的 STM32Cube KEILV5 + HAL库工程支持C++开发 C 和 C++混合编译

<span title='2023-05-17 17:35:00 +0800 CST'>2023-05-17</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;56 words&nbsp;·&nbsp;RamLife

stm32 不用的引脚,应该配置为什么状态

需求 mcu 不使用的引脚,应该如何配置,才比较合适。 解决 低功耗目的: 模拟输入,外部悬空 普通抗干扰: 内部上下拉,外部悬空 最强抗干扰: 外部直接连接 GND 参考 STM32未使用引脚如何处理

<span title='2023-05-17 17:13:00 +0800 CST'>2023-05-17</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;13 words&nbsp;·&nbsp;RamLife