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

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

[复制链接]
kylongmu 发布时间:2018-8-23 11:35
ST给的TIM例子都是实现一个固定频率的当时输出,如果想在每次定时中断后改变定时器值,那么需要动态的修改定时器周期配置。# p* p1 N' O* b$ f/ j- L
实测中发现一有坑,给大家共享。
! K2 l6 I9 @  L. b0 y7 _% @
  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)+ [& q  B/ J" w; |0 Z2 G! u
  2. {
    6 t5 ^! o' k- T) g0 u3 j- C7 F
  3.   /* USER CODE BEGIN Callback 0 */
    * a) W$ Z6 n% _0 J
  4. . F9 v7 R& U* b4 M8 X* |7 K/ b
  5.   /* USER CODE END Callback 0 */
    ' F; h" K" ?2 M/ f% ~! A( @& p
  6.   if (htim->Instance == TIM22) {
    ) p& b5 Z' \4 e, x! \
  7.     HAL_IncTick();
    + U4 p& {; N" ^# A  s. S; U. d4 k
  8.   }3 i6 J4 s( G2 H- ]' V7 ~# p
  9.   /* USER CODE BEGIN Callback 1 */
    1 c8 f, }; f; c# b5 U9 u
  10.   if (htim->Instance == TIM2) {) [: g' W1 W! ~
  11.     IrdaTransfer(pDataNEC);
    : J4 U6 O" J' u. Z+ x) b* ~
  12.         }
    ' I3 o" G$ ]: G0 p
  13.   /* USER CODE END Callback 1 */
    8 B* W! @! ?$ }- z+ j  l
  14. }
    # W" u3 @7 ?' f) Y( ^+ g# T4 J7 }
复制代码
首先在HAL_TIM_PeriodElapsedCallback中添加TIM的Update事件中断回调函数,自己写IrdaTransfer(pDataNEC)实现NEC编码的红外遥控。# `# n8 z5 H- o" X" x, w# O
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    . p1 i  ^0 Z7 M1 l$ {1 @
  2. {
    : Z# {$ Q# ?2 T8 c6 z; \5 f0 T, n
  3.         PulseVal=TimeSerial(pDataNEC,PulseSteps);0 H, I! r2 V1 q; k
  4.         PulseSteps++;
    9 n5 ]7 Y! U5 {
  5.         if(PulseVal>0)9 F8 }# j& c% U& y( Z0 L
  6.         {
    3 e$ I. n6 c4 s5 j. U/ s# F* w) K+ B/ u- q
  7.                 htim2.Init.Period = PulseVal&0x7fff;+ x. ?1 }( L! r( U
  8.                 HAL_TIM_Base_Init(&htim2);
    , V! A0 D3 c' f
  9.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
      H% [% j9 D: V3 |" Q; j3 h+ m- B
  10.                 HAL_TIM_Base_Start_IT(&htim2);& f" m6 i% ^/ l6 ^* O
  11.         }1 m$ Q9 s. E' f2 ?  i$ F% R9 b  J; |. y
  12.         else8 i  m* D; b' Q" e% d! `- G
  13.         {
    * w; j# x7 h5 d% T1 C
  14.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);1 A8 v. L  q3 N+ y, W
  15.                 HAL_TIM_Base_Stop_IT(&htim2);. W( y( w. [2 }' {
  16.         }
    # M6 c  x8 L0 f. b: S# N4 E, d
  17.         if(PulseVal&0x8000)  R# M7 l2 ^2 ?& `, f
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
    6 J" w$ o! J+ D( ]6 b! R
  19.         else! w! ^; P1 s  ^+ ~
  20.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);5 y5 H- e8 c! K# t3 H- ^% j0 E
  21.         return PulseVal;
    1 m) e$ t& u) S) ^
  22. }9 q1 V3 U, G( t* X* N
复制代码
注意这里的坑是:7 n  a9 O& Y7 O% V% ]
htim2.Init.Period = PulseVal&0x7fff;# q" o& u8 y$ o' F
                HAL_TIM_Base_Init(&htim2);
  x! p! s* y5 g4 R                __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。
% M. t8 K) `0 C) c  }2 Q7 BHAL_TIM_Base_Start_IT(&htim2);" a8 ]. e1 U& D  y' ]
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。6 ?" v6 l5 q2 K" a. x
以上代码即可实现每次定时后立即更新定时值,实现任意的序列控制。具体的NEC红外序列实现功能我就不放了,留点自己动脑子的地方,填的坑与大家共享。
/ ]& I$ L# K" r& K1 ~& ?, z
1 j0 T( u/ s2 n4 v1 ^
" H/ C2 s. _9 q4 p7 U) o
5 s0 N0 c) p& 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提前,代码如下:
* b7 V7 q; ~% @9 o7 v
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)8 H) ]/ R, B$ L% g
  2. {
    ) }' d$ C0 d9 H* N* c! E6 J# I
  3.         __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
    1 V9 {- r6 i1 j; \: A2 `
  4.         PulseVal=TimeSerial(pDataNEC,PulseSteps);1 _0 m6 X' L, T* c, |9 P0 D; k' r3 m
  5.         PulseSteps++;
    & P. [# p$ J5 a2 A% ?& b* ^! {6 r: ^
  6.         if(PulseVal>0)8 V" _0 Y" {* d7 y7 j0 u
  7.         {
    " ]2 O7 f# a/ ?6 i1 Y& i
  8.                 htim2.Instance->ARR = (uint32_t)PulseVal&0x7fff ;
    $ m$ {+ m7 \% v* \, J
  9.                 HAL_TIM_Base_Start_IT(&htim2);
    9 h% F  Z8 H% }
  10.         }+ f- m; t+ ]7 ^  q& v
  11.         else
    7 o" D) m- u) b
  12.         {9 @% B3 j4 a" E2 Z: Y: N3 h1 N
  13.                 HAL_TIM_Base_Stop_IT(&htim2);0 w* v' X* R: v  A
  14.         }
    % e9 C6 K$ \( b" H* e# j
  15.         if(PulseVal&0x8000)  [; n4 [) O, s6 z- s4 E( k
  16.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);0 [! j0 b' K7 R. v2 O
  17.         else4 l. x5 ~5 ~. p+ s% b( {9 ?+ @
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);2 @; i6 _4 X5 ?% K& X; D+ P: H7 A
  19.         return PulseVal;
    ) I- D( b; K) k5 c$ a4 ]0 D9 I4 g
  20. }
      C% f- S: T$ F% q$ P( g
复制代码
发现工作正常,看来这个坑真的是
HAL库里的。
6 |. ~" d: q$ e* T; w% a
# e+ H( t- U' \/ A  g, g/ C

4 m, a  P  W3 t6 N5 X. D/ n0 C+ J
butterflyspring 回答时间:2018-8-23 14:32:41
不错不错,如果可以共享整个工程就好了,但是我了解这种遥控器,最关键的还是解码库.特别是那个万能遥控器的.
xmshao 回答时间:2018-11-1 17:41:37
          __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。% k2 w5 U9 w+ c6 a. q
HAL_TIM_Base_Start_IT(&htim2);1 i, h% J& ^- {  F# Q- @# a
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。1 ]& X0 \- d2 k" t' O) w+ E# z  u
==>不能算是个坑,应该是手册没看清楚。
4 ]; m* `& U5 D& q因为有些寄存器比方PSC/RCR寄存器必须通过更新事件才能更新,我们初始化时只能操作预转载寄存器,所以让我们用户数据生效,就手动产生个更新事件,让预装载寄存器的数据拷贝到影子寄存器【实际寄存器】发挥作用。但这个操作会置位更新中断标志,所以我们在使能更新中断前有必要清除下该标志UIF,否则可能一使能更新中断就跳进更新中断服务程序。

所属标签

相似分享

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