电动车跷跷板程序

合集下载

电动车跷跷板设计方案

电动车跷跷板设计方案

电动车跷跷板设计方案电动车跷跷板是一种创新性的设计,可以帮助人们更方便地停靠和启动电动车。

在许多城市,电动车已经成为主要的出行方式。

然而,电动车在停车时,需要使用力量将车辆托起或降下,这对于一些年纪较大或身体不适的人来说可能会很困难。

因此,电动车跷跷板是一项非常有用的发明,能够让电动车的停放更加容易和便捷。

一般来说,电动车跷跷板有两种设计方案:手动操作和自动操作。

手动操作的设计需要用户手动旋转跷跷板,以将电动车推起或降下。

这种设计成本较低,但用户需要一定的力量和技能才能轻松完成操作。

另外,手动操作的设计需要更多的时间和精力,不太适合老年人或身体有残疾的人。

自动操作的设计是一种更加先进和高级的设计,它利用电动机和控制器来完成跷跷板的升降操作。

用户只需要轻按按钮或开关即可完成整个过程。

自动操作的设计有多种控制方式,包括遥控器、传感器和自动识别系统等等。

这种设计的成本更高,但用户可以省去很多时间和精力,使用起来非常方便。

除了操作方式的不同,电动车跷跷板的设计还有很多其他的特点。

比如,电动车跷跷板的材料可以采用钢板、铝合金、塑料等多种材质,不同的材料有着不同的优势和劣势,需要根据风险防范、耐用性、安全性和成本等多个因素来选择。

电动车跷跷板的设计还可以增加一些额外的功能,如夜视灯、加热器、视音频系统等等,这些增强功能可以使车辆的停放更加智能化和便捷。

除了以上提到的基本设计特点,为了满足不同用户的需求和喜好,电动车跷跷板还可以增加一些个性化的设计元素。

比如,可以在跷跷板表面印上个性化的图案或标志,让用户可以将自己的电动车个性化地装扮起来。

此外,电动车跷跷板的外形和尺寸也可以根据用户需求进行定制。

在选择电动车跷跷板方案时,需要考虑很多因素,如成本、设计和效果等等。

这些因素关系到电动车跷跷板的使用效果和意义,也与对于产品的整体评估有关。

因此,我们需要在设计电动车跷跷板时,充分考虑不同用户的需求和喜好,以期为用户提供最佳的使用体验。

电动车跷跷板设计方案

电动车跷跷板设计方案

电动车跷跷板设计方案柳州运输职业技术学院摘要该电动车以凌阳SPCE061A作为操纵及数据处理的核心,通过传感器检测、操纵电动车电机的快慢、启停。

电动车能够在跷跷板上自动查找平稳点,并具有实时显示电动车行驶时刻及任务完成之后自动播报从起始端自动行走到末端及返回所需时刻或从起始端自动行走到电动车保持平稳所需时刻。

关键字:SPCE061A 倾角传感器光电传感器 PWM一、方案设计与论证本项目按设计要求可分为五部分,分别为操纵模块、循迹模块、平稳检测模块、电机驱动模块、显示模块,如图1所示。

图1 系统模块框图〔一〕操纵模块方案一:采纳AT89C51系列单片机作为操纵的核心。

51单片机按单纯的操纵和数据处理是比较经济实惠的,但本项目触及到A/D转换和PWM操纵,假如要具备这两个功能必须要有专用的A/D芯片和PWM操纵电路,这无疑是提高了成本。

方案二:采纳凌阳16位单片机SPCE061A作为操纵的核心。

SPCE061A具有10位A/D转换和PWM操纵功能,且具备语音播报功能,使作品更加智能化。

综上分析,选择方案二。

〔二〕平稳检测模块方案一:采纳水银开关检测跷跷板平稳点。

其内部是由两根导线组合而成,只要当水银流淌到导线的两端即水银把两根导线短接在一起。

但当跷跷板平稳时,有可能水银开关还未闭合,可靠性不高。

方案二:采纳Accu StarⅡ倾角传感器检测跷跷板平稳点。

此倾角传感器是通过改变角度来改变其输出电压,具有良好的线性变化,如图2所示,通过读取输出电压的值来操纵小车的速度,有助于电动车找到平稳点。

因此选择方案二。

〔三〕电机驱动模块方案一:采纳分立元件构成的H桥式电机驱动电路。

该驱动电路的优点是成本低,缺点是电路制作比较苦恼,可靠性不高。

方案二:采纳L293D驱动电机。

使用该芯片驱动的好处是在额定的电压和电流内使用专门方便可靠,能够缩小PCB板。

用SPCE061A自带的PWM操纵电机成效更好,使电动车更容易的查找到跷跷板的平稳点。

基于PID 算法的电动车跷跷板系统设计

基于PID 算法的电动车跷跷板系统设计

基于PID算法的电动车跷跷板系统设计聂晓凯中南大学信息科学与工程学院,长沙(410083)E-mail:kasaos@摘要:本系统采用P89V51RD2单片机作为控制系统的核心,采用步进电机作为电动车驱动电机,以L298为驱动芯片,配以舵机改变转向,使用角度传感器检测跷跷板的角度变化,在车的前后端设计了红外黑线检测模块保证电动车顺利驶上板以及在板上笔直行驶,红外光电码盘通过脉冲计数确定电动车在板上的位置,红外遥控键盘启动系统开始运行,液晶显示相关参数信息。

系统的平衡调节采用了数字PID控制算法,利用凑试法整定PID参数,通过角度传感器所测角度变化来控制步进电机的的转动实现跷跷板达到平衡状态。

关键词:P89V51RD2单片机,PID,角度传感器中图分类号:TP2712007年全国大学生电子设计竞赛的一道控制类的题目是电动车跷跷板问题,本系统设计要求电动车能够在规定时间内到达跷跷板的中心点C处,并保持平衡,随后电动车到达跷跷板的末端B处,停留之后返回始端A处。

另外,如果将跷跷板配重,则要求跷跷板在规定范围内驶上板,同时,也能实现平衡,如果再加一块重物之后跷跷板重新达到平衡。

本系统的设计在本文中采用了数字PID控制算法来实现。

1 系统方案设计、比较与论证1.1 总体方案设计论证本系统采用P89V51RD2单片机作为控制系统的主模块,实现系统控制与信号检测,如图1-1所示系统框图。

主要包括单片机模块,驱动电机模块,舵机模块,平衡检测模块,寻线模块,位置检测模块,液晶显示模块以及红外遥控模块。

图 1-1 系统框图系统通过平衡检测来判断电动车是否处于平衡状态,使电动车停留在C处附近,采用位置检测使电动车行驶至B处停止,采用寻黑线方法使电动车直线前行以及由末端B处能够直线后退到始端A处。

红外遥控启动系统,液晶显示各阶段用时以及温度时间。

在配重情况下通过黑线检测的方法使电动车在规定区域内的任意指定位置顺利驶上跷跷板。

电动车跷跷板 新2

电动车跷跷板 新2

2007年全国大学生电子设计竞赛F题电动车跷跷板设计报告摘要本系统是以单片机AT89S52为核心,利用红外光电传感器,角度传感器以及他们的外围电路组成的测控系统,实现对在跷跷板上行驶的小车的运动状态的实时跟踪监测,由单片机对电动小车的位姿状态做出及时正确的反应,并输出相应的控制指令,经过驱动模块后由执行模块完成小车的爬行、减速、找出平衡位置并保持等一系列要求完成的整套动作。

关键词:步进电机;电动小汽车;控制AbstractThe system is at the core MCU AT89S52, using infrared photoelectric sensor, angle sensors and their external circuit composed of measurement and control system, in the seesaw of a car traveling on the state of real-time campaign tracking, MCU right by the electric trolley in state funding to timely correct response output control and the corresponding instructions, the driver module after module completed by the Executive car crawling, slow down, find balance and maintain the position, and a series of actions required to complete the package.Keywords: step motor; electronic automobile; control一、系统方案论证本系统采用的是AT89S52实现电动小车的寻迹、爬行、找平衡、返回,并达到时间上的精确控制与显示。

跷跷板小车程序

跷跷板小车程序

#include<reg52.h>#include<stdio.h>#include<intrins.h>#include"delay.h"#include"PWM.h"#include"1602.h"sfr ADC_CONTR = 0xBC; //A/D 转换控制寄存器ADC_POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0 0000,0000sfr ADC_RES = 0xBD; //A/D 转换结果高8位ADCV.9 ADCV.8 ADCV.7 ADCV.6 ADCV.5 ADCV.4 ADCV.3 ADCV.2 0000,0000sfr ADC_RESL = 0xBE; //A/D 转换结果低2位sfr P1ASF = 0x9D; //P1 analog special functionsfr AUXR = 0x8E; //Auxiliary Register T0x12 T1x12 UART_M0x6 BRTR S2SMOD BRTx12 EXTRAM S1BRS 0000,0000//-----------------------------------sfr AUXR1 = 0xA2; //Auxiliary Register 1 - PCA_P4 SPI_P4 S2_P4 GF2 ADRJ - DPS 0000,0000sbit key=P2^7;sbit dianji10=P1^1;sbit dianji11=P1^2;sbit dianji20=P1^5;sbit dianji21=P1^6;sbit XUNJIL=P2^0;sbit XUNJIR=P2^1;sbit XUNJI2L=P2^2;sbit XUNJI2R=P2^4;typedef unsigned char INT8U;typedef unsigned int INT16U;typedef unsigned long int INT32U;//---------------------------------------------------------------------//以下选择ADC 转换速率,只能选择其中一种// SPEED1 SPEED0 A/D转换所需时间#define AD_SPEED 0x60 // 0110,0000 1 1 70 个时钟周期转换一次,// CPU工作频率21MHz时A/D转换速度约300KHz//#define AD_SPEED 0x40 //0100,0000 1 0 140 个时钟周期转换一次//#define AD_SPEED 0x20 //0010,0000 0 1 280 个时钟周期转换一次//#define AD_SPEED 0x00 //0000,0000 0 0 420 个时钟周期转换一次//---------------------------------------------------------------------INT16U get_AD_result_10F(INT8U channel) //10位AD带均值滤波{INT8U AD_finished=0; //存储A/D 转换标志INT16U out=0;INT16U N=40;INT16U sum=0;INT8U m;ADC_RES = 0;ADC_RESL = 0;channel &= 0x07; //0000,0111 清0高5位ADC_CONTR |= channel; //选择A/D 当前通道_nop_();for(m=0;m<N;m++){ //均值滤波ADC_CONTR |= 0x08; //0000,1000 令ADCS = 1, 启动A/D转换,AD_finished = 0;while (AD_finished ==0 ) //等待A/D转换结束{AD_finished = (ADC_CONTR & 0x10); //0001,0000 测试A/D 转换结束否}ADC_CONTR &= 0xE7; //1110,0111 清ADC_FLAG 位, 关闭A/D转换,out= ADC_RES;out=(out<<2)+(ADC_RESL&0xfc);sum=sum+out;} //带均值滤波return (sum/N); //返回A/D 高8 位转换结果}//定义变量float Kp; //PID调节的比例常数float Ti; //PID调节的积分常数float T; //采样周期float Ki;float ek1; //偏差e[k-1]float ek2; //偏差e[k-2]float uk; //u[k]int uk1; //对uk四舍五入求整int adjust; //最终输出的调整量int ee;int bb,bb1,bb2;bit flag=1;INT16U ADC_result2;INT32U gg2;double a;float gabs(float a1){if(a1<0){a1=0-a1;}return a1;}int piadjust(float ek) //PI调节算法{if( gabs(ek)<2 ){adjust=0;}else{uk=Kp*(ek-ek1)+Ki*ek; //计算控制增量ek1=ek;uk1=(signed int)uk;if(uk>0){if(uk-uk1>=0.5){uk1=uk1+1;}}if(uk<0){if(uk1-uk>=0.5){uk1=uk1-1;}}adjust=uk1;}return adjust;}void INIT_TIME0(){TMOD=0x01;EA=1;ET0=1;TR0=1;TH0=(65535-5000)/256;TL0=(65535-5000)%256;}void main(){P1ASF = 0x01; //0000,0010, 将P1.0 置成模拟口//ADRJ = AUXR1^2:// 0: 10 位A/D 转换结果的高8 位放在ADC_RES 寄存器, 低2位放在ADC_RESL 寄存器// 1: 10 位A/D 转换结果的最高2 位放在ADC_RES 寄存器的低2 位, 低8 位放在ADC_RESL 寄存器AUXR1 &= ~0x04; //0000,0100, 令ADRJ=0// AUXR1 |= 0x04; //0000,0100, 令ADRJ=1 ADC_CONTR = AD_SPEED;_nop_();ADC_CONTR |= 0x80; //1000,0000 打开A/D 转换电源P0=0x00;PWMINIT();// LCD_Init();delay_50ms(100);dianji10=1;dianji11=0;dianji20=1;dianji21=0;//INIT_TIME0();/******************************************************** ********///变量初始化,根据实际情况初始化Kp=8;// Ti=0.05;T=0.01;Ki=0;// Ki=KpT/Ti=0.8,微分系数Kd=KpTd/T=0.8,Td=0.0002,根据实验调得的结果确定这些参数ek1=0;ek2=0;uk=0;uk1=0;adjust=0;bb=150;INIT_TIME0();while(1) //循迹{if(flag==1){/*if(XUNJIL==0&&XUNJIR==1){delay_50us(5);if(XUNJIL==0&&XUNJIR==1)PWMDR(10,0);}if(XUNJIR==0&&XUNJIL==1){delay_50us(5);if(XUNJIR==0&&XUNJIL==1)PWMDR(0,10);}if(XUNJIR==0&&XUNJIL==0){delay_50us(5);if(XUNJIR==0&&XUNJIL==0)PWMDR(1,2);}if(XUNJIR==1&&XUNJIL==1){delay_50us(5);if(XUNJIR==1&&XUNJIL==1)PWMDR(25,25);}*/if(XUNJIL==0&&XUNJIR==1){PWMDR(10,0);}if(XUNJIR==0&&XUNJIL==1){PWMDR(0,10);}if(XUNJIR==0&&XUNJIL==0){PWMDR(1,2);if(XUNJIR==1&&XUNJIL==1){PWMDR(25,25);}}if(flag==0){// PWMDR(2,3);/*if(XUNJI2L==0&&XUNJI2R==1){//delay_50us(5);// if(XUNJI2L==0&&XUNJI2R==1)PWMDR(0,10);}if(XUNJI2R==0&&XUNJI2L==1){//delay_50us(5);// if(XUNJI2R==0&&XUNJI2L==1)PWMDR(10,2);}if(XUNJI2R==0&&XUNJI2L==0){//delay_50us(5);// if(XUNJI2R==0&&XUNJI2L==0)PWMDR(2,1);}if(XUNJI2R==1&&XUNJI2L==1){//delay_50us(5);// if(XUNJI2R==1&&XUNJI2L==1)PWMDR(25,25);}*/if(XUNJI2L==0&&XUNJI2R==1){PWMDR(0,10);}if(XUNJI2R==0&&XUNJI2L==1){PWMDR(10,0);}if(XUNJI2R==0&&XUNJI2L==0){PWMDR(2,1);if(XUNJI2R==1&&XUNJI2L==1){PWMDR(25,25);}}}}void time0() interrupt 1{TR0=0;TH0=(65535-10000)/256;TL0=(65535-10000)%256;ADC_result2 = get_AD_result_10F(0);//P1.0 为A/D 当前通道, 测量并发送结果gg2=(INT32U)((INT32U)ADC_result2*5000)/1024;if(gg2<500) gg2=500;a=(float)(gg2-500)*0.045; // 转换成角度/* a=a-90;bb=bb+piadjust(a);bb2=bb;if(bb2>255) bb2=255;if(bb2<0) bb2=0;CCAP0H = CCAP0L = bb2; //P1.3输出CCAP1H = CCAP1L = bb2; //P1.4输出*/if(a>95){d ianji10=1;dianji11=0;dianji20=1;dianji21=0;flag=0;}if(a<95&&a>85){d ianji10=0;dianji11=0;dianji20=0;dianji21=0;//flag=2;}if(a<85){dianji10=0;dianji11=1;dianji20=0;dianji21=1;flag=1;}TR0=1;}。

跷跷板小车制作

跷跷板小车制作

电动车跷跷板设计任务:设计并制作一个电动车跷跷板,在跷跷板起始端A一侧装有可移动的配重。

配重的位置可以在从始端开始的200mm~600mm范围内调整,调整步长不大于50mm;配重可拆卸。

电动车从起始端A出发,可以自动在跷跷板上行驶。

电动车跷跷板起始状态和平衡状态示意图分别如图1和图2所示。

设计思路:因为小车要在跷跷板上自动寻找平衡点所以要有一个平衡装置当小车倾斜时小车就会向前或后走的地方走而达到平衡。

因为翘翘板的宽度较小所以要小车按固定的直线行走,小车要时刻记时所以用电子显示装置计时。

基本设计(1)平衡部分因为小车在板上寻找平衡点所以要用到平衡装置有以下三个方案方案一:利用SCA100T传感器。

SCA100T优点:(1)双轴倾角传感器。

(2)测量范围0.5g或者1g。

(3)单极5伏供电,比例电压输出。

(4)长期稳定性非常好。

(5)高分辨率,低声,工作温度范围广。

缺点:灵敏度太高,价格昂贵,抗干扰能力差。

方案二:利用水银开关。

优点:(1)价格低,容易买到。

(2)制作方便,操控性好。

(3)工作范围广缺点:不稳定,水银液体不太容易控制。

方案三:利用旋转型可调电阻和铅坠。

优点:(1)价格低,容易组装。

(2)操控性好,灵敏度高。

(3)可以利用电阻的变化算出倾斜角。

缺点:有摩擦影响,受外界影响。

综上所述:经比较方案三比较好实验室中可以找到所用器材,可以通过电阻的变化算出倾角,价格较为便宜。

方案三的具体方法:首先将可变电阻的旋钮与铁杆连接起来,铁杆的另一端是较重的铅锤。

当小车的倾角变化时由于铅锤的重力作用在小车的带动下可变电阻的阻值产生变化,电压或电流发生变换传给单片机从而控制小车来找平衡点。

平衡装置原理图:(2)小车寻路装置:方案一启发:利用小车红外向寻路装置,可以让小车沿黑线在桥面上行走,当小车找到平衡点时小车自动停止,当小车到达桥的尽头是黑线消失小车停止倒行,这样可以防止小车一直沿直线行走能掉下桥。

方案二可以在小车两侧按上传感装置让小车不能掉下桥去。

2007电动车跷跷板

2007电动车跷跷板
直流电机具有很高的速度、调速平滑方便、调整范围广等优点,但是当低速运行时,输出力矩很小。在本题目中当小车处在平衡系统的平衡点附近时,小范围的移动和反馈变得十分重要,这很难用直流电机完成,而且直流电机在小角度转动的时候接近短路,大电流给驱动电路带来了很大负担。
方案三:直流减速电机
减速电机是一种带有减速齿轮的直流电机。因此它具有直流的优点,另外它在低速运行时也能够实现较大的力矩输出。
图8.程序流程图
五、测试结果及分析
测试仪器:数字万用表、游标高度计、秒表、卷尺、示波器,测试环境为室内。
1.测试步骤
1)在外界环境光变化比较缓和的情况下用数字滤波算法,测定反射物分别是白色和黑色表面的反射参数。
2)在舵机正常供电的情况下输入PWM信号确定与舵机转角的线性关系。
六、结束语
本次设计按照题目要求,采用模块化的硬件和软件设计方法,以及较合适的控制算法,成功地实现了小车自动平衡控制,以及自动方向导行功能,整个系统紧凑,完成了题目基本部分和发挥部分的全部要求。
2.倾角检测电路
角度传感器(SCA60C)的供电电压为5V,其模拟输出电压范围为0.5-4.5V,对应倾斜角为 ,其输出信号最高刷新频率为80Hz,该信号送至单片机内部10位高速A/D口。得到的A/D值可以经过运算转换为倾角度数。
3.红外循迹电路
红外发射管的安全工作电流为40mA左右,三极管的饱和压降为0.3V,红外发射管的正压向降为1.3V左右,因此最小限流电阻R=(5-1.3-0.3)/0.04=85(Ω),选用100Ω。红外发射电路如图7所示。红外管安装结构是小车前部为8对,一字型等距排开,主要起正向导向作用,后部安装两对,主要起后退导向作用。由于红外管对外界光比较敏感,因此硬件和软件都需采取一定的技术措施,主要采用脉冲调制方法去除外部干扰信号。将一定频率的PWM信号调制在红外发射管上,使得红外发射管按照PWM信号开关,在相邻两次的开和关状态对接收管上反馈电阻进行A/D采样,当PWM频率较高时,就可以将外部低频干扰滤除。由表1和表2可见,当差值以0.5V为阈值时,可以将黑线很好地判别出来。

电动车跷跷板 (电子设计大赛)

电动车跷跷板 (电子设计大赛)

电动车跷跷板摘要本系统以freescale公司提供的DG128芯片作为核心控制芯片,且通过在白色衬底上贴一条长2.5cm的黑线作为小车的引导线,让小车在跷跷板上能稳定的行驶。

为实现题目所要求的功能,用角度传感器作为跷跷板角度反馈量,通过一定的算法控制小车的速度使小车能够在跷跷板上找到平衡点。

小车的设计包括如下几个模块:摄像头采集,角度传感器安装与采集,驱动和转向的控制,速度检测,液晶显示模块等。

一、系统方案(一)方案的论证与比较根据大赛题目的设计要求,跷跷板的尺寸规格已经在题目中规定好,只需按照规定自制一个就可,所以此次设计的主要精力放在小车的设计上。

1、小车的引导由于可以在跷跷板上加引导措施,受2003年简易智能小车启发,在跷跷板表面铺白色衬底,在中间贴2.5cm的黑线,用传感器检测中间黑线的位置即可使小车在板上能稳定的行驶。

方案一:红外管,即用红外管检测黑线,通过黑白线之间的电压值的变化识别黑线,此方案电路较为简单,处理数据也较简单,但是红外管受环境光的影响比较大,及容易出现偏离轨道等错误。

方案二:摄像头,受环境光影响比红外管小很多,但在光照很强的情况下也会有很大的影响。

但是由于这是室内的比赛,所以光照很强的情况可以不用太多考虑。

另一方面是摄像头照射范围宽并且广,所以采集的信息比红外管多,对黑线的识别更为精确和有效。

选取方案二。

2、驱动电路的选择采用专门的小功率电机驱动芯片MC33886,可用单片机PWM端口给直接控制,但一片发热量比较大,所以采用4片33886并联驱动,首先驱动能力加强,而且在不加散热片反压时的发热量也很低。

4片也有一定的缺点:一是所占面积比较大,二是对电池电压的损耗比较大。

3、检测角度传感器的选择由于小车需要在加重的情况下在木板上保持平衡,需要采用木板所倾斜的角度作为回馈量,理想状态下当木板的倾斜角度为0时表示木板已经平衡。

方案一:电位器电阻值法,即在电位器上挂一个重物,重物由于重力总是垂直与水平面,当角度变化时则可以带动电位器的中心抽头变化,从而通过电阻值变化计算出角度的变化。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

我自己写的电动车跷跷板程序,做了一个1602菜单(只用了3个键哟!),使用步进电机,采用折半查找法寻找平衡点,最小步进达到1mm,还有很多其他功能,自己用51单片机试试看,这个是源程序,文库里还有个报告,加上一句我用的是倾角传感器,用AD采样算倾角。

#include<reg52.h>#define uchar unsigned char#define uint unsigned int#define Xiaodou 50 //消抖时间#define OneCircle 512//OneCircle次循环为360度#define LCircle 23//轮子转一圈为LCircle cm#define FirstJour 256//找重心第一步#define SAOMIAO 600//延迟600ms测一次角度#define QueDing 700//平衡确定延时#define UpAngle 0x82//上限角度,大于上限角表示向前翘起,2.56V#define DownAngle 0x7e//下限角度,小于下限角表示向后翘起,2.45Vsbit KeyEnter=P3^2;//调整确定键sbit KeyUp=P3^3;//上方向键sbit KeyRight=P3^4;//右方向键sbit LCDRs=P3^0;//液晶的命令数据端sbit LCDEn=P3^1;//液晶的使能端sbit ADST=P3^5;//AD0809的转换启动信号端STsbit ADEOC=P3^6;//AD0809的转换结束信号,高电平表示转换结束sbit ADCLK=P3^7;//AD0809的时钟为500KHzsbit FLLight=P1^4;//前左灯,低电平发光sbit FRLight=P1^5;//前右灯,低电平发光sbit BLLight=P1^6;//后左灯,低电平发光sbit BRLight=P1^7;//后右灯,低电平发光uchar timecount=0;uint count[4]={0,0,0,0};//控制时间,4个过程的时间uint journey[4]={60,65,55,115};//设置行程uchar speed=3;//速度参量uchar step=0;//步骤游标uchar protype[4]={0,2,0,1};//每个步骤指令uchar CharDisp[3];//用于显示字符uchar code F_Rotation[]={0xc9,0xc1,0xc3,0xc2,0xc6,0xc4,0xcc,0xc8};//正转表格,前灯亮uchar code B_Rotation[]={0x38,0x3c,0x34,0x36,0x32,0x33,0x31,0x39};//反转表格,后灯亮void Delay(uint x,uint y)//x=1,y=110每执行一次大概为1ms{for(;x>0;x--)for(y=110;y>0;y--);}void WriteCommond(uchar com)//给液晶写入指令,com为16进制{LCDRs=0;P0=com;//液晶的数据端口Delay(5,110);LCDEn=1;Delay(5,110);LCDEn=0;}void WriteData(uchar date)//给液晶写入字符,com为16进制{LCDRs=1;P0=date;//液晶的数据端口Delay(5,110);LCDEn=1;Delay(5,110);LCDEn=0;}void WriteString(uchar * string)//写入字符串{for(;*string;string++)WriteData(*string);}void DispTimeS(uint times,uchar address)//显示时间或者距离{uchar i=0;CharDisp[0]=times/100;CharDisp[1]=times%100/10;CharDisp[2]=times%10;WriteCommond(address);for(;i<=2;i++){WriteData(CharDisp[i]+'0');}}void RunXCircle(uchar drec,uint num)//轮子跑num圈,drec为0向前,为1向后{uchar i;uint j;while(num--){j=OneCircle;while(j--){for(i=0;i<8;i++) //4相{if(!drec)P1=F_Rotation[i]; //输出对应的相,可以自行换成反转表格elseP1=B_Rotation[i];Delay(speed,110); //改变这个参数可以调整电机转速}}}P1=0xf0;//停止行走,灯熄灭}void RunNCircle(uchar drec,uint num)//轮子转num个最小单位,drec为1向前,为0向后{uchar i;//num*=OneCircle/LCircle;while(num--){for(i=0;i<8;i++) //4相{if(!drec)P1=F_Rotation[i]; //输出对应的相,可以自行换成反转表格elseP1=B_Rotation[i];Delay(speed,110); //改变这个参数可以调整电机转速}}P1=0xf0;//停止行走,灯熄灭}uchar DeltFind()//返回指为2表示平衡了,为0需要向前走,为1需要向后走{uchar angle,result=2;ADST=0;ADST=1;ADST=0;//启动AD0809转换while(!ADEOC);//等待AD0809转换结束angle=P2;//读取转化后的数据if(angle>UpAngle) result=0;//小车向前翘起,需要向前走else if(angle<DownAngle) result=1;//小车向后翘起,需要向后走else result=2;//小车平衡return result;}void RunFwodBak(uchar drec,uchar jour)//drec为方向,0向前,1向后,jour为路程,单位是cm {RunXCircle(drec,jour/LCircle);//先跑完整圈RunNCircle(drec,(jour%LCircle)*OneCircle/LCircle);//再跑半圈}void RunFind(){uchar delt=0,flag=0;uint jour=FirstJour;TR1=1;//开时钟让AD工作for(delt=DeltFind();;delt=DeltFind()){if(delt==2){Delay(QueDing,110);delt=DeltFind();if(delt==2){WriteCommond(0x86);WriteString("balanced!!");Delay(5000,110);break;}}if(delt!=flag) jour/=2;if(!jour){WriteCommond(0x86);WriteString("Failed");Delay(3000,110);break;}RunNCircle(delt,jour);flag=delt;Delay(SAOMIAO,110);}TR1=0;//关时钟}void WindowMain()//输出主界面{WriteCommond(0x81);WriteString("SET");WriteCommond(0x8c);WriteString("VIEW");WriteCommond(0xc1);WriteString("RUN");}void WindowSet()//输出设置界面{WriteCommond(0x81);WriteString("P1");WriteCommond(0x87);WriteString("P2");WriteCommond(0x8c);WriteString("P3");WriteCommond(0xc1);WriteString("P4");WriteCommond(0xc5);WriteString("SPEED");WriteCommond(0xcc);WriteString("EXIT");}void WindowFunction()//输出功能界面{WriteCommond(0x81);WriteString("FOWORD");WriteCommond(0x8c);WriteString("BACK");WriteCommond(0xc1);WriteString("FIND");}void WindowParamet()//输出参数设置界面{WriteCommond(0x80);WriteString("S:");WriteCommond(0x85);WriteString("CM");}void WindowRun()//输出运行时界面{WriteCommond(0x80);WriteData('P');WriteCommond(0xc0);WriteString("AL:");WriteCommond(0xc6);WriteData('s');WriteCommond(0xc8);WriteString("SIG:");WriteCommond(0xcf);WriteData('s');}void WindowView()//输出查看界面{WriteCommond(0x80);WriteString("P1:");WriteCommond(0x89);WriteString("P2:");WriteCommond(0xc0);WriteString("P3:");WriteCommond(0xc9);WriteString("P4:");}void WindowSpeed(){WriteCommond(0x80);WriteString("SPEED STAGE:");}void MenuSpeed(){WriteCommond(0x0e);//显示光标WindowSpeed();WriteCommond(0xc0);WriteData(speed-2+'0');WriteCommond(0xc0);while(1){if(!KeyUp){Delay(Xiaodou,110);if(!KeyUp){while(!KeyUp){}speed++;if(speed>11) speed=3;WriteCommond(0xc0);WriteData(speed-2+'0');WriteCommond(0xc0);}}if(!KeyEnter){Delay(Xiaodou,110);if(!KeyEnter){while(!KeyEnter){}break;}}}}MenuParamet(uchar process){uchar cursor=0;WriteCommond(0x0e);//显示光标WindowParamet();DispTimeS(journey[process],0x82);while(1){if(!KeyEnter){Delay(Xiaodou,110);if(!KeyEnter){while(!KeyEnter){}break;}}if(!KeyRight){Delay(Xiaodou,110);if(!KeyRight){while(!KeyRight){}cursor++;cursor%=3;}}if(!KeyUp){Delay(Xiaodou,110);if(!KeyUp){while(!KeyUp){}CharDisp[cursor]++;CharDisp[cursor]%=10;journey[process]=CharDisp[0]*100+CharDisp[1]*10+CharDisp[2];DispTimeS(journey[process],0x82);}}WriteCommond(0x82+cursor);}}void MenuFunction(uchar process)//每步功能设置{uchar cursor=0,address=0x80;WriteCommond(0x0c);//不显示光标也不闪烁while(1){if(!KeyUp){Delay(Xiaodou,110);if(!KeyUp){while(!KeyUp){}cursor+=2;cursor%=4;WriteCommond(0x01);//清除显示}}if(!KeyRight){Delay(Xiaodou,110);if(!KeyRight){while(!KeyRight){}if(cursor==3) cursor=2;cursor+=1;cursor%=3;WriteCommond(0x01);//清除显示}}if(!KeyEnter){Delay(Xiaodou,110);if(!KeyEnter){while(!KeyEnter){}WriteCommond(0x01);//清除显示if(cursor==2||cursor==3) protype[process]=2;else{protype[process]=cursor;MenuParamet(process);}break;}WriteCommond(0x01);//清除显示WriteCommond(0x0c);//不显示光标也不闪烁}switch(cursor){case 0:address=0x80;break;case 1:address=0x8b;break;case 2:case 3:default:address=0xc0;}WindowFunction();//显示设置界面WriteCommond(address);WriteData(0x7e);}}void MenuSet(){uchar cursor=0,address=0x80;WriteCommond(0x0c);//不显示光标也不闪烁while(1){if(!KeyUp){Delay(Xiaodou,110);if(!KeyUp){while(!KeyUp){}cursor+=3;cursor%=6;WriteCommond(0x01);//清除显示}}if(!KeyRight){Delay(Xiaodou,110);if(!KeyRight){while(!KeyRight){}cursor+=1;cursor%=6;WriteCommond(0x01);//清除显示}}if(!KeyEnter){Delay(Xiaodou,110);if(!KeyEnter){while(!KeyEnter){}WriteCommond(0x01);//清除显示if(cursor==5) break;else if(cursor==4) MenuSpeed();elseMenuFunction(cursor);}WriteCommond(0x01);//清除显示WriteCommond(0x0c);//不显示光标也不闪烁}switch(cursor){case 0:address=0x80;break;case 1:address=0x86;break;case 2:address=0x8b;break;case 3:address=0xc0;break;case 4:address=0xc4;break;case 5:default:address=0xcb;}WindowSet();//显示设置界面WriteCommond(address);WriteData(0x7e);}}void MenuView()//View功能{WriteCommond(0x0c);//不显示光标也不闪烁WindowView();DispTimeS(count[0],0x83);WriteData('s');DispTimeS(count[1],0x8c);WriteData('s');DispTimeS(count[2],0xc3);WriteData('s');DispTimeS(count[3],0xcc);WriteData('s');while(1){if(!KeyEnter){Delay(Xiaodou,110);if(!KeyEnter){while(!KeyEnter){}WriteCommond(0x01);//清除显示WriteCommond(0x80);WriteString("OVER ALL TIME:");DispTimeS(count[0]+count[1]+count[2]+count[3],0xc0);WriteData('s');while(1){if(!KeyEnter){Delay(Xiaodou,110);if(!KeyEnter){while(!KeyEnter){}break;}}}break;}}}}void MenuRun(){WriteCommond(0x0c);//不显示光标也不闪烁WindowRun();count[0]=0;count[1]=0;count[2]=0;count[3]=0;TR0=1;//开定时器WriteCommond(0xc3);WriteString("000");//DispTimeS(count[0]+count[1]+count[2]+count[3],0xc3);for(;step<4;step++){timecount=0;//必须加的WriteCommond(0x81);WriteData(step+1+'0');WriteCommond(0x86);WriteString("Running...");WriteCommond(0xcc);WriteString("000s");//DispTimeS(count[step],0xcc);//必须加的switch(protype[step]){case 0:RunFwodBak(0,journey[step]);break;case 1:RunFwodBak(1,journey[step]);break;case 2:RunFind();}WriteCommond(0x86);WriteString("Completed!");if(step==2) Delay(3000,110);Delay(2000,110);}TR0=0;//关定时器step=0;}void MenuMain()//调整菜单{uchar cursor=0,address=0x80;WriteCommond(0x01);//清除显示WriteCommond(0x0c);//不显示光标也不闪烁while(1){if(!KeyUp){Delay(Xiaodou,110);if(!KeyUp){while(!KeyUp){}cursor+=2;cursor%=4;WriteCommond(0x01);//清除显示}}if(!KeyRight){Delay(Xiaodou,110);if(!KeyRight){while(!KeyRight){}if(cursor==3) cursor=2;cursor+=1;cursor%=3;WriteCommond(0x01);//清除显示}}if(!KeyEnter){Delay(Xiaodou,110);if(!KeyEnter){while(!KeyEnter){}WriteCommond(0x01);//清除显示switch(cursor){case 0:MenuSet();break;case 1:MenuView();break;case 2:case 3:default:MenuRun();}WriteCommond(0x01);//清除显示WriteCommond(0x0c);//不显示光标也不闪烁}}switch(cursor){case 0:address=0x80;break;case 1:address=0x8b;break;case 2:case 3:default:address=0xc0;}WindowMain();//显示主界面WriteCommond(address);WriteData(0x7e);}}void MCUInitial()//初始化MCU{EA=1;TMOD=0x01;//16位定时器TH0=(65536-10000)/256;TL0=(65536-10000)%256;TH1=(65536-235)/256;TL1=(65536-235)%256;ET0=1;//开定时器0中断ET1=1;//开定时器1中断}void LCDInitial()//初始化LCD{WriteCommond(0x38);//设置为16X2,5X7点阵WriteCommond(0x06);//写一个字符地址自加1}void Timer0_Int() interrupt 1{TH0=(65536-10000)/256;TL0=(65536-10000)%256;timecount++;if(timecount>=100){timecount=0;count[step]++;DispTimeS(count[0]+count[1]+count[2]+count[3],0xc3);DispTimeS(count[step],0xcc);}}void Timer1_Int() interrupt 3{TH1=(65536-235)/256;TL1=(65536-235)%256;ADCLK=!ADCLK;}void main(){MCUInitial();LCDInitial();MenuMain();}。

相关文档
最新文档