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

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

[复制链接]
kylongmu 发布时间:2018-8-23 11:35
ST给的TIM例子都是实现一个固定频率的当时输出,如果想在每次定时中断后改变定时器值,那么需要动态的修改定时器周期配置。
2 t" i& t% l2 p, N! U9 ]5 M实测中发现一有坑,给大家共享。
3 B0 ?  E! U- z+ H& N( G' B7 l' @
  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    + g$ i3 k$ L! r6 n/ m( o0 X; Z
  2. {4 o9 f3 `! ]4 [! R' A3 B
  3.   /* USER CODE BEGIN Callback 0 */
    ; H" g2 r( E1 M$ @. i$ u8 e

  4. 8 Z/ i3 b, g6 e6 u. z
  5.   /* USER CODE END Callback 0 */, q+ U2 b( P- C) V3 I: D
  6.   if (htim->Instance == TIM22) {+ z* f% q6 ~3 a, s' J( z, o# Q
  7.     HAL_IncTick();
    " n# g/ k7 u1 X/ P" o1 T. |
  8.   }
    ! B! s, r* ?$ t1 ]# z7 }
  9.   /* USER CODE BEGIN Callback 1 */# I3 A; {$ ~7 M+ k- J! ~' F
  10.   if (htim->Instance == TIM2) {7 X. Z) M6 B4 a( b2 |- r
  11.     IrdaTransfer(pDataNEC);
    , N1 Q0 u% V3 h' G7 z( ^
  12.         }
    3 j  E4 {; z, K' k
  13.   /* USER CODE END Callback 1 */
    ! {) O7 P) O9 L7 {9 X: f
  14. }: l1 U' G4 z! e) h
复制代码
首先在HAL_TIM_PeriodElapsedCallback中添加TIM的Update事件中断回调函数,自己写IrdaTransfer(pDataNEC)实现NEC编码的红外遥控。3 r/ C0 E3 c& z( r' z
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    1 F* }5 i1 @' \; [, x
  2. {
    ) g+ [' |$ L, y6 u- Z
  3.         PulseVal=TimeSerial(pDataNEC,PulseSteps);
    ' y" b& w  l5 O) u! z- O
  4.         PulseSteps++;: |9 ?1 N" a. I+ n5 r( P6 S1 `) w
  5.         if(PulseVal>0)
    9 ~3 R1 e7 s! ~& A% x4 u
  6.         {) l$ x$ h  E5 x2 I$ d  j: r9 Y& ?
  7.                 htim2.Init.Period = PulseVal&0x7fff;- @. |# K+ E+ S. \! W3 v9 M5 [' J8 Q
  8.                 HAL_TIM_Base_Init(&htim2);+ G0 w% @. T2 [" e/ l1 \( p; i! X
  9.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);, y7 r$ L' T  n7 G0 q8 l: q) S
  10.                 HAL_TIM_Base_Start_IT(&htim2);
    2 w: z- T1 z# ?! ]" Y4 `& P
  11.         }
    9 w) z( {6 M6 K4 l
  12.         else
      F6 P; W# Y+ e, {4 N. w
  13.         {
    & ]4 r5 c) I' A, }9 M1 z
  14.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);8 g) s/ G! g" u& M
  15.                 HAL_TIM_Base_Stop_IT(&htim2);; B$ S  b5 [7 e" h# r' Q
  16.         }9 T+ b/ T: X" r0 V* S4 j
  17.         if(PulseVal&0x8000)* d1 a% L+ a7 f  D+ A/ K$ d6 t
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
    . B. I: Y1 H& y: H
  19.         else1 i/ U6 s2 d, L* A; C* w+ B& g- R3 t1 m
  20.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);
    ) }# i6 g. X4 S7 a' x2 V3 G% p
  21.         return PulseVal;- l5 N% T) k1 H* I6 [1 d, ^9 s' x
  22. }
    + U: ?1 K0 ]- x; G
复制代码
注意这里的坑是:
) z+ o( `/ m8 D0 b& vhtim2.Init.Period = PulseVal&0x7fff;1 `" {3 ]! U3 i/ f
                HAL_TIM_Base_Init(&htim2);3 P& ]5 n( J% s# o: U
                __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。
! u( g! }4 O- d$ rHAL_TIM_Base_Start_IT(&htim2);
: A) A  a. A. d: Q2 D! K- p在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。
  Y( c( S) D$ Q: \5 T' |  _以上代码即可实现每次定时后立即更新定时值,实现任意的序列控制。具体的NEC红外序列实现功能我就不放了,留点自己动脑子的地方,填的坑与大家共享。
% D9 u  T! P$ w4 Y6 ?
. o8 {3 F; X5 R* [2 T# S) M) [  D6 f: L8 b9 @5 P' y. x1 o

6 k. J/ E# u+ \: U$ V
赞 收藏 评论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提前,代码如下:$ ]; g  `% L% {
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    , _* A- u) w: d( K  V" F
  2. {
    3 U! N8 e8 [" u7 O. \, l5 \  f! z
  3.         __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
    : H7 }) A" K, o. B: `2 W% N
  4.         PulseVal=TimeSerial(pDataNEC,PulseSteps);4 B7 w" j- n/ A% B' H' l+ {3 ~2 _
  5.         PulseSteps++;
    + q( Y* p& i/ F8 _# t1 P1 p
  6.         if(PulseVal>0)
      J. E5 K& W8 U
  7.         {" r' u6 N8 \3 R. m
  8.                 htim2.Instance->ARR = (uint32_t)PulseVal&0x7fff ;2 p8 J5 W# A! B) i- g/ R
  9.                 HAL_TIM_Base_Start_IT(&htim2);! M9 q' y1 v% `( [1 {+ m
  10.         }
    1 \# s0 N: Z8 r# R9 Z
  11.         else
    5 {: z0 N+ _  Q# r6 r5 P
  12.         {: }8 C% l& ^: V# a  Y) p& |" `
  13.                 HAL_TIM_Base_Stop_IT(&htim2);4 M, f* ^( h9 f5 {7 z6 X7 M2 }
  14.         }
    , w6 f, w6 D% B- O) }
  15.         if(PulseVal&0x8000)
    $ T4 g6 a$ {$ K9 O* B
  16.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
    ! V. k# a9 S* j5 ^+ l! b
  17.         else
    9 v7 i6 L$ M9 Y, L  _- i/ k( s
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);
    6 K, T6 [% |7 t9 s
  19.         return PulseVal;; E+ B: h6 J# ?  ?! n0 i$ ^
  20. }( V% B0 Y) m; N5 Q8 T7 ]* z4 c4 a
复制代码
发现工作正常,看来这个坑真的是
HAL库里的。
% y6 a: E1 E4 Q4 v: u/ ?

! x. h6 N( B; |5 I  f1 a7 ^: ~0 Q* C# L- s6 E
butterflyspring 回答时间:2018-8-23 14:32:41
不错不错,如果可以共享整个工程就好了,但是我了解这种遥控器,最关键的还是解码库.特别是那个万能遥控器的.
xmshao 回答时间:2018-11-1 17:41:37
          __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。
' k- @  q0 F7 a* B+ a3 S# \HAL_TIM_Base_Start_IT(&htim2);- v5 G* ~* F" ^& k5 F
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。
" B# \' e! T! L0 C% J==>不能算是个坑,应该是手册没看清楚。1 r6 B$ \/ K% S
因为有些寄存器比方PSC/RCR寄存器必须通过更新事件才能更新,我们初始化时只能操作预转载寄存器,所以让我们用户数据生效,就手动产生个更新事件,让预装载寄存器的数据拷贝到影子寄存器【实际寄存器】发挥作用。但这个操作会置位更新中断标志,所以我们在使能更新中断前有必要清除下该标志UIF,否则可能一使能更新中断就跳进更新中断服务程序。
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版