5iMX宗旨:分享遥控模型兴趣爱好

5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年)
查看: 6277|回复: 26
打印 上一主题 下一主题

简单的用单片机控制舵机的实验,给初学者做个参考(10月21日加个4通的模拟波形图)

[复制链接]
跳转到指定楼层
楼主
发表于 2012-10-12 23:21 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 铁皮 于 2012-10-21 20:05 编辑

N年没发贴了,先上程序,这是可以直接编译后写入单片机的程序,不要笑话,程序还有很大优化的余地,喜欢的自已优吧
ORG 0000H
LJMP MAIN
ORG 000BH  ;周期定时器T0中断服务程序
LJMP INTT0
ORG 001BH  ;占空比定时器T1中断服务程序
LJMP INTT1
ORG 0100H
MAIN: CLR P1.7  ;P1.7置低电平,第一个周期全低电平
MOV IE, #00H ;关所有中断
SETB PT0  ;T0中断为最高优先级
MOV TMOD, #11H ;T1为16位,T0为16位
MOV TH0, #0B1H ;T0初值45536,周期20mS
MOV TL0, #0E0H
MOV R0, #7DH ;占空值寄存器赋初值125,中间位置,R0范围:0-250
SETB EA  ;开总中断
SETB ET0  ;允许T0中断
SETB ET1  ;允许T1中断
SETB TR0  ;开启T0
BUTTON: MOV P3, #0FFH ;P3=1再读判断
JNB P3.0, BUTTON1 ;没按下P3.0则判断P3.1,按下P3.0则转+程序
JNB P3.1, BUTTON2 ;没按下P3.1继续扫描,按下P3.1时转-程序
AJMP BUTTON

;周期定时器T0中断服务程序,主要功能为将输出变高,计算T1值
INTT0: PUSH ACC
CLR TR1  ;停止T1定时器
MOV TH0, #0B1H ;T0初值45536,周期20mS
MOV TL0, #0E0H ;重装T0初值
STT1: SETB P1.7
MOV A, R0 ;T1=65536-((R0*4)+1000)=64536-R0*4
MOV B, #4H ;R0*4
MUL AB  ;R0*4
MOV  R6, A ;将低8位寄存入R6,空出A
MOV  A, #18H
SUBB A, R6 ;#18H-R6得出低8位值
MOV TL1, A ;装计算出的低8位装入T1
MOV A, #0FCH ;计算高8位
SUBB A, B ;高8位-#0FC
MOV TH1, A ;装计算出的高8位装入T1
SETB TR1  ;开启T1定时器
CLR  C
OUT0:POP ACC
RETI
;占空比定时器T1中断服务程序
INTT1: PUSH ACC
CLR P1.7  ;P1.7=0
POP ACC
RETI
;P3.0+键程序
BUTTON1:ACALL DL20MS  ;调用延时20mS程序消抖
JB P3.0, BUTTON ;没按P3.0则转回BUTTON(P3.0=1转)
CJNE R0,#0FAH,R0NO250;按+程序,先判R0=250已到最大,不转
AJMP BUTTON  ;已到最大跳回
R0NO250:INC R0  ;没到最大则R0+1
AJMP BUTTON
;P3.1-键程序
BUTTON2:ACALL DL20MS  ;调用延时20mS程序消抖
JB P3.1, BUTTON ;没按P3.1则转回BUTTON(P3.1=1转)
CJNE R0,#00H,R0NO00 ;-程序,先判R0=00不转
AJMP BUTTON  ;跳出,等待按键
R0NO00: DEC R0  ;R0-1
AJMP BUTTON
;20mS延时子程序
DL20MS: MOV R1, #0FAH ;R1赋值250
MOV R2, #28H ;R2赋值40,40*250=10000
XHR1: DJNZ R1, XHR1
MOV R1, #0FAH
DJNZ R2, XHR1
RET
END

说明:
用的是89C2051,白菜价2元一片
p1.7输出信号
P3.0按键逆时针转,p3.1按键顺时针转
T0做周期定时器,周期为20ms,时间到使p1.7输出高电平。
R0做占空比寄存器,数值通过按键控制在0至250之间,
T1做高电平时间定时器,溢出时间为1至2mS之间(要想再精确点还得减去T1启动前运行程序的时间),时间到使p1.7输出低电平,时间值由R0决定
按P3.0时R0慢慢增加,直至250,按P3.1时R0慢慢减小,直至0,通过T0中断服务程序中用R0计算得出对应T1值在1至2mS范围
用Keil uVision4调试程序、生成HEX文件,用ISIS 7 Professional模拟、看波形,用硕飞SP300写入单片机,简单搭的2051最小系统
上机实验舵机角度变化范围为90度,将T1值范围加大应该角度变化会变大
开机时R0设为125,即中间位置

开机时在中间



顺时针到底


逆时针到底


手绘简图,P1.7要直驱那个1K上拉电阻不能少

10月21日加个4通的测试波形图(CH1:0度,CH2:72度,CH3:90度,CH4:180度)4个通道的角度由4个存储器的值决定,4通的程序跟上面单通相差较大,0-180度,8位分辨率,只用了T0一个定时器,为的是留一个定时器做串行通信用,不要笑话,我还不会串口程序,8通及以下用51都没问题,而且程序变化不大


欢迎继续阅读楼主其他信息

沙发
发表于 2012-10-12 23:29 | 只看该作者
3
发表于 2012-10-13 00:09 | 只看该作者
4
发表于 2012-10-13 11:29 | 只看该作者
本帖最后由 3dbuild 于 2012-10-13 11:33 编辑

高手啊,当年我就是看着这些复杂的单片机汇编指令,觉得这个太麻烦了没学,现在用了AVR和Arduino,才知道单片机也可以用C++,才玩起了单片机。用Arduino写这个程序更简单,可以写到4圆多一片的M8单片机里,运行速度是51的20倍左右

程序:

#include <Servo.h>

Servo myservo;  // 舵机object

int potpin = 0;  // 电位器输入PIN
int val;    // 电位器读数

void setup()
{
  myservo.attach(9);  // 舵机object使用PIN9
}

void loop()
{
  val = analogRead(potpin);            // 读出电位器读数(结果范围0 - 1023)
  val = map(val, 0, 1023, 0, 179);     // 电位器读数转换到舵机角度(结果范围0 - 180)
  myservo.write(val);                  // 设置舵机角度
  delay(15);                           // 等待15ms,使舵机转动到指定角度
}
5
发表于 2012-10-13 11:43 | 只看该作者
LZ的控制精度是250级,最小调节角度0.72度,上面Arduino的程序使用了write函数,直接输入角度,控制精度是180级

把map(val, 0, 1023, 0, 179)换成map(val, 0, 1023, 0, 2000);
把write换成writeMicroseconds就变成1024级,最小调节角度0.18度
6
 楼主| 发表于 2012-10-13 11:45 | 只看该作者
3dbuild 发表于 2012-10-13 11:29
高手啊,当年我就是看着这些复杂的单片机汇编指令,觉得这个太麻烦了没学,现在用了AVR和Arduino,才知道单 ...

当初也学了一下单片机的C,可能是没学到位,编译出来乱78遭的,所以又回到汇编了,汇编除了在做数学运算方面差点外其它方面还是很直观的很好用的,51太落后了,所以也想换avr玩玩
7
 楼主| 发表于 2012-10-13 11:49 | 只看该作者
3dbuild 发表于 2012-10-13 11:43
LZ的控制精度是250级,最小调节角度0.72度,上面Arduino的程序使用了write函数,直接输入角度,控制精度是1 ...

对于8位单片机又用汇编来做的话最简单的就是做8位精度,8位实在不够用的情况才考虑10位以上
8
发表于 2012-10-13 11:50 | 只看该作者
建议换avr时先买一个Arduino来玩,几十圆就好了,现成的库函数一大把,基本上常见的芯片都有对应的程序,很方便,等搞熟悉了,就可以用Arduino的库,自己搭硬件来玩

看看官网:http://www.arduino.cc/
9
发表于 2012-10-14 21:15 | 只看该作者
高手云集呀
10
发表于 2012-10-15 18:23 | 只看该作者
pic单片机也可以,还可用PICBASIC PRO编程,与C一样简单:
12f509中的舵机测试程序:
INPUT GPIO.0
INPUT GPIO.1
INPUT GPIO.2
OUTPUT GPIO.5
B1 VAR BYTE
B2 VAR BYTE
B3 VAR BYTE
B1=0
B2=0
B3=150
LOW GPIO.5
MAIN:
IF GPIO.1=0 THEN B1=B1+1
IF B1=5 THEN B3=B3+1
IF B1=5 THEN B1=0
IF B3>=200 THEN B3=200
IF GPIO.2=0 THEN SUBGER
IF GPIO.0=0 THEN B3=150
PAUSE 18
PULSOUT GPIO.5,B3
GOTO MAIN
SUBGER:
IF GPIO.2=1 THEN MAIN
B2=B2+1
IF B2=5 THEN B3=B3-1
IF B2=5 THEN B2=0
IF B3<=100 THEN B3=100
PAUSE 18
PULSOUT GPIO.5,B3
GOTO SUBGER
11
发表于 2012-10-15 18:26 | 只看该作者
分辨率10微秒的
12
发表于 2012-10-15 21:41 | 只看该作者
太强大了
13
发表于 2012-10-19 19:05 | 只看该作者
这帖子要留个名备查。
14
发表于 2012-10-21 23:43 | 只看该作者
不错用汇编写功底深厚啊
15
发表于 2012-10-22 10:54 | 只看该作者
用C51,C语言写的程序,舵机玩死了也就只能做到4位步进。。。折腾死我了。。。
读取红外遥控信号,解码,然后控制舵机完成一个动作。就这点,折腾死我。。唉
16
 楼主| 发表于 2012-10-22 10:56 | 只看该作者
谁能提供个单片机之间无线通信的好办法,最好是加密的,不会相互干扰
17
发表于 2012-10-23 00:17 | 只看该作者

可以用HC-11 433无线串口,使用方便,支持3~5V宽电压使用,自己写加密通讯协议。还可以同时使用N个组网,通讯协议和485一样
18
 楼主| 发表于 2012-10-23 09:15 | 只看该作者
gyro 发表于 2012-10-22 10:54
用C51,C语言写的程序,舵机玩死了也就只能做到4位步进。。。折腾死我了。。。
读取红外遥控信号,解码,然 ...

能做到4位应该就能做到8位啊,一个通道用一个存储器就是8位了,可能是C程序太臃余,不太好精确的计算时间吧
19
发表于 2012-10-23 09:46 | 只看该作者
铁皮 发表于 2012-10-23 09:15
能做到4位应该就能做到8位啊,一个通道用一个存储器就是8位了,可能是C程序太臃余,不太好精确的计算时间 ...

没错,目前我就只会循环延时法。结果11.095mhz的情况下,实际测量一个++就高达2us了。加上判断,本来1000us的信号宽度,就没剩下几个。。。
计时器用在红外接收上了。

20
 楼主| 发表于 2012-10-23 10:05 | 只看该作者
gyro 发表于 2012-10-23 09:46
没错,目前我就只会循环延时法。结果11.095mhz的情况下,实际测量一个++就高达2us了。加上判断,本来1000 ...

我认为这种程序中最重要的是保证输出的脉冲宽度和周期的准确性,其它的事都可以在空闲的时候再做,所以决定宽度和周期的定时器中断为最高优先级。以4通来说,我是将20MS平分给4个通道,每个通道5MS的时间,一个通道中高电平时间最长是2.5MS,也就是说至少还有2.5MS的纯空闲时间可以干其它事,足够了。8通道时就紧张点,每个通道只得2.5MS,只能在定时器计数期间的0.5MS-2.5MS之间干其它事,应该也足够了,不够就任由中断打断也没多大影响。
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

关闭

【站内推荐】上一条 /1 下一条

快速回复 返回顶部 返回列表