• 通过51单片机控制SG90舵机按角度正反转转动


    一、前言

    本文介绍如何通过51单片机控制SG90舵机实现角度的正反转转动。SG90舵机是一种常用的微型舵机,具有体积小、重量轻、结构简单等特点,被广泛应用于机器人、遥控模型和各种自动控制系统中。

    使用51单片机(STC89C52)作为控制器,利用其强大的IO口和定时器功能来实现对SG90舵机的控制。通过编程控制,可以精确地控制舵机按指定的角度进行正转或反转运动。

    舵机的控制是通过脉冲宽度调制(PWM)来实现的。在控制舵机时,需要向舵机发送一系列的脉冲信号,脉冲的宽度决定了舵机的角度位置。通常情况下,SG90舵机的控制脉冲周期为20毫秒,脉冲宽度在0.5毫秒到2.5毫秒之间,对应的角度范围为0度到180度。

    为了实现舵机的正反转转动,需要控制脉冲的宽度在不同的范围内,以达到不同的角度位置。通过调整脉冲的宽度和周期,我们可以控制舵机按照我们的要求进行旋转。

    下面将介绍如何通过51单片机的IO口和定时器来生成适用于SG90舵机的PWM信号。编写相应的程序,通过调整脉冲宽度来实现舵机的正反转转动,并提供示例代码。

    image-20230810162124895

    image-20230810162054785

    二、SG90电机介绍

    SG90电机是一种微型舵机,常用于模型、机器人和其他小型机械装置中。

    1. 工作原理: SG90电机基于直流电机的原理,通过PWM(脉宽调制)信号控制舵机转动角度。它由一个电机、减速齿轮组和一个位置反馈电路组成。该反馈电路使用了一个电位器来检测舵机的当前位置并将其反馈给控制电路。

    2. 特点:

    • 尺寸小巧:SG90电机非常小巧,体积轻盈,适合于空间有限的应用。
    • 转动角度范围广:通常情况下,SG90电机可以转动约180度左右,但具体转动范围可以通过控制信号调整。
    • 高精度:SG90电机具有较高的转动精度和稳定性,适用于需要精确控制的应用。
    • 低功耗:SG90电机功耗较低,可以在低电压下工作。
    • 相对经济:相比大型舵机或步进电机,SG90电机价格相对较低,适合在预算有限的项目中使用。

    3. 控制方式: 控制SG90电机需要提供PWM信号。以下是控制SG90电机的基本步骤:

    • 将SG90电机的VCC引脚连接到正电源(通常为5V),将GND引脚连接到地。
    • 将信号线(例如,控制舵机角度的引脚)连接到微控制器或其他控制设备的数字输出引脚。
    • 在控制设备上设置指定的PWM输出引脚,并使用相应的编程语言或库发送PWM信号。PWM的工作周期通常为20ms,并且脉宽的范围可以在0.5ms到2.5ms之间调整。
    • 根据所发送的PWM信号,SG90电机会转动到相应的角度位置。一般来说,0.5ms的脉宽对应最左端角度,2.5ms的脉宽对应最右端角度,1.5ms的脉宽对应中间位置。具体的脉宽范围和对应的角度可以根据电机型号和要求进行调整。

    SG90电机的额定工作电压为4.8V-6V,超过这个范围可能会损坏电机。舵机在运行时会产生一定的电流峰值,在使用时应确保电源能够提供足够的电流。

    三、实现代码

    3.1 正反转实现-模拟延时

    以下是通过51单片机控制SG90舵机按角度正反转转动的实现代码,封装子函数调用:

    #include 
    
    // 定义IO口连接舵机的引脚
    sbit servoPin = P1^0;
    
    // 延时函数
    void delay(unsigned int time) {
        unsigned int i, j;
        for(i = 0; i < time; i++) {
            for(j = 0; j < 1000; j++);
        }
    }
    
    // 控制舵机按指定角度进行正转
    void rotateClockwise(unsigned int angle) {
        unsigned int pulseWidth = 500 + angle * 11.11;
        unsigned int i;
        for(i = 0; i < 50; i++) {
            servoPin = 1; // 输出高电平
            delay(pulseWidth);
            servoPin = 0; // 输出低电平
            delay(20000 - pulseWidth);
        }
    }
    
    // 控制舵机按指定角度进行反转
    void rotateCounterclockwise(unsigned int angle) {
        unsigned int pulseWidth = 2500 - angle * 11.11;
        unsigned int i;
        for(i = 0; i < 50; i++) {
            servoPin = 1; // 输出高电平
            delay(pulseWidth);
            servoPin = 0; // 输出低电平
            delay(20000 - pulseWidth);
        }
    }
    
    void main() {
        while(1) {
            // 正转90度
            rotateClockwise(90);
            delay(2000); // 停留2秒
    
            // 反转90度
            rotateCounterclockwise(90);
            delay(2000); // 停留2秒
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.2 正反转角度控制-PWM控制

    下面是使用STC89C52的定时器0和GPIO口来模拟产生PWM信号的实现代码:

    #include 
    
    #define FREQ_OSC 11059200UL   // 单片机工作频率
    #define PWM_FREQ 50           // PWM信号频率
    #define PWM_RESOLUTION 100    // PWM信号分辨率
    
    sbit Servo = P1^0;   // SG90舵机控制引脚
    
    unsigned int pwmWidth = 0;   // PWM脉宽
    
    // 定时器0初始化函数
    void Timer0Init() {
        EA = 0;   // 关闭总中断
        TMOD &= 0xF0;   // 清除T0控制位
        TMOD |= 0x01;   // 设置T0为工作方式1(16位定时器)
        TH0 = (65536 - (FREQ_OSC / 12 / PWM_FREQ)) / 256;   // 计算并设置初始计数值高8位
        TL0 = (65536 - (FREQ_OSC / 12 / PWM_FREQ)) % 256;   // 计算并设置初始计数值低8位
        TR0 = 1;   // 启动定时器0
        ET0 = 1;   // 允许定时器0中断
        EA = 1;   // 开启总中断
    }
    
    // 定时器0中断服务函数
    void Timer0Interrupt() interrupt 1 {
        if (pwmWidth > PWM_RESOLUTION) {
            Servo = 0;   // 舵机复位
        } else {
            Servo = 1;   // 舵机置位
        }
        TH0 = (65536 - (FREQ_OSC / 12 / PWM_FREQ)) / 256;   // 重新设置计数值高8位
        TL0 = (65536 - (FREQ_OSC / 12 / PWM_FREQ)) % 256;   // 重新设置计数值低8位
        pwmWidth++;   // 每次中断增加PWM脉宽
    }
    
    // 主函数
    void main() {
        Timer0Init();   // 初始化定时器0
    
        while (1) {
            if (pwmWidth > PWM_RESOLUTION) {
                pwmWidth = 0;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    代码中,使用P1^0引脚作为SG90舵机的控制引脚,并通过定时器0来产生PWM信号。

    在Timer0Init函数中,设置定时器0为16位定时器工作方式1,计算并设置初始计数值,启动定时器0,并允许定时器0中断。

    在Timer0Interrupt函数中,每次定时器0中断时调整舵机控制引脚的电平状态,并更新定时器0的计数值。

    在主函数中,循环检测PWM脉宽是否达到设定的分辨率,如果超过则重新从0开始计数。

  • 相关阅读:
    中睿天下&Coremail | 2023年Q3企业邮箱安全态势观察报告
    css选择器优先级问题
    springboot+基于vue的响应式代购商城APP的设计与实现 毕业设计-附源码191654
    小目标检测高效解决方案汇总,附19篇原论文&开源代码
    Windows10打开应用总是会弹出提示窗口的解决方法
    Unity 2D 游戏学习笔记(2)
    Linux·安装编译libncurses5-dev遇到的问题
    skimage学习(2)——RGB转灰度、RGB 转 HSV、直方图匹配
    [回归指标]R2、PCC(Pearson’s r )
    Linux/Ubuntu环境搭建(二):创建添加新磁盘、搭建Samba服务器
  • 原文地址:https://blog.csdn.net/xiaolong1126626497/article/details/134239262