【6-4】 PWM控制的呼吸灯、舵机程序

【注意,标注“*”的部分属于了解即可,无需过多关注】

一:库函数

1.配置输出比较模块

(1)输出比较单元控制

在硬件电路中,输出比较控制器一共有4个,对应的有4个输出比较 单元

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

(2)给输出比较结构体赋默认值

void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);

(3)用来单独更改输出比较单元控制器中结构体的函数

a.单独更改CCR寄存器值的函数

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);

b.修改输出使能函数*

void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);

c.选择输出比较模式*

void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
d.单独设置输出比较的极性*

带有“N”的就是高级定时器里互补通道的配置,其中OC4没有互补通道,结构体初始化的地方也可以设置极性

void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

(4)配置强制输出模式*

void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);

(5)配置CCR寄存器的预装功能,即是影子寄存器*

void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

(6)配置快速使能,在功能手册的单脉冲模式有介绍*

void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);

(7)外部事件时清除REF信号*

void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);

(8)仅高级计时器使用,使能主输出。否则PWM不能正常输出*

void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

二、书写PWM初始化函数

步骤:

1.RCC开启时钟,将TIM外设和GPIO外设全部打开

2.配置时基单元,包括之前的时钟源选择

3.配置输出比较单元,包括CCR的值,输出比较模式,极性选择,输出使能

4.配置GPIO,将PWM对应的GPIO口初始化为复用推挽输出的配置

5.运行控制,启动计数器,输出PWM

因为该图中不经过NVIC部分,即无需写输出控制以及NVIC相关的函数,复制之前的工程即可获得1.2.5.的代码,无需再次书写

3.输出比较单元的书写

(1)使用PA0的口,根据引脚对应表显示,使用的正是一号通路

TIM_OC1Init()

参数2是一个结构体,但是该结构体中的许多成员都是高级定时器才有的,但是如果不进行配置会导致结构体成员为空,会出现一定的错误。所以在此之前要给结构体的所有成员赋予初始值,使用TIM_OCStructInit()函数,该函数就是用来给结构体赋初始值的

通用定时器需要使用的结构体成员有:

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_OCMode_PWM1

(2)TIM_OCPolarity  输出比较极性

TIM_OCPolarity_High   高极性,即极性不翻转,REF波直接输出;有效电平为低电平

TIM_OCPolarity_Low  低极性,REF极性取反,有效电平为低电平

此处选用TIM_OCPolarity_High 

(3)TIM_OutputState    输出状态,输出使能

TIM_OutputState_Disable

TIM_OutputState_Enable

(4)TIM_Pulse  脉冲,用来设置CCR寄存器

取值范围是 0x0000 and 0xFFFF

4.配置GPIO口

根据引脚定义表,可知TIM2_CH1与PA0口对应上,即需要初始化PA0号口

需要使用复用推挽输出,输出控制寄存器的控制断开,转而接上片上外设

6.针对ARR,PSC,CCR的数据选择

这三个数据分别来自于时基单元与输出比较单元的结构体,若是想要获得一个1000Hz,50%占空比,1%分辨率的状态,根据公式

• PWM 频率:   Freq = CK_PSC (72M )/ (PSC + 1) / (ARR + 1)
• PWM 占空比:   Duty = CCR / (ARR + 1)
• PWM 分辨率:   Reso = 1 / (ARR + 1)

计算值分别为100,720,50 

三、PWM控制呼吸灯主程序

需要利用TIM_SetCompare1()函数设置一个新的函数PWM_TIMSetCompare1(),以便于能够在主函数中随时调用更改CCR寄存器内部值,实现呼吸灯

while (1)
	{
		for (i = 1;i<=100;i++)
		{
			PWM_TIMSetCompare1(i);
			Delay_ms(10);
		}
		for (i = 1;i<=100;i++)
		{
			PWM_TIMSetCompare1(100-i);
			Delay_ms(10);
		}
	}

此外,如果想要使用重映射,就需要加入一下代码:

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);                                                 开启AFIO的时钟,重映射必须先开启AFIO的时钟
   GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);                                                     将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
   GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);                                           将JTAG引脚失能,作为普通GPIO引脚使用
并且将端口PA0改为PA15(根据引脚对定义表)

四、PWM控制舵机

1.如果同时使用2个及以上捕获/比较寄存器时,由于他们共用一个CNT计数器,所以他们的PWM频率是相同的,相位也是同步的。

2.舵机对频率的要求是固定的20ms,50Hz,高电平时间为0.5ms-2.5ms,对应的占空比为2.5%-12.5%。其中,ARR设置为20000,PSC=72即可,ARR的20k对应20ms,则输入的CCR0.5k对应0.5ms等等

  • 29
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的STM32F103C8T6 PWM控制程序示例: ```c #include "stm32f10x.h" #define PWM_FREQ 50 // PWM频率为50Hz #define PWM_PERIOD (72000000/PWM_FREQ/1000) // PWM周期计算公式 #define SERVO_MAX 2000 // 最大角度 #define SERVO_MIN 1000 // 最小角度 void delay_ms(uint32_t ms) // 延时函数 { uint32_t i,j; for(i=0;i<ms;i++) { for(j=0;j<7200;j++); } } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); // 使能GPIOA和AFIO时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能TIM2时钟 // 配置PA1引脚为复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置TIM2的基本参数 TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD - 1; TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 配置TIM2的输出比较通道1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = SERVO_MIN; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_CtrlPWMOutputs(TIM2, ENABLE); // 使能TIM2的PWM输出 TIM_Cmd(TIM2, ENABLE); // 使能TIM2 while(1) { TIM_SetCompare1(TIM2, SERVO_MIN); // 设置PWM输出脉宽为最小角度 delay_ms(1000); TIM_SetCompare1(TIM2, SERVO_MAX); // 设置PWM输出脉宽为最大角度 delay_ms(1000); } } ``` 这个程序使用TIM2的PWM输出控制PA1引脚输出PWM信号,从而控制的转动角度。程序中使用了一个简单的延时函数`delay_ms()`来控制的转动周期。程序中的`PWM_FREQ`和`PWM_PERIOD`变量用于计算PWM输出的周期和脉宽,可以根据具体的要求进行调整。程序中的`SERVO_MAX`和`SERVO_MIN`变量用于控制的最大和最小转动角度,可以根据具体的要求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值