• 14.TIM输出比较示例程序(PWM驱动LED呼吸灯&PWM驱动舵机&PWM驱动直流电机)


    目录

    输出比较相关库函数

    PWM驱动LED呼吸灯

    PWM驱动舵机

    PWM驱动直流电机


    STM32标准库开发-超详细笔记-传送门_Archie_IT的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_61712829/article/details/132434192?spm=1001.2014.3001.5501输出比较相关库函数

    1.OC初始化(掌握

    1. // 配置输出比较模块,输出比较单元有四个,对应也有四个函数
    2. // 第二个参数是结构体,就是输出比较的一些参数
    3. void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
    4. void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
    5. void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
    6. void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
    7. // 给输出比较结构体赋一个默认值(防止结构体的值不确定导致一些奇怪的问题)
    8. void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);

    2.OC参数更改(TIM_SetComparex函数最重要,其他的了解即可)

    1. // 使用高级定时器输出PWM波形时使能主输出,否则PWM波形不能正常输出
    2. void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
    3. // 单独设置输出比较的输出极性(带N的是高级定时器中互补通道的配置)
    4. // 在这里可以设置输出极性,在OC初始化函数中也可以用结构体设置输出极性,这里相当于将单独修改结构体中的某一参数封装到一个函数中
    5. //在结构体初始化的那个函数里也可以设置极性,这两个地方设置极性的作用是一样的,只不过是用结构体是一起初始化的,在这里是单独函数进行修改的
    6. //一般来说,结构体里的参数都会有一个单独的函数可进行更改
    7. void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
    8. void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
    9. void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
    10. void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
    11. void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
    12. void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
    13. void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
    14. // 单独修改输出使能参数
    15. void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
    16. void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);
    17. // 单独更改输出比较模式的函数
    18. void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
    19. // 单独更改CCR寄存器值的函数
    20. //在运行时,更改占空比,就需要用到这四个函数
    21. void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
    22. void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
    23. void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
    24. void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);

     3.OC输出比较的一些小功能(不常用,了解即可)

    1. // 配置强制输出模式(运行中暂停输出波形且强制输出高/低电平)
    2. // 强制输出高电平和设置100%占空比等效,强制输出低电平和设置0%占空比等效
    3. void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
    4. void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
    5. void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
    6. void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
    7. // 配置CCR寄存器的预装功能(影子寄存器,就是写入的值不会立即生效而是在更新事件才会生效,可以避免一些小问题)
    8. void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    9. void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    10. void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    11. void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    12. // 配置快速使能(手册中“单脉冲模式”一节有介绍)
    13. void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
    14. void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
    15. void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
    16. void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
    17. // 清除REF信号(手册中在“外部事件时清除REF信号”一节有介绍)
    18. void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
    19. void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
    20. void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
    21. void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);

    4.补充

    1. //仅高级定时器使用
    2. //在使用高级定时器输出PWM时。需要调用这个函数,使能输出。否则PWM将不能正常输出
    3. void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

    5.补充

     //TIM_OCMode 输出比较模式中的选择

    • TIM_OCMode_Timing//冻结模式
    • TIM_OCMode_Active//相等时置有效电平
    • TIM_OCMode_Inactive//相等时置无效电平
    • TIM_OCMode_Toggle//相等时电平翻转
    • TIM_OCMode_PWM1//PWM模式1,主要用
    • TIM_OCMode_PWM2//PWM模式2
    • TIM_ForcedAction_Active//强制输出模式,初始化时不使用
    • TIM_ForcedAction_InActive

    TIM_Output_Compare_Polarity  输出比较的极性选择

    • TIM_OCPolarity_High  //高极性,就是极性不翻转,REF波形直接输出,或者说是有效电平是高电平,REF有效时,输出高电平
    • TIM_OCPolarity_Low //低极性,就是REF电平取反,或者说是有效电平为低电平

    PWM驱动LED呼吸灯

            接线图如下:注意LED是正极接在PA0引脚,负极接在GND的驱动方法,这样就是高电平点亮,低电平熄灭,这是正极性的驱动方法,这样的话观察更直观一点,就是占空比越大LED越亮,占空比越小LED越暗 。

    main.c

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "PWM_LED.h"
    5. uint8_t i;
    6. int main(void)
    7. {
    8. OLED_Init(); //初始化OLED
    9. pwm_init();
    10. while(1)
    11. {
    12. //不断调用PWM_SetCompare1函数,更改CCR的值,实现LED呼吸灯的效果
    13. for(i=0;i<=100;i++)
    14. {
    15. PWM_SetCompare1(i);//设置CCR寄存器的值
    16. Delay_ms(10);
    17. }
    18. for(i=0;i<=100;i++)
    19. {
    20. PWM_SetCompare1(100-i);
    21. Delay_ms(10);
    22. }
    23. }
    24. }

    PWM_LED.c

    1. #include "stm32f10x.h" // Device header
    2. /*
    3. pwm初始化函数基本步骤(参考笔记PWM基本结构图)
    4. 第一步,RCC开启时钟,把要用的TIM外设和GPIO外设的时钟打开
    5. 第二步,配置单元,包括时钟源选择和时基单元都配置好
    6. 第三步,配置输出比较单元,包括CCR值、输出比较模式、极性选择、输出使能这些参数,在库函数里也是用结构体统一来配置
    7. 第四步,配置GPIO,把PWM对应的GPIO口,初始化为复用推挽输出的配置,Pwm和GPIO的对应关系可以参考引脚定义表
    8. 第五步,运行控制,启动计数器,这样就能输出PWM了
    9. */
    10. void pwm_init(void)
    11. {
    12. //1.打开时钟,选择内部时钟
    13. //使用APB1的开启时钟函数,TIM2是APB1总线的外设
    14. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    15. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //打开时钟
    16. //引脚重映射内容,将PA0引脚重映射到PA15,将下面GPIO改为PA15其它不动
    17. // RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//引脚重映射;引脚重映射(TIM2CH1本来是挂载在PA0引脚的,现在我想在其他引脚使用TIM2CH1通道
    18. // GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//参考手册AFIO。将PA0引脚重映射到PA15,第一个参数可以是GPIO_PartialRemap1_TIM2或GPIO_FullRemap_TIM2
    19. // GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//取消调试端口复用JTAG,PA15端口默认使用JTAG调试端口,需要关闭;SWJ就是SWD和JTAG两种调试方式;若想用PA15\PB3\PB4三个引脚做GPIO使用,先打开AFIO再将JTAG复用解除
    20. //2.初始化时基单元
    21. //选择时基单元的时钟,选择内部时钟;若不调用这个函数,系统上电也是默认是内部时钟
    22. TIM_InternalClockConfig(TIM2);
    23. //3.配置时基单元
    24. TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    25. TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //指定时钟分频
    26. TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式
    27. /*
    28. 公式:
    29. PWM频率:Freq = CK_PSC / (PSC + 1) / (ARR + 1)
    30. PWM占空比:Duty = CCR / (ARR + 1)
    31. PWM分辨率:Reso = 1 / (ARR + 1)
    32. 若PWM波形为频率为1KHz,占空比为50%,分辨率为1%
    33. CK_PSC=72MHz
    34. 代入公式:
    35. Freq =1000Hz=72MHz / 720 / 100
    36. Duty = 50% = 50 / 100
    37. Reso = 1% = 1 / 100
    38. 因此:PSC=719,ARR=99,ARR=50
    39. */
    40. TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR 周期
    41. TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSC 预分频器
    42. TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值
    43. TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    44. TIM_ClearFlag(TIM2,TIM_FLAG_Update);
    45. //4.初始化输出比较单元(通道)
    46. TIM_OCInitTypeDef TIM_OCInitStructure;
    47. TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值;若不想把所有成员都列一遍赋值,就可以先用这个函数赋一个初始值,再更改你想改的值
    48. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置输出比较的模式
    49. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//设置输出比较的极性
    50. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能(输出状态)
    51. TIM_OCInitStructure.TIM_Pulse = 50;//设置CCR,Pulse直译是脉冲
    52. TIM_OC1Init(TIM2, &TIM_OCInitStructure);//使用PA0口对应是第一个输出比较通道;在TIM2的OC1通道上就可以输出PWM波形了
    53. //5.初始化GPIO
    54. GPIO_InitTypeDef GPIO_InitStructure; //结构体变量名GPIO_InitStructure
    55. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出;PWM波形通过引脚输出,使用定时器来控制引脚,输出数据寄存器将被断开,输出控制权将转移给片上外设(这里片上外设引脚连接的就是TIM2CH1通道)
    56. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    57. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //默认50mhz输出
    58. GPIO_Init(GPIOA,&GPIO_InitStructure); //使用的是地址传递
    59. //6.启动定时器
    60. TIM_Cmd(TIM2,ENABLE);//PWM波形就能通过PA0输出了
    61. }
    62. //让LED呈现呼吸灯的效果,那就是不断更改CCR的值就行了
    63. //在运行过程更改CCR,使用函数TIM_SetCompare1封装用来单独更改通道1的CCR值
    64. //TIM_SetCompare1封装
    65. void PWM_SetCompare1(uint16_t Compare1)
    66. {
    67. TIM_SetCompare1(TIM2,Compare1);
    68. }

    PWM驱动舵机

            驱动舵机的关键就是输出一个下面一样的PWM波形,只要波形能够按照如下规定,准确的输出,那驱动舵机就非常简单了。

    main.c

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "serve.h"
    5. #include "key.h"
    6. uint8_t keynum; //按键键码
    7. float angle;//角度变量
    8. int main(void)
    9. {
    10. OLED_Init(); //初始化OLED
    11. serve_init();
    12. key_init();
    13. OLED_ShowString(1, 1 ,"angle:");
    14. //serve_setangle(120); //舵机设置角度
    15. //PWM_SetCompare2(500); //对应舵机0度的位置
    16. //建立一个舵机模块,封装函数。调用函数就能变为对应的角度,舵机设置角度,参数是0180
    17. while(1)
    18. {
    19. keynum = key_getnum();
    20. if(keynum == 1)
    21. {
    22. angle += 30;
    23. if(angle > 180)
    24. {
    25. angle = 0;
    26. }
    27. }
    28. serve_setangle(angle); //舵机设置角度
    29. OLED_ShowNum(1,7,angle,3);//一行七列显示angle变量长度为3
    30. }
    31. }

    pwm_led.c

    1. #include "stm32f10x.h" // Device header
    2. /*
    3. pwm初始化函数基本步骤(参考笔记PWM基本结构图)
    4. 第一步,RCC开启时钟,把要用的TIM外设和GPIO外设的时钟打开
    5. 第二步,配置单元,包括时钟源选择和时基单元都配置好
    6. 第三步,配置输出比较单元,包括CCR值、输出比较模式、极性选择、输出使能这些参数,在库函数里也是用结构体统一来配置
    7. 第四步,配置GPIO,把PWM对应的GPIO口,初始化为复用推挽输出的配置,Pwm和GPIO的对应关系可以参考引脚定义表
    8. 第五步,运行控制,启动计数器,这样就能输出PWM了
    9. */
    10. //驱动舵机用的是PA1口的通道2
    11. void pwm_init(void)
    12. {
    13. //1.打开时钟,选择内部时钟
    14. //使用APB1的开启时钟函数,TIM2是APB1总线的外设
    15. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    16. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //打开时钟
    17. //2.初始化时基单元
    18. //选择时基单元的时钟,选择内部时钟;若不调用这个函数,系统上电也是默认是内部时钟
    19. TIM_InternalClockConfig(TIM2);
    20. //3.配置时基单元
    21. /*
    22. **********************************************************
    23. 公式:
    24. PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
    25. PWM占空比:Duty = CCR / (ARR + 1)
    26. PWM分辨率:Reso = 1 / (ARR + 1)
    27. ************************************************************
    28. 若PWM波形为频率为1KHz,占空比为50%,分辨率为1%
    29. 舵机要求的周期是20ms,频率就是1/20ms=50hz;舵机要求高电平时间是0.5ms-2.5ms,也就是占空比
    30. ARR设置为20k对应20ms(计数器加一次就是1us)
    31. CCR设置500就是0.5ms,设置2500就是2.5ms
    32. */
    33. TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    34. TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //指定时钟分频
    35. TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式
    36. TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //ARR 周期
    37. TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC 预分频器
    38. TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值
    39. TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    40. TIM_ClearFlag(TIM2,TIM_FLAG_Update);
    41. //4.初始化输出比较单元(通道)
    42. TIM_OCInitTypeDef TIM_OCInitStructure;
    43. TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值;若不想把所有成员都列一遍赋值,就可以先用这个函数赋一个初始值,再更改你想改的值
    44. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置输出比较的模式
    45. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//设置输出比较的极性
    46. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能(输出状态)
    47. TIM_OCInitStructure.TIM_Pulse = 50;//设置CCR,Pulse直译是脉冲
    48. TIM_OC2Init(TIM2, &TIM_OCInitStructure);//OC2是通道2;通道和引脚是对应的;对于同一个定时器的不同通道输出的PWM的特点如后:因为不同通道共用一个计数器,所以它们的频率必须是一样的,它们的占空比由各自的CCR决定的;由于计数器的更新,所有PWM同时跳变,所以它们的相位是同步的
    49. //5.初始化GPIO
    50. GPIO_InitTypeDef GPIO_InitStructure; //结构体变量名GPIO_InitStructure
    51. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出;PWM波形通过引脚输出,使用定时器来控制引脚,输出数据寄存器将被断开,输出控制权将转移给片上外设(这里片上外设引脚连接的就是TIM2CH1通道)
    52. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    53. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //默认50mhz输出
    54. GPIO_Init(GPIOA,&GPIO_InitStructure); //使用的是地址传递
    55. //6.启动定时器
    56. TIM_Cmd(TIM2,ENABLE);//PWM波形就能通过PA0输出了
    57. }
    58. //TIM_SetCompare2封装,使用通道2
    59. void PWM_SetCompare2(uint16_t Compare)
    60. {
    61. TIM_SetCompare2(TIM2,Compare);
    62. }

    serve.c

    1. #include "stm32f10x.h" // Device header
    2. #include "PWM_LED.h" //继承pwm的功能
    3. //舵机初始化函数
    4. void serve_init(void)
    5. {
    6. pwm_init();//将pwm底层初始化
    7. }
    8. /*
    9. 0度 对应 CCR 500
    10. 180 2500
    11. 对angle进行缩放。0-180180范围,500-25002000范围,所以angle / 180*2000 + 500偏移,就得到目标比例了完成0-180500-2500的映射了
    12. */
    13. void serve_setangle(float angle) //舵机设置角度
    14. {
    15. PWM_SetCompare2(angle / 180 * 2000 + 500);//线性映射
    16. }

    PWM驱动直流电机

    • VM是电机电源,接在STLINK的5v引脚
    • VCC逻辑电源接在面包板3.3v正极
    • A01和AO2是电机输出端接电机的两根线,接线不分正反,对调两根线,电机的旋转方向就会反过来
    • STBY是待机控制脚,不需要待机,直接接逻辑电源正3.3v
    • 控制引脚 AIN1和AIN2是方向控制,任意接两个GPIO就可以
    • 控制引脚 PWMA是速度控制,需接PWM的输出脚,PA2对应的是TIM2的通道3

            加大PWM频率,当PWM频率足够大时,超出人耳的范围,人耳就听不到了,人耳听到的范围是20Hz到20KHz。可以减小PSC来加大频率且不会影响占空比  

    main.c

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "OLED.h"
    4. #include "moter.h"
    5. #include "key.h"
    6. uint8_t keynum;//按键键码
    7. int8_t speed;//有符号的速度变量
    8. int main(void)
    9. {
    10. OLED_Init(); //初始化OLED
    11. moter_init();
    12. key_init();
    13. OLED_ShowString(1,1,"speed:");
    14. while(1)
    15. {
    16. keynum = key_getnum();
    17. if(keynum == 1)
    18. {
    19. speed += 20;
    20. if(speed > 100)
    21. {
    22. speed = -100;//speed从-100100变化
    23. }
    24. }
    25. moter_setspeed(speed);//实现按键控制速度
    26. OLED_ShowSignedNum(1,7,speed,3);
    27. }
    28. }

    PWM_LED.c

    1. #include "stm32f10x.h" // Device header
    2. /*
    3. pwm初始化函数基本步骤(参考笔记PWM基本结构图)
    4. 第一步,RCC开启时钟,把要用的TIM外设和GPIO外设的时钟打开
    5. 第二步,配置单元,包括时钟源选择和时基单元都配置好
    6. 第三步,配置输出比较单元,包括CCR值、输出比较模式、极性选择、输出使能这些参数,在库函数里也是用结构体统一来配置
    7. 第四步,配置GPIO,把PWM对应的GPIO口,初始化为复用推挽输出的配置,Pwm和GPIO的对应关系可以参考引脚定义表
    8. 第五步,运行控制,启动计数器,这样就能输出PWM了
    9. */
    10. //1.电机接在TIM2的通道3上。修改:GPIO_Pin_2。TIM_OC3Init。PWM_SetCompare3
    11. //2.对于直流电机也建立一个hardware模块
    12. void pwm_init(void)
    13. {
    14. //1.打开时钟,选择内部时钟
    15. //使用APB1的开启时钟函数,TIM2是APB1总线的外设
    16. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    17. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //打开时钟
    18. //2.初始化时基单元
    19. //选择时基单元的时钟,选择内部时钟;若不调用这个函数,系统上电也是默认是内部时钟
    20. TIM_InternalClockConfig(TIM2);
    21. //3.配置时基单元
    22. TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    23. TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //指定时钟分频
    24. TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式
    25. /*
    26. 公式:
    27. PWM频率:Freq = CK_PSC / (PSC + 1) / (ARR + 1)
    28. PWM占空比:Duty = CCR / (ARR + 1)
    29. PWM分辨率:Reso = 1 / (ARR + 1)
    30. 若PWM波形为频率为1KHz,占空比为50%,分辨率为1%
    31. CK_PSC=72MHz
    32. 代入公式:
    33. Freq =1000Hz=72MHz / 720 / 100
    34. Duty = 50% = 50 / 100
    35. Reso = 1% = 1 / 100
    36. 因此:PSC=719,ARR=99,ARR=50
    37. */
    38. TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR 周期
    39. TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; //PSC 预分频器,现在为20KHz
    40. TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值
    41. TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    42. TIM_ClearFlag(TIM2,TIM_FLAG_Update);
    43. //4.初始化输出比较单元(通道)
    44. TIM_OCInitTypeDef TIM_OCInitStructure;
    45. TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值;若不想把所有成员都列一遍赋值,就可以先用这个函数赋一个初始值,再更改你想改的值
    46. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置输出比较的模式
    47. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//设置输出比较的极性
    48. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能(输出状态)
    49. TIM_OCInitStructure.TIM_Pulse = 50;//设置CCR,Pulse直译是脉冲
    50. TIM_OC3Init(TIM2, &TIM_OCInitStructure);//TIM2通道3
    51. //5.初始化GPIO
    52. GPIO_InitTypeDef GPIO_InitStructure; //结构体变量名GPIO_InitStructure
    53. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出;PWM波形通过引脚输出,使用定时器来控制引脚,输出数据寄存器将被断开,输出控制权将转移给片上外设(这里片上外设引脚连接的就是TIM2CH1通道)
    54. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    55. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //默认50mhz输出
    56. GPIO_Init(GPIOA,&GPIO_InitStructure); //使用的是地址传递
    57. //6.启动定时器
    58. TIM_Cmd(TIM2,ENABLE);//PWM波形就能通过PA0输出了
    59. }
    60. //TIM_SetCompare1封装
    61. void PWM_SetCompare3(uint16_t Compare)
    62. {
    63. TIM_SetCompare3(TIM2,Compare);
    64. }

    moter.c

    1. #include "stm32f10x.h" // Device header
    2. #include "PWM_LED.h" //继承PWM模块
    3. void moter_init(void) //初始化函数
    4. {
    5. pwm_init();//调用底层的PWM_init,初始化pwm
    6. //需要额外初始化方向控制的两个脚,即初始化GPIO引脚
    7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //打开时钟
    8. //配置端口模式
    9. GPIO_InitTypeDef GPIO_InitStructA; //结构体变量名GPIO_InitStructA
    10. GPIO_InitStructA.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
    11. GPIO_InitStructA.GPIO_Pin = GPIO_Pin_4 |GPIO_Pin_5; //或运算,选择两个引脚
    12. GPIO_InitStructA.GPIO_Speed = GPIO_Speed_50MHz; //默认50mhz输出
    13. GPIO_Init(GPIOA,&GPIO_InitStructA); //使用的是地址传递
    14. }
    15. //设置速度的函数
    16. void moter_setspeed(int8_t speed)
    17. {
    18. //针对正转和翻转,用if来分别处理
    19. if(speed >= 0)//正转的逻辑
    20. {
    21. //首先将方向控制脚设置为一个高电平,一个低电平.哪个为高哪个为底无所谓
    22. GPIO_SetBits(GPIOA,GPIO_Pin_4);
    23. GPIO_ResetBits(GPIOA,GPIO_Pin_5);
    24. //速度
    25. PWM_SetCompare3(speed);
    26. }
    27. else//speed就是负数,代表反转
    28. {
    29. //首先是正反转,将setreset反过来就能反转了
    30. GPIO_ResetBits(GPIOA,GPIO_Pin_4);
    31. GPIO_SetBits(GPIOA,GPIO_Pin_5);
    32. PWM_SetCompare3(-speed);//此时speed为负数,必须为正数,在speed前加负号
    33. }
    34. }
  • 相关阅读:
    如何在 SwiftUI 中配置 SwiftData
    C++类模板再学习
    vue路由传参
    Eureka删除失效服务
    OpenCV每日函数 计算摄影模块(5) 无缝克隆算法
    关于项目管理的若干建议
    [附源码]Python计算机毕业设计Django贷款申请审核管理系统论文
    vue.js:用户登录切换的小案例
    C#调用C++动态库接口函数和回调函数方法
    vue3+ts做echarts做一个简单的折线渐变图
  • 原文地址:https://blog.csdn.net/m0_61712829/article/details/133252404