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

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

[复制链接]
kylongmu 发布时间:2018-8-23 11:35
ST给的TIM例子都是实现一个固定频率的当时输出,如果想在每次定时中断后改变定时器值,那么需要动态的修改定时器周期配置。
9 n/ p5 @* M$ j8 Y  d& Y实测中发现一有坑,给大家共享。' }$ E% l  d( A7 h7 M( G0 U
  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)- W% U2 _* I# P
  2. {
    : j+ o6 }' `; F+ q# t9 J/ E3 E2 L6 I
  3.   /* USER CODE BEGIN Callback 0 */' i5 {; c, P' g

  4. / Q) U& w  k# [
  5.   /* USER CODE END Callback 0 */
    * F% _$ P( x6 I( j0 q* C& K
  6.   if (htim->Instance == TIM22) {$ u6 }1 O) Y0 O
  7.     HAL_IncTick();; ~6 f! [9 p  F7 R3 }" j; S- S
  8.   }$ K2 Z$ E" P, t* [) i
  9.   /* USER CODE BEGIN Callback 1 */
    2 I; i) m& e& z: ?. }
  10.   if (htim->Instance == TIM2) {" b2 {+ ]3 t6 e$ I3 r/ h+ E1 @( `* B
  11.     IrdaTransfer(pDataNEC);
    / J8 P. F/ @$ {2 Y5 S
  12.         }
    % W% D# i4 J/ S  q
  13.   /* USER CODE END Callback 1 */
    9 N% _' R0 u0 J
  14. }
    ) P0 f3 U4 a" @
复制代码
首先在HAL_TIM_PeriodElapsedCallback中添加TIM的Update事件中断回调函数,自己写IrdaTransfer(pDataNEC)实现NEC编码的红外遥控。
. K: |5 G/ R& w
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)  G" |6 f5 _4 }! m- F( r
  2. {
    9 w: [3 ~8 Q4 s) x7 t# [; e: ]
  3.         PulseVal=TimeSerial(pDataNEC,PulseSteps);9 U- U5 R, s" D4 f. [5 {
  4.         PulseSteps++;0 [) J$ j: k1 d* q4 e  ?
  5.         if(PulseVal>0)
    * U, I. v4 W2 D0 q7 z$ R
  6.         {+ [' _4 g/ o( K: A3 @# S, _
  7.                 htim2.Init.Period = PulseVal&0x7fff;8 S0 a; y( u; P+ @8 Y
  8.                 HAL_TIM_Base_Init(&htim2);
    7 c  Y$ G5 ^: c$ M( p; t
  9.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);4 z9 O; |  C  R4 r- Y0 A: L! O
  10.                 HAL_TIM_Base_Start_IT(&htim2);
      R, \, c1 |+ m/ d
  11.         }! y' {; ]! ?0 V+ B1 M
  12.         else
    & O) ?5 n% N3 Q, e
  13.         {
    6 g" }- v9 _, z& A. V$ u* a& [$ C
  14.                 __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);9 h+ Q, T; k( d! E5 r
  15.                 HAL_TIM_Base_Stop_IT(&htim2);
    3 C( z( ]0 j% {5 f8 \, h
  16.         }
    % o2 \0 r1 V- q0 d0 P7 U. @* \  |
  17.         if(PulseVal&0x8000)0 u: R3 A' r* u: U& v( x# v
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);$ W  m3 X: }! p6 `' H
  19.         else
    , E( D1 l2 I  y) L& [
  20.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);
    5 D1 s$ l/ ^  D
  21.         return PulseVal;. W( M* Q. ]2 o1 W
  22. }
    ' ^& x7 e' ~3 j) Y: U7 \
复制代码
注意这里的坑是:2 B( c2 O' r% \! {
htim2.Init.Period = PulseVal&0x7fff;3 a& C% `2 N" r9 ~# v: r7 s
                HAL_TIM_Base_Init(&htim2);3 B$ Z. o7 ?% P/ I0 _  U
                __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。9 Q5 v7 D4 z. J" _9 u9 i
HAL_TIM_Base_Start_IT(&htim2);, _  n0 Q# l2 j9 S9 k& z# z
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。: s, ]0 K9 U  F
以上代码即可实现每次定时后立即更新定时值,实现任意的序列控制。具体的NEC红外序列实现功能我就不放了,留点自己动脑子的地方,填的坑与大家共享。
) J+ t! l1 ~- Y- n6 d& t+ r( M, w) E  B, B8 U7 p
/ R$ C1 v5 [' H- o9 Z

: N5 {* ^6 ]3 G2 l1 n+ X
收藏 评论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提前,代码如下:( _# K; j. M+ n% C
  1. uint16_t IrdaTransfer(uint8_t* pDataNEC)8 E, V4 t- h; S/ F5 E0 C% r# V
  2. {; @) R  t& n  K; ]
  3.         __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);6 j* V0 d$ J9 g( k' Z  \
  4.         PulseVal=TimeSerial(pDataNEC,PulseSteps);$ C, g" r" y% f$ i" N* M  F5 m
  5.         PulseSteps++;. T: \6 O& P/ o8 Q* w  @
  6.         if(PulseVal>0)
      \* q& W  i1 l8 J( X4 ~& j
  7.         {$ t2 i( b6 T3 `" M4 g0 R
  8.                 htim2.Instance->ARR = (uint32_t)PulseVal&0x7fff ;" }3 @( x" A* Z8 w2 W) t0 F5 {
  9.                 HAL_TIM_Base_Start_IT(&htim2);4 A3 b; n% |  a
  10.         }. z; E! ?: b2 o" y/ Z, D( q
  11.         else
    " n+ U, Z. E4 z: p2 R& ?3 ]
  12.         {2 p8 i2 d' v" l$ ?- C0 t  A
  13.                 HAL_TIM_Base_Stop_IT(&htim2);: A. Z  o3 M1 @& S. W
  14.         }2 h) n0 ^" A% r$ D# @
  15.         if(PulseVal&0x8000)7 \- M$ x: d, ]/ B! N5 h, G9 f
  16.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_SET);
    + q& @5 J- G" }0 [& A7 ?4 j
  17.         else9 P% }- z/ }0 ]
  18.                 HAL_GPIO_WritePin(IrDA_Output_GPIO_Port, IrDA_Output_Pin, GPIO_PIN_RESET);
    ) L( ]. N. Z0 \- T7 q1 @3 N
  19.         return PulseVal;
    6 E4 E) T  h+ H, `. M; I7 f! R- {
  20. }
    % _" A+ r$ U- ~5 j$ K
复制代码
发现工作正常,看来这个坑真的是
HAL库里的。

% s% S% U7 Y; `) w/ H  ~0 Q  o
% S2 W' n2 P+ |% w2 c! q  s: F+ ^4 e: j
butterflyspring 回答时间:2018-8-23 14:32:41
不错不错,如果可以共享整个工程就好了,但是我了解这种遥控器,最关键的还是解码库.特别是那个万能遥控器的.
xmshao 回答时间:2018-11-1 17:41:37
          __HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);//这是坑,必须在此处加。
  F$ |( S$ k& s" S# A( uHAL_TIM_Base_Start_IT(&htim2);; U. n; E- c3 x. a  ~
在初始化定时时长后,必须先清除中断标志,再启动定时器中断,否则会直接进中断而没有在定时结束时进,这个坑调了我一天,不明白为啥初始化定时器就会触发一次UPDATE中断。
; j3 }) F- D! C; g==>不能算是个坑,应该是手册没看清楚。
2 o* J, D% z+ _- R因为有些寄存器比方PSC/RCR寄存器必须通过更新事件才能更新,我们初始化时只能操作预转载寄存器,所以让我们用户数据生效,就手动产生个更新事件,让预装载寄存器的数据拷贝到影子寄存器【实际寄存器】发挥作用。但这个操作会置位更新中断标志,所以我们在使能更新中断前有必要清除下该标志UIF,否则可能一使能更新中断就跳进更新中断服务程序。

所属标签

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