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

一个关于STM32 PWM输出无信号的话题

[复制链接]
STMCU小助手 发布时间:2021-1-26 10:51
一个关于STM32PWM输出无信号的话题
近日,从ST MCU技术论坛看到一个贴子,觉得有点意思,拿过来稍作整理交流下。
发帖者问: “我利用stm32f103要做PWM輸出,利用timer1 對GPIO PE8, PE9 做輸出程式碼如下,當我將PE8,9設定為out_pp時利用示波器可以看到波形輸出,但是一設定成AF_PP時,示波器就看不到任何輸出了!所以想要請問,我下面的程式碼哪裡出錯了呢?”
从上面的繁体字和措辞不难看出发帖者极可能是港台同胞。文字信息就这么多。另外发帖者还附加了下面一些程序配置代码。
  1. void Time_init(void)# b7 O% h- W2 R, j, [: L. n
  2. {
    7 X) z7 C: M/ v# o2 o
  3. TIM_TimeBaseInitTypeDef TIM1_TimeBaseInitStruct;
    7 ?* G0 e8 S: P7 e/ _
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);% u5 S9 r* D% f1 J6 U
  5. RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1,DISABLE);8 Q3 x2 K* Z* Q
  6. TIM1_TimeBaseInitStruct.TIM_Prescaler = 999;
    7 q5 K! }7 R2 L  J1 Q- [
  7. TIM1_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    $ f/ m5 O: Z/ K
  8. TIM1_TimeBaseInitStruct.TIM_Period = 8; / }, `0 `1 U0 q4 o
  9. TIM1_TimeBaseInitStruct.TIM_ClockDivision = 0x0;
    4 w9 X# k6 f0 P/ N
  10. TIM1_TimeBaseInitStruct.TIM_RepetitionCounter = 0;9 [& E9 l! E8 K1 Z
  11. TIM_TimeBaseInit(TIM1,&TIM1_TimeBaseInitStruct);
    3 v& l- k& a/ F/ O$ Q! F  S
  12. TIM_ClearITPendingBit(TIM1,TIM_IT_CC1); 0 |) n; d2 m2 W6 w
  13. TIM_ITConfig(TIM1,TIM_IT_CC1,ENABLE); 5 z1 y1 ^8 g9 j, |* t6 g
  14. TIM_Cmd(TIM1,ENABLE);6 ]9 E- Y& L" f4 l$ V
  15. }
    / G$ H4 X/ }! z/ _
  16. / S2 N5 I4 ?2 H, K5 u
  17. void pwm_init(void). t8 ~5 J& r" o' A; [* F: j
  18. {' C3 Y9 L) `: p* a
  19. TIM_OCInitTypeDef TIM_OCInitStructure;
    ( w, R- `8 u/ M0 J
  20. TIM_BDTRInitTypeDef TIM_BDTRInitStructure;: t+ L! Y* ?2 T6 n. e! c
  21. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;( K) [& I. d+ }% B9 V
  22. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  u0 T" J8 t! |6 w5 F, ?5 Y% d" t
  23. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;2 V/ Z/ Y) L# f( a  p
  24. TIM_OCInitStructure.TIM_Pulse = 120;% V2 \9 ~: A9 c, n3 b* ^
  25. TIM_OC1Init(TIM1,&TIM_OCInitStructure);
    $ L- x* d; }7 H0 A0 o# z6 Q+ _- x& ?
  26. TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
    ! V* N3 W! i; Y# [
  27. ; f/ H/ j  w6 C: ^# ^
  28. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      N0 t4 F$ d, m0 J0 T& g3 S& M
  29. TIM_OCInitStructure.TIM_Pulse = 680;
    3 B' V- w7 v+ a5 U. w* U: j" g
  30. TIM_OC2Init(TIM1, &TIM_OCInitStructure);' g% V+ A6 A  x+ r

  31. + r3 [9 Q8 [6 k, W; O
  32. TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable);1 D/ a' F" G" T' g2 `2 ?

  33. # S5 ?6 T+ ~7 O7 u" |
  34. TIM_ARRPreloadConfig(TIM1, ENABLE);$ _2 c5 k& Q  F' s* a8 g7 t# L2 B4 a
  35. TIM_ClearITPendingBit(TIM1, TIM_IT_CC1 );( a7 S. g* {4 L8 @' J& Q# t' a

  36. , a5 Z+ n+ L9 p2 [0 g
  37. TIM_ITConfig(TIM1,TIM_IT_CC1,ENABLE); & N6 @) _- V- b+ S& r
  38. TIM_Cmd(TIM1, ENABLE);% h4 V. a. w% M5 N4 _" E4 q
  39. }
    , e0 c4 Y0 I/ l) g6 {8 m: P% e& V/ F

  40. - _) l8 T# u! H* R4 F! i1 b
  41. void GPIO_Configuration(void), S) I: g1 W$ B3 [2 a& |0 h
  42. {) {8 `7 V5 e& Y8 Z( [! n4 ^0 p
  43. GPIO_InitTypeDef g; 6 x: @! w2 Q& Y% ^5 {# f
  44. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE| RCC_APB2Periph_AFIO, ENABLE); . y2 v) H( c/ W
  45. ' v+ L3 z9 y/ Y
  46. g.GPIO_Pin = GPIO_Pin_9; % q, s* R- Z6 v( ~) ~* E
  47. g.GPIO_Mode = GPIO_Mode_AF_PP;
    : Z' x' V7 o( w
  48. g.GPIO_Speed = GPIO_Speed_50MHz; 5 ?, A$ |; b  n! @  ^
  49. GPIO_Init(GPIOE, &g); % j8 R. }+ |& `" l' _7 \0 s6 V1 c! P* B
  50. 9 q* q5 P) q5 [0 N, d# C
  51. g.GPIO_Pin = GPIO_Pin_8 |GPIO_Pin_9 ;
    $ J3 l0 e& P, h% j7 W$ }' m" u
  52. g.GPIO_Mode = GPIO_Mode_AF_PP;
    - v- r1 a! T" F! ~* S
  53. g.GPIO_Speed =GPIO_Speed_50MHz; $ R$ _8 J& N3 m  V: M- C
  54. GPIO_Init(GPIOE, &g); % i6 u$ s" d* U
  55. GPIO_PinRemapConfig(GPIO_PartialRemap_TIM1, ENABLE);
    4 T; P3 i, ?! b8 O" B) L
  56. }: w' ]) q# X# Y
  57. 9 ~4 a+ ~( j; g' E) H
  58. int main(void)! a- G+ r' }2 Q, v- h
  59. { 4 R9 S6 G4 R: c/ C, f; [( ]
  60. RCC_Configuration(); 8 K% X; j  W+ D3 D  p* K7 A
  61. NVIC_Configuration();7 t3 {6 |8 ]  m3 ~' X
  62. GPIO_Configuration();
    : k+ |) ~! d5 Z3 Q: I
  63. Time_init();
    ; Z6 J) o! Y. _% ]7 [: N
  64. pwm_init();1 ]& q9 W5 n& C5 F6 a. Q
  65. while(1);5 O/ U& i4 b& g) T! l
  66. }
    - n3 V3 J7 d) t
  67. void TIM1_CC_IRQHandler(void) //Interruptroutine
    $ l3 W  B! w# E# m
  68. {% }+ k4 Y0 h' p. Y
  69. if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET)
    * s( o4 g! H! Z% m! Y3 S9 [! t. k3 m
  70. {
    % P" g8 r! H  |0 f
  71. TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
    8 e$ K4 G' A$ B) J

  72. 4 t7 u5 s9 ]5 p+ n
  73. GPIOE-> ODR ^= GPIO_Pin_9;
    0 ?, v5 h0 y4 @0 x' k) l( j5 Y' D
  74. }
    ( q4 {# j) [7 X- m& t2 {- w" F
  75. }
复制代码
! F' f; X* u: C, {/ p8 _7 p
可以看出,发帖者的代码是基于ST 官方的传统标准外设库来写的。上面代码对TIM1的ARR、CCR1、CCR2及相关捕捉中断做了配置并使能。对PE8/PE9做了GPIO及复用配置,开启了TIM1复用脚的部分REMAP功能。针对上述问题,下面拟出几点一起交流下。

1 h# i+ F: `% f1 @
1看看上面红色的捕捉中断代码。竟然发现有对GPIO口PE9的翻转操作,感觉上他是希望利用捕捉中断做GPIO翻转来实现PWM输出?
诚然,在使用有些其它品牌MCU芯片的时候,要实现PWM输出可能不太方便,需借助定时中断和GPIO翻转来实现。这个过程实现起来往往并不是很方便,也有诸多局限性。对于ST MCU,不论STM8还是STM32所有芯片都能利用内部的定时器轻松实现PWM输出。只需做些基本配置,给定信号周期和脉宽就好,无须借助CPU中断来协助实现。

4 _6 j9 o3 I9 [$ H8 W
2发帖者的描述信息中没有给出完整的STM32芯片型号,不说完整芯片型号经常是个麻烦事。STM32有9大系列,几百个料号。其实不少问题是跟具体料号息息相关的。所以,如果通过邮件或网络咨询时,提供完整的信息是必须的。
1.1.jpg
上图是STM32F1系列参考手册里关于TIM1复用功能REMAP的表格。
发帖者配置了PE8/PE9却又只是做了PARTIALREMAP, 结合上图表格得知TIM1的OC1/OC2输出只能出现在PA8/PA9。不知怎么又扯到PE8/PE9了。如果用PE8、PE9,那对应的OC输出应该是OC1和OC1N这对互补输出,这跟OC1/OC2又并不一样,而且还得做FULL REMAP操作才行。也就是说,按照他的配置,在PE口是看不到TIM1_CH1/2的OC输出的,具体到这里就是不能在PE口看到PWM输出。

& J+ y9 |* a/ {. V$ ]
3发帖者说当他把PE9的GPIO模式配置为OUT_PP时能看到脉冲,配置为AF_PP时又看不到,这是怎么回事呢?
在标准库里对GPIO输出模式有相关定义,这里的OUT_PP、AF_PP分别是指GPIO_MODE_OUT_PP和GPIO_Mode_AF_PP。前者指GPIO不做复用时的输出配置;后者是指GPIO做复用输出时的配置。
尽管发帖者的代码有点混乱,但他的定时器1的基本配置还是能工作的,导致捕捉中断能进入。前面提过,在捕捉中断里他做了PE9的IO翻转。作为普通GPIO口,即配置为GPIO_MODE_OUT_PP,当然能用示波器看到该脚翻转的脉冲,但这并等同于来自STM32定时器硬件实现的PWM信号,纯粹IO翻转脉冲。而当PE9被配置为GPIO_Mode_AF_PP时,意味着它要输出其它复用信号,而不是本身IO通道的信号。前面说了,按他现有配置,PWM输出是到不了PE9的,此时看不到IO翻转信号也就不难理解了。
下面是STM32F1系列GPIO管脚复用时的原理框图
1.2.jpg
: p1 N& h) e& g% K
4发帖者的代码混乱还有个地方,那就是关于PWM的脉宽和信号周期的设置。上面的代码里信号周期设置为8个预分频时钟,而2个通道的脉宽却配置为120和680个,即CCR比ARR大得多。按照这样的配置,即使其它有关GPIO复用及REMAP的地方配置无误,它也无法在相应管脚看到PWM跳变脉冲。因为两个通道都没有电平翻转的机会,输出一定是个固定电平。具体是高还是低跟PWM输出模式与CCR的值有关。经常有人在参考库代码基础上,机械地对个别数据一通神改,结果发现PWM出不来了。还比如,对DEADTIME参数的随意修改,也会导致同样问题。
5 ~3 Y" }6 r9 {# B4 ~
5STM32F1系列是目前STM32 九大系列中推出得最早的,其有关管脚复用配置个人觉得是最啰嗦的,没有后面推出的STM32F0、F4、F3等系列的配置简洁。另外印象中STM32F1系列也是唯一没有二级加密保护的芯片。如果可能的话,在新品选型时不一定要拘泥于STM32F1,其实STM32家族中有很多性价比很好的型号可以选择。再就是对于初学者的STM32开发,建议使用STM32CUBEMX做初始化配置。尤其涉及到管脚复用和重映射的地方,操作简单快捷,不易出错。也建议尽量使用ST官方推出CUBE固件库,里面资源比传统固件库更为丰富。
9 _/ A; s7 \. n
6程序代码的正确,终究离不开对原理的清晰理解。不论有多好、多方便的工具,它不论代替你对原理的理解和把握。

$ a: X5 q" C' X# A4 O  F/ ~. r
文章出处: 茶话MCU
8 x/ Q8 i9 c- A/ r, C- ^" {+ z
收藏 评论0 发布时间:2021-1-26 10:51

举报

0个回答

所属标签

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