使用STM32F103C8T6实现摇杆按键控制SG90舵机云台

1.材料准备

  • STM32F103C8T6最小系统板*1
  • SG90舵机(180°)*2
  • 摇杆按键*1
  • 舵机支架*1
  • 面包板*1(非必须)
  • 杜邦线若干

    类似这种的支架,不过需要自己裁切嵌入的部分
  • 代码部分

    代码很简单,主要使用ADC双通道读取两个电位器的值(实际上就是电压),通过获取到的值的范围来确定上下左右,从而来改变两个舵机的角度。

    ps2_joystick.c

    #include "ps2_joystick.h"
    
    void Joystick_Init(void)
    {
        ADC_InitTypeDef ADC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
    
        // 使能GPIOA时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
        // 配置PA2和PA3引脚为模拟输入模式
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_2 | GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        // 使能ADC1时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    
        // 配置ADC1参数
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
        ADC_InitStructure.ADC_NbrOfChannel = 1;
        ADC_Init(ADC1, &ADC_InitStructure);
    
        // 配置ADC1通道2(电位器1)为采样序列1
        ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_55Cycles5);
    
        // 配置ADC1通道3(电位器2)为采样序列2
        ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_55Cycles5);
    
        // 使能ADC1
        ADC_Cmd(ADC1, ENABLE);
    }
    
    uint16_t Read_ADC_Value(uint8_t channel) {
        ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_55Cycles5);
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);
        while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
        return ADC_GetConversionValue(ADC1);
    }
    
    void Servo_Configuration(void) {
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
    
        // 使能GPIOB时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
        // 配置PB8和PB9引脚为复用推挽输出模式
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
    
        // 使能TIM4时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    
        // 配置定时器4的基本参数
        TIM_TimeBaseStructure.TIM_Period = 19999; // 20ms周期
        TIM_TimeBaseStructure.TIM_Prescaler = 71; // 分频系数,72MHz时钟
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    
        // 配置定时器4的通道3和通道4为PWM模式
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_Pulse = 1500; // 初始脉冲宽度为1.5ms(中间位置)
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    
        TIM_OC3Init(TIM4, &TIM_OCInitStructure);
        TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);
    
        TIM_OC4Init(TIM4, &TIM_OCInitStructure);
        TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
    
        // 启动定时器4
        TIM_Cmd(TIM4, ENABLE);
    }
    
    void Set_Servo_Angle(u8 angle1, u8 angle2){
    	u16 position1 = 500 + (2000 /180 * angle1);
    	u16 position2 = 500 + (2000 /180 * angle2);
    	TIM_SetCompare3(TIM4, position1); // 设置通道3的脉冲宽度
        TIM_SetCompare4(TIM4, position2); // 设置通道4的脉冲宽度
    }
    
    

    ps2_joystick.h

    #ifndef __PS2_JOYSTICK_H_
    #define __PS2_JOYSTICK_H_
    
    #include "stm32f10x.h"
    #include "sys.h"
    
    void Joystick_Init(void);//摇杆按键初始化
    uint16_t Read_ADC_Value(uint8_t channel);//获取AD转换数据
    
    void Servo_Configuration(void);
    void Set_Servo_Angle(u8 angle1, u8 angle2);	
    
    #endif /* __PS2_JOYSTICK_H_ */
    
    
    

    main.c

    #include "sys.h"
    #include "delay.h"
    #include "led.h"
    #include "ps2_joystick.h"
    /********IO配置*******
    A2 - URy
    A3 - URx
    
    B8 - 舵机下
    B9 - 舵机上
    
    **********************/
    // 定义全局变量用于保存摇杆的X和Y轴数值
    volatile int16_t VRxData = 0;
    volatile int16_t VRyData = 0;
    u8 Angle1 = 90;
    u8 Angle2 = 90;
    u8 AngleSpeed = 5;//每次改变舵机的角度,需要保证改后的范围在0-180度
    
    int main(void)
    {
    	delay_init();
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	LedInit();  
    	Joystick_Init();
    	Servo_Configuration();
        // 进入主循环
        while (1)
        {
            // 读取X轴和Y轴的数值 5V电源读取的数值范围为0-5000
    		VRyData = Read_ADC_Value(ADC_Channel_3);
    		VRxData = Read_ADC_Value(ADC_Channel_2);
          
            // 处理摇杆的数值
    		if(VRxData < 1500){ //右
    			//--
    			if(Angle1 < 180) Angle1 += AngleSpeed;	//控制舵机
    		}
    		else if(VRxData > 3500){//左
    			//++			
    			if(Angle1 > 0) Angle1 -= AngleSpeed;	
    		}
    		if(VRyData < 1500){ //上
    			if(Angle2 > 0) Angle2 -= AngleSpeed;		
    		}
    		else if(VRyData > 3500){ //下			
    			if(Angle2 < 180) Angle2 += AngleSpeed;			
    		}
    		Set_Servo_Angle(Angle1,Angle2);
            // ...
    		delay_ms(50);
        }
    }
    //改变if语言与VRyData等 比较的值可以提高摇杆按键的灵敏度(即小幅度变化即可触发舵机运行)
    

    通过改变if语言中与VRyData等 比较的值可以提高摇杆按键的灵敏度(即小幅度变化即可触发舵机运行)

    演示视频

    摇杆控制舵机云台

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用STM32F103C8T6实现摇杆按键控制SG90舵机云台

    发表评论