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

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

[复制链接]
kylongmu 发布时间:2018-8-23 11:35
ST给的TIM例子都是实现一个固定频率的当时输出,如果想在每次定时中断后改变定时器值,那么需要动态的修改定时器周期配置。
0 d; ~" _" G8 K) O) ?实测中发现一有坑,给大家共享。
' r- L7 F5 w) v
  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    6 {6 `  Y, A5 s0 u
  2. {2 o( Q! P: [" R! a( r5 ~& N
  3.   /* USER CODE BEGIN Callback 0 */! W6 q0 y! w4 S( S: e/ p" n

  4. ! g- M5 w2 m. w* x0 p2 D& m
  5.   /* USER CODE END Callback 0 */3 M7 O% X( g' J+ d( l$ v
  6.   if (htim->Instance == TIM22) {
    8 D0 m/ D! p# M9 ^. o3 j
  7.     HAL_IncTick();7 }* d4 x. N- P/ B  ~! Z1 y
  8.   }
    . N" t: z6 C& Z3 k* }4 o% V
  9.   /* USER CODE BEGIN Callback 1 */
    * ^! Y! T' i8 P9 V  }6 w
  10.   if (htim->Instance == TIM2) {
    * L4 n+ J5 ?, z2 n
  11.     IrdaTransfer(pDataNEC);) S0 T1 t9 [; x' [6 m! B+ W
  12.         }
    ' c% I& x; E& H8 p
  13.   /* USER CODE END Callback 1 */' u+ t! s1 |$ K4 O) }  c/ K9 a8 x
  14. }
    / O: c& m& C% E9 ]( ^' b: r
复制代码
首先在HAL_TIM_PeriodElapsedCallback中添加TIM的Update事件中断回调函数,自己写IrdaTransfer(pDataNEC)实现NEC编码的红外遥控。
$ C. g& N: q" t' K. S& `
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    & S" K: }% ^0 `$ X
  2. {) v/ f6 r2 D& d) T8 e5 l5 B: q
  3.         PulseVal=TimeSerial(pDataNEC,PulseSteps);0 Z5 F7 z: ^7 ]. y, j
  4.         PulseSteps++;% U; }( d3 S/ t/ s- D5 D8 s
  5.         if(PulseVal>0)- c  v: c- a6 M, e: {3 s
  6.         {$ q6 O& |. y6 u: K# Q9 N" |
  7.                 htim2.Init.Period = PulseVal&0x7fff;/ E/ r6 M6 z2 G' b9 F
  8.                 HAL_TIM_Base_Init(&htim2);
    - q0 @$ X0 l  i9 ^" E% S
  9.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
    " O' k4 X5 O4 x: p8 O
  10.                 HAL_TIM_Base_Start_IT(&htim2);' O8 G! U0 K) u7 o
  11.         }
    6 i8 G9 ]* ?2 q- V) w4 m! W$ w. V' V
  12.         else
    1 J' \' W3 a8 I3 [
  13.         {
    - Y8 N- C4 T/ o6 U2 R. Z; h9 V0 q( c8 {
  14.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
    1 \) w0 @; c) E+ p2 ^9 s
  15.                 HAL_TIM_Base_Stop_IT(&htim2);
    # B5 M; c; o/ c' B1 r9 L% p
  16.         }
    / _6 |, i% S- j* c0 X6 T
  17.         if(PulseVal&0x8000)
    9 |7 P+ {6 D4 N, H7 [: E
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);, S& \' j- e, c( b+ n
  19.         else. M1 l8 u- b/ _
  20.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);/ Y/ s1 z) @- g
  21.         return PulseVal;4 ]. k6 v# o( X" U/ t
  22. }
    " @# o: V4 [2 s" p4 m( n3 w
复制代码
注意这里的坑是:4 g4 ~) ?+ a0 Z4 F5 r
htim2.Init.Period = PulseVal&0x7fff;
) @" g2 i( p4 s- n+ H                HAL_TIM_Base_Init(&htim2);
) \+ c3 O% S8 K! {" u. D                __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。
$ c% |! H  B6 @: g( D: HHAL_TIM_Base_Start_IT(&htim2);
% j* N2 I2 k0 s! Q在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。9 s8 k9 v* F2 c2 h1 w  l/ R
以上代码即可实现每次定时后立即更新定时值,实现任意的序列控制。具体的NEC红外序列实现功能我就不放了,留点自己动脑子的地方,填的坑与大家共享。
9 X6 k+ D+ @* \: s3 o
& v" _0 K* X7 j$ H: k& [4 m6 P3 Y0 z$ s; }3 _% B& j8 }
# s# k1 u. w- f' E( t4 \& M4 c
收藏 评论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提前,代码如下:
  A3 W* ^; x) ?1 V2 C
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)2 Y! R" `" z: z* q# S' p/ @$ b4 _
  2. {
    " }2 L  P' S" G- U- X/ O/ \" c5 L3 L
  3.         __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);) ]+ W6 }* @+ [. i
  4.         PulseVal=TimeSerial(pDataNEC,PulseSteps);
    - }% q& X+ `) e, A1 O2 ]" I# M
  5.         PulseSteps++;9 X4 L5 x4 M) P/ C4 j5 |
  6.         if(PulseVal>0)8 Y) T7 E$ ]$ B) w+ \/ O- T& t
  7.         {
    7 J2 c  b  h) t0 m! z0 U
  8.                 htim2.Instance->ARR = (uint32_t)PulseVal&0x7fff ;& j# C4 d; L6 U3 J. b  U& _3 X1 d
  9.                 HAL_TIM_Base_Start_IT(&htim2);
    1 e  t. {6 m+ C3 ^4 ~# E
  10.         }* \4 Y0 g: `7 n: }1 h3 Y0 O7 o5 r; X
  11.         else
    & y( y' \0 W8 Q' I! E- y
  12.         {. m! \9 h- H, _& i7 q& E
  13.                 HAL_TIM_Base_Stop_IT(&htim2);
    . @0 M3 E$ X  J8 K. O, s1 }3 Q
  14.         }
    . h" n  K5 e: m$ W0 d
  15.         if(PulseVal&0x8000)
    0 q  P8 `) O( e) p& e
  16.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);& r+ l" n; C; v" }5 r0 y% r* X
  17.         else) l- d- G7 q! Q0 |
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);( J7 A# O$ p4 T% W) F
  19.         return PulseVal;
    8 y4 [" H; F0 @+ {/ Q' Z' H
  20. }
    ' D1 l7 }$ V6 A
复制代码
发现工作正常,看来这个坑真的是
HAL库里的。
7 L' u# F7 U2 o  _* m0 |- T

& W% u6 E! \. P  _# q1 ~0 ^5 b; I
butterflyspring 回答时间:2018-8-23 14:32:41
不错不错,如果可以共享整个工程就好了,但是我了解这种遥控器,最关键的还是解码库.特别是那个万能遥控器的.
xmshao 回答时间:2018-11-1 17:41:37
          __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。* V+ S& l) l+ `- n' |
HAL_TIM_Base_Start_IT(&htim2);% u2 V7 p; {# ~/ w* O( A
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。0 z* v$ y: m, G/ p/ n$ G
==>不能算是个坑,应该是手册没看清楚。
5 ]: Q) K4 Y3 I' E因为有些寄存器比方PSC/RCR寄存器必须通过更新事件才能更新,我们初始化时只能操作预转载寄存器,所以让我们用户数据生效,就手动产生个更新事件,让预装载寄存器的数据拷贝到影子寄存器【实际寄存器】发挥作用。但这个操作会置位更新中断标志,所以我们在使能更新中断前有必要清除下该标志UIF,否则可能一使能更新中断就跳进更新中断服务程序。

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版