起因
由于使用了CUBE,原子哥的延时就用不了,所以尝试其他延时函数:CUBE的HAL_Delay()和使用STM32的DWT(Data watchpoint trigger)
前言
为什么要学习这种延时的方法?
- HAL_Delay实用程序函数:它建立在SysTick计时器上,当我们跑操作系统,就一般会占用一个硬件定时器——SysTick(也可以把其他定时器当成时钟),这样一来又难免产生冲突。
- 以便为在阻塞和非阻塞模式下工作的驱动程序提供两个版本。阻塞函数将使用我们今天将要开发的延迟实用程序(DWT)。非阻塞功能将由 SysTick 计时器处理
1.系统图
2.DWT_Initialization() 函数
要实现延时的功能,总共涉及到三个寄存器:DEMCR 、DWT_CTRL 、DWT_CYCCNT ,分别用于开启DWT功能、开启CYCCNT及获得系统时钟计数值。
uint32_t DWT_Delay_Init(void)
{
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0;
__ASM volatile ("NOP");
__ASM volatile ("NOP");
__ASM volatile ("NOP");
if(DWT->CYCCNT)
{
return 0;
}
else
{
return 1;
}
}
3.DEMCR寄存器
DEMCR寄存器为使能寄存器
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
24位置1对应0x01000000;
4.DWT_CTRL寄存器
DWT_CTRL寄存器是时钟周期计数器
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
第一位置"1"对应0x00000001
5.DWT_CYCCNT寄存器
/* 重置时钟周期计数器值 */
DWT->CYCCNT = 0;
它是一个向上的计数器,记录的是内核时钟运行的个数,内核时钟跳动一次,该计数器就加1,精度非常高,决定内核的频率是多少,如果是F103系列,内核时钟是72M,那精度就是1/72M = 14ns
6.DWT_Delay_us() 函数
此函数使用DWT提供以微秒计的延迟
__STATIC_INLINE void DWT_Delay_ms(volatile uint32_t au32_milliseconds)
{
uint32_t au32_initial_ticks = DWT->CYCCNT;
uint32_t au32_ticks = (HAL_RCC_GetHCLKFreq() / 1000);
au32_milliseconds *= au32_ticks;
while ((DWT->CYCCNT - au32_initial_ticks) < au32_milliseconds);
}
演示
以下是本实验的应用程序代码
#include "main.h"
#include "../util/Timer_Delay.h"
#include "../util/DWT_Delay.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
TimerDelay_Init();
while (1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
delay_ms(100);
}
}
结果:每10ms翻转一次,动图去帧数才看起来不像
总结一下:
a.先使能DWT外设,由内核调试寄存器DEM_CR的位24控制,写1使能。
b.使能CYCCNT寄存器,由DWT_CTRL的位0控制,写1使能。
c.使能CYCCNT寄存器之前,先清0。
结束
他们从风雨中走来,倒在了泥泞中,后来人踏着他们走出的路,奔赴黎明。 – 《觉醒年代》
|