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

TIM在base模式时的任意定时的实现,NEC红外编码

[复制链接]
kylongmu 发布时间:2018-8-23 11:35
ST给的TIM例子都是实现一个固定频率的当时输出,如果想在每次定时中断后改变定时器值,那么需要动态的修改定时器周期配置。
6 _4 p$ g; _0 {( Q+ K9 @实测中发现一有坑,给大家共享。. ]/ J- i& o4 N& t4 T8 ^. K0 p" ^" [0 A
  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    ) W1 q3 s. b2 ?
  2. {
    ; ^0 r1 a9 X; X+ L' {& i2 t4 H' C3 {
  3.   /* USER CODE BEGIN Callback 0 */
    2 F; w$ h8 E" b* _) m5 \( }

  4. 2 w  _& _- @' F1 z/ U) Y
  5.   /* USER CODE END Callback 0 */
    6 r. k8 g$ f- q# R  J5 O
  6.   if (htim->Instance == TIM22) {6 \8 x6 I. I6 g
  7.     HAL_IncTick();
    * v7 d' E; c7 W( `5 {$ c
  8.   }: F4 m+ U. m5 U- g& D  D; Q
  9.   /* USER CODE BEGIN Callback 1 */% K: e$ y' d$ o- M
  10.   if (htim->Instance == TIM2) {. V4 H* ^/ N9 Q, y6 B
  11.     IrdaTransfer(pDataNEC);
    * _5 A+ s( n$ t7 Z) ~- {8 V6 g% C
  12.         }
    & i6 o, D% \( a, `; U- }8 [2 F
  13.   /* USER CODE END Callback 1 */
      @: h: S( W1 A/ }2 c1 M/ @
  14. }, v' @4 a+ K  @2 p' x/ `# d
复制代码
首先在HAL_TIM_PeriodElapsedCallback中添加TIM的Update事件中断回调函数,自己写IrdaTransfer(pDataNEC)实现NEC编码的红外遥控。
$ x/ I# T/ j$ z' e; _
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    ! k' S- i2 ~! Q/ Q
  2. {: r; j# Y* j8 N  C
  3.         PulseVal=TimeSerial(pDataNEC,PulseSteps);
    9 O6 H/ S) I. P1 {
  4.         PulseSteps++;" O; h2 T5 B2 x( m+ _
  5.         if(PulseVal>0)
    + x' k$ o$ ~% `
  6.         {0 r, i, \4 {" K& O; b" q
  7.                 htim2.Init.Period = PulseVal&0x7fff;/ T9 K' B& \9 ?  b
  8.                 HAL_TIM_Base_Init(&htim2);
    + e0 ^1 A' ^$ c/ l& C7 H- A) b
  9.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);, j/ j! G% x! g. T" z( _: f6 r9 ~
  10.                 HAL_TIM_Base_Start_IT(&htim2);9 Z* X+ K' ^, w& T! W* w* j0 b
  11.         }3 u+ d, v& }0 R/ I; k3 }4 [
  12.         else$ c' d+ w! z5 h
  13.         {
    " @  i  j5 Z+ |) {0 x$ h
  14.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);% C, G' y0 m  j( f9 A; N
  15.                 HAL_TIM_Base_Stop_IT(&htim2);' P7 `$ O  \/ N: O/ w- M5 [: [
  16.         }
    0 ^; I1 q9 P& \: g5 s
  17.         if(PulseVal&0x8000)$ M6 P6 ?5 Y. D7 W4 R  L# O5 V
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
    - t" ]- n0 w4 H8 T# E1 F6 D7 m
  19.         else* s8 h7 @7 `' Z/ C+ H: I% \+ A
  20.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);
    & R0 n- L& T, ?+ s0 b% B
  21.         return PulseVal;
    % o3 s( L) O$ f/ |* a" u
  22. }
    ( ?0 b8 z+ f* u  U: ?
复制代码
注意这里的坑是:
. e+ u! F0 U2 e9 k1 I/ {  Khtim2.Init.Period = PulseVal&0x7fff;( P3 j' S# W' a- I! D
                HAL_TIM_Base_Init(&htim2);
9 f( _" }* i) `# P8 X5 e                __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。$ g- X; [; ]* v' q5 Z; S  V1 h
HAL_TIM_Base_Start_IT(&htim2);+ Q7 W$ e- `. E" v* e
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。- \5 i+ @$ q8 n9 P, Z8 G9 ^- _
以上代码即可实现每次定时后立即更新定时值,实现任意的序列控制。具体的NEC红外序列实现功能我就不放了,留点自己动脑子的地方,填的坑与大家共享。
: Y! p5 x3 Q5 ?) x* t( l" x% t8 _6 L1 D3 g6 Y: M7 ?, g
: k/ h. R, a3 V/ d0 _6 U

# Z/ r) T4 }  v4 {
收藏 评论4 发布时间:2018-8-23 11:35

举报

4个回答
kylongmu 回答时间:2018-8-23 11:46:26
以定时器方式实现任意序列的输出,最大的好处是MCU可以完全处于低功耗状态,不用写跑死MCU的Delay函数。
kylongmu 回答时间:2018-8-23 13:26:46
感觉是提供的库函数HAL_TIM_Base_Init(&htim2)带来的问题,触发了UPDATE中断,为了验证此想法,直接操作TIM的ARR寄存器,把__HAL_TIM_CLEAR_FLAG提前,代码如下:- f9 n' b" }8 W9 O# k0 v/ K
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    7 i7 \9 o9 g. d% T) N( U9 ]- d# f
  2. {/ A+ N  C. o3 w* i
  3.         __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);, `" H# w) ?* x2 {7 O# h# w
  4.         PulseVal=TimeSerial(pDataNEC,PulseSteps);6 a9 `. ~. N2 o. Y5 u* B% Y4 r$ O+ U
  5.         PulseSteps++;+ e, _- ]$ e$ n( V! v
  6.         if(PulseVal>0)
    & [5 N/ F& x" d5 f# D
  7.         {) w* V4 W6 d) G" N5 N
  8.                 htim2.Instance->ARR = (uint32_t)PulseVal&0x7fff ;0 h6 s8 ]9 Y$ w& x: ^& E2 ~1 ~+ n
  9.                 HAL_TIM_Base_Start_IT(&htim2);: `- x/ s0 [# P) i+ Q$ P' P
  10.         }
    - _% @" |: M2 L
  11.         else# |9 Q0 ?, n0 ^# N6 `
  12.         {/ I& R: I; Z" d; g; e1 p, D
  13.                 HAL_TIM_Base_Stop_IT(&htim2);4 {/ X% t+ ~; }) U+ z
  14.         }
    8 \5 N" p7 x3 O; k3 y" H
  15.         if(PulseVal&0x8000)! v+ ]/ {7 v% f- _5 A  N  Z: U
  16.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
      R: a. l& O! V. p
  17.         else) n' i; {  m/ u8 ?' J- Q' S+ p
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);9 T0 t7 [/ T1 q6 F( H
  19.         return PulseVal;
    3 X- D/ K4 y1 G* B+ N
  20. }
    * A; P$ \+ Q: ]  ~+ j
复制代码
发现工作正常,看来这个坑真的是
HAL库里的。
9 Y+ z# r" I" d& Q/ z5 j' x% e0 e
. y# Z. [# o2 u1 y

7 d. y" d. j5 }8 b$ [* N& l  D* `
butterflyspring 回答时间:2018-8-23 14:32:41
不错不错,如果可以共享整个工程就好了,但是我了解这种遥控器,最关键的还是解码库.特别是那个万能遥控器的.
xmshao 回答时间:2018-11-1 17:41:37
          __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。
- |# a7 S0 @# {: PHAL_TIM_Base_Start_IT(&htim2);
  R7 a9 L* Q0 V! z8 P在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。
. y# E' |3 Q+ J1 u==>不能算是个坑,应该是手册没看清楚。
' S3 ^; x$ a3 o. ^1 }! Q7 [因为有些寄存器比方PSC/RCR寄存器必须通过更新事件才能更新,我们初始化时只能操作预转载寄存器,所以让我们用户数据生效,就手动产生个更新事件,让预装载寄存器的数据拷贝到影子寄存器【实际寄存器】发挥作用。但这个操作会置位更新中断标志,所以我们在使能更新中断前有必要清除下该标志UIF,否则可能一使能更新中断就跳进更新中断服务程序。

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版