2010/2011学年第1学期
专用周实习报告
课程名称 :班 级 :姓 名 :学 号 :教学周数 :地 点 :指导教师 :
可编程控制器的设计
摘要:介绍了一种基于ATS52单片机控制的步进电机的设计,系统分为单片机控制、LCD显示、步进电机驱动和按键设置四个模块,设计的系统能通过按键来控制步进电机,并且步进电机的状态能通过LCD液晶模块实时显示出来,使人们直观的看出步进电机的运行状态。用ULN2003驱动步进电机,并由按键分别控制步进电机的启/停,快速/慢速,正转/反转。实现了步进电机的基本功能。本报告对该系统的工作原理、硬件电路和软件进行了详细介绍。
关键词: LCD液晶显示 ULN2003电机驱动、按键控制、步进电机
第1章 引言
本系统是基于单片机控制的综合系统,单片机通过按键的设置实现步进电机的变速及LCD实时显示步进电机的转速。它综合了电子技术和单片机软硬件技术,在控制模块选择、电机选择和驱动模块选择中都进行了各种方案的对比比较,从中选出最合适的方案。
第2章 方案比较与论证
总体系统框图如图1所示:
LCD液晶显示 按键控制 ATS52微控制 ULN2003驱动模块
图1 系统框图
2.1 微控制模块选择
方案一:采用S52作为步进电机控制器。经典52单片机具有价格低廉、使用简单等优点。一个微型计算机,其控制模块功能较全。 方案二:采用STM32F103XX作为步进电机控制器。STM32通过寄存器模式,寻址方式灵活,RAM和FLASH容量大,运算速度快、低功耗、低电压等,且通过TIM2的输出比较模式来控制步进电机以连续周期的50%和一个可变频率。DMA控制器可用来改变时钟周期,Systick定时器灵活地产生中断。但这次设计可编程控制器控制电机较简单没必要采用STM32,51就可以。 基于以上分析,选择方案一。
2.2 步进电机
步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件。在非超载的情况下,电机的转速、启停的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,即给电机一个脉冲信号, 电机则转过一个步距角。因此,步进电机具有快速启停能力,如果负荷不超过步进电机所能提供的动态转矩值,就能立即使步进电机启动或反转,而且步进电机的转换精度高,驱动电路简单,非常适合
定位控制系统。
2.3 步进电机驱动模块的选择
方案一:采用继电器对电动机的开和关进行控制,通过开关的切换对电机的速度进行调整。这个方案的优点是电路较为简单,实现容易;缺点是继电器的响应速度慢、机械结构易损坏、寿命较短。 方案二: 采用DSP芯片,配以电机控制所需要的外围功能电路,通过数控电压源调节电机运行速度,实现控制物体的运动轨迹。该方案优点是体积小、结构紧凑、使用便捷、可靠性提高。但系统软硬件复杂、成本高。
方案三: 采用专用芯片ULN2003。ULN2003 是高压大电流达林顿晶体管阵列系列产品,具有电流增益高、工作电压高、温度范围宽、带负载能力强等特点,适应于各类要求高速大功率驱动的系统。
基于上述理论分析和实际情况,拟定选择方案三。
第3章 系统硬件设计 3.1 电机驱动系统的设计
ULN2003的原理和封装图分别如图2和图3所示:
图3 ULN2003封装图
ULN2003引脚的功能如下所示:
引脚 引脚 引脚 引脚1:CPU2:CPU3:CPU4:CPU脉冲输入端,端口对应一个信号输出端。 脉冲输入端。 脉冲输入端。 脉冲输入端。
引脚5:CPU脉冲输入端。
引脚6:CPU脉冲输入端。 引脚7:CPU脉冲输入端。 引脚8:接地。
引脚9:该脚是内部7个续流二极管负极的公共端,各二极管的正极分别接各达林顿管的集电极。用于感性负载时,该脚接负载电源正极,实现续流作用。如果该脚接地,实际上就是达林顿管的集电极对地接通。 引脚10:脉冲信号输出端,对应7脚信号输入端。
参考电路接法
引脚11:脉冲信号输出端,对应6脚信号输入端。 引脚12:脉冲信号输出端,对应5脚信号输入端。 引脚13:脉冲信号输出端,对应4脚信号输入端。 引脚14:脉冲信号输出端,对应3脚信号输入端。 引脚15:脉冲信号输出端,对应2脚信号输入端。
引脚16:脉冲信号输出端,对应1脚信号输入端。
3.2 LCD1602显示:
在本系统中我们采用1602字符型液晶显示模块来显示步进电机的转速、起停以及正反转等步
进电机的状态。字符型液晶显示模块是专门用于显示字母、数字、符号等的点阵型液晶显示模块。分4位和8位数据传输方式。提供内部自动上电复位电路,+5V工作电压。一共有16个引脚,其中一对电源引脚、一对LED背光电源引脚、LCD驱动电压引脚、一个模式选择引脚用p2.2口来控制、一个读写操作引脚用p2.1口控制、一个使能引脚用p2.0口来控制、7个数据引脚用p0口来控制。其中LCD驱动电压V0可通过滑动变阻器进行调节,一般V0为零伏。具体应用电路图如图5所示: U2RESISTOR TAPPED1234P0.05P0.16P0.27P0.3P0.410P0.511P0.612P0.713141516R2DEB0DB1DB2DB3DB4DB5DBBG6 VCCDBBG7 GNDGNDVCCVOR/SRWVCC10kVCC
图5 LCD显示模块应用电路
第4章 系统软件设计
本系统的软件设计分LCD显示子程序、按键扫描测试、步进电机控制程序和主程序组
成。整个系统采用C语言进行编写。 1. 主程序
主程序包括系统的初始化、LCD子程序的调用以及定时器中断函数和步进电机控制函数组成。系统初始化包括对LCD显示模块数据位、命令位,步进电机停止、转速的定义与初始化,LCD显示程序显示静态的“Step Motor”和动态的不同速度水平式步进电机的转速以及正反转的标志,定时器中断函数主要设定定时器中断间隔和步进电机的转速,步进电机控制函数由步进电机索引函数和对索引值的加减函数组成。系统的主程序流程图如图10所示
图10 主函数流程图
2. LCD子程序
LCD子程序主要实现的功能是显示步进电机的状态。显示动态字符函数是用来显示步进电机的转速计转向状态,例如:第一行显示:Step Motor 第二行显示:rate: 6 STOP系统LCD显示子程序流程图如图所示
程序流程图如:
通过用P2.3控制停止键、P2.4控制正转键、P2.5控制反转键、P2.6控制加速键、用P2.7控制减速键,在程序中我们通过按键来调试电机的速度与正反转,再根据他的速度进行数据处理,再在
开始 按键扫描检测 否 按键按下? 否 按键1? 是 电机停止 是 进行数据处理 电机正转 是 进行数据处理 按键2? 是 否 按键3? 是 电机反转 是 进行数据处理 否 按键4? 是 电机加速 是 进行数据处理 否 按键5? 否 是 电机减速 是 进行数据处理 LED显示速度正反转标志显示屏上显示出来:
参考文献
[1] 李宁,《基于MDK的STM32处理器开发应用》,北京航空航天大学出版社 [2] 黄智伟,《全国大学生电子设计竞赛系统设计》,北京航空航天大学出版社 [3] 康华光,陈大钦,《电子技术基础》,高等教育出版社
附录一
主要元器件清单: 器件名称 ATS52微控制器 电机驱动芯片ULN2003 步进电机 晶振、电阻、电容、按键等 器件数量 1片 1片 1个 若干 附录二
源代码包括两个文件:步进电机.C、LCD.C; 步进电机.C:
#include #define uchar unsigned char #define uint unsigned int sbit BEEP = P3^7; //蜂鸣器 sbit k0 = P2^3; sbit k1 = P2^4; sbit k2 = P2^5; sbit k3 = P2^6; sbit k4 = P2^7; bit direction; //方向标志 uchar code cdis1[ ] = {\" Step Motor \uchar code cdis2[ ] = {\" RATE: \uchar code cdis3[ ] = {\"STOP\ //停止 uchar code cdis4[ ] = {\">>>>\ //正转 uchar code cdis5[ ] = {\"<<<<\ //反转 uchar count1 = 0,count2 = 0; uchar rate=9; //预设定速率值 uchar code FFW[8]= //正转表 { 0xf1,0xf3,0xf2,0xf6,0xf4,0xfc,0xf8,0xf9 }; uchar code REV[8]= //反转表 { 0xf9,0xf8,0xfc,0xf4,0xf6,0xf2,0xf3,0xf1 }; char code reserve[3]_at_ 0x3b; //保留0x3b开始的3个字节 /********************************************************** x*0.14ms 延时子函数 **********************************************************/ void delay(uchar x) { uchar i; while(x--) { for (i = 0; i<14; i++) ; } } /********************************************************** 蜂鸣器响一声 **********************************************************/ void beep(void) { uchar i; for (i=0;i<200;i++) { delay(5); BEEP=!BEEP; //BEEP取反 } BEEP=1; //关闭蜂鸣器 } /********************************************************** 速率显示子函数 **********************************************************/ void rate_conv(void) { uchar rate_l,rate_h; rate_h = (rate-3)/10; //高位 if(rate_h == 0) rate_h = 0x20; //高位为0不显示 else rate_h = rate_h+0x30; rate_l = (rate-3)%10; //低位 rate_l = rate_l+0x30; lcd_pos(7,2); //第二行7列 lcd_wdat(rate_h); lcd_wdat(rate_l); } /********************************************************** 主函数 **********************************************************/ void main(void) { P0 = 0xff; //端口初始化 P2 = 0xff; P1 = 0xf0; //步进电机断电 lcd_init(); //LCD1602初始化 lcd_pos(0,1); //设置显示位置为第一行 wr_string(cdis1,0); //显示字符串1 lcd_pos(0,2); //设置显示位置为第二行 wr_string(cdis2,0); //显示字符串2 lcd_pos(10,2); //第二行10列 wr_string(cdis3,0); //显示停止标记 TMOD = 0x01; //Timer0工作方式1 TH0 = 0xf8; //2ms定时常数 TL0 = 0xcc; ET0 = 1; //允许Timer0中断 EA = 1; //允许总中断 TR0 = 0; //关闭Timer0中断 direction = 1; //置运行方向标志位(正转) while(1) { rate_conv(); //速率显示 if(0==k0) { beep(); delayms(10); if(0==k0) //为遥控器的K1键 { lcd_pos(10,2); //第二行10列 wr_string(cdis3,0); //显示停止标记 TR0 = 0; P0 = 0xf0; //步进电机断电 while(!k0); } } if(0==k1) { beep(); delayms(10); if(0==k1) //为遥控器的UP键 { direction = 1; //置运行方向标志位(正转) lcd_pos(10,2); //第二行10列 wr_string(cdis4,0); //显示正转标记 TR0 = 1; while(!k1); } } if(0==k2) { beep(); delayms(10); if(0==k2) //为遥控器的DOWN键 { direction = 0; //清运行方向标志位(反转) lcd_pos(10,2); //第二行10列 wr_string(cdis5,0); //显示反转标记 TR0 = 1; while(!k2); } } if(0==k3) { beep(); delayms(10); if (0==k3) //“+”键 { if(rate >4) rate--; else rate = 4; while(!k3); } } if(0==k4) { beep(); delayms(10); if (0==k4) //“-”键 { if(rate <15) rate++; else rate = 15; while(!k4); } } } } /********************************************************** 定时器 0 中断服务子函数 (负责步进电机运行) **********************************************************/ void motor_onoff() interrupt 1 { TL0 = 0xcc; //2ms定时常数 TH0 = 0xf8; count1++; //基本延时rate设为9 if(count1 < rate) { return; } else { count1=0; if(direction==1) //运行方向标志 { if(count2 < 8) P1 = FFW[count2]; //取数据,正转 count2++; //取数据次数加1 if(count2==8) count2=0; } else { if(count2 < 8) P1 = REV[count2]; //取数据,反转 count2++; //取数据次数加1 if(count2 == 8) count2=0; } } } /*********************************************************/ LCD.C: #include #define DATA_PORT P0 sbit LCD_RS = P2 ^ 0; sbit LCD_RW = P2 ^ 1; sbit LCD_EN = P2 ^ 2; /********************************************************** us延时子程序 (4.34us) **********************************************************/ void delayNOP() { _nop_(); _nop_(); _nop_(); _nop_(); } /********************************************************** ms延时子程序 **********************************************************/ void delayms(unsigned int ms) { unsigned char k; while (ms--) { for (k = 0; k < 114; k++) ; } } /********************************************************** 检查LCD忙状态 lcd_busy为1时,忙,等待。 lcd-busy为0时, 闲,可写指令与数据。 **********************************************************/ void lcd_busy() { bit busy; busy = 1; while (busy) { LCD_RS = 0; LCD_RW = 1; LCD_EN = 1; busy = (bit)(DATA_PORT &0x80); delayNOP(); } LCD_EN = 0; } /********************************************************** 写指令数据到LCD RS=L,RW=L,EN 下降沿执行写操作。D0-D7=指令码。 Check=1,进行忙检测。 **********************************************************/ void lcd_wcmd(unsigned char cmd, bit Check) { if (Check) lcd_busy(); //进行忙检测 LCD_RS = 0; LCD_RW = 0; LCD_EN = 1; DATA_PORT = cmd; delayNOP(); LCD_EN = 0; } /********************************************************** 写显示数据到LCD RS=H,RW=L,EN 下降沿执行写操作。D0-D7=数据。 **********************************************************/ void lcd_wdat(unsigned char dat) { lcd_busy(); //进行忙检测 LCD_RS = 1; LCD_RW = 0; LCD_EN = 1; DATA_PORT = dat; delayNOP(); LCD_EN = 0; } /********************************************************** LCD初始化设定 **********************************************************/ void lcd_init() { delayms(15); lcd_wcmd(0x38, 0); //16*2显示,5*7点阵,8位数据 delayms(5); lcd_wcmd(0x38, 0); //不进行忙检测,强制执行三次。 delayms(5); lcd_wcmd(0x38, 0); delayms(5); lcd_wcmd(0x38, 1); //进行忙检测 delayms(5); lcd_wcmd(0x0c, 1); //显示开,关光标 delayms(5); lcd_wcmd(0x06, 1); //移动光标 delayms(5); lcd_wcmd(0x01, 1); //清除LCD的显示内容 delayms(5); } /********************************************************** 设定显示位置 **********************************************************/ void lcd_pos(unsigned char xpos, unsigned char ypos) { if (ypos == 0x01) lcd_wcmd((xpos | 0x80), 1); if (ypos == 0x02) lcd_wcmd((xpos | 0xc0), 1); } /********************************************************** 自定义字符写入CGRAM **********************************************************/ /* void writetab(unsigned char mytab[]) { unsigned char i; lcd_wcmd(0x40,1); //写CGRAM for (i = 0; i< 8; i++) lcd_wdat(mytab[i]); } */ /********************************************************** 写字符串子函数 **********************************************************/ void wr_string(unsigned char str[],unsigned int time) { unsigned char num = 0; while (str[num]) { lcd_wdat(str[num++]); delayms(time); } } /*********************************************************/
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- gamedaodao.com 版权所有 湘ICP备2022005869号-6
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务