你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

用 STM32 通用定时器做微秒延时函数(STM32CubeMX版本)

[复制链接]
STMCU-管管 发布时间:2020-12-1 13:33
用 STM32 通用定时器做微秒延时函数(STM32CubeMX版本)
1 E0 j# `( }5 g& D. K
概述
% F7 k& ^8 w3 C7 T9 d        在使用 DHT11 的时候,时序通信需要微秒来操作,STM32CubeMX 自带一个系统时钟,但是实现的是毫秒级别的。因此就自己用通用计时器实现一个。4 |# N/ E2 n1 X, S. A' C
  s% P9 v1 R2 k! }" Q7 x, _

/ w5 ]6 D  A5 a- s& G) ]5 H' d2 E8 b; ]# e3 @* W
$ `3 y3 y8 h3 l" V( a
    环境:) P9 f' S# ]" ]! v0 y

$ ^" O; N0 i1 a# v3 A6 d' Q

% N! n. @: |1 a3 `2 r- [; u开发板:STM32F4探索者(正点原子)0 S- s9 ?9 I; h( u$ h/ g

* B, n$ }* r) q) U9 W

% k7 b, [+ R: _# \+ I9 h7 Q文章目录
# t3 h5 I& E% L( S  l2 w8 S1.配置定时器时钟  j* Z- t4 [8 d  |4 D( p* q
2.计数器时钟频率及计数模式
$ u( ?1 k- L4 ], Z" [- @# \  h0 D' a, _$ e6 M* R
& V" `1 \# ]+ L6 ~1 g
预分频系数
3 ]% B1 v8 |+ ^2 h- W计数器模式3 C/ b3 p- y. z* N: R* k$ d/ b3 l" ^
自动重装载值; n# C: u" M, {  V$ u4 B0 b
3.打开定时器中断7 l0 ^$ J  v- b8 f
4.具体实现代码
. f: s/ w& k$ y, S3 ~0 ~, |5.代码测试
0 M5 p* s7 \3 [# @# _* f  M! h) C$ }# a6 H

0 X, A+ |0 j/ C$ \, k1.配置定时器时钟
5 c; V7 p: j0 v- T+ v·选择时钟源
5 w1 t$ b: D0 Z
11.png
这里选择的是内部时钟,来自 RCC 的TIMxCLK,在通用定时器框图中我们可以看到如下:
/ m) z* k! j9 \' M
12.png
而我们可以在 STM32F4xx中文参考手册中找到,TIM2 在外设总线1(APB1上),因此其时钟为 84MHz,如下图所示:
) i- H, a1 F% E
13.png
2.计数器时钟频率及计数模式
  m/ v$ j& y9 O/ d- U/ r! O除了配置定时器的时钟,还需要配置计数器时钟频率,我们要实现微秒延时,因此计数器时钟频率应该是1MHz,
; ~; Q" e6 ?, x; Y
3 h0 V* G: S- y: I9 e5 ]( [
% J& B/ I$ x) M  _. N+ n8 p
而要实现还需要以下3个参数:
4 l) |& p: e% Y. G9 q
14.png
预分频系数
7 W0 ?7 L) P$ K% O- V" \根据STM32F4xx中文参考手册中的时钟频率计算,如下图所示:4 T5 T/ G" e  O. m
15.png
其中fCK_PSC就是通用定时器框图中的CK_PSC, 即值为84MHz,而我们所要的计数器时钟频率1MHz9 f8 n) h! |- Z8 g: Q' Z( O

9 _) i7 q# c' }( R: {$ m% A
1 l1 k) H& b5 h
因此:8 X2 G- S$ c- p# E4 a: x  r
  1. PSC[15:0] = (fCK_PSC/CK_CNT) - 1 + W3 m$ _* N$ f3 ]  X
  2.           = (84/1) - 11 U0 i% O( q6 n: Y  N5 F8 {
  3.           = 83
复制代码
因此预分频系数为 83
' N0 d7 s" [, T- T6 J- X/ L: W& }  a
; l1 `& q' P0 ~4 f; @' z9 s. f' K1 ~
$ g4 Y, E/ `7 n2 V  Q
计数器模式: P8 {3 R% S. P7 g( f3 M) h9 t" l
计数器这里采用向下计数模式,也就是 如设置计数值为 1000,那么每隔一个微秒,就减一,一直减到 0, g! r5 V: V( y5 g

" D4 i& M5 |+ o3 v% M& K8 s& ~
* \1 O9 t' f& T+ c( P1 a
自动重装载值
/ y5 }1 b( Q# v虽然我们并不使用自动重装载功能,但是,我们还是要对自动重装载寄存器进行赋值且不赋值为0即可,但是我测试时发送,如果为1,延时会出现偏差,因此这里赋值为 2,依据如下:
3 m# ^5 H5 g! R) z& X! z
7 g- e- ]; n5 A* K7 ?2 p! L% C8 O3.打开定时器中断2 b! K/ Z  h1 X. p( c
16.png
4.具体实现代码
) ]# K  _( t, o7 t8 z  e
  1. volatile bool elapsed = false; //用于判断设置的计数值是否耗尽(向下计数模式),耗尽时,在中断中奖会设置为true, J0 z$ g/ e% b: [% @5 N5 d: D$ q5 l6 o
  2. * ]- U6 {8 H) ]- u) s- Y
  3. void setState(bool state)3 m7 D& s6 Z" u
  4. {7 F% x* B1 ]; Q9 F) H( ^, l
  5.     elapsed = state;
    ' X8 L5 V1 |% J( g8 X3 |8 k
  6. }
    2 q  e+ u- @, m+ q

  7. - v, t7 c- j: k9 E5 V; m4 B6 q# W
  8. bool getState()
    ! }: b+ W" y4 x3 p9 j$ |$ c" |# m; L
  9. {; N+ {1 f  \5 T
  10.     return elapsed;
    : l! c$ @' }' P  R8 O' d, c
  11. }$ h9 H' W/ F. g

  12. : a& g, D, j, K' E8 i' k
  13. void usDelay(uint32_t time)
    & \: ?7 f# H+ i
  14. {1 h" K+ ^9 w; h( X7 [6 f: K4 X

  15. ' f0 j+ P7 @6 G8 I- V$ \
  16.     __HAL_TIM_SetCounter(&htim2,time); //设置计数值
    ) z* A' v! h! n
  17.      setState(false);                  
    ! r1 l# t( M9 Z
  18.      HAL_TIM_Base_Start_IT(&htim2);     //开启定时器
    % c; L, Q" i+ V+ S) Q' ~! K
  19.      while(!getState());                //判断计数值是否耗尽
    2 ]" x% {2 E+ f  `$ X
  20.      HAL_TIM_Base_Stop_IT(&htim2);      //关闭定时器. M' l& r3 Y7 c* R' H9 Z' C' s6 D

  21. ; u' c. X8 h, i6 ]* C
  22. }
复制代码
计数值耗尽回调函数- f4 n1 o0 C! R' N
  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)$ m4 I( ?4 @6 Q* ~9 H
  2. {  J3 M- z; C0 A8 |
  3.     if (htim->Instance == TIM2) {
      l1 b' f0 P( b! k$ l, O1 d" ?4 u( U
  4.         setState(true);
    2 v  n+ x% v/ F. y4 j' w
  5.     }
    2 K% Z- ?* O. F- ?/ R
  6.    
    ) Z1 ]% F0 y* P  r) T4 _. U
  7. }
复制代码
5.代码测试0 _0 ]! H5 |! C- c) l; r
主函数的主循环中:* A2 Z# ]  q* @  P. d
  1. while (1)
    7 N, c4 R9 j; ?1 Y6 a: n
  2.   {
    + @; L8 D* H% K& Q0 `, ~$ y" X+ e6 l& t
  3.     /* USER CODE END WHILE */
    8 d  _# z9 h! z$ f8 L# M( T
  4. ( R3 W6 t( D& D& x% C' n
  5.     /* USER CODE BEGIN 3 */
    3 h- d4 W" C3 G6 Z$ o3 ]' M; _9 N
  6.       printf("hello usDelay");9 {+ H) |# I, I/ s2 ^* n1 H
  7.       for(int i = 0; i < 1000; i++)
    3 ]9 ], }. n6 e5 \
  8.       {7 \; z5 Y1 u! T; y6 t$ F. Y
  9.             usDelay(1000);
    # G% X- ?$ o$ u, G3 {
  10.       }
    3 i1 a2 W! I- c
  11.         b# n2 y7 ?1 P4 ?4 m# {
  12.   }
复制代码
在串口调试助手中,可以看到如下,一秒打印一条语句
/ c7 _0 ~% E) [& N2 s  I
17.png
在后台回复“微秒延时”,将获取项目代码!
+ Q; H( R% K6 Q# {- A& h1 n* T2 V后续也将分享如何使用该函数读取 DHT11 温湿度传感器的值,欢迎关注我与我交流!# a. o. u7 A. h6 T' \# g+ V, K. j: g
$ E/ j8 \0 _0 I% L
赞 收藏 评论0 发布时间:2020-12-1 13:33

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版