STM32F1与STM32CubeIDE快速入门-DWT精确延时

DWT(Data Watchpoint and Trigger)精确延时

文章目录

1、DWT介绍

在 Cortex-M3 中,有一个外设叫做 DWT(Data Watchpoint and Trigger),用于系统调试和跟踪,同时也具备延时功能。

在这里插入图片描述

DWT之所以能实现延时功能,是因为它有一个32位的计数器CYCCNT,它是一个向上计数的计数器。 溢出时会自动复位并重新开始向上计数。 它的频率是内核的主频率。 简单来说,如果内核时钟跳动,则CYCCNT计数器将增加 1。因此DWT可以代替定时器外设来实现延时功能和测量代码运行时间的功能,但是DWT 不能替代定时器的其他功能。

DWT 计数器的精度与系统的主频有关。比如,STM32F103的主频是72MHz,其精度为1 / 72MHz = 14纳秒,这足以满足大部分延时功能的要求。 同理,程序的运行时间为微秒级,远远满足衡量代码运行时间的要求。

2、DWT配置

DWT实现延时的功能,需要使用到三个寄存器:DEMCRDWT_CTRLDWT_CYCCNT,分别用于开启DWT功能、开启CYCCNT及获得系统时钟计数值。具体配置并使用DWT的步骤如下:

  • 先使能DWT外设,由内核调试寄存器DEMCR的位24控制,设置为1使能
  • 启用CYCCNT寄存器之前,先将其设置为零。
  • 启用CYCCNT寄存器,它由DWT的CYCCNTENA 控制,也就是DWT控制寄存器的位0控制,设置为1使能

STM32CubeIDE创建工程、系统配置、调试配置,在这里不再做介绍,请参考:

具体实现如下:

2.1 基本定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/\*
\* dwt\_delay.h
\*
\* Created on: Apr 24, 2022
\* Author: jenson
\*/

#ifndef DWT\_DELAY\_H\_
#define DWT\_DELAY\_H\_

#include <stdio.h>
#include <stm32f1xx\_hal.h>

/\*\*\*
\*@brief DWT初始化
\*@returen 初始化成功,返回1;否则,返回0
\*/
uint8\_t dwt\_init(void);

/\*\*\*
\* @brief 延时微秒
\* @param us 指定延时微秒值
\*/
void dwt\_delay\_us(volatile uint16\_t us);

/\*\*\*
\* @brief 延时毫秒
\* @param us 指定延时毫秒值
\*/
void dwt\_delay\_ms(volatile uint16\_t ms);

#endif /\* DWT\_DELAY\_H\_ \*/

2.2 DWT延时初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
uint8\_t dwt\_init(void) {
/\* 禁用 TRC \*/
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; // ~0x01000000;
/\* 开启 TRC \*/
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // 0x01000000;

/\* 禁用时钟周期计数器 \*/
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; //~0x00000001;
/\*启用时钟周期计数器 \*/
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; //0x00000001;

/\* 重置时钟周期计数器值 \*/
DWT->CYCCNT = 0;

__ASM volatile ("NOP");
__ASM volatile ("NOP");
__ASM volatile ("NOP");

/\* 检查时钟周期计数器是否已启动 \*/
if (DWT->CYCCNT) {
return 1; /\*时钟周期计数器启动\*/
} else {
return 0; /\*时钟周期计数器未启动\*/
}
}

2.3 DWT延时实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void dwt\_delay\_us(volatile uint16\_t us) {
uint32\_t au32_initial_ticks = DWT->CYCCNT;
uint32\_t au32_ticks = (HAL\_RCC\_GetHCLKFreq() / 1000000);
us \*= au32_ticks;
while ((DWT->CYCCNT - au32_initial_ticks) < (us - au32_ticks))
;
}

void dwt\_delay\_ms(volatile uint16\_t ms) {
uint32\_t au32_initial_ticks = DWT->CYCCNT;
uint32\_t au32_ticks = (HAL\_RCC\_GetHCLKFreq() / 1000);
uint32\_t ms_new = ms \* au32_ticks;
while ((DWT->CYCCNT - au32_initial_ticks) < (ms_new - au32_ticks))
;
}

2.4 简单使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include <stdio.h>
#include "dwt\_delay.h"
/\* USER CODE END Includes \*/

int main(void) {
/\* USER CODE BEGIN 1 \*/
int32\_t counter = 0;
/\* USER CODE END 1 \*/

/\* MCU Configuration--------------------------------------------------------\*/

/\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/
HAL\_Init();

/\* USER CODE BEGIN Init \*/

/\* USER CODE END Init \*/

/\* Configure the system clock \*/
SystemClock\_Config();

/\* USER CODE BEGIN SysInit \*/

/\* USER CODE END SysInit \*/

/\* Initialize all configured peripherals \*/
MX\_GPIO\_Init();
MX\_USART1\_UART\_Init();
MX\_TIM4\_Init();
/\* USER CODE BEGIN 2 \*/
printf("\*\*\*\*STM32CubeIDE:DWT Demo\*\*\*\*\r\n");
if(dwt\_init()){
printf("DWT inited.\r\n");
}else{
printf("DWT init failed.\r\n");
while(1);
}
/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/
printf("counter = %ld\r\n", counter);
counter++;
if (counter >= 65535) {
counter = 0;
}

dwt\_delay\_us(1000);
//dwt\_delay\_ms(100);

}
/\* USER CODE END 3 \*/
}

3、STM32F1与STM32CubeIDE系列文章

3.1 STM32F1与STM32CubeIDE快速入门

3.2 STM32F1与STM32CubeIDE编程实例

文章来源: https://iotsmart.blog.csdn.net/article/details/124801263