简易旋转倒立摆及控制装置
简易旋转倒立摆及控制装
置
This manuscript was revised by the office on December 22, 2012
2013年全国大学生电子设计竞赛简易旋转倒立摆及控制装置(C题)
【本科组】
2013年9月7日
摘要
本题要求设计一个简易旋转倒立摆及控制系统,其中角度传感器、步进电机和单片机890C521是系统核心部件。系统接收角度传感器反馈的信号,通过PCF8591将接收的信号转换成数字信号,将数值送入单片机中进行计算,可得出摆杆的位置,进而单片机控制步进电机,对摆杆进行控制,达到所要的旋转或者倒立的控制目标。
关键词:简易旋转倒立摆步进电机单片机角度传感器
目录
简易旋转倒立摆及控制装置(C题)
【本科组】
1 设计任务及要求
1.1 设计任务
设计并制作一套简易旋转倒立摆及其控制装置。旋转倒立摆的结构如图1-1
所示。电动机 A 固定在支架 B 上,通过转轴 F 驱动旋转臂 C 旋转。摆杆 E 通过转轴 D 固定在旋转臂 C 的一端,当旋转臂 C 在电动机 A 驱动下作往复旋转运动时,带动摆杆 E 在垂直于旋转臂 C 的平面作自由旋转。
图1-1 旋转倒立摆结构示意图
1.2 基本要求
(1)摆杆从处于自然下垂状态(摆角 0°)开始,驱动电机带动旋转臂作往复旋转使摆杆摆动,并尽快使摆角达到或超过-60°~ +60°;
(2)从摆杆处于自然下垂状态开始,尽快增大摆杆的摆动幅度,直至完成圆周运动;
(3)在摆杆处于自然下垂状态下,外力拉起摆杆至接近 165°位置,外力撤除同时,启动控制旋转臂使摆杆保持倒立状态时间不少于 5s;期间旋转臂的转动角度不大于 90°。
2主控制器件的论证与选择
2.1控制器选用
方案一: 采用ARM,运行速度快,引脚多,内部资源丰富,具有很高的运算速率,但是价格较高,对于初学者,ARM不易掌握.
方案二: 采用STC89C52单片机, 选用STC89C52单片机作为控制核心,它具有8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,2 个数据指针,三个16 位定时器/计数器,一个6向量2级中断结构,全双工串行口,片内晶振及时钟电路,且容易烧录,使用方便。
所以我们选用STC89V52作为主控芯片
2.2控制系统方案选择
方案一:采用在面包板上搭建简易单片机系统
在面包板上搭建单片机系统可以方便的对硬件做随时修改,也易于搭建,但是系统连线较多,不仅相互干扰,使电路杂乱无章,而且系统可靠性低。
方案二:自制单片机印刷电路板
自制印刷电路实现较为困难,实现周期长,此外也会花费较多的时间,影响整体设计进程。
方案三:采用单片机最小系统。
单片机最小系统,能明显减少外围电路的设计,降低系统设计的难度,非常适合本系统的设计。
综上所述,我们选择方案三。
2.3角度的获取模块论证与选择
方案一:采用加速度传感器
加速度传感器采用模拟量输出,需要放大电路及A/D完成角度的测量,测量精度高,但是摆杆上不易安装重物,且不易固定。
方案二:采用增量式光电旋转编码器
光电旋转编码器是一种角度(角速度)检测装置,它将输入给轴的角度量,利用光电转换原理转换成相应的电脉冲。旋转编码器具有体积小,精度高,工作可靠,接口数字化等优点。但是旋转编码器安装较为不便,增加了系统硬件电路设计的工作量。
方案三:采用电位器作为角度传感器
简易旋转倒立摆系统的角度测量也可采用可变电阻器。精密的可变电阻器具易获得、重复性高、分辨率高、高频响应特性好、易使用等特点。且电位器传感器结构简单,体积小,价格低廉,受环境因素影响小,性能稳定。
综合以上三种方案微调电位器可以很好地达到我们的要求,角度有效范围载33.3度左右,由于本课题精度不高,考虑带经济性和灵活性,我们选择方案三。
2.4步进电机及其驱动模块的选择
方案一:采用直流减速电机,转速较低,反应速度慢,但是驱动模块简单。
方案二:采用型号为57 步进电机,为两相四线步进电机,它的步距角仅为1.8°,扭矩为0.50N/m,有较高的空载启动频率,在十六细分后能实现0.225°的步距角能够满足本系统的控制要求,驱动电路较复杂,用42/57专用驱动模块TB6560AHQ驱动,能满足要求,而驱动L298N模块功率较小,无法满足要求,易造成失步。
最终选定的步进电机为57步进电机,驱动电路模块选用TB6560AHQ模块。
2.5 AD/DA的选择
方案一:采用ADC0832
ADC0832为8位分辨率A/D转换芯片,其最高分辨可达256级,可以适应一般的模拟量转换要求。其内部电源输入与参考电压的复用,使得芯片的模拟电压输入在0~5V之间。芯片转换时间仅为32μS,据有双数据输出可作为数据校验,以减少数据误差,转换速度慢且稳定性能较差,而且占用I/O口多。
方案二:采用PCF8591
PCF8591具有I2C总线结构的多通道8bits的逐次逼近型ADC和一个内置
8bits单通道ADC,功能多,速度超快,功耗低,单电源供电,串行输入输
出,节约I/O口资源,并能在一个处理系统中外接多个PCF8591,能进行更多更强的处理。
综上,从各方面考虑,我们选择方案二。
3 系统的硬件设计
3.1总体电路框图
为了使系统能够实现各种复杂的控制功能,本设计采用一种功能强大的、高速低功耗性价比高的单片机STC89C52完成对其他部分控制。本设计采用SV01A103AEA01R00 旋转角度传感器(旋转电位器)对摆杆的倾斜角度进行数据采集,通过PCF8591 D/A转换芯片将数据送入单片机,单片机通过数据分析控制TB6560AHQ驱动电路,进而控制步进电机使步进机旋转达到设定的位置,用数码管显示A/D的数据。总体框图如图3-1所示。
图3-1 系统框图
3.2系统电路与程序设计
3.2.1 STC89C52单片机最小系统
最小系统包括复位、按键、显示和电源部分,而下载模块用单片机最小系统直接下载,减少了系统的浪费,而且防止连续的拔插单片机。STC89C52单片机最小系统如图3-4所示。
图3-4 最小系统
3.2.2 PCF8591模块图如图3-2。
图3-2 PCF8591模块图
3.3.3 模块芯片TB6560AHQ原理图如图3-3。
图3-3 模块芯片TB6560AHQ原理图
3.3.4 供电电源
由于需要驱动57步进电机,防止失步,其需要的功率较大,我们采用现有的直流稳压电源直接供电,电源模块的示意图如图3-5。为了达到较好的工作效果,我们选用兆信RXD-302-Ⅱ双路电源供电,具有很好的可靠性和灵活性,电压电流均可调,而且还在带一个5V电压输出端。
图3-5 电源电路
4系统软件总体设计框图如图4-1所示。
6 总结
经过四天三夜的辛勤努力,此次基于单片机为控制核心的简易旋转倒立摆的系统设计终于完成。通过合理的系统构建和软件编程,本系统也未能够完成题目的要求,实现摆杆的旋转及倒立,实际测试表明,所设计系统的稳定性有待改进。但由于时间紧,任务重,系统还有一些功能未能实现,比如摆杆在受到干扰后,能够及时恢复倒立状态。若经过改进,相信性能还会有进一步的提升。本次竞赛极大的锻炼了我们各方面的能力,虽然我们遇到了很多困难和障碍,但总体上成功与挫折交替,困难与希望并存,我们将继续努力争取更大的进步。
参考文献
[1]刘宝延.步进电机及其驱动控制系统[M].哈尔滨:哈尔滨工业大学出版社,1972.
[2]周航慈.单片机应用程序设计技术[M].北京:北京航空航天大学出版社,1991.
[3]郁有文.传感器原理及工程应用[M].西安:西安电子科技大学出版,2008.
[4]宋戈.51单片机应用开发范例大全[M].北京:人民邮电出版社,2010.
[5]张毅刚.单片机原理及应用[M].北京:高等教育出版社,2009.
[6]吴建平.传感器原理及应用[M].北京:机械工业出版社,2009.
[7]唐继贤.51单片机工程应用实例[M].北京:北京航空航天大学出版社,2009.
附录
第一部分
$NOMOD51
;------------------------------------------------------------------------------
; This file is part of the C51 Compiler package
; Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.
;------------------------------------------------------------------------------
; STARTUP.A51: This code is executed after processor reset.
;
; To translate this file use A51 with the following invocation:
;
; A51 STARTUP.A51
;
; To link the modified STARTUP.OBJ file to your application use the following
; BL51 invocation:
;
; BL51
;
;------------------------------------------------------------------------------
;
; User-defined Power-On Initialization of Memory
;
; With the following EQU statements the initialization of memory
; at processor reset can be defined:
;
; ; the absolute start-address of IDATA memory is always 0
IDATALEN EQU 80H ; the length of IDATA memory in bytes.
;
XDATASTART EQU 0H ; the absolute start-address of XDATA memory
XDATALEN EQU 0H ; the length of XDATA memory in bytes.
;
PDATASTART EQU 0H ; the absolute start-address of PDATA memory
PDATALEN EQU 0H ; the length of PDATA memory in bytes.
;
; Notes: The IDATA space overlaps physically the DATA and BIT areas of the
; 8051 CPU. At minimum the memory space occupied from the C51
; run-time routines must be set to zero.
;------------------------------------------------------------------------------
;
; Reentrant Stack Initilization
;
; The following EQU statements define the stack pointer for reentrant
; functions and initialized it:
;
; Stack Space for reentrant functions in the SMALL model. IBPSTACK EQU 0 ; set to 1 if small reentrant is used.
IBPSTACKTOP EQU 0FFH+1 ; set top of stack to highest location+1.
;
; Stack Space for reentrant functions in the LARGE model. XBPSTACK EQU 0 ; set to 1 if large reentrant is used.
XBPSTACKTOP EQU 0FFFFH+1; set top of stack to highest location+1.
;
; Stack Space for reentrant functions in the COMPACT model. PBPSTACK EQU 0 ; set to 1 if compact reentrant is used.
PBPSTACKTOP EQU 0FFFFH+1; set top of stack to highest location+1.
;
;------------------------------------------------------------------------------
;
; Page Definition for Using the Compact Model with 64 KByte xdata RAM
;
; The following EQU statements define the xdata page used for pdata ; variables. The EQU PPAGE must conform with the PPAGE control used
; in the linker invocation.
;
PPAGEENABLE EQU 0 ; set to 1 if pdata object are used. ;
PPAGE EQU 0 ; define PPAGE number.
;
PPAGE_SFR DATA 0A0H ; SFR that supplies uppermost address byte
; (most 8051 variants use P2 as uppermost address byte) ;
;------------------------------------------------------------------------------
; Standard SFR Symbols
ACC DATA 0E0H
B DATA 0F0H
SP DATA 81H
DPL DATA 82H
DPH DATA 83H
NAME C_STARTUP
C_C51STARTUP SEGMENT CODE
STACK SEGMENT IDATA
RSEG STACK
DS 1
EXTRN CODE (C_START)
PUBLIC C_STARTUP
CSEG AT 0
C_STARTUP: LJMP STARTUP1
RSEG C_C51STARTUP
STARTUP1:
IF IDATALEN <> 0
MOV R0,#IDATALEN - 1
CLR A
IDATALOOP: MOV @R0,A
DJNZ R0,IDATALOOP
ENDIF
IF XDATALEN <> 0
MOV DPTR,#XDATASTART
MOV R7,#LOW (XDATALEN)
IF (LOW (XDATALEN)) <> 0
MOV R6,#(HIGH (XDATALEN)) +1
ELSE
MOV R6,#HIGH (XDATALEN)
ENDIF
CLR A
XDATALOOP: MOVX @DPTR,A
INC DPTR
DJNZ R7,XDATALOOP
DJNZ R6,XDATALOOP
ENDIF
IF PPAGEENABLE <> 0
MOV PPAGE_SFR,#PPAGE
ENDIF
IF PDATALEN <> 0
MOV R0,#LOW (PDATASTART)
MOV R7,#LOW (PDATALEN)
CLR A
PDATALOOP: MOVX @R0,A
INC R0
DJNZ R7,PDATALOOP
ENDIF
IF IBPSTACK <> 0
EXTRN DATA (C_IBP)
MOV C_IBP,#LOW IBPSTACKTOP
ENDIF
IF XBPSTACK <> 0
EXTRN DATA (C_XBP)
MOV C_XBP,#HIGH XBPSTACKTOP
MOV C_XBP+1,#LOW XBPSTACKTOP
ENDIF
IF PBPSTACK <> 0
EXTRN DATA (C_PBP)
MOV C_PBP,#LOW PBPSTACKTOP
ENDIF
MOV SP,#STACK-1
; This code is required if you use L51_BANK.A51 with Banking Mode 4
; EXTRN CODE (B_SWITCH0)
; CALL B_SWITCH0 ; init bank mechanism to code
bank 0
LJMP C_START
END
第二部分
/*******************************************************************
***************
* 标题: ************* DA-AD试验******************* *
*
/******************************主程序
*****************************************************/
#include
#include
#define PCF8591 0x90 //PCF8591 地址
//else IO
sbit LS138A=P2^2;
sbit LS138B=P2^3;
sbit LS138C=P2^4;
sbit first=P2^5; //按键1 模式1选择
sbit second=P2^6; //按键2 模式2选择
sbit third=P2^7; //按键3 模式3选择
sbit fouth=P3^0; //按键4 模式4选择
sbit fith=P3^1; //按键5 模式清零选择
sbit shi_neng=P1^0; // 使能控制位
sbit fang_xiang=P1^1;// 旋转方向控制位
sbit mai_chong=P1^2; // 脉冲控制位
//此表为 LED 的字模, 共阴数码管 0-9 -
unsigned char code Disp_Tab[] =
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char AD_CHANNEL;
unsigned long xdata LedOut[8];
signed int D[32];
unsigned int ad=0,ad0=0;
unsigned int ms15=0;
unsigned char i=0,a=0,b=0,c=0,e=0;
unsigned char xiang;
signed char n=0;
unsigned int xx();
void round();
void system()
{
TMOD=0x01;
TH0=(65535-2000)/256;
TL0=(65535-2000)%256;
IE=0x8a;
IT0=0;
TR0=1;
}
/******************************************************************* DAC 变换, 转化函数
*******************************************************************/ bit DACconversion(unsigned char sla,unsigned char c, unsigned char Val)
{
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(c); //发送控制字节
if(ack==0)return(0);
SendByte(Val); //发送DAC的数值
if(ack==0)return(0);
Stop_I2c(); //结束总线
return(1);
}
/******************************************************************* ADC发送字节[命令]数据函数
*******************************************************************/ bit ISendByte(unsigned char sla,unsigned char c)
{
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(c); //发送数据
if(ack==0)return(0);
Stop_I2c(); //结束总线
return(1);
}
/******************************************************************* ADC读字节数据函数
*******************************************************************/ unsigned char IRcvByte(unsigned char sla)
{ unsigned char c;
Start_I2c(); //启动总线
SendByte(sla+1); //发送器件地址
if(ack==0)return(0);
c=RcvByte(); //读取数据0
Ack_I2c(1); //发送非就答位
Stop_I2c(); //结束总线
return(c);
}
//****************************************************************** /
main()
{
system();
shi_neng=0;
first=1;
second=1;
third=1;
fouth=1;
fith=1;
while(1)
{/********以下AD-DA处理*************/
switch(AD_CHANNEL)
{
case 0: ISendByte(PCF8591,0x41);
D[0]=IRcvByte(PCF8591)*2; //ADC0 模数转换1 放大2倍显示
break;
case 1: ISendByte(PCF8591,0x42);
D[1]=IRcvByte(PCF8591)*2; //ADC1 模数转换2
break;
case 2: ISendByte(PCF8591,0x43);
D[2]=IRcvByte(PCF8591)*2; //ADC2 模数转换3
break;
case 3: ISendByte(PCF8591,0x40);
D[3]=IRcvByte(PCF8591)*2; //ADC3 模数转换4
break;
case 4: DACconversion(PCF8591,0x40, D[4]/2); //DAC 数模转换
break;
}
// D[4]=400; //数字--->>模拟输出
D[4]=D[0]; // 把模拟输入采样的信号通过数模转换输出
if(++AD_CHANNEL>4) AD_CHANNEL=0;
ad=D[0]*10;
xiang=xx();
if(first==0)a=1,b=0,c=0,e=0;
if(second==0)b=1,a=0,c=0,e=0;
if(third==0)c=1,a=0,b=0,e=0;
if(fouth==0)e=1,a=0,b=0,c=0;
if(fith==0)a=0,b=0,c=0,e=0;
if(a==1)
{
if(xiang==0)
{
if(ad<=510&&ad>=4250)
n=1;
if(ad>=0&&ad<=850)
n=-1;
}
else n=0;
}
if(b==1)
{
if(xiang==0)
{
if(ad<=ad0)
n=-1;
if(ad>=ad0)
n=1;
}
else
round();
}
if(c==1)
{
if(ad>=2440&&ad<=2640)
n=1;
if(ad>=2720&&ad<=2860)
n=-1;
}
if(e==1)
{
if(ad<=2980&&2380)
{
if(ad>=2380&&ad<=2640)
n=1;
if(ad>=2720&&ad<=2980)
n=-1;
}
else round();
}
ad0=ad;
/********以下将AD的值送到LED数码管显示*************/ LedOut[0]=Disp_Tab[D[0]%10000/1000];
LedOut[1]=Disp_Tab[D[0]%1000/100];
LedOut[2]=Disp_Tab[D[0]%100/10]|0x80;
LedOut[3]=Disp_Tab[D[0]%10];
}
}
unsigned int xx() //摆杆象限检测
{
unsigned char Q;
if(ad>20&&ad<1360)
{
Q=1;
}
else if(ad>1360&&ad<2380)
{
Q=2;
}
else if(ad>2380&&ad<2680)
{
Q=3;
}
else if(ad>2680&&ad<2980)
{
Q=4;
}
else if(ad>2980&&ad<4040)
{
Q=5;
}
else if(ad>4040&&ad<5100)
{
Q=6;
}
else Q=0;
return(Q);
}
void round() //状态检测及相应操作{
if(ad>ad0&&xiang==6)
{
n=1;
}
else if(ad>ad0&&xiang==5)
{
n=1;
}
else if(ad { n=-1; } else if(ad>ad0&&xiang==3) { n=1; } else if(ad { n=-1; } else if(ad { n=-1; } else n=0; } void T0ZD(void) interrupt 1 using 2 { TH0=(65535-2000)/256;//250us TL0=(65535-2000)%256; //us50++; ms15++; mai_chong=1; P0 = LedOut[i]; switch(i) //使用switch 语句控制138译码器 { case 0:LS138A=0; LS138B=0; LS138C=0; break; case 1:LS138A=1; LS138B=0; LS138C=0; break; case 2:LS138A=0; LS138B=1; LS138C=0; break; case 3:LS138A=1; LS138B=1; LS138C=0; break; case 4:LS138A=0; LS138B=0; LS138C=1; break; case 5:LS138A=1; LS138B=0; LS138C=1; break; case 6:LS138A=0; LS138B=1; LS138C=1; break; case 7:LS138A=1; LS138B=1; LS138C=1; break; } if(++i>7) i=0; if(ms15>5) { ms15=0; if(n>0) //电机反转程序 { fang_xiang=1; mai_chong=0; } if(n<0) //电机正转程序 { fang_xiang=0; mai_chong=0; } if(n==0) //电机锁定程序 { mai_chong=1; } } } 第三部分 /*************************此部分为I2C总线的驱动程序,用来读取adda 数据*************************************/ #include #include #include #define NOP() _nop_() /* 定义空指令 */ #define _Nop() _nop_() /*定义空指令*/ sbit SCL=P2^1; //I2C 时钟 sbit SDA=P2^0; //I2C 数据 bit ack; /*应答标志位*/ /******************************************************************* 起动总线函数 函数原型: void Start_I2c(); 功能: 启动I2C总线,即发送I2C起始条件. ******************************************************************** / void Start_I2c() { SDA=1; /*发送起始条件的数据信号*/ _Nop(); SCL=1; _Nop(); /*起始条件建立时间大于4.7us,延时*/ _Nop(); _Nop(); _Nop(); _Nop();