stm32驱使舵机任意角度转动,看完必懂系列,不懂薇哥给你补!
一、准备
硬件:stm32任意型号,这里我使用stm32f103c8t6,sg90舵机,电位器。
软件:keil上号!
目标:使用梅花柄电位器控制舵机任意角度旋转。
二、相关资料
2.1 舵机驱使方法
舵机是一种根据输入PWM信号占空比来控制输出角度的装置
输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms
stm32f1标准库PWM驱动的配置代码
void PWM_Init() { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//打开定时器晶振 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //GPIOA口晶振使能 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //模拟ad口 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); TIM_InternalClockConfig(TIM3); //选择TIM3内部时钟 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置时基单元,建立结构体,配置参数,初始化单元 TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//一分频 TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInitStructure.TIM_Period =18000 - 1; //ARR TIM_TimeBaseInitStructure.TIM_Prescaler = 80 - 1; //PSC计数时间=晶振频率(72M)/ARR+1/PSC+1;计1s则为1hz;PSC越低频率越高 TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); TIM_OCInitTypeDef TIM_OCInitStructure; //比较单元的结构体 TIM_OCStructInit(&TIM_OCInitStructure); //初始化结构体里所有的值,防止出现小问题 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM1模式 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效电平为高电平 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能 TIM_OCInitStructure.TIM_Pulse = 0; //CCR TIM_OC3Init(TIM3, &TIM_OCInitStructure); //初始化 //TIM_OC2Init(TIM3, &TIM_OCInitStructure); //PWM频率=晶振(72MHZ)/(ARR+1)/(PSC+1) //PWM占空比=CCR/(ARR+1) //PWM分辨率=1/(ARR+1) TIM_Cmd(TIM3, ENABLE);//开启计数器使能 }
这里使用TIM3定时器,过程:先配置时基单元,再配置输出比较(PWM),对于计数值(ARR)和分频系数(PSC)为什么要配置为18000-1,80-1我在下面会细细解说。
2.2 计算ARR,PSC和每度的计数值
还是看到这张图
先算出PSC和ARR的乘积
算到这里就完成了第一步,接下来需要确定ARR-1的具体值才能将PSC-1求出,对于ARR-1的值,需要按照当前的情况计算。这里可以使用此方法快速得出ARR-1的值:
然后在加上此函数则可将舵机精度控制为1度,如果有精度为0.1度的需求也可以按上面的方法。
//从450开始每十个计数为一度,到2250 void set_sg90_angle(uint16_t angle) { //-90度对应的起始脉冲宽度为0.5ms,及计数值为450 //按照设置每计10个数角度+1 uint16_t count=450+angle*10; TIM_SetCompare3(TIM3,count); }
三、电位器驱动
电位器驱动使用ADC模块:
void AD_Init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //GPIO口时钟配置 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //adc1时钟配置 RCC_ADCCLKConfig(RCC_PCLK2_Div6); //adc1分频器配置,配置为6分频 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; //配置为模拟输入模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); //配置adc1的规则通道,如果想配置多个可向下复制 ADC_InitTypeDef ADC_InitStructure; //建立adc1的结构体 ADC_InitStructure.ADC_ContinuousConvMode=DISABLE; //是否开启连续模式,否 ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right; //数据左或右对其,右 ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //外部时钟配置,无 ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; //独立或交叉模式,独立 ADC_InitStructure.ADC_NbrOfChannel=1; //通道数量,1 ADC_InitStructure.ADC_ScanConvMode=DISABLE; //是否配置多通道模式,否 ADC_Init(ADC1,&ADC_InitStructure); ADC_Cmd(ADC1,ENABLE); //adc1启动使能 //校准模块 ADC_ResetCalibration(ADC1); //开始复位adc1 while (ADC_GetResetCalibrationStatus(ADC1) == SET); //等待复位结束,跳出循环 ADC_StartCalibration(ADC1); //开始校准adc1 while (ADC_GetCalibrationStatus(ADC1) == SET); //等待adc1校准结束,跳出循环 }
获取当前ADC值:
uint16_t get_adc_data() { ADC_SoftwareStartConvCmd(ADC1,ENABLE); //软件开启转换使能 while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET); //adc1(规则和注入)转换结束标志位,0为正在转换,1为转换完成,转换完成跳出while return ADC_GetConversionValue(ADC1); //获取adc1数据寄存器的12位数据 }
四、最终演示代码
int main() { uint16_t ADvalue=0; uint16_t angle=0; OLED_Init(); PWM_Init(); AD_Init(); OLED_ShowString(1,1,"angle:"); while(1) { ADvalue=get_adc_data(); //获取ADC值 angle=ADvalue/22; // 4095/180=22 OLED_ShowNum(3,1,ADvalue,4); set_sg90_angle(angle); } }
最终实物效果:
stm32电位器控制舵机
五、结语
对于本次的设计,可以提高对PWM和ADC的理解。如有不足,请予指正,感谢!
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。