难点:ARR、PSC
/**********************************************************************************************************/
一、知识补充
舵机原理:总想固定在一个固定角度(比较设定和现状,不匹配就转)
小车知识点:同一个定时器不同通道的PWM驱动多个舵机
同一个定时器TIM2不同CH(PA0是TIM2的通道一,PA1是TIM2的通道2)输出的PWM,频率是一样的,占空比由各自的CCR决定
相位,由于计数器更新,所有PWM同时跳变,所以相位一样
注意如果用的是360度的舵机是没办法控制角度的,只能控制旋转速度和旋转方向。
舵机要求频率20ms,高电平时间0.5ms~2.5ms
参数值确定
频率=20ms=50Hz 1kHz=1ms
经验:设置PSC+1=72 ARR+1=20k
20k对应20ms,CRR设置500,对应0.5ms; 2500 也就是2.5ms
二、代码分析
pwm.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
/*****时钟*****/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*****GPIO初始化******/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//舵机接在PA1 查找引脚定义知,TIM2_CH2_ETR在PA1口
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
/*****时钟源选择*****/
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 = 20000 - 1;//ARR的值 20k
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1 ;//PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器(高级计数器才有)
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
/*****OC初始化*****/
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//总结:赋一个初始值
//下面再改自己想改的参数
//防止配置通用定时器时未配置全部结构体成员导致改为高级定时器时出现错误
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//输出模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
TIM_OCInitStructure.TIM_Pulse = 0 ;//初始化CCR
TIM_OC2Init( TIM2,&TIM_OCInitStructure);//PA1
/*****启动定时器*****/
TIM_Cmd(TIM2,ENABLE);
}
/*****单独设置OC的函数*****/
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2,Compare);
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "Servo.h"
#include "Key.h"
uint8_t KeyNum;//接收Getnum返回值
float Angle;
int main(void)
{
OLED_Init();
Servo_Init();
Key_Init();
OLED_ShowString(1,1,"Angle:");
while(1)
{
KeyNum = Key_GetNum();//确定按键位置与是否有按下操作
if(KeyNum == 1)
{
Angle += 30 ;
if (Angle > 180)
{
Angle = 0;
}
Servo_SetAngle(Angle);
OLED_ShowNum(1,7,Angle,3);
}
}
}
三、现象
按一次角度加30 直到180 恢复到初位置
0度
180度