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

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

[复制链接]
kylongmu 发布时间:2018-8-23 11:35
ST给的TIM例子都是实现一个固定频率的当时输出,如果想在每次定时中断后改变定时器值,那么需要动态的修改定时器周期配置。
7 p: l( f# w. m# j/ O1 K* E$ v2 A实测中发现一有坑,给大家共享。% @: Z2 F4 |$ y) {0 b  `+ U2 H5 |, `
  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)2 _' O! d0 ~8 m, |3 B
  2. {  [9 @/ Q" n" t& r9 u$ e8 G
  3.   /* USER CODE BEGIN Callback 0 */% E% g: Y4 n6 x4 y4 D! c! O, R

  4. & B6 n  h9 \& b! s9 @$ ~
  5.   /* USER CODE END Callback 0 */
    ' ?' ^. ^2 _0 Y9 }  |1 Q
  6.   if (htim->Instance == TIM22) {+ e4 l8 b. a0 p
  7.     HAL_IncTick();7 C4 Z4 W- w& U; Z7 |3 x
  8.   }
    ) F( d# u# H' [( _  n7 V* ~
  9.   /* USER CODE BEGIN Callback 1 */* v( o  O0 d) V& v" k$ ?
  10.   if (htim->Instance == TIM2) {9 p/ d5 D% @+ c" o5 D
  11.     IrdaTransfer(pDataNEC);
    8 ^. k0 D* \4 G( s" n
  12.         }
    & n) [7 l$ j2 \; M( {/ |  o
  13.   /* USER CODE END Callback 1 */5 d: |5 P5 q+ ~+ G% ]
  14. }' C3 X% n7 u  k9 ]- A
复制代码
首先在HAL_TIM_PeriodElapsedCallback中添加TIM的Update事件中断回调函数,自己写IrdaTransfer(pDataNEC)实现NEC编码的红外遥控。) Q0 S/ D+ t8 f! Z
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    8 V2 \) D" q( H. Y
  2. {: s( i% j) c/ h4 j# A2 z) t+ r; v/ y
  3.         PulseVal=TimeSerial(pDataNEC,PulseSteps);( l$ E6 r% D$ P5 X! H
  4.         PulseSteps++;
      a6 ]3 b; n( E; f- Z  T4 g. w
  5.         if(PulseVal>0)
    0 v1 e: r( b% x: I+ W
  6.         {
      b& O. t$ s% f1 f8 T1 {
  7.                 htim2.Init.Period = PulseVal&0x7fff;, W: ?. l) e( P5 F7 m9 H8 b5 b
  8.                 HAL_TIM_Base_Init(&htim2);& w( q% m) c3 z+ j; s+ T
  9.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
    : X7 v2 p" f  s9 F& v
  10.                 HAL_TIM_Base_Start_IT(&htim2);
    : U1 \' ]7 e# F  K2 b% O6 k3 Q; |
  11.         }
    + f8 H$ @% _) |. y* Q1 `8 V
  12.         else
    $ P2 D* z/ ?; h
  13.         {
    7 Y) G" \5 w# h1 Z
  14.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
    6 w% R6 w7 U( f9 L* L. b8 ~
  15.                 HAL_TIM_Base_Stop_IT(&htim2);. @4 \' M# ?) z
  16.         }9 r* U4 L/ K/ `* T0 D* T# M. Z
  17.         if(PulseVal&0x8000)
    3 G; [' D4 R7 F6 w) F
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
    6 q. b- s1 C/ Y) F
  19.         else& a$ l6 \4 M( @7 r9 V" }
  20.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);/ d* E* u$ b- U
  21.         return PulseVal;
    ! K! v$ n6 \3 ~1 G) h& B% N4 l5 ~
  22. }# V; j* _* H% A  D2 ^( y) Q' C+ P
复制代码
注意这里的坑是:
- k+ x+ U8 L$ mhtim2.Init.Period = PulseVal&0x7fff;
# U: V" _# j7 U. a( m/ J  K+ v: z  p                HAL_TIM_Base_Init(&htim2);) u  ~5 X& t/ g8 \) c6 @# Y7 a: ^% v
                __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。  a. |6 d' Q/ u5 z% [2 {
HAL_TIM_Base_Start_IT(&htim2);
. Y$ Y, D5 D+ R6 N6 ], T  g# b5 y在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。+ U/ Z8 j$ a0 w  O6 U' n
以上代码即可实现每次定时后立即更新定时值,实现任意的序列控制。具体的NEC红外序列实现功能我就不放了,留点自己动脑子的地方,填的坑与大家共享。( Y% n/ h) |* c! u
0 X) W2 o! c/ U: x
0 t; m1 `) D, G3 t

! V+ ]& N4 J% H& K
收藏 评论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提前,代码如下:. V4 ^- u. e6 n
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    8 a& _9 s7 W$ g/ f5 O
  2. {
    ' h# T, r% l5 S7 T: |6 v/ d
  3.         __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);% i7 k" C1 b& b/ x* w: M0 b
  4.         PulseVal=TimeSerial(pDataNEC,PulseSteps);
    , O% h. {  K# h' w$ ?2 _
  5.         PulseSteps++;
    ( V5 U' m; ~# W, |8 a5 C% H8 W, |
  6.         if(PulseVal>0)% L3 F& N8 c9 ?& k  Y5 S) D% @% I
  7.         {
    . ]* v. ]; _8 s' h5 i2 e5 u
  8.                 htim2.Instance->ARR = (uint32_t)PulseVal&0x7fff ;( \# U! Q2 Q5 W; R# N: E
  9.                 HAL_TIM_Base_Start_IT(&htim2);
    4 O0 K& [- P% h% v
  10.         }/ a# k; [* K$ ^
  11.         else* K! k# z0 z0 B9 h0 Z- f
  12.         {
    8 R4 `: O- G6 h$ w7 C+ A' I( C/ ^
  13.                 HAL_TIM_Base_Stop_IT(&htim2);9 A; e# O) |: d& D* ^* n: j
  14.         }; ?$ `# J% K- d8 w" h/ B
  15.         if(PulseVal&0x8000)% }( F$ F) @4 |( o: q
  16.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
    - l  N8 _. D2 e$ u9 v3 g
  17.         else
    ( |4 V4 s, z. w; K* J. n; k
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);# i- m) Y9 Z: k, o. k3 x: y# j
  19.         return PulseVal;
    $ J' N* {, t: P# r/ n" V4 _
  20. }3 c: h# z) L+ C. u, W/ c! O0 _
复制代码
发现工作正常,看来这个坑真的是
HAL库里的。

0 A1 v$ N3 y% X* Z6 N. c& J, H- l! ?+ d( s

# S% S+ o% [2 U0 \  N
butterflyspring 回答时间:2018-8-23 14:32:41
不错不错,如果可以共享整个工程就好了,但是我了解这种遥控器,最关键的还是解码库.特别是那个万能遥控器的.
xmshao 回答时间:2018-11-1 17:41:37
          __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。; J- h) [# d) D# |* p" M0 d4 Q
HAL_TIM_Base_Start_IT(&htim2);
; Q% p1 K+ k% B' V8 H4 M/ H, g在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。  B/ N+ Q5 M* y9 @
==>不能算是个坑,应该是手册没看清楚。
' T/ ~3 d, S$ Z' M' n& o* U0 I& f6 T1 Y; o因为有些寄存器比方PSC/RCR寄存器必须通过更新事件才能更新,我们初始化时只能操作预转载寄存器,所以让我们用户数据生效,就手动产生个更新事件,让预装载寄存器的数据拷贝到影子寄存器【实际寄存器】发挥作用。但这个操作会置位更新中断标志,所以我们在使能更新中断前有必要清除下该标志UIF,否则可能一使能更新中断就跳进更新中断服务程序。

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版