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

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

[复制链接]
kylongmu 发布时间:2018-8-23 11:35
ST给的TIM例子都是实现一个固定频率的当时输出,如果想在每次定时中断后改变定时器值,那么需要动态的修改定时器周期配置。
% \7 W7 ^6 E, L1 h实测中发现一有坑,给大家共享。8 r# X# F0 Z3 \+ z# r
  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)7 r# s9 ~; V! f0 A2 S
  2. {
    + t; R# k5 d2 d6 u0 k% ~
  3.   /* USER CODE BEGIN Callback 0 */
    ( y# ~% B& z" [5 U" X1 ^

  4. # y0 e* b. v2 ^5 U: c. e
  5.   /* USER CODE END Callback 0 */
    5 @' `, K. |2 n9 K. w
  6.   if (htim->Instance == TIM22) {
    9 `, o. `+ T# q2 i4 i5 n
  7.     HAL_IncTick();) V  B# S9 d( h' f" u5 I% }
  8.   }; Y+ `  i7 ?% T: \
  9.   /* USER CODE BEGIN Callback 1 */5 F' W$ K2 {- x; I
  10.   if (htim->Instance == TIM2) {8 g- |" N/ p. m" O3 Z$ J% B
  11.     IrdaTransfer(pDataNEC);
    * [0 ]* A" L1 \' B3 E  [  C
  12.         }
    + N9 K+ h7 K; v" C( ]0 j' l
  13.   /* USER CODE END Callback 1 */
    # G1 N! d% }5 @9 g
  14. }
    4 }) m& I$ p) Y2 M2 g4 L) ]
复制代码
首先在HAL_TIM_PeriodElapsedCallback中添加TIM的Update事件中断回调函数,自己写IrdaTransfer(pDataNEC)实现NEC编码的红外遥控。
. U4 H8 d4 Z/ p" o0 K
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    ( g: ]8 ?# M- ?* T: t
  2. {0 ?: o, Y4 c. K" e
  3.         PulseVal=TimeSerial(pDataNEC,PulseSteps);
    + k4 \6 |, j! Q, j
  4.         PulseSteps++;
    $ b4 T* }# [2 I' t( _
  5.         if(PulseVal>0)
    5 B/ }( f5 p% v: S( u
  6.         {
    5 h3 u$ C2 p7 A: W
  7.                 htim2.Init.Period = PulseVal&0x7fff;. @3 `4 l* J" w$ a, n! y% @
  8.                 HAL_TIM_Base_Init(&htim2);6 o2 K' k. z, {9 R. R% r3 d4 o% F
  9.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);. _" X" H9 Y4 l7 T; R. i
  10.                 HAL_TIM_Base_Start_IT(&htim2);$ [) u+ i& K; u- E
  11.         }) R# t& i# J9 V
  12.         else) @3 D5 [0 |# P+ f6 {8 J7 A
  13.         {7 E! z( z2 c  P- _, M" V
  14.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);1 R5 A/ g2 }* J6 E) i" R
  15.                 HAL_TIM_Base_Stop_IT(&htim2);
    0 k. g2 i4 T/ ^
  16.         }
    " q+ N  d+ C9 C4 T  U
  17.         if(PulseVal&0x8000)
    # l9 L- C' K$ v
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);1 D! g$ [( e: f* u
  19.         else6 j$ Z0 N* G2 y* H5 j
  20.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);8 @/ o6 |. l( O, ^1 I2 f9 I/ N
  21.         return PulseVal;& r8 I( M& q9 y5 S
  22. }
    9 b; |7 x: Z" i! Y
复制代码
注意这里的坑是:# p( U% g, O5 t
htim2.Init.Period = PulseVal&0x7fff;
" N3 |. y. |' m4 n" d1 `                HAL_TIM_Base_Init(&htim2);
, F" e( V& A' x$ @0 W: M6 ?+ p                __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。3 x5 p5 U# K) M- t& r
HAL_TIM_Base_Start_IT(&htim2);
* b  w" E& j2 S3 c# j在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。7 |3 C$ R" }" ?* q7 y! I
以上代码即可实现每次定时后立即更新定时值,实现任意的序列控制。具体的NEC红外序列实现功能我就不放了,留点自己动脑子的地方,填的坑与大家共享。
+ ]; W1 A0 T# e1 t
; Y* e2 N" ?2 i0 G' v' V* r8 i2 L) l1 m4 E

+ a7 D) F, N, A3 H, w; r' W+ Y
收藏 评论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提前,代码如下:
2 i: m! B* V2 U; Z# M
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)
    9 G9 U4 ~) t- _  H; a
  2. {
    # R7 r* F, }, x" z: ]8 Z+ o
  3.         __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);$ u6 ?7 z& W8 X2 m# ?5 k. W6 e
  4.         PulseVal=TimeSerial(pDataNEC,PulseSteps);( Z! m. U; h. W
  5.         PulseSteps++;0 Z6 N: f- B' v: @  }6 G* ^# h
  6.         if(PulseVal>0)1 E% E7 }8 W" D; K& {
  7.         {1 J  j' H) A/ T# \+ r, F
  8.                 htim2.Instance->ARR = (uint32_t)PulseVal&0x7fff ;
    * d! D9 W: V0 P2 \4 A
  9.                 HAL_TIM_Base_Start_IT(&htim2);
    . ^* G  P$ q' W  G5 H' U
  10.         }
    * M5 W5 e3 G1 ?! f
  11.         else
    2 h2 }: O& X  A
  12.         {& ~3 Q9 U! Y  h5 y
  13.                 HAL_TIM_Base_Stop_IT(&htim2);
    / r) k0 c5 J3 Q  n) |2 i
  14.         }
    ' ^, z4 F! M5 c
  15.         if(PulseVal&0x8000)5 j1 c5 z/ ]" i* ]* K
  16.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);& z8 V8 e. c. R, ~) d
  17.         else- L: u/ C0 h. `/ G
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);
    ! z2 W" E& T1 V, y
  19.         return PulseVal;
    0 c& S' [4 h6 i* S
  20. }
    7 Z; }& d. ?1 A. q! {3 h: [+ J
复制代码
发现工作正常,看来这个坑真的是
HAL库里的。
  N5 b- |1 j3 V7 r% D, }

1 O* }$ C, O8 }$ ?4 @6 i0 e* ]$ B0 U9 \- c/ G6 R* o
butterflyspring 回答时间:2018-8-23 14:32:41
不错不错,如果可以共享整个工程就好了,但是我了解这种遥控器,最关键的还是解码库.特别是那个万能遥控器的.
xmshao 回答时间:2018-11-1 17:41:37
          __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。+ I, O0 i/ C; q; }, F. z
HAL_TIM_Base_Start_IT(&htim2);" U; g% I, h5 n/ h
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。+ ]8 r" f0 N3 D! D6 E0 g
==>不能算是个坑,应该是手册没看清楚。
& K" T, B5 ?" ]: v8 l因为有些寄存器比方PSC/RCR寄存器必须通过更新事件才能更新,我们初始化时只能操作预转载寄存器,所以让我们用户数据生效,就手动产生个更新事件,让预装载寄存器的数据拷贝到影子寄存器【实际寄存器】发挥作用。但这个操作会置位更新中断标志,所以我们在使能更新中断前有必要清除下该标志UIF,否则可能一使能更新中断就跳进更新中断服务程序。

所属标签

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