[单片机芯片] CH32L103 TIM应用

[复制链接]
7032|10
 楼主| L-MCU 发表于 2024-7-10 13:33 | 显示全部楼层 |阅读模式
本帖最后由 L-MCU 于 2024-7-10 16:28 编辑

1、定时器介绍
CH32L103具有一个16位的高级定时器TIM1、两个16位的通用定时器TIM2、TIM3以及一个32位的通用定时器TIM4。其中,高级定时器相较于通用定时器,支持可编程死区时间的互补输出、支持使用重复计数器在确定周期后更新定时器、支持使用刹车信号将定时器复位或置其于确定状态,高级定时器更适用于电机控制等相关领域。
CH32L103具有一个32位的通用定时器,相较于16位定时器,其具有一个32位自动重装计数器。
关于CH32L103定时器的具体介绍,可见CH32L103应用手册。

2、定时器应用
(1)定时器更新中断
关于定时器更新中断的产生:
当配置向上计数模式时,定时器计数器从0向上计数到重装载值之后会产生更新事件,则会进入更新中断。计数器会重新从0开始向上计数。
当配置向下计数模式时,定时器计数器从重装载值向下计数到0之后会产生更新事件,则会进入更新中断。计数器会重新从重装载值向下计数。
定时器更新中断程序如下:
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2023/12/26
  6. * Description        : Main program body.
  7. *********************************************************************************
  8. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
  9. * Attention: This software (modified or not) and binary are used for
  10. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
  11. *******************************************************************************/

  12. /*
  13. *@Note
  14. *USART Print debugging routine:
  15. *USART1_Tx(PA9).
  16. *This example demonstrates using USART1(PA9) as a print debug port output.
  17. *
  18. */

  19. #include "debug.h"

  20. /* Global typedef */

  21. /* Global define */

  22. /* Global Variable */

  23. //LED初始化
  24. void LED_Init(void)
  25. {
  26.     GPIO_InitTypeDef  GPIO_InitStructure={0};

  27.     RCC_PB2PeriphClockCmd(RCC_PB2Periph_GPIOA, ENABLE);

  28.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  29.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //设置GPIO模式为推挽输出
  30.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  31.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  32.     GPIO_SetBits(GPIOA,GPIO_Pin_1);
  33. }

  34. //定时器更新中断初始化
  35. void TIM1_INT_Init(u16 arr,u16 psc)
  36. {
  37.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure={0};
  38.     NVIC_InitTypeDef         NVIC_InitStructure={0};

  39.     RCC_PB2PeriphClockCmd(RCC_PB2Periph_TIM1, ENABLE);        //使能TIM1时钟

  40.     TIM_TimeBaseStructure.TIM_Period = arr;                    //重装载值
  41.     TIM_TimeBaseStructure.TIM_Prescaler =psc;                  //预分频器值
  42.     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;    //时钟分频因子
  43.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM计数模式,向上计数模式
  44.     TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  45.     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);            //根据指定的参数初始化TIMx的时间基数单位

  46.     //初始化TIM NVIC,设置中断优先级分组
  47.     NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;         //TIM1更新中断
  48.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //设置抢占优先级0
  49.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;         //设置响应优先级3
  50.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //使能通道1中断
  51.     NVIC_Init(&NVIC_InitStructure);                            //初始化NVIC

  52.     TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE );                  //使能TIM1中断,允许更新中断

  53.     TIM_Cmd(TIM1, ENABLE); //TIM1使能
  54. }

  55. void TIM1_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
  56. void TIM1_UP_IRQHandler(void)
  57. {
  58.     static u8 i=0;

  59.     if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) //检查TIM1中断是否发生。
  60.     {
  61.         TIM_ClearITPendingBit(TIM1,TIM_IT_Update);      //清除TIM1的中断挂起位。
  62.         GPIO_WriteBit(GPIOA, GPIO_Pin_1, (i==0) ? (i=Bit_SET):(i=Bit_RESET));
  63.     }
  64. }
  65. /*********************************************************************
  66. * @fn      main
  67. *
  68. * [url=home.php?mod=space&uid=247401]@brief[/url]   Main program.
  69. *
  70. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  71. */
  72. int main(void)
  73. {
  74.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  75.     SystemCoreClockUpdate();
  76.     Delay_Init();
  77.     USART_Printf_Init(115200);
  78.     printf("SystemClk:%d\r\n", SystemCoreClock);
  79.     printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
  80.     printf("This is printf example\r\n");

  81.     LED_Init();
  82.     TIM1_INT_Init(1000-1,96-1);

  83.     while(1)
  84.     {
  85.     }
  86. }
程序中,主要对定时器自动重装值寄存器值、计数时钟预分频器值、时钟分频因子、计数模式、重复计数器值进行配置。
关于自动重装值寄存器,主要用于设置定时器计数的次数,对于TIM1、2、3,该寄存器是16位的,最大值可设置为2的16次方,即65536;对于TIM4,该寄存器是32位的,最大值可设置为2的32次方;
关于计数时钟预分频器,主要用于设置定时器预分频器的分频系数,计数器的时钟频率等于分频器的输入频率/(PSC+1)。以例程TIM1为例,系统主频96MHz,PB2总线时钟为96MHz,TIM1是挂载在PB2总线下面的,如下图,当预分频器的分频系数设置为95时,则计数器的时钟频率f为96MHz/(95+1)=1MHz,则计数一次的时间t为1/f=1us,因此计数器计数一次的时间为1us;
43125668dff250099c.png
关于时钟分频因子,主要用于死区相关应用中,此处用不到,后面用到会做具体介绍;
关于计数模式,可配置为向上计数模式、向下计数模式或中央对齐模式,中央对齐模式为计数器交替向上向下计数模式,有3种中央对齐模式;
关于重复计数器,主要用于高级定时器中,关于重复计数器的介绍,可参考下链接:
https://www.cnblogs.com/liaigu/p/17782198.html
以上就是对定时器相关配置的介绍,关于定时器更新中断,有前面介绍可知,程序中预分频器的值设置为95,因此计数一次的时间是1us。程序中,自动重装值寄存器的值为1000-1,即999,从0计数到999需要计数1000次,因此总共计数时间为1us*1000=1ms,因此1ms进一次更新中断,可以在定时器中断中翻转IO查看对应时间,如下图:
85281668dff45c4b2e.png

(2)定时器PWM输出
PWM输出模式是定时器的基本功能之一。PWM 输出模式最常见的是使用重装值确定PWM 频率,使用捕获比较寄存器确定占空比的方法。PWM输出常用的模式有两种,PWM模式1和PWM模式2,关于这两种模式的介绍如下:
PWM模式1:
当向上计数模式时,当 计数器的值<比较/捕获寄存器的值 时,对应的PWM通道输出为高电平,否则为低电平。对应波形如下,配置自动重装值寄存器的值为100,比较/捕获寄存器的值为40,因此,高电平占比40%,低电平占比60%;
38670668dff7309c84.png
当向下计数模式时,当 计数器的值>比较/捕获寄存器的值 时,对应的PWM通道输出为低电平,否则为高电平。对应波形如下,配置自动重装值寄存器的值为100,比较/捕获寄存器的值为40,因此,高电平占比40%,低电平占比60%;
63842668dff82ecf9e.png
关于向上计数与向下计数模式的区别在于:
向上计数先输出高电平
向下计数先输出低电平
PWM模式2:
当向上计数模式时,当 计数器的值<比较/捕获寄存器的值 时,对应的PWM通道输出为低电平,否则为高电平。对应波形如下,配置自动重装值寄存器的值为100,比较/捕获寄存器的值为40,因此,高电平占比60%,低电平占比40%;
46286668dff97b9c42.png
当向下计数模式时,当 计数器的值>比较/捕获寄存器的值 时,对应的PWM通道输出为高电平,否则为低电平。对应波形如下,配置自动重装值寄存器的值为100,比较/捕获寄存器的值为40,因此,高电平占比40%,低电平占比60%;
69540668dffaa7b5dd.png
关于向上计数与向下计数模式的区别在于:
向上计数先输出低电平
向下计数先输出高电平
关于PWM周期、频率的计算:
81654668dffe9a69ba.png
其中:
arr表示自动重装值寄存器的值;
psc表示预分频器寄存器的值;
PCLK表示定时器挂载总线的时钟,如下图。其中TIM1是挂载在PB2总线上的,TIM2、TIM3和TIM4是挂载在PB1总线上的。
45465668e0000d839a.png
以EVT PWM输出例程为例,设置arr值为100-1,psc的值为48000-1,PB2总线时钟为96MHz,则PWM输出的周期
T=100*48000/96MHz=50ms
则PWM输出的频率
f=1/T=20Hz
使用逻辑分析仪采样PWM输出,波形如下:
34993668e0024d4e9a.png
从波形可以看到,PWM输出波形周期为50ms,频率为20Hz,与计算结果基本一致。
关于PWM输出占空比,主要是比较/捕获寄存器值与arr的值,arr的值为100-1,即99,从0开始计数,则计数100次,比较/捕获寄存器值设置为50,即计数到50进行一次翻转,50/100,因此占空比为50%。

(3)定时器输入捕获模式和PWM输入模式
输入捕获模式可用于测量捕获脉冲或脉宽频率。PWM输入模式是输入捕获模式的一种特殊情况,PWM输入模式一般用来测量PWM输出的占空比和频率。输入捕获模式可以对TIM的4个通道进行配置,但PWM输入模式只能使用TIM的CH1和CH2信号。此外,输入捕获模式和PWM输入模式在初始化配置上也有所不同。EVT例程中,输入捕获例程实际上就是PWM输入例程。
关于EVT输入捕获例程,在对PWM输入模式通道1进行配置的时候,实际上也是对通道2进行了配置,点进TIM_PWMIConfig函数,如下图:
69562668e00592c49e.png
该函数中,对通道1和通道2同时进行配置,因此在初始化的时候配置一个即可,在库函数中会将另外一个通道配置完成。
下面例程为EVT输入捕获例程:
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2023/12/26
  6. * Description        : Main program body.
  7. *********************************************************************************
  8. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
  9. * Attention: This software (modified or not) and binary are used for
  10. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
  11. *******************************************************************************/

  12. /*
  13. *@Note
  14. *Input capture routine:
  15. *TIM1_CH1(PA8)
  16. *This example demonstrates the TIM_CH1(PA8) pin floating input, which detects an
  17. *edge transition to trigger a TIM1 capture interrupt,The rising edge triggers the
  18. *TIM_IT_CC1 interrupt, and the falling edge triggers the TIM_IT_CC2 interrupt.
  19. *
  20. */

  21. #include "debug.h"

  22. /*********************************************************************
  23. * @fn      Input_Capture_Init
  24. *
  25. * [url=home.php?mod=space&uid=247401]@brief[/url]   Initializes TIM1 input capture.
  26. *
  27. * @param   arr - the period value.
  28. *          psc - the prescaler value.
  29. *          ccp - the pulse value.
  30. *
  31. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  32. */
  33. void Input_Capture_Init(u16 arr, u16 psc)
  34. {
  35.     GPIO_InitTypeDef        GPIO_InitStructure = {0};
  36.     TIM_ICInitTypeDef       TIM_ICInitStructure = {0};
  37.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};
  38.     NVIC_InitTypeDef        NVIC_InitStructure = {0};

  39.     RCC_PB2PeriphClockCmd(RCC_PB2Periph_GPIOA | RCC_PB2Periph_TIM1, ENABLE);

  40.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  41.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  42.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  43.     GPIO_ResetBits(GPIOA, GPIO_Pin_8);

  44.     TIM_TimeBaseInitStructure.TIM_Period = arr;
  45.     TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
  46.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  47.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  48.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
  49.     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

  50.     TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
  51.     TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  52.     TIM_ICInitStructure.TIM_ICFilter = 0x00;
  53.     TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  54.     TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

  55.     TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);

  56.     NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
  57.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  58.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  59.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  60.     NVIC_Init(&NVIC_InitStructure);

  61.     TIM_ITConfig(TIM1, TIM_IT_CC1 | TIM_IT_CC2, ENABLE);

  62.     TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);
  63.     TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
  64.     TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);
  65.     TIM_Cmd(TIM1, ENABLE);
  66. }

  67. /*********************************************************************
  68. * @fn      main
  69. *
  70. * [url=home.php?mod=space&uid=247401]@brief[/url]   Main program.
  71. *
  72. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  73. */
  74. int main(void)
  75. {
  76.     SystemCoreClockUpdate();
  77.     USART_Printf_Init(115200);
  78.     printf("SystemClk:%d\r\n", SystemCoreClock);
  79.     printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );

  80.     Input_Capture_Init(0xFFFF, 48000 - 1);

  81.     while(1);
  82. }

  83. void TIM1_CC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

  84. /*********************************************************************
  85. * @fn      TIM1_CC_IRQHandler
  86. *
  87. * [url=home.php?mod=space&uid=247401]@brief[/url]   This function handles TIM1  Capture Compare Interrupt exception.
  88. *
  89. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  90. */
  91. void TIM1_CC_IRQHandler(void)
  92. {
  93.     if( TIM_GetITStatus( TIM1, TIM_IT_CC1 ) != RESET )
  94.     {
  95.         printf( "CH1_Val:%d\r\n", TIM_GetCapture1( TIM1 ) );
  96.         TIM_SetCounter( TIM1, 0 );
  97.     }

  98.     if( TIM_GetITStatus( TIM1, TIM_IT_CC2 ) != RESET )
  99.     {
  100.         printf( "CH2_Val:%d\r\n", TIM_GetCapture2( TIM1 ) );
  101.     }

  102.     TIM_ClearITPendingBit( TIM1, TIM_IT_CC1 | TIM_IT_CC2 );
  103. }
若使用EVT例程对PWM输出波形进行采样,注意定时器的计数频率要在PWM输出频率的10倍以上,一般越大会越好一些。比如要采样的PWM输出频率为1KHz,周期为1ms,占空比为50%,那么定时器的计数频率可以设置在200KHz,arr值一般设置为最大,0xFFFF。psc的值则根据计数器频率进行计算,若计数器频率为200KHz,例程中PB2总线的时钟时96MHz,那么psc的值为480-1。根据上结果对例程进行修改,如下:
75230668e00b33a29e.png
修改之后对PWM输出波形进行采样,得到比较捕获寄存1的值是199,比较捕获寄存2的值是99,由手册可知,比较捕获寄存器1 的值就是PWM的周期,而比较捕获寄存器2的值就是其占空比。
57121668e00ed1c3c5.png
定时器的计数频率是200KHz,则计数一次的时间是5us。
根据比较捕获寄存器1 的值就是PWM的周期,比较捕获寄存1的值是199,那么周期大约为1000us,即1ms,与波形周期相符;
根据比较捕获寄存器2的值就是PWM的占空比,比较捕获寄存2的值是99,那么周期大约为500us,即0.5ms,与波形周期相比,占空比就是50%,与波形占空比相符;
下面例程为定时器输入捕获例程,如下:
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2023/12/26
  6. * Description        : Main program body.
  7. *********************************************************************************
  8. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
  9. * Attention: This software (modified or not) and binary are used for
  10. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
  11. *******************************************************************************/

  12. /*
  13. *@Note
  14. *USART Print debugging routine:
  15. *USART1_Tx(PA9).
  16. *This example demonstrates using USART1(PA9) as a print debug port output.
  17. *
  18. */

  19. #include "debug.h"

  20. /* Global typedef */

  21. /* Global define */

  22. /* Global Variable */
  23. volatile u8 flag=0;
  24. /*********************************************************************
  25. * @fn      Input_Capture_Init
  26. *
  27. * [url=home.php?mod=space&uid=247401]@brief[/url]   Initializes TIM1 input capture.
  28. *
  29. * @param   arr - the period value.
  30. *          psc - the prescaler value.
  31. *          ccp - the pulse value.
  32. *
  33. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  34. */
  35. void Input_Capture_Init(u16 arr, u16 psc)
  36. {

  37.     GPIO_InitTypeDef        GPIO_InitStructure = {0};
  38.     TIM_ICInitTypeDef       TIM_ICInitStructure = {0};
  39.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};
  40.     NVIC_InitTypeDef        NVIC_InitStructure = {0};

  41.     RCC_PB2PeriphClockCmd(RCC_PB2Periph_GPIOA | RCC_PB2Periph_TIM1, ENABLE);

  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  44.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  45.     GPIO_ResetBits(GPIOA, GPIO_Pin_8);

  46.     TIM_TimeBaseInitStructure.TIM_Period = arr;
  47.     TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
  48.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  49.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  50.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
  51.     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

  52.     TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
  53.     TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  54.     TIM_ICInitStructure.TIM_ICFilter = 0x00;
  55.     TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  56.     TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  57.     TIM_ICInit(TIM1, &TIM_ICInitStructure);

  58.     NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
  59.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  60.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  61.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  62.     NVIC_Init(&NVIC_InitStructure);

  63.     TIM_ClearITPendingBit( TIM1, TIM_IT_CC1 );

  64.     TIM_ITConfig(TIM1, TIM_IT_CC1 , ENABLE);

  65.     TIM_Cmd(TIM1, ENABLE);
  66. }


  67. /*********************************************************************
  68. * @fn      main
  69. *
  70. * [url=home.php?mod=space&uid=247401]@brief[/url]   Main program.
  71. *
  72. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  73. */
  74. int main(void)
  75. {
  76.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  77.     SystemCoreClockUpdate();
  78.     Delay_Init();
  79.     USART_Printf_Init(115200);
  80.     printf("SystemClk:%d\r\n", SystemCoreClock);
  81.     printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
  82.     printf("This is printf example\r\n");
  83.     Input_Capture_Init(0xFFFF, 960 - 1);

  84.     while(1)
  85.     {
  86.         if(flag==1)
  87.         {
  88.             flag=0;
  89.             printf( "CH1_Val:%d\r\n", TIM_GetCapture1( TIM1 ) );
  90.         }

  91.     }
  92. }


  93. void TIM1_CC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

  94. /*********************************************************************
  95. * @fn      TIM1_CC_IRQHandler
  96. *
  97. * @brief   This function handles TIM1  Capture Compare Interrupt exception.
  98. *
  99. * @return  none
  100. */
  101. void TIM1_CC_IRQHandler(void)
  102. {
  103.     if( TIM_GetITStatus( TIM1, TIM_IT_CC1 ) != RESET )
  104.     {
  105.         TIM_ClearITPendingBit( TIM1, TIM_IT_CC1 );
  106.         TIM_SetCounter( TIM1, 0 );
  107.         flag=1;
  108.     }
  109. }
该例程配置了单通道-通道1,且设置上升沿捕获,可用于捕获脉冲,在中断中将计数器的值清0并打印比较/捕获寄存器的值,注意打印通过相关标志位放在while循环中,不要放在中断中。通过该值可计算脉冲周期和频率。程序中,PB2总线时钟为96MHz,arr的值设置为0xFFFF,psc的值设置为960-1,则计数器计数一次的时间为0.01ms。程序中,打印值如下:
76283668e01740cc38.png
根据比较/捕获寄存器的值100,则计算出周期T=100*0.01ms=1ms,则频率f=1/T=1KHz。与实际相符。
49099668e01855db93.png

(4)定时器单脉冲模式
单脉冲模式可以用于让MCU响应一个特定的事件,使之在一个延迟之后产生一个脉冲,延迟和脉冲的宽度可编程。CH32L103 EVT提供了单脉冲模式例程,代码如下:
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2023/07/08
  6. * Description        : Main program body.
  7. *********************************************************************************
  8. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
  9. * Attention: This software (modified or not) and binary are used for
  10. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
  11. *******************************************************************************/

  12. /*
  13. *@Note
  14. *Single pulse output routine:
  15. *TIM2_CH1(PA0),TIM2_CH2(PA1)
  16. *This routine demonstrates that in single-pulse mode, when a rising edge is detected
  17. *on the TIM2_CH2(PA1) pin, the TIM2_CH1(PA0) outputs positive pulse.
  18. *
  19. */
  20. #include "debug.h"

  21. /*********************************************************************
  22. * @fn      One_Pulse_Init
  23. *
  24. * @brief   Initializes TIM1 one pulse.
  25. *
  26. * @param   arr - the period value.
  27. *          psc - the prescaler value.
  28. *          ccp - the pulse value.
  29. *
  30. * @return  none
  31. */
  32. void One_Pulse_Init(u16 arr, u16 psc, u16 ccp)
  33. {
  34.         GPIO_InitTypeDef GPIO_InitStructure={0};
  35.         TIM_OCInitTypeDef TIM_OCInitStructure={0};
  36.         TIM_ICInitTypeDef TIM_ICInitStructure={0};
  37.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};

  38.         RCC_PB2PeriphClockCmd( RCC_PB2Periph_GPIOA, ENABLE );
  39.         RCC_PB1PeriphClockCmd( RCC_PB1Periph_TIM2, ENABLE );

  40.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  41.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  42.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  43.         GPIO_Init( GPIOA, &GPIO_InitStructure );

  44.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  45.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  46.         GPIO_Init( GPIOA, &GPIO_InitStructure);

  47.         TIM_TimeBaseInitStructure.TIM_Period = arr;
  48.         TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
  49.         TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  50.         TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  51.         TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStructure);

  52.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
  53.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  54.         TIM_OCInitStructure.TIM_Pulse = ccp;
  55.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  56.         TIM_OC1Init( TIM2, &TIM_OCInitStructure );

  57.         TIM_ICStructInit( &TIM_ICInitStructure );
  58.         TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  59.         TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  60.         TIM_ICInitStructure.TIM_ICFilter = 0x00;
  61.         TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  62.         TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  63.         TIM_ICInit( TIM2, &TIM_ICInitStructure );

  64.         TIM_SelectOnePulseMode( TIM2,TIM_OPMode_Single );
  65.         TIM_SelectInputTrigger( TIM2, TIM_TS_TI2FP2 );
  66.         TIM_SelectSlaveMode( TIM2, TIM_SlaveMode_Trigger );
  67. }

  68. /*********************************************************************
  69. * @fn      main
  70. *
  71. * @brief   Main program.
  72. *
  73. * @return  none
  74. */
  75. int main(void)
  76. {
  77.         SystemCoreClockUpdate();
  78.         USART_Printf_Init(115200);
  79.         printf("SystemClk:%d\r\n",SystemCoreClock);
  80.         printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );

  81.         One_Pulse_Init( 200, 48000-1, 100 );

  82.         while(1);
  83. }
程序中,配置TIM2 通道1产生脉冲,通道2用于输入捕获,捕获到上升沿,则通道1产生脉冲事件。
需要注意,脉冲的产生需要一定的延迟Tdelay,比如程序中配置检测到上升沿后经过Tdelay产生一个脉冲,这个Tdelay时间由比较捕获寄存器的值确定,例程中比较捕获寄存器的值是100,而定时器2计数一次的时间为1/(96MHz/(48000-1+1))=0.5ms,则延迟时间Tdelay=100*0.5=50ms。脉冲的脉宽=(200-100)*0.5=50ms。
关于此处计数一次时间的计算,TIM2是挂载在PB1总线上的,其中PB1总线时钟为HCLK/2=48MHz,具体可看系统主频配置那部分,当用于TIM2时钟时,由于是2分频,因此还要乘以2,如下图,则就是96MHz.
70279668e01da1d3dc.png
程序中,配置计数时钟预分频器的值是48000-1,则计数器的时钟频率等于96MHz/(48000-1+1)=2KHz,则计数一次的时间等于1/2KHz=0.5ms
71112668e01ecbb9d4.png
该例程测试波形如下:
17182668e0203db7c4.png
如图,通道2检测到上升沿50ms后,通道1产生1个脉冲,脉宽为50ms。

(5)定时器比较输出模式
比较输出模式的原理是在计数器的值与比较捕获寄存器的值一致时,输出特定的变化或波形。CH32L103 EVT提供了比较输出模式例程,代码如下:
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2023/07/08
  6. * Description        : Main program body.
  7. *********************************************************************************
  8. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
  9. * Attention: This software (modified or not) and binary are used for
  10. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
  11. *******************************************************************************/

  12. /*
  13. *@Note
  14. *Output comparison mode routine:
  15. *TIM1_CH1(PA8)
  16. *This example demonstrates the output waveform of the TIM_CH1(PA8) pin
  17. *in 4 output comparison modes.Output compare modes include OutCompare_Timing\
  18. *OutCompare_Active\OutCompare_Inactive\OutCompare_Toggle.
  19. *
  20. */

  21. #include "debug.h"

  22. /* Output Compare Mode Definition */
  23. #define OutCompare_Timing   0
  24. #define OutCompare_Active   1
  25. #define OutCompare_Inactive 2
  26. #define OutCompare_Toggle   3

  27. /* Output Compare Mode Selection */
  28. //#define OutCompare_MODE OutCompare_Timing
  29. //#define OutCompare_MODE OutCompare_Active
  30. //#define OutCompare_MODE OutCompare_Inactive
  31. #define OutCompare_MODE OutCompare_Toggle

  32. /*********************************************************************
  33. * @fn      TIM1_OutCompare_Init
  34. *
  35. * @brief   Initializes TIM1 output compare.
  36. *
  37. * @param   arr - the period value.
  38. *          psc - the prescaler value.
  39. *          ccp - the pulse value.
  40. *
  41. * @return  none
  42. */
  43. void TIM1_OutCompare_Init(u16 arr, u16 psc, u16 ccp)
  44. {
  45.         GPIO_InitTypeDef GPIO_InitStructure={0};
  46.         TIM_OCInitTypeDef TIM_OCInitStructure={0};
  47.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};

  48.         RCC_PB2PeriphClockCmd( RCC_PB2Periph_GPIOA | RCC_PB2Periph_TIM1, ENABLE );

  49.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  50.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  51.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  52.         GPIO_Init( GPIOA, &GPIO_InitStructure );

  53.         TIM_TimeBaseInitStructure.TIM_Period = arr;
  54.         TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
  55.         TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  56.         TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  57.         TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure);

  58. #if (OutCompare_MODE == OutCompare_Timing)
  59.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;

  60. #elif (OutCompare_MODE == OutCompare_Active)
  61.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active;

  62. #elif (OutCompare_MODE == OutCompare_Inactive)
  63.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Inactive;

  64. #elif (OutCompare_MODE == OutCompare_Toggle)
  65.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;

  66. #endif

  67.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  68.         TIM_OCInitStructure.TIM_Pulse = ccp;
  69.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  70.         TIM_OC1Init( TIM1, &TIM_OCInitStructure );

  71.         TIM_CtrlPWMOutputs(TIM1, ENABLE );
  72.         TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Disable );
  73.         TIM_ARRPreloadConfig( TIM1, ENABLE );
  74.         TIM_Cmd( TIM1, ENABLE );
  75. }

  76. /*********************************************************************
  77. * @fn      main
  78. *
  79. * @brief   Main program.
  80. *
  81. * @return  none
  82. */
  83. int main(void)
  84. {
  85.         SystemCoreClockUpdate();
  86.         USART_Printf_Init(115200);
  87.         printf("SystemClk:%d\r\n",SystemCoreClock);
  88.         printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );

  89.         TIM1_OutCompare_Init( 100, 48000-1, 50 );

  90.         while(1);
  91. }
例程中,提供了比较输出模式下的4种配置:
第一种:冻结,即比较捕获寄存器的值与核心计数器间的比较值对OC1REF不起作用;
第二种: 强制设为有效电平,即当核心计数器与比较捕获寄存器的值相同时,强制OC1REF 为高,波形如下:
64316668e02596b787.png
第三种: 强制设为无效电平,即当核心计数器与比较捕获寄存器的值相同时,强制OC1REF 为低,波形如下:
81445668e02709c692.png
第四种,翻转,即当核心计数器与比较捕获寄存器的值相同时,翻转OC1REF的电平,波形如下:
58195668e02834423a.png
程序中计数器计数一次的时间是0.5ms,比较寄存器的值为100,因此50ms翻转一次。
关于翻转模式,可以理解为在一个周期内产生多个翻转。正常PWM输出可以理解为一个周期产生一次翻转。翻转模式下,一个周期内可以产生多次翻转。
关于翻转模式,就是将定时器输出模式设置为TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle。普通的PWM输出高低电平是根据CNT计数器中的值和CCR进行比较,若CNT<CCR则输出一种状态电平,当CNT介于CCR和ARR之间时,输出另一种状态电平。TIM_OCMode_Toggle模式就是当CNT=CCR时,输出引脚的电平会进行翻转,可以通过TIM_OCMode_Toggle模式进入中断后重新设置CCR寄存器中的值,即可以在一个周期内产生多次翻转。
TIM_OCMode_Toggle模式下,当CNT计数值=CCR时,会进入比较中断(在这里中断源是TIM_IT_CC1/2/3/4),也就是说当CNT计数值从0开始一直计数到CCR时,会触发TIM_IT_CC中断源,并进入中断,进入中断后修改CCR寄存器中的值。先将此时的CCR寄存器中的值放入到一个变量中(TIM_GetCapture1(TIM1)),再在这个变量的基础上加上相同的数,同时赋给CCR寄存器中TIM_SetCompare1(TIM1),那么在下一次CNT=CCR时又会进行翻转电平。具体程序配置如下图:
63731668e02adced13.png
举一个例子:若一开始定时器ARR为65535,CCR为9999,那么当CNT从0开始一直加到9999,假设电平为低电平,当加到9999时,会通过TIM_IT_CC中断源进入TIM中断(这个中断源只有当CNT计数值到CCR时才会触发)在中断服务函数中,将当前CCR的值放入capture这个变量中,再在capture值的基础上再加上相同的数(9999),同时作为新的CCR赋给定时器,这里叫CCR_NEW,CCR_NEW=9999+9999=19998。在CNT从9999计数19998时,此时CNT=CCR_NEM,又会进行翻转变为高电平,此时又会进入中断,在在CCR_NEW的基础上加上9999,以此类推,因此可以实现在一个周期内有多个脉冲出现,且占空比为50%。

(6)定时器互补输出和死区
比较捕获通道一般有两个输出引脚(比较捕获通道 4 只有一个输出引脚),如下图,能输出两个互补的信号(OCx 和 OCxN),OCx 和 OCxN 可以通过 CCxP 和 CCxNP 位独立地设置极性,通过 CCxE 和 CCxNE独立地设置输出使能,通过 MOE、OIS、OISN、OSSI、OSSR 位进行死区和其他的控制。
51435668e02df1ef43.png
同时使能OCx和OCxN输出将插入死区,每个通道都有一个 10 位的死区发生器。如果存在刹车电路则还要设置MOE位。OCx和OCxN由OCxREF关联产生,如果OCx和OCxN都是高有效,那么OCx与OCxREF相同,只是 OCx 的上升沿相当于OCxREF有一个延迟,OCxN与 OCxREF相反,它的上升沿相对参考信号的下降沿会有一个延迟,如果延迟大于有效输出宽度,则不会产生相应的脉冲。
下图图展示了OCx和OCxN与OCxREF的关系,并展示出死区。
23687668e02ff62b47.png
EVT例程演示了TIM1死区的3种互补输出模式:
第一种:互补输出带死区插入,波形如下图:
44706668e0310a624f.png
图中,延迟时间delay大约是10.5us,关于delay时间的计算,主要由刹车和死区寄存器(TIM1_BDTR)的位[7:0]决定的,如下图:
92110668e0322147dc.png
例程中,对死区时间设置为0xFF,即该8位均为1,则DT=(32+31)*16*TDTS,其中Tdts由控制寄存器 1(TIMx_CTLR1)位[9:8]决定,如下图:
620668e033739c80.png
例程中,该两位配置为00,即Tdts=Tck_int,Tck_int=1/96MHz,则DT=63*16/96MHz=10.5us。
第二种:死区波形延迟大于负脉冲,波形如下图:
32763668e034aea8a4.png
图中,互补通道输出一直为高电平,因为delay时间为10.5us,而程序中定时器重装载值为100,预分频器值为48-1,比较寄存器值为10,而定时器计数一次的时间为0.5us,因此有效输出宽度为5us,小于delay时间,因此不会产生相应的脉冲。
程序中通道1 PWM输出模式配置为PWM模式2,且向上计数,因此计数器值大于比较寄存器值时为有效电平,此处极性配置为低,因此有效电平为低电平,互补通道同样为低有效。
第三种:死区波形延迟大于正脉冲,波形如下图:
85300668e035b51744.png
图中,通道1输出一直为高电平,因为delay时间为10.5us,而程序中定时器重装载值为100,预分频器值为48-1,比较寄存器值为90,而定时器计数一次的时间为0.5us,因此有效输出宽度为5us,小于delay时间,因此不会产生相应的脉冲。
程序中PWM输出模式配置为PWM模式2,且向上计数,因此计数器值大于比较寄存器值时为有效电平,此处极性配置为低,因此有效电平为低电平,有效电平宽度为5us。

(7)定时器刹车信号
当产生刹车信号时,输出使能信号和无效电平都会根据MOE、OIS、OISN、OSSI和OSSR等位进行修改。但OCx和 OCxN不会在任何时间都处在有效电平。刹车事件源可以来自于刹车输入引脚,也可以是一个时钟失败事件,而时钟失败事件由CSS(时钟安全系统)产生。下为刹车信号相关代码:
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2023/07/08
  6. * Description        : Main program body.
  7. *********************************************************************************
  8. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
  9. * Attention: This software (modified or not) and binary are used for
  10. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
  11. *******************************************************************************/

  12. /*
  13. *@Note
  14. *Complementary output and deadband insertion mode routines:
  15. *TIM1_CH1(PA8),TIM1_CH1N(PB13)
  16. *This example demonstrates three complementary output modes with dead zone of TIM1: complementary
  17. *output with dead zone insertion, dead zone waveform delay Greater than the negative pulse, the dead
  18. *zone waveform delay is greater than the positive pulse.
  19. *
  20. */

  21. #include "debug.h"

  22. /*********************************************************************
  23. * @fn      TIM1_Dead_Time_Init
  24. *
  25. * @brief   Initializes TIM1 complementary output and dead time.
  26. *
  27. * @param   arr - the period value.
  28. *          psc - the prescaler value.
  29. *          ccp - the pulse value.
  30. *
  31. * @return  none
  32. */
  33. void TIM1_Dead_Time_Init(u16 arr, u16 psc, u16 ccp)
  34. {
  35.     GPIO_InitTypeDef        GPIO_InitStructure = {0};
  36.     TIM_OCInitTypeDef       TIM_OCInitStructure = {0};
  37.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};
  38.     TIM_BDTRInitTypeDef     TIM_BDTRInitStructure = {0};

  39.     RCC_PB2PeriphClockCmd(RCC_PB2Periph_GPIOA | RCC_PB2Periph_GPIOB | RCC_PB2Periph_TIM1, ENABLE);

  40.     /* TIM1_CH1 */
  41.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  42.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  43.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  44.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  45.     /* TIM1_CH1N */
  46.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  47.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  48.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  49.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  50.     /* TIM1_BK1N */
  51.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  52.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  53.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  54.     GPIO_Init(GPIOB, &GPIO_InitStructure);
  55.     GPIO_ResetBits(GPIOB, GPIO_Pin_12);

  56.     TIM_TimeBaseInitStructure.TIM_Period = arr;
  57.     TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
  58.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  59.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  60.     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

  61.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  62.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  63.     TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
  64.     TIM_OCInitStructure.TIM_Pulse = ccp;
  65.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  66.     TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
  67.     TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  68.     TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
  69.     TIM_OC1Init(TIM1, &TIM_OCInitStructure);

  70.     TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
  71.     TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
  72.     TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
  73.     TIM_BDTRInitStructure.TIM_DeadTime = 0xFF;
  74.     TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
  75.     TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
  76.     TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  77.     TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

  78.     TIM_CtrlPWMOutputs(TIM1, ENABLE);
  79.     TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Disable);
  80.     TIM_ARRPreloadConfig(TIM1, ENABLE);
  81.     TIM_Cmd(TIM1, ENABLE);
  82. }

  83. /*********************************************************************
  84. * @fn      main
  85. *
  86. * @brief   Main program.
  87. *
  88. * @return  none
  89. */
  90. int main(void)
  91. {
  92.     SystemCoreClockUpdate();
  93.     USART_Printf_Init(115200);
  94.     printf("SystemClk:%d\r\n", SystemCoreClock);
  95.     printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );

  96.     /* Complementary output with dead-time insertion */
  97.     TIM1_Dead_Time_Init(100, 48 - 1, 50);
  98.     /* Dead-time waveforms with delay greater than the negative pulse */
  99. //      TIM1_Dead_Time_Init( 100, 48-1, 10 );
  100.     /* Dead-time waveforms with delay greater than the positive pulse. */
  101. //        TIM1_Dead_Time_Init( 100, 48-1, 90 );

  102.     while(1);
  103. }
程序中,对于刹车信号的配置主要是对刹车和死区寄存器(TIM1_BDTR)进行配置。程序中,使能配置开启刹车输入,且刹车输入高电平有效,即当刹车输入引脚PB12引脚检测到高电平信号时,会进行刹车,停止PWM输出,如下图:
82218668e039a329b7.png

(8)关于利用PWM实现播放音乐
利用PWM实现播放音乐,可参考下帖:
https://bbs.21ic.com/icview-3134310-1-1.html
https://bbs.21ic.com/icview-3134344-1-1.html

附件为相关例程,可以参考一下。

     

CH32L103 TIM例程.zip

4.09 MB, 下载次数: 4

我喜欢打游戏 发表于 2024-7-15 15:13 | 显示全部楼层
好详细,好完整
tpgf 发表于 2024-7-18 09:34 | 显示全部楼层
高级定时器和普通的定时器的区别体现在哪些方面呢
观海 发表于 2024-7-18 10:04 | 显示全部楼层
普通的定时器为什么不建议用在pwm的输出上呢

评论

都可以用,没有不建议用  发表于 2024-7-18 15:57
guanjiaer 发表于 2024-7-18 11:01 | 显示全部楼层
想要输出不同的音乐 是需要调节pwm的频率还是pwm的占空比呢

评论

占空比吧  发表于 2024-7-18 16:00
 楼主| L-MCU 发表于 2024-7-18 15:57 | 显示全部楼层
tpgf 发表于 2024-7-18 09:34
高级定时器和普通的定时器的区别体现在哪些方面呢

631606698cacda6a7e.png
keaibukelian 发表于 2024-7-18 22:45 | 显示全部楼层
向上计数达到最大值之后自动从0开始计数吗
heimaojingzhang 发表于 2024-7-18 23:17 | 显示全部楼层
单片机能输出的pwm的频率是受到主频的限制还是引脚的限制呢
八层楼 发表于 2024-7-18 23:49 | 显示全部楼层
定时器上下计数模式如果溢出了 会产生中断吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

39

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部