51单片机舵机控制

article/2025/8/18 18:27:34

51单片机舵机控制系统

    • 概述
    • 硬件设计
    • 程序设计
      • PWM波的产生
      • 矩阵按键功能与数码管显示参数传递
      • 完整程序
    • 外加模块

概述

在这篇博客中,将介绍一个基于51单片机的舵机控制系统,其可以通过矩阵按键输入角度,舵机打到预定角度,并在数码管上显示。

硬件设计

这次的小系统电路都由洞洞板搭建,主要包括51单片机最小系统,矩阵按键,数码管驱动和舵机四个部分。Protues仿真电路图如下
在这里插入图片描述

  • 数码管驱动
    仿真测试程序数码管时可以直接用IO口驱动,但是实物搭建电路需要再接驱动电路,这次选择了74HC245芯片来驱动。这款芯片使用非常简单,在驱动显示屏,做隔离芯片时应用都非常多。它有A0-A7,B0-B7两组输入输出口,可以DIR管脚选择数据传输方向,在使用时如果不需要转换传输方向可以直接将此管脚接到芯片VCC或者GND。
    在这里插入图片描述

  • 矩阵按键
    4*4的矩阵按键每一行每一列接在一个口上,通过行列扫描确定哪一个按键被按下,也就是导通。

  • 舵机
    舵机一般分为数字舵机和模拟电机。它们都由马达,减速齿轮组和控制电路组成。主要区别是数字电机有微处理器和晶振,能产生一周期为20ms,占空比为7.5%(即1.5ms高电平)的基准信号,通过输入与信号比较确定打角。而模拟电机则通过电位器产生的差分电压驱动电机正反转从而改变角度。这次选用的是SG90 180度的模拟舵机,价格低,带动一个激光头绰绰有余。通过单片机输出的周期为20ms的PWM波控制,在宽度从0.5ms到2.5ms,每一个占空比对应一个角度,示意图如下
    在这里插入图片描述

程序设计

PWM波的产生

在51单片机中,没有可以直接调用产生PWM波的底层库,需要自己用定时器写。一般产生PWM波能用两个定时器写,每一个定时器只固定拉高或者拉低,靠时间差确定周期。也可以只用一个定时器写,通过改变装载值来反复改变电平。以下详细说明用一个定时器写的方式,另外一个定时器空余出来可以实现更多功能。
一个定时器产生PWM波需要两组装载值,分别控制高低电平时间。设置一个全局变量作为中断标志位确定用哪一组装载值,拉高还是拉低电平,每一次进入中断后改变标志位的值。舵机180度对应每周期高电平时间0.5到2.5ms,可调范围2ms,用12M晶振时也就是2000个机器周期长,得到装载值与角度关系系数为11.11,取11,再加0.5ms对应的500个机器周期,就能得到角度与高电平对应值的关系。
机器周期数=角度*11+500
*周期20ms减去高电平时间就能换算出低电平对应装载值。*如果想要更精确,系数和对应值可以用浮点型,在最后计算装载值时再强制转换成整型。
把这段程序单独贴出来

 /*******************************************************装载值计算函数
*******************************************************/void zhuang(u8 jiaodu){u16 zhuangza; //高电平对应机械周期数zhuangza=jiaodu*11+500;  //2000/180=11.11  H1=  (65536-zhuangza)/256; L1 = (65536-zhuangza)%256;H2 = (45536+zhuangza)/256;//65535-(2000-高电平值)L2 = (45536+zhuangza)%256;}/*******************************************************
定时器1中断服务函数
*******************************************************/
void Time1(void) interrupt 3    
{if(servoflag==0) //中断标志位{TH1 = H1; TL1 = L1;   PWM=1;servoflag=1;}else if(servoflag==1){TH1 = H2; TL1 = L2;   PWM=0;servoflag=0;} 
}    

矩阵按键功能与数码管显示参数传递

矩阵按键前10个值分别对应0到9。10为确定键,按下后在主函数中将按键读到的几个一位数转换成角度,传给装载值计算函数,改变PWM波占空比,舵机打到对应角度。另外设计了11,12,13三个键,按下后能使舵机直接打到程序预定好的角度。相应按键功能分配在主函数中。具体程序不再赘述。
为了使输入多位数时能正确显示,让数码管的每一位固定显示个、十、百位,对应数组的四个元素,初值不显示,输入低位后,接受按键值的元素移向高位。

完整程序

#include "reg52.h"typedef unsigned int u16;   
typedef unsigned char u8;sbit LA=P2^4;     //数码管位选
sbit LB=P2^1;
sbit LC=P2^2;
sbit LD=P2^3;
sbit PWM=P2^5;   //PWM输出口
u8 code smgduan[17]={0x3f,0x06,0x9b,0x8f,0xA6,0xAd,0xBd,0x07,0xBf,
0xAf,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//0到9,大于9不显示
u8 f=0; 
static u8 jiaodu=0; //角度
u8 keyflag,servoflag;  //按键标志位,中断标志位
u8 H1=0xFA,L1=0x24,H2=0xB7,L2=0xBC;  //两组装载值
u16 zhuangzai;    
u8 w[4]={16,16,16,16};   //按键输入值保存数组,初值16不显示
u8 KeyValue;  //按键值
/*******************************************************
延时函数
*******************************************************/
void delay(u16 i)
{while(i--); 
}
/*******************************************************
定时器1初始化
*******************************************************/void Timer1Init()
{TMOD|=0X10;TH1 = 0xFC; TL1 = 0x18;ET1=1;   EA=1;TR1=1; 
}
/******************************************************
装载值计算函数
*******************************************************/
void zhuang(u8 jiaodu){ u16 zhuangza;zhuangza=jiaodu*11+500;  //高电平对应值与角度换算H1=  (65536-zhuangza)/256; //H,L分别是装载值高、低8位L1 = (65536-zhuangza)%256;  //1是高电平装载值,2是低电平装载值H2 = (45536+zhuangza)/256;L2 = (45536+zhuangza)%256;
}
/*******************************************************
数码管动态扫描
*******************************************************/
void DigDisplay()    
{u8 i;for(i=0;i<4;i++){switch(i)  {case(0):LA=0;LB=1;LC=1;LD=1; P0=smgduan[w[0]];break;case(1):LA=1;LB=0;LC=1;LD=1; P0=smgduan[w[1]];break;case(2):LA=1;LB=1;LC=0;LD=1; P0=smgduan[w[2]];break;case(3):LA=1;LB=1;LC=1;LD=0; P0=smgduan[w[3]];break;} delay(10);  P0=0x00;
//  delay(100);   //不加亮度更高}
}
/*******************************************************
矩阵按键扫描
*******************************************************/
void KeyDown(void)
{char a=0;P1=0x0f;if(P1!=0x0f){delay(1000);//消抖if(P1!=0x0f){ keyflag=1;//测试列P1=0X0F;switch(P1){case(0X0e): KeyValue=0;break;case(0X0d): KeyValue=1;break;case(0X0b): KeyValue=2;break;case(0X07): KeyValue=3;break;}//测试行P1=0XF0;switch(P1){case(0Xe0): KeyValue=KeyValue;break;case(0Xd0): KeyValue=KeyValue+4;break;case(0Xb0): KeyValue=KeyValue+8;break;case(0X70): KeyValue=KeyValue+12;break;}while((a<50)&&(P1!=0xf0))  //松手检测{delay(1000);a++;}}}
}
/*******************************************************
主函数
*******************************************************/
void main()  
{u8 i=0;Timer1Init();  //定时器1初始化while(1){DigDisplay();KeyDown();if(keyflag==1){w[i]=KeyValue;i++;keyflag=0;}if(KeyValue==10)    //确定键{for(i=0;w[i]<10;i++)jiaodu=jiaodu*10+w[i];zhuang(jiaodu);jiaodu=0;}if(KeyValue==12){zhuang(87);      //特定角度}if(KeyValue==13){zhuang(97);}if(KeyValue==14){zhuang(109);}}  
}
/*******************************************************
定时器中断服务函数
*******************************************************/
void Time1(void) interrupt 3    
{if(servoflag==0) {TH1 = H1; TL1 = L1;   PWM=1;servoflag=1;   //改变值,下次进入中断用另一组装载值}else if(servoflag==1){TH1 = H2; TL1 = L2;   PWM=0;servoflag=0;} 
}

外加模块

为了增加系统的趣味性,可以在舵机上安装激光头,距离一定距离放置三个目标靶,将其角度写入程序,则可以通过特定按键打靶。还可以在目标靶上增加指示电路,是激光打到靶后指示灯亮,可以通过光敏电阻的简单电路实现。


http://chatgpt.dhexx.cn/article/aaTf5opp.shtml

相关文章

Arduino基础入门篇28—舵机控制

舵机是一种位置「角度」伺服的驱动器&#xff0c;适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具、航模、机器人中已经得到普遍使用。舵机是一种俗称&#xff0c;其实是一种伺服马达。本篇通过官方驱动库来实现舵机控制。 1. 舵机介绍 结构组成 舵机实…

OpenMV输出PWM,实现对舵机控制

OpenMV的定时器官方函数介绍&#xff1a;Timer类 – 控制内部定时器 目录 OpenMV的PWM资源介绍 为什么要用OpenMV输出PWM OpenMV的PWM资源分配 资源 注意 建议 PWM输出代码 代码讲解 Timer Timer.channel tim.channel与Timer.channel区别 Timer.channel解析 OpenM…

舵机控制原理及常见问题

舵机控制 工作电压&#xff1a;3.5V/4,2V/4.8V —— 6V/6.8V/7.2V/8.4V(看具体型号参数) 切记&#xff1a;舵机不要接在电脑USB上调试&#xff0c;舵机启动瞬间大电流&#xff08;10-24倍工作电流&#xff09;可能会导致电脑死机 注意事项&#xff1a;PWM波形正确时&#xf…

第9章 舵机控制

有一种电机可以在程序的控制下&#xff0c;在一定范围内连续改变输出轴角度并且可以保持住。这种电机最早被用在航模和船模等遥控模型中&#xff0c;控制各种舵面的转动&#xff0c;这就是舵机。现在舵机除了运用在 遥控模型中&#xff0c;也大量的运用在各种机器人、机械臂的关…

Arduino入门001 - 舵机控制

Arduio基础入门篇001 - 舵机控制 一、舵机介绍 1&#xff0c;结构组成 一般来讲舵机主要由以下几个部分组成&#xff0c;舵盘、减速齿轮组、位置反馈电位计、直流电机、控制电路等。舵机的输入线共有三条&#xff0c;如图1所示&#xff0c;红色中间&#xff0c;是电源线&…

舵机控制(STM32F103C8T6)

前言 本文是以STM32F103C8T6作为主控芯片&#xff0c;通过PB6端口输出PWM&#xff0c;实现控制180舵机。 一、舵机控制原理 &#xff08;一&#xff09;概述 舵机是一种位置伺服驱动器器&#xff0c;是一种带有输出轴的小装置。当我们向伺服器发送一个控制信号时&#xff0c;…

Java 源代码怎么执行的

许多 Java 虚拟机的执行引擎在执行 Java 代码的时候都是解释执行&#xff08;通过解释器执行&#xff09;和编译执行&#xff08;通过即时编译器产生本地代码执行&#xff09;混合运行。 大体流程为&#xff1a; 编写 java 文件源码通过 javac 编译器将 java 源码编译为字节码流…

Java基础-java程序代码截取字符串及判断字符串是否包含某个字符(串)

文章目录 有一串字符串&#xff0c;是一串拼接码&#xff0c;如何截取获取想要的字段&#xff1f;判断字符串是否包含某个字符&#xff08;串&#xff09;indexOf方法 有一串字符串&#xff0c;是一串拼接码&#xff0c;如何截取获取想要的字段&#xff1f; public class Inte…

编写高质量JAVA程序代码的建议

--------------------------------------------------------------------------------------------------- 前言&#xff1a;原著《改善JAVA程序的151个建议》有151个建议&#xff0c;我在拜读的过程根据自己的理解合并了其中的几个&#xff0c;并将每个建议的核心要义进行了一…

java简单记事本代码_简单记事本的java程序代码

展开全部 天啊&#xff0c; 冖_Na0 为什么会有62616964757a686964616fe4b893e5b19e31333262343038我编的记事本代码呢&#xff1f;&#xff1f;&#xff1f;呵呵……你肯定是“请教”过我的吧&#xff1f;&#xff1f; 呵呵……我自己编了一个&#xff0c;不过呢&#xff0c;没…

IntelliJ IDEA 写java程序代码

快捷键 注释 单行&#xff1a;选中代码 ctrl/ 再来一次就是取消 多行&#xff1a;选中代码 ctrlshift/ 再来一次就是取消 格式化 CtrlAltL

Android studio如何运行java程序代码

先看Java程序类 public class GGG {public static void main(String[] args) {System.out.println("我是java程序");} }就是这么简单的一个java程序&#xff0c;在之前studio上可以直接运行&#xff0c;但是像现在升级studio后就发现运行报错&#xff1a; 首先java…

怎样使用lntelliJ IDEA 编写Java程序代码?

下面使用IDEA创建一个Java程序&#xff0c;实现在控制台上打印HelloWorld!的功能&#xff0c;具体步骤如下。 1.创建Java项目 进入New Project界面后&#xff0c;单击New Project选项按钮创建新项目&#xff0c;弹出New Project对话框&#xff0c;如下图所示。 New Projeet 对…

Java学习代码合集

其实我学习java最根本的原因是&#xff1a;我是一个挺关注外在的人&#xff0c;虽然是个程序员&#xff0c;所以我很喜欢写出那些带有漂亮的界面的程序&#xff0c;因为C总是控制台&#xff0c;我不是很喜欢&#xff0c;在这份java代码合集中&#xff0c;我会记录自己学习Java界…

Java开发常用代码

一.获取UUID UUID uuid UUID.randomUUID(); String str uuid.toString(); // 去掉“-” String s str.replaceAll("-", "");二.获取固定格式的时间字符串 第一种 //获取当前时间对象 Date d new Date(); //创建日期格式化类对象,”yyyy/MM/dd HH:mm…

一个简单的Java例程

编写一个程序&#xff0c;输出如下&#xff1a; 1.在IDEA中新建一个helloworld类&#xff0c;注意Java中严格区分大小写 2.在文件中添加如下代码&#xff1a; 源代码如下&#xff1a; public class helloworld{public static void main(String[] args){System.out.println(&q…

Python3读取大文件的方法

Python3读取大文件的方法 1. 方法一&#xff1a;利用yield生成器2. 方法二&#xff1a;利用open()自带方法生成迭代对象&#xff0c;这个是一行一行的读取3. 二者的比较 1. 方法一&#xff1a;利用yield生成器 def readPart(filePath, size1024, encoding"utf-8"):w…

大文件处理(上传,下载)思考

文件处理一直都是前端人的心头病&#xff0c;如何控制好文件大小&#xff0c;文件太大上传不了&#xff0c;文件下载时间太长&#xff0c;tcp直接给断开了&#x1f631;&#x1f631;&#x1f631;等 效果 为了方便大家有意义的学习&#xff0c;这里就先放效果图&#xff0c;如…

python拆分大文件(大文件分割)

python拆分大文件 前言实现过程实验结果 前言 在工作中常常会遇见一些大文件&#xff0c;由于内容太多&#xff0c;使用比如记事本、notePad等软件也打不开&#xff0c;无法查看内容&#xff0c;最好是将整个文件进行拆分&#xff0c;分开处理&#xff0c;现在处理的文件原本是…

如何快速地向服务器传大文件,大文件如何快速传输

在这个互联网时代&#xff0c;信息更新速度逐渐加快。用户在进行文件传输时&#xff0c;一定是希望既稳定又快速的&#xff0c;并且还能够保证安全。但是通常来讲&#xff0c;FTP文件传输并不能同时实现这三点的&#xff0c;特别是上传大文件时&#xff0c;FTP上传文件速度明显…