stm32驱使舵机任意角度转动,看完必懂系列,不懂薇哥给你补!

06-13 1540阅读

一、准备

硬件: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和每度的计数值

还是看到这张图

stm32驱使舵机任意角度转动,看完必懂系列,不懂薇哥给你补!

        先算出PSC和ARR的乘积

stm32驱使舵机任意角度转动,看完必懂系列,不懂薇哥给你补!

        算到这里就完成了第一步,接下来需要确定ARR-1的具体值才能将PSC-1求出,对于ARR-1的值,需要按照当前的情况计算。这里可以使用此方法快速得出ARR-1的值:

stm32驱使舵机任意角度转动,看完必懂系列,不懂薇哥给你补!

        然后在加上此函数则可将舵机精度控制为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的理解。如有不足,请予指正,感谢!

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]