简易旋转倒立摆及控制装置

简易旋转倒立摆及控制装置
简易旋转倒立摆及控制装置

简易旋转倒立摆及控制装

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 , STARTUP.OBJ

;

;------------------------------------------------------------------------------

;

; 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();

相关主题
相关文档
最新文档