本博客中示例代码下载路径: https://github.com/maziot-stm32/A1/releases/tag/v0.3
HAL_Delay 延时时间不准确
在上一篇文章中有编写一个点灯的 demo 程序用于验证工程. 其中主函数测试代码如下:
#define LED0_Pin GPIO_PIN_8
#define LED0_GPIO_Port GPIOA
#define LED1_Pin GPIO_PIN_2
#define LED1_GPIO_Port GPIOD
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
led_init();
while (1)
{
HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, LED_ON);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, LED_ON);
HAL_Delay(200);
HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, LED_OFF);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, LED_OFF);
HAL_Delay(200);
}
}
这里的逻辑很简单, 200ms切换一次 LED 的状态. 但是烧写到板子上后, 发现 LED 闪烁的并没有想象的那么快. 因此便用逻辑分析仪抓了下 PA8 引脚波形.
通过波形确认到 HAL_Delay(200) 实际延时了 400ms, 果然不对.
晶振时钟配置不对
追了下代码, 最后发现是晶振频率代码和板子没有对应上, 板子上贴的是 8M 晶振, 代码中的配置却是 16M, 修正后, 延时正常.
修改 diff 如下:
Paul@DESKTOP-PUB20JQ MINGW64 /f/Workspaces/stm32/A1 (master)
$ git diff
diff --git a/MAZ_Applications/system_stm32f1xx.c b/MAZ_Applications/system_stm32f1xx.c
index 7cacb32..40f4488 100644
--- a/MAZ_Applications/system_stm32f1xx.c
+++ b/MAZ_Applications/system_stm32f1xx.c
@@ -120,7 +120,7 @@
is no need to call the 2 first functions listed above, since SystemCoreClock
variable is updated automatically.
*/
-uint32_t SystemCoreClock = 16000000;
+uint32_t SystemCoreClock = 8000000;
const uint8_t AHBPrescTable[16U] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8U] = {0, 0, 0, 0, 1, 2, 3, 4};
修正后重新用逻辑分析仪抓取波形确认延时就比较正常了, 201ms多一点.
延时误差较大
讲道理, 硬件嘀嗒定时器延时, 应该比较精确, us级别可以理解, 不应该出现ms级别的误差. 找找原因.
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq); // 强制加1
}
while ((HAL_GetTick() - tickstart) < wait)
{
}
}
最后发现, 居然是在 HAL_Delay 函数内部对延时时间进行了强制加1动作. 该强制加1动作是为了防止延迟时间为设置0时卡死在后面的 while ((HAL_GetTick() - tickstart) < wait)
循环中.
因此做出如下修正:
Paul@DESKTOP-PUB20JQ MINGW64 /f/Workspaces/stm32/A1 (master)
$ git diff
diff --git a/MAZ_Vendors/ST/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_def.h b/MAZ_Vendors/ST/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_def.h
index c287eb3..c8630f8 100644
--- a/MAZ_Vendors/ST/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_def.h
+++ b/MAZ_Vendors/ST/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_def.h
@@ -57,6 +57,7 @@ typedef enum
/* Exported macro ------------------------------------------------------------*/
#define HAL_MAX_DELAY 0xFFFFFFFFU
+#define HAL_NO_DELAY 0x0
#define HAL_IS_BIT_SET(REG, BIT) (((REG) & (BIT)) != 0U)
#define HAL_IS_BIT_CLR(REG, BIT) (((REG) & (BIT)) == 0U)
diff --git a/MAZ_Vendors/ST/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c b/MAZ_Vendors/ST/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
index 252f973..aa3f5c5 100644
--- a/MAZ_Vendors/ST/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
+++ b/MAZ_Vendors/ST/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
@@ -363,7 +363,8 @@ __weak void HAL_Delay(uint32_t Delay)
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
- if (wait < HAL_MAX_DELAY)
+// if (wait < HAL_MAX_DELAY)
+ if (wait == HAL_NO_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}
修正后, 时间就在 200ms 左右, 误差为 us 级别, 波形如下: