前言:
舵机控制的另一个专业名字叫伺服控制。
经过百度,伺服”—词源于希腊语“奴隶”的意思。人们想把“伺服机构”当个得心应手的驯服工具,服从控制信号的要求而动作。在讯号来到之前,转子静止不动;讯号来到之后,转子立即转动;当讯号消失,转子能即时自行停转。由于它的“伺服”性能,因此而得名——伺服系统。
我们这次就是要控制舵机转动任意角度。

接线方法:
红-------------------------VCC
棕色----------------------GND
橙色----------------------信号线

舵机的控制信号为周期是20ms 的脉宽调制(PWM)信号,其中脉冲宽度从0.5ms-2.5ms,相对应舵盘的位置为0—180度,呈线性变化。也就是说,给它提供一定的脉宽,它的输出轴就会保持在一个相对应的角度上,无论外界转矩怎样改变,直到给它提供一个另外宽度的脉冲信号,它才会改变输出角度到新的对应的位置上。舵机内部有一个基准电路,产生周期20ms,宽度1.5ms的基准信号,有一个比较器,将外加信号与基准信号相比较,判断出方向和大小,从而产生电机的转动信号。
控制电路板接受来自信号线相应的PWM控制信号,进而控制电机转动,电机带动一系列齿轮组,减速后传动至输出舵盘。舵机的输出轴和位置反馈电位计是相连的,舵盘转动的同时,带动位置反馈电位计,电位计将输出一个电压信号到控制电路板,进行反馈,然后控制电路板根据所在位置决定电机的转动方向和速度,从而达到目标停止。
舵机的控制需要MCU产生一个周期为20ms的脉冲信号,以0.5ms到2.5ms的高电平来控制舵机转动的角度。

1、在购买时,需要分清楚你的舵机可以转180度,还是360度。相关区别购买时可以了解。


2、舵机又分为数字舵机和模拟舵机。
模拟舵机:需要不断的发送相应角度的PWM信号,才能旋转到指定位置。例如:我现在让它旋转90度,我就需要在一个时间内不断的发送90度的PWM信号,舵机转动到指定位置就会停止。
数字舵机:只需给一个目的地PWM信号,即可旋转到指定位置。例如:我现在让它旋转90度,我只需要发送一次90度的PWM信号,它就可以旋转到90度。
SG90舵机 是模拟舵机,SG90S舵机 我记得好像是数字舵机,总之数字舵机比模拟舵机好些,无论实在程序控制方面还是在运行情况方面都要好些
舵机要用PWM来控制,PWM的产生可以用软件延时和定时器的方法。这里为了体现精确性,采用定时器的方式。
首先还是看下这张图片,这个是PWM控制SG90舵机的关键。我们只有按照给舵机输入正确的PWM波形,舵机才会转动到指定的角度。

上代码:
1、PWM波形的周期我们用定时器产生,所以先对定时器做初始化:
void Timer_Init()
{
TMOD=0X01; //T0定时方式1
TH0=0Xfe;
TL0=0X33; //计数初值设置为0.5ms
ET0=1; //打开定时器0的中断
TR0=1; //打开定时器0
EA=1; //开总中断
}
2、然后就是编写定时器中断函数,和输出对应的PWM波形了:
PWM波形这里是在定时器里产生的。
sbit PWM=P2^3; //对应舵机的PWM引脚
int count=0; //全局变量count用于定时器计数
int c=0; //这个值为高低电平的临界值,可以改变,
//这里初始化为0表示开始让舵机复位到0度位置(输出0.5ms的高电平)
void Timer() interrupt 1
{
TH0=0Xfe;
TL0=0X33; //重新赋计数初值为0.5ms
if(count<=c) //进入定时器的时间和高低电平临界值比较
{
PWM=1; //输出PWM波形中的高电平
}
else
{
PWM=0;
}
count++;
if(count>=40) //计数40次,每次0.5ms,总共达到20ms周期后清零,为下一周期开始计数做准备
{
count=0;
}
}
3、主函数代码的书写:
void main()
{
Timer_Init();
while(1);
}
嗯嗯,上面就是代码全部了,没有给出整体代码,防止只复制粘贴,不动脑瓜子的童鞋
1、那。。。,博主博主,我把上面的代码组装到工程里去了,烧写到单片机中去,开机舵机没反应呀?
答:看看舵机原本是不是在0度的位置,如果是,请手动把他转到其它角度,在上电,看舵机转到0度了没有。
2、那。。。,博主博主,我想让舵机上电就复位到90度的位置,咋办?
答:认真看下代码里语句的注释,我们将程序中的高低电平临界值变量c,赋值为2,即c=2;上电后,舵机如果不在90度的位置,就会复位到90度了。
3、那。。。,博主博主,我想定义两个按键,按下一个按键舵机转到0度位置,按下另一个按键,舵机转到180位置,咋办?
答:先用sbit定义两个按键引脚,然后在主函数中的while循环里,判断哪个按键按下,然后改变临界值C就行。如下
while(1)
{
if(key1==0)
{
delay_ms(5);
if(key1==0)
{
c=0; //对应高电平输出0.5ms,转到0度
while(!key1);
}
}
else if(key2==0)
{
delay_ms(5);
if(key2==0)
{
c=4; //对应高电平输出2.5ms,转到180度
while(!key2);
}
}
}
嗯。。。,咋子优化哦,上面不就可以让舵机抓到指定位置了吗?
SG90是模拟舵机,需要在一个时间内不断的输出一定的PWM波形给舵机,它才会转到到指定位置,上面的代码中我是让定时器不断的工作,不断的输出PWM波形。
其实对于模拟舵机,不需要一直让定时器工作输出PWM波形,只用在一段时间内输出一定的PWM波形就可以。那为什么这样考虑呢?因为给一段时间的PWM波形后,舵机就可以转动到位了,后面再给PWM波形就没有意义了,舵机转动到位后,就可以关闭定时器了(除非你的其它功能要用到定时器,就可以不用关),这样可以避免后面不断的触发定时中断,影响主函数while里其它功能的执行效率,毕竟进入定时中断函数里时,主函数时不得执行的。
上面讲到的那个时间,可以通过实际调试多次测出来,博主这里测出来了。
**完整并优化的项目代码放到最后:
【51单片机控制SG90舵机】
**
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
使用Ruby1.9.2运行IDE提示说需要gemruby-debug-base19x并提供安装它。但是,在尝试安装它时会显示消息Failedtoinstallgems.Followinggemswerenotinstalled:C:/ProgramFiles(x86)/JetBrains/RubyMine3.2.4/rb/gems/ruby-debug-base19x-0.11.30.pre2.gem:Errorinstallingruby-debug-base19x-0.11.30.pre2.gem:The'linecache19'nativegemrequiresinstall
我知道全局变量$!包含最新的异常对象,但我对下面的语法感到困惑。谁能帮助我理解以下语法?rescue$! 最佳答案 此构造可防止异常停止您的程序并使堆栈跟踪冒泡。它还会将该异常作为值返回,这很有用。a=get_me_datarescue$!在此行之后,a将保存请求的数据或异常。然后您可以分析该异常并采取相应措施。defget_me_dataraise'Nodataforyou'enda=get_me_datarescue$!puts"Executioncarrieson"pa#>>Executioncarrieson#>>#更现实的
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
我在我正在处理的一些代码中发现了这一点。它旨在解决从磁盘读取key文件的要求。在生产环境中,key文件的内容位于环境变量中。旧代码:key=File.read('path/to/key.pem')新代码:key=File.read('|echo$KEY_VARIABLE')这是如何工作的? 最佳答案 来自IOdocs:Astringstartingwith“|”indicatesasubprocess.Theremainderofthestringfollowingthe“|”isinvokedasaprocesswithappro
我今天看到了一个ruby代码片段。[1,2,3,4,5,6,7].inject(:+)=>28[1,2,3,4,5,6,7].inject(:*)=>5040这里的注入(inject)和之前看到的完全不一样,比如[1,2,3,4,5,6,7].inject{|sum,x|sum+x}请解释一下它是如何工作的? 最佳答案 没有魔法,符号(方法)只是可能的参数之一。这是来自文档:#enum.inject(initial,sym)=>obj#enum.inject(sym)=>obj#enum.inject(initial){|mem