毕业设计 胡良成.doc
2012 2013 学年第 二 学期毕业设计(论文)课题 舵机远距离数字控制 姓名 胡良成 系部 电子信息工程系 专业 交通安全与智能控制 班级 10级智能交通(1)班 学号 指导教师 罗云高 武汉交通职业学院教务处制摘要随着船舶工业的发展以前我们所用的模拟电路控制舵机存在着这样或那样的问题已经收到越来越多的关注。当传输距离很长的时候,模拟电子线路就会容易收到外部信号的干扰从而出现舵机的角度出现大的偏差。并且如果反馈电位器长时间工作就会出现磨损的情况,另外模拟电路和电源的漂移等等诸多的问题都影响舵机准确性。现在很多大型的船舶都采用动舵轮或者是液压舵 ,但由于它是机械式的控制所以它的控制受人的反应熟读的影响,误差范围大,精确度不高。本设计采用的控制器件有ARM2148和STC89C52单片机。采用E6B2-CWZ5G作为角度传感器,通过ARM2148控制舵机传动,将角度传给STC89C52单片机控制的LCD1602来显示。单片机会定时采集舵机的角度从而实时的显示相应角度。其中ARM2148为核心控制器,STC89C52单片机为辅助控制器。核心控制器与辅助控制器通过串口数据线进行数据传输,从而实现对舵机的远程控制。这种数字电路控制舵机的方法精确度高,结构简单。数字电路控制舵机,再结合轮船的动力系统,GPS技术与GIS技术从而实现船舶的自动驾驶。相对于汽车无人驾驶其难度更低,安全性跟高,前景很广阔。关键词:ARM2148;角度传感器;远程控制;自动驾驶;目录1 绪论32 系统相关技术分析- 4 -2.1核心控制器件的选择- 4 - 2.2辅助器件的选择- 5-2.3 角度传感器的选择- 5 -2.4显示器件的选择 -5-2.5电动机驱动模块的选择-5-2.6小结-6-3 系统硬件电路设计- 7 -3.1电源的设计- 7 -3.2 LCD液晶显示电路设计- 7-3.3驱动电路设计-8-4 系统软件设计- 9-4.1整体流程图设计- 9 -4.2 整体程序设计论证- 10-4.2.1 角度检测程序:- 10 -4.2.2LCD1602液晶显示程序- 11 -4.2.3 串口通信程序- 15 -5 实现相关技术- 29 -5.1 ARM2148的简介及运用领域- 29-5.2 单片机的简介及运用- 31 -6 总结- 33 -致谢信- 34 -参考文献- 35 -附录程序清单和专利申请书- 36 -1. 绪论我们采用数字电路控制舵机是考虑了模拟电路控制舵机的缺点的,正是为了克服这些缺点,从而跟好对舵机进行远程控制,提高其精确度。论文中包括本次设计的整体简介,硬件连接,软件编程。本次设计采用核心控制器件ARM2148和辅助控制器件STC89C52单片机。我们选择ARM2148是因为其比较实用,也是初学者首先接触的因此比较熟悉。至于单片机的悬着是由于其易用,外围模块较少。系统的硬件包括:ARM模块、单片机最小系统、L298电动机驱动模块、角度传感器、电动机、 蓄电池,LCD1602、编码器等。软件部分包括:电动机驱动模块程序、ARM控制电动机模块、单片机控制LCD1602显示模块。2. 系统相关技术分析整体设计如下图所示:采用ARM2148为核心控制器件, 采用STC89C52来控制LCD1602来动态显示舵机角度,采用C语言编程实现各种逻辑的算法和逻辑控制,角度传感器的脉冲信号作为中端引入ARM2148,然后通过串口线通过单片机控制的液晶显示显示相应的角度。按键控制舵机左转还是右转。角度传感器液晶显示器辅助控制系统 串口线主控制系统()()按键控制电机驱动模块 图1 总体结构图2.1核心控制器件的选择核心控制器件的选择没有选择单片机而是选择ARM2148来控制是由于本次设计采用的是三级流水线模式。它需要软件有很快的处理指令的速度。为了避免52单片机执行指令过多出现卡死的情况,来实现多个操作同时进行,使处理和存储之间的操作更加流畅连续,能提供0.9MIPS/MHZ的指令执行速度,这样在舵机快速偏转时,处理器仍然可以远远满足编码器瞬间给出的众多条代码值,使系统更加稳定。并且我们首先接触的也是ARM2148这款软件相对于其它款的我们更熟悉。在整个系统中ARM2148起着控制电动机驱动模块使电动机运转,同时接受来自角度传感器的数据即舵机旋转角度然后将其传输给STC89C52单片机从而实现角度的显示。因此它是核心模块。2.2辅助器件的选择辅助模块只需接受来自ARM2148的关于舵机角度的数据和控制LCD1602液晶显示。由于STC89C52单片机功耗低、性能高、灵活性高且使我们经常接触到的单片机类软件,所以我们选择了这款单片机。2.3角度传感器的选择角度传感我们我们采用工业用E6B2-CWZ5G角度传感器,它拥有非常低的阻尼,在轴上固定一重物只需要10来克就能将实时角度准确的传输到ARM2148中。它是一种增量式的旋转译码器,它是通过内部两个光敏接受管转化其角度码盘的时序和相位关系,从而得到其角度码盘角度位移量增加或减少。增加为正方向,减少为反方向。它具有价格低廉和简易的优势,因此我们选择了它。如下图为它的工作原理:图2 E6B2-CWZ5G工作原理图2.4显示器件的选择显示模块我们有两种设计方案,分别为数码管显示和液晶显示。数码管静态显示编程简单,但其占用的I/O口过多,电路复杂,成本高。动态显示又不能满足太复杂的电路。因此我们选择液晶显示。液晶显示就克服了数码管显示的缺点,同时它还具有功耗低、显示信息多、操作简便等优点。2.5电动机驱动模块的选择驱动模块我们选择的是L298N,L298N是ST公司生产的一种高电压、大电流电机驱动芯片。该芯片采用15脚封装。它内含含两个H桥的高电压大电流全桥式驱动器,可以用来驱动直流电动机和步进电动机、继电器线圈等感性负载;采用标准逻辑电平信号控制;具有两个使能控制端,在不受输入信号影响的情况下允许或禁止器件工作有一个逻辑电源输入端,使内部逻辑电路部分在低电压下工作;可以外接检测电阻,将变化量反馈给控制电路。使用L298N芯片驱动电机,该芯片可以驱动一台两相步进电机或四相步进电机,也可以驱动两台直流电机。而且L298N有过电流保护功能,当出现电机卡死时,可以保护电路和电机等。 因此,我们采用安全性更高的L298N驱动芯片来驱动电机,。以下为该芯片的相关参数:额定电流2A额定电压 12.5V额定功率25W最大电流3A最大电压46V2.6小结经过一番的论证与比较,我们决定了系统各个主要模块的方案如下:电机驱动模块采用L298N;角度传感模块采用E6B2-CWZ5G角度传感器;液晶显示模块采用现成的数码管;电源采用单电源双输出模块。硬件电路设计3.1电源的设计图3 电源原理图3.2 LCD液晶显示电路设计图4 液晶显示3.3 驱动电路设计图5 驱动电路3. 系统软件设计4.1整体流程图设计开始左转(大于现有角度)度)右转(小于现有角度)检测串口向单片机发送角度检测限位开关初始化各种参数偏转 N Y N和现有角度对比 Y Y 4.2整体程序设计论证 4.2.1角度检测程序我们采用的角度传感器是通过计算脉冲的数量来计算小车的偏转角的。由于脉冲的时间很短,如果采用端口扫描那么在ARM2148没有执行扫描时就会错过一些脉冲的检测,数据就会出现错误。我们采用外部中断来计算角度,程序很短所以可以迅速的执行不会耽误其它程序执行的执行,数值在0-900,实际值为0-90度。/*/* 函数名称: void _irq IRQ_Eint3(void)* 功能描述: 外部中断计算旋转角度* 参 数: 每一个角度有不同的脉冲组成/*/void _irq IRQ_Eint3(void)/* a2脉冲触发中断服务主程序 */ / EXTINT = EINT3;/* clear interrupt中断服务主程序 */ k=IOPIN0; /输入状态 if(k&1<<KEY3)=0) /测试b2脉冲位置 eint2_counter+; /* 如果超前+*/ else eint2_counter-; /* 如果超前+*/ ii5=eint2_counter ; /脉冲数传送到ii5寄存器EXTINT =8;/* clear interrupt中断服务主程序 */ / 清除EINT3 中断标志VICVectAddr = 0x00; / 通知VIC 向量中断结束void EINT1_Handler (void) _irq/* a1脉冲触发中断服务主程序 */ IENABLE;/* handles nested interrupt嵌套中断 */k=IOPIN0; /输入状态 if(k&1<<KEY1)=0) /测试b脉冲位置KEY1= b /IOSET1 = 0x000F0000; eint1_counter+; /* 如果超前+*/ else /IOCLR1 = 0x000F0000; eint1_counter-;/*如果反转 - */ /测试原点位置if(k&1<<KEY2)=1&&(ii3 =0) ) /原本原点位置从0改变为1 eint1_counter=1000; ii3 = k&1<<KEY2 ; / 记录z原点位置 0、1,KEY2=z ii4 =eint1_counter ; /脉冲数传送到ii4寄存器 IDISABLE; IOPIN1=0xf50000; VICVectAddr = 0; EXTINT =2;/* clear interrupt中断服务主程序 */ 4.2.2 LCD1602液晶显示程序本系统采用的是1602液晶显示。前面我给大家介绍了选择该软件的原因。它的显示是由STC89C52控制的。它显示的角度由操作台操作,它将操作台实时操作显示出来,同时由串口线发送数据给ARM2148控制舵机的旋转。程序如下:# include <AT89x51.h> /* P1-DB0DB7 P2.0-RS P2.1-RW P2.2-E */ # define LCD_DB P1 sbit LCD_RS=P20; sbit LCD_RW=P21; sbit LCD_E=P22; /*定义函数*/ # define uchar unsigned char # define uint unsigned int void LCD_init(void);/void LCD_write_command(uchar command);/写指令函数 void LCD_write_data(uchar dat);/写数据函数 void LCD_disp_char(uchar x,uchar y,uchar dat);/在某个屏幕位置上显示一个字符,X(0-16),y(1-2) /void LCD_check_busy(void);/检查忙函数。我没用到此函数,因为通过率极低。 void delay_n40us(uint n);/延时函数 /* /*初始化函数* void LCD_init(void) LCD_write_command(0x38);/设置8位格式,2行,5x7 LCD_write_command(0x0c);/整体显示,关光标,不闪烁 LCD_write_command(0x06);/设定输入方式,增量不移位 LCD_write_command(0x01);/清除屏幕显示 delay_n40us(100); /* /*写指令函数* void LCD_write_command(uchar dat) LCD_DB=dat; LCD_RS=0;/指令 LCD_RW=0;/写入 LCD_E=1;/允许 LCD_E=0; delay_n40us(1); /* /*写数据函数* void LCD_write_data(uchar dat) LCD_DB=dat; LCD_RS=1;/数据 LCD_RW=0;/写入 LCD_E=1;/允许 LCD_E=0; delay_n40us(1); /* /*显示一个字符函数* void LCD_disp_char(uchar x,uchar y,uchar dat) uchar address; if(y=1) address=0x80+x; else address=0xc0+x; LCD_write_command(address); LCD_write_data(dat); /* /*检查忙函数* void LCD_check_busy() do LCD_E=0; /for循环作延时,普通指令只要1次循就可完成。清屏指令 LCD_RS=0; /要用200次循环便能完成。 LCD_RW=1; LCD_DB=0xff; LCD_E=1; while(LCD_DB7=1); */ /*延时函数* void delay_n40us(uint n) uint i; uchar j; for(i=n;i>0;i-) for(j=0;j<2;j+); /在这个延时循环函数中我只做了2次循环, /* /*主函数* void main(void) LCD_init(); LCD_disp_char(0,1,"A"); while(1); 4.2.3 串口通信程序 串口在本设计中起着至关重要的作用,它连接了单片机和ARM,它将ARM接受的角度传感器的数据送给单片机让单片机把实时角度与操作台的操作角度对比然后将指令在送给ARM再由ARM控制舵机左转还是右转。程序如下:/*P0.14中断功能演示按下板子INT键,2组4个LED交替灭或亮.*/#include "LPC214x.H" /* LPC21xx definitions */#include "type.h"#include "irq.h"#include "extint.h" #include "Config.H" /* standard I/O .h-file */#pragma _printf_args; /#include <intrins.h>#include <STDIO.H>/#defineuchar unsigned char#define CR 0x0D#define UART_BAUD(baud)(unsigned int)(FOSC*PLL_M ) / (baud *4 *16 )#define uint unsigned int #define RW22 /读写控制端 0为写 1为读#define RS4 /A0为1时是数据,0时为指令数据#define Elcm 21/#define busy0x0800extern Scan_Key(void); /intprintf( char ) ; extern int ii4,ii5;int xx1, x,xx4,xx5,ii6 ; / int i2,k , i3 ;unsigned int io_data=1,rcv_dat;unsigned char const mcu123="WWW.MCU222.COM"unsigned long val1,val3,val;int i3,i2 ,t=0x31 , tmp ;uchar mcu124="0x34 " ; uchar mcu122=" " ; long su44; unsigned char key,i,i4, strdata20 ; /* 系统设置, Fosc、Fcclk、Fcco、Fpclk必须定义*/#define Fosc /Crystal frequence,10MHz25MHz,should be the same as actual status. /应当与实际一至晶振频率,10MHz25MHz,应当与实际一至#define Fcclk (Fosc*1) /System frequence,should be (132)multiples of Fosc,and should be equal or less than 60MHz. /系统频率,必须为Fosc的整数倍(132),且<=60MHZ#define Fcco (Fcclk *1) /CCO frequence,should be 2、4、8、16 multiples of Fcclk, ranged from 156MHz to 320MHz. /CCO频率,必须为Fcclk的2、4、8、16倍,范围为156MHz320MHz#define Fpclk (Fcclk / 4) * 1 /VPB clock frequence , must be 1、2、4 multiples of (Fcclk / 4). /VPB时钟频率,只能为(Fcclk / 4)的1、2、4倍 #define BEEP 1<<17 /#defineLED 0x00FF0000/延时/#define UART_BAUD(baud) (unsigned int)(FOSC*PLL_M*4 )/ (baud * 16)#define UART_BPS / 串口通讯波特率/* 函数名称:UART0_Init()* 函数功能:串口初始化,设置为 8 位数据位,1 位停止位,无奇偶校验,波特率。* (2400)U0DLM =0X1; U0DLL =0X86;* (9600)U0DLM =0X0; U0DLL =0X5D; ()U0DLM =0X8; U0DLL =0X8;*/ void Init_Uart0(unsigned int Baud) /* initialize the serial interface */ / #define UART_BAUD(baud) (unsigned int)(FOSC*PLL_M) / (baud * 16) / PINSEL0=0x ; /* Enable RxD0 and TxD0 */ / PINSEL1 = 0x; U0LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ U0DLM= (unsigned char)(Baud>>8); /0X1; 0;/ 0 U0DLL = (unsigned char)Baud; / 0X86; 0X5D; / 8 U0LCR = 0x03; /* DLAB = 0 */ /* 函数名称:UART0_GetByte()* 函数功能:从串口接收 1 字节数据,使用查询方式接收。* 入口参数:无* 出口参数:接收到的数据*/void UART0_GetByte (void) while (U0LSR & 0x01) =0); / 等待接收标志置位rcv_dat = U0RBR; / 读取数据U0LSR =0x60;/return (rcv_dat);/*接收一个字节*/int Get_Byte (void) /* Read character from Serial Port */ while (!(U0LSR & 0x01); return (U0RBR); /* 函数名称:UART0_GetStr()* 函数功能:从串口接收* 入口参数:s 指向接收数据数组的指针* n 接收的个数* 出口参数: 无*/void UART0_GetStr (unsigned int n)/ unsigned char *s, for ( ; n>0; n-) UART0_GetByte () ; / UART0_GetByte () ; strdata tmp=rcv_dat ; /*s=rcv_dat ; / *s=rcv_dat; tmp+; /* 函数名称:UART0_SendByte()* 函数功能:向串口发送字节数据,并等待发送完毕,查询方式。* 入口参数:dat 要发送的数据* 出口参数:无*/void UART0_SendByte (unsigned char dat) U0THR = dat; / 写入数据while (U0LSR & 0x20) = 0); / 等待数据发送完毕/* 函数名称:UART0_SendStr()* 函数功能:向串口发送一字符串* 入口参数:str 要发送的字符串的指针* 出口参数:无*/void UART0_SendStr (unsigned int const *str) while (1) if (*str = '0') break; / 遇到结束符,退出UART0_SendByte(*str+); / 发送数据/*发送一个字节*/void Sent_Byte2(unsigned char data) U0THR = data; / 发送数据 while( (U0LSR&0x20)=0 ); / 等待数据发送完毕int sendchar (int ch) /* Write character to Serial Port */ if (ch = 'n') while (!(U0LSR & 0x20); U0THR = CR; /* output CR */ while (!(U0LSR & 0x20); return (U0THR = ch); /*发送一串字符*/void Sent_Str (unsigned char const *str) while(1) if( *str = '0' ) break; Sent_Byte2(*str+); / 发送数据 void delay(unsigned int i)unsigned int k=300;while(i>0)i-;while(k>1)k-;/void delayms2(unsigned int i) /* Delay function */unsigned int n;while(i>1)for(n=18;n>1;n-);i-;void delayms (unsigned int i) /* Delay function */unsigned int n;while(i>1)for(n=8535;n>1;n-);i-;voiddelay1s(unsigned char i)while(i>1)i-;delayms(20); void init_port(void) /port initialized IODIR1=0x00FF0000; IODIR0=0x; / IODIR0=0x; void Io_Set(uchar pin) /单个IO口置位函数unsigned int io_data=1;io_data=io_data<<pin;IOSET0=io_data; /IOSET0为IO线上置位寄存器,1有效,0无 void Io_Clr(uchar pin) /单个IO口清零函数unsigned int io_data=1;io_data=io_data<<pin;IOCLR0=io_data; /IOCLR0为IO线上清零寄存器,1有效,0无 void Io_Set1(uchar pin) /单个IO口置位函数unsigned int io_data=1;io_data=io_data<<pin;IOSET1=io_data; /IOSET0为IO线上置位寄存器,1有效,0无 void Io_Clr1(uchar pin) /单个IO口清零函数unsigned int io_data=1;io_data=io_data<<pin;IOCLR1=io_data; /IOCLR0为IO线上清零寄存器,1有效,0无void Sent_Byte(unsigned char data)unsigned char i;for(i=0;i<8;i+) if(data&1) Io_Set1(i+16); /把相应的IO口置位或者清零 else Io_Clr1(i+16); data=data>>1