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

2013年全国大学生电子设计竞赛

简易旋转倒立摆及控制装置(C题)

【本科组】

2013年9月7

摘要

本题要求设计一个简易旋转倒立摆及控制系统,其中角度传感器、步进电机和单片机

890C521是系统核心部件。系统接收角度传感器反馈的信号,通过PCF8591将接收的信号转换成数字信号,将数值送入单片机中进行计算,可得出摆杆的位置,进而单片机控制步进电机,对摆杆进行控制,达到所要的旋转或者倒立的控制目标。

关键词:简易旋转倒立摆

步进电机

单片机 角度传感器

目录

1 设计任务及要求 .................................................... 5

1.1 设计任务 .................................................... 5 1.2 基本要求 ................................................... 5 2主控制器件的论证与选择 ............................................ 6

2.1控制器选用 ................................................... 6 2.2控制系统方案选择 ............................................. 6 2.3角度的获取模块论证与选择 ..................................... 6 2.4步进电机及其驱动模块的选择 ................................... 7 2.5 AD/DA的选择 ................................................. 7 3 系统的硬件设计 .................................................... 7

3.1总体电路框图 ................................................. 7 图3-1 系统框图 ..................................................... 8

3.2系统电路与程序设计 ........................................... 9

3.2.1 STC89C52单片机最小系统 ................................ 9 3.2.2 PCF8591模块图如图3-2。 ............................... 10 3.3.3 模块芯片TB6560AHQ原理图如图3-3。 .................... 10 3.3.4 供电电源 .............................................. 11

4系统软件总体设计框图 ............................................. 13 5 测试方案与测试结果 ............................................... 13 6 总结 ............................................................. 15 参考文献 ........................................................... 16 附录 ............................................................... 17

简易旋转倒立摆及控制装置(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.4 供电电源

图3-3 模块芯片TB6560AHQ原理图

由于需要驱动57步进电机,防止失步,其需要的功率较大,我们采用现有的直流稳压电源直接供电,电源模块的示意图如图3-5。为了达到较好的工作效果,我们选用兆信RXD-302-Ⅱ双路电源供电,具有很好的可靠性和灵活性,电压电流均可调,而且还在带一个5V电压输出端。

图3-5 电源电路

4系统软件总体设计框图 如图4-1所示。

图4-1 总体程序框图

5 测试方案与测试结果

测试结果(S)

这次设计的要求,所设计的系统要有较高的灵敏度和相应的转矩,这两样是最为重要的,我们所设计的系统,不能很好地满足要求,有待进一步改进

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 {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; }

Disp_Tab[] =

/******************************************************************* 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=4250)

n=1;

if(ad>=0&&ad

n=-1;

}

else n=0;

}

if(b==1)

{

if(xiang==0)

{

if(ad

n=-1;

if(ad>=ad0)

n=1;

}

else

round();

}

if(c==1)

{

if(ad>=2440&&ad

n=1;

if(ad>=2720&&ad

n=-1;

}

if(e==1)

{

if(ad

{

if(ad>=2380&&ad

n=1;

if(ad>=2720&&ad

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

{

Q=1;

}

else if(ad>1360&&ad

{

Q=2;

}

else if(ad>2380&&ad

{

Q=3;

}

else if(ad>2680&&ad

{

Q=4;

}

else if(ad>2980&&ad

{

Q=5;

}

else if(ad>4040&&ad

{

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

{

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

SDA=0; /*发送起始信号*/

_Nop(); /* 起始条件锁定时间大于4μs*/

_Nop();

_Nop();

_Nop();

_Nop();

SCL=0; /*钳住I2C总线,准备发送或接收数据 */

_Nop();

_Nop();

}

/******************************************************************* 结束总线函数

函数原型: void Stop_I2c();

功能: 结束I2C总线,即发送I2C结束条件.

********************************************************************/ void Stop_I2c()

{

SDA=0; /*发送结束条件的数据信号*/

_Nop(); /*发送结束条件的时钟信号*/

SCL=1; /*结束条件建立时间大于4μs*/

_Nop();

_Nop();

_Nop();

_Nop();

_Nop();

SDA=1; /*发送I2C总线结束信号*/

_Nop();

_Nop();

_Nop();

_Nop();

}

/******************************************************************* 字节数据发送函数

函数原型: void SendByte(UCHAR c);

功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 此状态位进行操作.(不应答或非应答都使ack=0)

发送数据正常,ack=1; ack=0表示被控器无应答或损坏。

********************************************************************/ void SendByte(unsigned char c)

{

unsigned char BitCnt;

for(BitCnt=0;BitCnt

{

if((c

else SDA=0;

_Nop();

SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/ _Nop();

_Nop(); /*保证时钟高电平周期大于4μs*/

_Nop();

_Nop();

_Nop();

SCL=0;

}

_Nop();

_Nop();

SDA=1; /*8位发送完后释放数据线,准备接收应答位*/ _Nop();

_Nop();

SCL=1;

_Nop();

_Nop();

_Nop();

if(SDA==1)ack=0;

else ack=1; /*判断是否接收到应答信号*/

SCL=0;

_Nop();

_Nop();

}

/******************************************************************* 字节数据接收函数

函数原型: UCHAR RcvByte();

功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号), 发完后请用应答函数应答从机。

********************************************************************/ unsigned char RcvByte()

{

unsigned char retc;

unsigned char BitCnt;

retc=0;

/*置数据线为输入方式*/

for(BitCnt=0;BitCnt

{

SDA=1;

_Nop();

SCL=0; /*置时钟线为低,准备接收数据位*/ _Nop();

_Nop(); /*时钟低电平周期大于4.7μs*/ _Nop();

_Nop();

_Nop();

SCL=1; /*置时钟线为高使数据线上数据有效*/ _Nop();

_Nop();

retc=retc

if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */ _Nop();

_Nop();

SCL=0;

_Nop();

_Nop();

}

return(retc);

}

/******************************************************************** 应答子函数

函数原型: void Ack_I2c(bit a);

功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定) ********************************************************************/ void Ack_I2c(bit a)

{

if(a==0)SDA=0; /*在此发出应答或非应答信号 */ else SDA=1;

_Nop();

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop(); /*时钟低电平周期大于4μs*/

_Nop();

_Nop();

_Nop();

SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/ _Nop();

_Nop(); }

32

2013年全国大学生电子设计竞赛

简易旋转倒立摆及控制装置(C题)

【本科组】

2013年9月7

摘要

本题要求设计一个简易旋转倒立摆及控制系统,其中角度传感器、步进电机和单片机

890C521是系统核心部件。系统接收角度传感器反馈的信号,通过PCF8591将接收的信号转换成数字信号,将数值送入单片机中进行计算,可得出摆杆的位置,进而单片机控制步进电机,对摆杆进行控制,达到所要的旋转或者倒立的控制目标。

关键词:简易旋转倒立摆

步进电机

单片机 角度传感器

目录

1 设计任务及要求 .................................................... 5

1.1 设计任务 .................................................... 5 1.2 基本要求 ................................................... 5 2主控制器件的论证与选择 ............................................ 6

2.1控制器选用 ................................................... 6 2.2控制系统方案选择 ............................................. 6 2.3角度的获取模块论证与选择 ..................................... 6 2.4步进电机及其驱动模块的选择 ................................... 7 2.5 AD/DA的选择 ................................................. 7 3 系统的硬件设计 .................................................... 7

3.1总体电路框图 ................................................. 7 图3-1 系统框图 ..................................................... 8

3.2系统电路与程序设计 ........................................... 9

3.2.1 STC89C52单片机最小系统 ................................ 9 3.2.2 PCF8591模块图如图3-2。 ............................... 10 3.3.3 模块芯片TB6560AHQ原理图如图3-3。 .................... 10 3.3.4 供电电源 .............................................. 11

4系统软件总体设计框图 ............................................. 13 5 测试方案与测试结果 ............................................... 13 6 总结 ............................................................. 15 参考文献 ........................................................... 16 附录 ............................................................... 17

简易旋转倒立摆及控制装置(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.4 供电电源

图3-3 模块芯片TB6560AHQ原理图

由于需要驱动57步进电机,防止失步,其需要的功率较大,我们采用现有的直流稳压电源直接供电,电源模块的示意图如图3-5。为了达到较好的工作效果,我们选用兆信RXD-302-Ⅱ双路电源供电,具有很好的可靠性和灵活性,电压电流均可调,而且还在带一个5V电压输出端。

图3-5 电源电路

4系统软件总体设计框图 如图4-1所示。

图4-1 总体程序框图

5 测试方案与测试结果

测试结果(S)

这次设计的要求,所设计的系统要有较高的灵敏度和相应的转矩,这两样是最为重要的,我们所设计的系统,不能很好地满足要求,有待进一步改进

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 {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; }

Disp_Tab[] =

/******************************************************************* 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=4250)

n=1;

if(ad>=0&&ad

n=-1;

}

else n=0;

}

if(b==1)

{

if(xiang==0)

{

if(ad

n=-1;

if(ad>=ad0)

n=1;

}

else

round();

}

if(c==1)

{

if(ad>=2440&&ad

n=1;

if(ad>=2720&&ad

n=-1;

}

if(e==1)

{

if(ad

{

if(ad>=2380&&ad

n=1;

if(ad>=2720&&ad

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

{

Q=1;

}

else if(ad>1360&&ad

{

Q=2;

}

else if(ad>2380&&ad

{

Q=3;

}

else if(ad>2680&&ad

{

Q=4;

}

else if(ad>2980&&ad

{

Q=5;

}

else if(ad>4040&&ad

{

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

{

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

SDA=0; /*发送起始信号*/

_Nop(); /* 起始条件锁定时间大于4μs*/

_Nop();

_Nop();

_Nop();

_Nop();

SCL=0; /*钳住I2C总线,准备发送或接收数据 */

_Nop();

_Nop();

}

/******************************************************************* 结束总线函数

函数原型: void Stop_I2c();

功能: 结束I2C总线,即发送I2C结束条件.

********************************************************************/ void Stop_I2c()

{

SDA=0; /*发送结束条件的数据信号*/

_Nop(); /*发送结束条件的时钟信号*/

SCL=1; /*结束条件建立时间大于4μs*/

_Nop();

_Nop();

_Nop();

_Nop();

_Nop();

SDA=1; /*发送I2C总线结束信号*/

_Nop();

_Nop();

_Nop();

_Nop();

}

/******************************************************************* 字节数据发送函数

函数原型: void SendByte(UCHAR c);

功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 此状态位进行操作.(不应答或非应答都使ack=0)

发送数据正常,ack=1; ack=0表示被控器无应答或损坏。

********************************************************************/ void SendByte(unsigned char c)

{

unsigned char BitCnt;

for(BitCnt=0;BitCnt

{

if((c

else SDA=0;

_Nop();

SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/ _Nop();

_Nop(); /*保证时钟高电平周期大于4μs*/

_Nop();

_Nop();

_Nop();

SCL=0;

}

_Nop();

_Nop();

SDA=1; /*8位发送完后释放数据线,准备接收应答位*/ _Nop();

_Nop();

SCL=1;

_Nop();

_Nop();

_Nop();

if(SDA==1)ack=0;

else ack=1; /*判断是否接收到应答信号*/

SCL=0;

_Nop();

_Nop();

}

/******************************************************************* 字节数据接收函数

函数原型: UCHAR RcvByte();

功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号), 发完后请用应答函数应答从机。

********************************************************************/ unsigned char RcvByte()

{

unsigned char retc;

unsigned char BitCnt;

retc=0;

/*置数据线为输入方式*/

for(BitCnt=0;BitCnt

{

SDA=1;

_Nop();

SCL=0; /*置时钟线为低,准备接收数据位*/ _Nop();

_Nop(); /*时钟低电平周期大于4.7μs*/ _Nop();

_Nop();

_Nop();

SCL=1; /*置时钟线为高使数据线上数据有效*/ _Nop();

_Nop();

retc=retc

if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */ _Nop();

_Nop();

SCL=0;

_Nop();

_Nop();

}

return(retc);

}

/******************************************************************** 应答子函数

函数原型: void Ack_I2c(bit a);

功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定) ********************************************************************/ void Ack_I2c(bit a)

{

if(a==0)SDA=0; /*在此发出应答或非应答信号 */ else SDA=1;

_Nop();

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop(); /*时钟低电平周期大于4μs*/

_Nop();

_Nop();

_Nop();

SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/ _Nop();

_Nop(); }

32


相关文章

  • 2013全国电子大赛论文
  • 2013全国电子设计大赛瑞萨杯 2013年全国大学生电子设计竞赛 简易旋转倒立摆控制及控制装置( [本科组] 2013年9月4日 C题) 摘 要 旋转倒立摆是一个具有多变量.高阶.非线性.强耦合等系统特性的本征不稳定系统,涉及有关力学.数学 ...查看


  • 全国电子设计大赛报告
  • 2013年全国大学生电子设计竞赛 简易旋转倒立摆及控制装置(C题) [本科组] 摘要: 通过对该测控系统结构和特点的分析,结合现代控制技术设计理念实现了以微控制器MC9S12XS128系列单片机为核心的旋转倒立摆控制系统.通过采集的角度值与 ...查看


  • 旋转倒立摆的数学建模与计算机控制
  • 第26卷第8期增刊 仪器仪表学报 2005年8月 旋转倒立摆的数学建模与计算机控制 孙宏放王显峰彭秀艳 (哈尔滨工程大学自动化学院哈尔滨150001) 摘要运用动力学原理建立了单级旋转倒立摆系统的数学模型.在此基础上基于计算机辅助设计,进行 ...查看


  • 张蕙兰瑜伽全教程
  • 张蕙兰瑜伽全教程 免费下载地址:http://dwz.cn/6Zkgv(复制到IE浏览器打开即可下载) 目录 1. 瑜伽科学和文化 瑜伽的功法和益处 瑜伽功法简介 练习瑜伽需要的配备 2. 肩旋转功 脚踝功 蹲功 仰卧放鬆功 冥想作功 - ...查看


  • 一级倒立摆分析
  • 一级倒立摆的极点配置及仿真 摘要 倒立摆系统是一个复杂的.高度非线性的.不稳定的高阶系统,是学习和研究现代控制理论最合适的实验装置.倒立摆的控制是控制理论应用的一个典型范例,一个稳定的倒立摆系统对于证实状态空间理论的实用性是非常有用的. 本 ...查看


  • 重庆大学自动控制课程设计
  • 自动控制理论课程设计 倒立摆系统的控制器设计 学生姓名: 陆源 指导教师: 班 级: 重庆大学自动化学院 二O 一一年十二月 课程设计指导教师评定成绩表 指导教师评定成绩: 指导教师签名: 年 月 日 重庆大学本科学生课程设计任务书 目录 ...查看


  • 中等职业学校专业课有效教学模式应用方法研究
  • 广西机械高级技工学校   杨杰忠 [摘要]随着社会经济的发展,中等职业学校必须对专业课程目标重新定位,创新教学模式,实现教学环境企业化.专业课程项目化.教学方式理实一体化.教学关系师徒化.教学评价多元化,以符合现代技术工人的培养要求. [关 ...查看


  • 八年级物理专题训练[透镜及凸透镜成像规律]
  • 八年级物理专题训练<透镜及凸透镜成像规律>(1) 1.(2013.南宁)如图所示,一束平行光经过凸透镜后,在光屏上得到一个最小.最亮的光斑.由此可知,凸透镜对光有_______作用,它的焦距是_______cm. 2.(2013 ...查看


  • 电子信息工程毕业设计题目大全
  • 1 压力容器液位测量 2 多功能遥控小车 3基于RS232的仓库多点温度.湿度.气 4压检测系统 5自动控制升降旗系统 6基于RS485的温度报警系统 7基于模糊算法的水温控制系统的设计 8多分机电话交换机 9简易火灾自动报警系统 10基于 ...查看


热门内容