PWM驱动LED呼吸灯
为什么led为PA0引脚时要用TIM2的CH1引脚:在下标可以看出默认复用功能的引脚对应关系。
引脚功能重映射 同时也有重定义功能需要用AFIO配置,如果把引脚重定义到PA15,需要用到函数GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);然后再查看手册表43 TIM2复用功能重映像选择合适的参数。但是从表中看出还要关闭PA15对应的调试功能,同样用这个(可以参考表35)
PWM初始化代码:
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//AFIO用来设置引脚的重映射
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//打开AFIO时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//重映射外设复用的引脚
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//接触ITAG复用
//
//GPIO
GPIO_InitTypeDef GPIO_Init_Structure;
//要用复用推挽输出 普通开漏推挽输出引脚控制权来自输出数据寄存器,如果想要定时器控制引脚,要用复用开漏推挽模式
GPIO_Init_Structure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init_Structure.GPIO_Pin=GPIO_Pin_0; //15
GPIO_Init_Structure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_Init_Structure);
//TIMx internal Clock
TIM_InternalClockConfig(TIM2);
//时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=100-1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler=720-1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//TIM peripheral
TIM_Cmd(TIM2,ENABLE);
//输出比较初始化
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit (&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCNPolarity_High;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse=0; //CCR 求占空比;数值越大灯光越亮;根据参数计算的三个公式可以得出参数的值
//通道和GPIO对应引脚 需要查看引脚对应表
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
}
void PWM_SetCompare1(uint16_t Compare)
{
//设置CCR的值,注意这里只是CCR的值要和ARR一起才能算占空比
TIM_SetCompare1(TIM2,Compare);
}
PWM驱动舵机
对于同一个定时器的不同通道,在TIM通用寄存器的框图中可以看到,他们共用一个CNT所以频率一样,它们又有各自的CCR所以可以设置不同的占空比,计数器更新,所有的PWM同时跳变,所以相位是同步的。
舵机要求周期20ms则频率50hz,由公式可以给定ARR和PSC的值
PWM初始化部分代码:
GPIO_Init_Structure.GPIO_Pin=GPIO_Pin_1;
TIM_TimeBaseInitStructure.TIM_Period=20000-1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler=72-1; //PSC
//用P1口对应通道2
TIM_OC2Init(TIM2,&TIM_OCInitStruct);
舵机部分代码:
//180 2500
//0 500
//找出角度和占空比的线性关系
void Servo_SetAngle(float angle)
{
PWM_SetCompare2(angle/180*2000+500);
}
PWM驱动直流电机
PWM初始化部分:
GPIO_Init_Structure.GPIO_Pin=GPIO_Pin_2;
TIM_TimeBaseInitStructure.TIM_Period=100-1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler=36-1; //PSC
//这里选用P2口,对应通道3
TIM_OC3Init(TIM2,&TIM_OCInitStruct);
直流电机代码:还需要通过设置IN1/IN2高低电平控制电机正反转,所以还要两个GPIO引脚
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
PWM_Init();
}
//注意这里是int8_t不要写成无符号的
//因为设置ARR+1=100 所以CCR speed范围在-100,100
void Motor_SetSpeed(int8_t speed)
{
if(speed>=0)
{
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
PWM_SetCompare3(speed);
}
else{
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
GPIO_SetBits(GPIOA,GPIO_Pin_5);
PWM_SetCompare3(-speed);
}
}