单片机课程设计报告

更新时间:2024-04-05 09:25:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

电气工程学院

单片机课程设计报告

班 级:姓 名:学 号:

设计题目:设计时间:

评定成绩:评定教师: 电132 袁吉收 1312021047 直流电机调速系统设计 2015.12.22~12.28

摘要

本文设计的直流电机调速系统以AT89C51单片机为核心控制单元,扫描键盘后,通过改变定时器的定时长短调节PWM波的占空比来实现电机调速的目的,使用L298芯片为电机驱动芯片,并通过LCD1602来显示转速实现人机交互界面。

关键字:AT89c51、PWM、L298、LCD1602

2

目 录

一、题目要求

1.1 题目介绍

1.2 模块分解 二、 方案设计

2.1 方案介绍

三、硬件设计

3.1硬件原理图 3.2各部分介绍

四、软件设计

4.1流程图 4.2时序图 4.3部分程序说明

五、调试过程

5.1软硬件调试及其问题和解决方法 5.2仿真与实际的区别即仿真的局限性

六、设计总结 七、参考文献

附件:程序代码

3

一、题目要求

1.1直流电机调速控制

实现具有电机速度设定、控制及显示的调速系统,功能及指标如下: (1)满足通用要求)

1. 通用要求就是可以调电机转速 2. 可以显示转速 3. 可以显示电机状态

1.2模块分解

a) 首先是对电机的调速模块,本次设计使用基于PWM(脉冲宽度调制)的方法来实现电机的调速。具体实现详见方案中2.1.3

b) 对于显示电机的转速模块,由于LCD1602的显示直观性及性价比本次采用了LCD1602模块。详见方案中2.1.5

c) 我们知道一般单片机驱动能力有限,一般为mA级,不足以驱动直流电机,为此我选用了L298作为电机驱动芯片。详见2.1.4 d) 本次采用键盘来控制电机的方式,并且用指示灯表示电机的正转、反转、停止。

4

二、方案设计 2.1方案设计及选择

在实际设计中我们要考虑的因素有很多,比如成本最低、性价比最高、性能最优、功能最强、界面最友好等等。而本次课设我采用了性价比最高的方案(首先能实现基本功能)。选用了L298、LCD1602模块实现本次设计。

功能框如下

输入 速度给定 PWM输出 电机驱动输出 输出 速度控制示意图 基于AT89c51的直流电机控制系统设计

现在电气传动的主要方向之一是电机调速系统采用微处理器实现数字

5

化控制。采用微处理器控制,使整个调速系统的数字化程度、智能化程度大大提高;采用微处理器控制也使得调速系统在结构上简单化,可靠性提高,操作维护变得简洁,电机稳定运行时转速精度达到较高水平。 2.1.1直流电机的工作原理

直流电机里边固定有环状永磁体,电流通过转子上的线圈产生安培力,当转子上的线圈与磁场平行时,再继续转受到的磁场方向将改变,因此此时转子末端的电刷跟转换片交替接触,从而线圈上的电流方向也改变,产生的洛伦兹力方向不变,所以电机能保持一个方向转动。 直流发电机的工作原理就是把电枢线圈中感应的交变电动势,

直流电机(图1)

靠换向器配合电刷的换向作用,使之从电刷端引出时变为直流电动势的原理。

感应电动势的方向按右手定则确定(磁感线指向手心,大拇指指向导体运动方向,其他四指的指向就是导体中感应电动势的方向)。

导体受力的方向用左手定则确定。这一对电磁力形成了作用于电枢一个力矩,这个力矩在旋转电机里称为电磁转矩,转矩的方向是逆时针方向,企图使电枢逆时针方向转动。如果此电磁转矩能够克服电枢上的阻转矩(例如由摩擦引起的阻转矩以及其它负载转矩),电枢就能按逆时针方向旋转起来。

6

2.1.2直流电动机的调速原理

根据励磁方式不同,直流电机分为自励和他励两种类型。不同励磁方式

的直流电机机械特性曲线头所不同。对于直流电机来说,人为机械特性与额定电压、额定磁通量有关,还和电枢电阻有关。

分别改变其中的额定电压、磁通量、电阻可以实现对速度的调节。

通过改变磁

n 通量的大小可以达到变磁通调速的目的。但由于励磁线圈发热和电机磁通饱和的限制,只能弱磁调速。对于调节电枢

外加电阻是,会使电机特性变软,导致电机带负载能力减弱。对于他励直流电机来书,当改变电枢电压是可得到人为机械特性曲线。

0 图(2)他励直流电机降压的人为机械特性曲线 T 7

理想空载转速点随电枢电压升降而发生的相应的升降变化。不同的电枢电压机械特性曲线平行,说明挺度不随电枢电压的变化而变化,电机带负载能力恒定。当我们平滑的调节他励直流电机的电枢电压时,可实现电机的无极调速。基于以上特性,改变电枢电压,实现对直流电机调速的方法被广泛采用。改变电枢电压可以通过多种途径实现,如晶闸管供电速度调节系统、大功率晶体管速度控制系统、直流发电机控制系统及晶闸管直流脉宽调速系统等。调压条数法具有平滑度高、能耗少、精度高等优点。在工业生产中,广泛使用脉宽调制(PWM)法。

调速方法 特点 晶闸管供电调速系统 稳定性较好,可以同大电流 大功率晶体管速度控制 脉宽调制 能耗大,耐压高 平滑度高,能耗小,精度高 脉宽调制利用一个固定的频率来控制电源的开通或管段,并通过改变一

个周期内接通和关断时间的长短,即改变直流电机电枢上电压的占空比来改变平均电压的大小,从而改变电机的转速,因此,PWM又被称为“开关驱动装置”。电枢占空比和平均电压的关系如图3

8

脉冲信号 t t 图3 电枢占空比 和平均电压的关系 如果电机始终接通电源,电机最大转速为N,占空比为入=t/T,可见只要改变占空比,就可以得到不同的转速,从而达到调速的目的。

与传统的直流调速想比较,PWM直流调速系统具有较大的优越性:主

线路简单,需要的功率元件少;开关频率高;电流容易连续,谐波少,电机损耗和发热都较小;低速性能好,稳速精度高,因而调速范围宽;系统频带宽,快速相应性能好,抗干扰能力强。

2.1.3基于AT89C51的PWM信号产生

PWM信号可以通过硬件方法或软件方法产生,如采用NE555可以产生

控制信号。基于单片机的调速系统可以分为定宽调频法、调宽调频法及定频调宽法。其中定宽调频法、调宽调频法改变了周期(频率),当控制脉冲与系统的固有频率接近时,会引起震荡,因此常采用定频调宽法。

9

设PWM信号波的周期为T,则T=Tl+Th,占空比入=Th/T。本次设计

采用单片机定时器作为脉冲宽度调制的定时方式2。本次定时t=250us.周期为10t=2.5ms,高电平持续时间为t,低电平就为9t,基于at89c51的PWM信号流程图如下

开始 定时器赋初值 定时时间到? Y 循环次数>t? N PWM=1 Y N PWM=0

2.1.4基于L298直流电机驱动

由于单片机驱动能力有限,因此不能将电机直接接到单片机的输出引脚。驱动芯片有很多比如

SA60,LMD18245,L298,LG9110,BTS7710GP01,TA7257P,SN754410,A3988等等。表2列出常用芯片的区别。

10

芯片 SA60 L298 46 LMD18245 55 最大输出电压80 (V) 峰值电流(A) 价格(元) 特点 10 暂无资料 该芯片还可以外接一个可兼容的TTL 型的PWM 的信号来同步四象限模式的幅值和方向。SA60 主要应用在3 10 内涵高电压、大电流双6 30-60 芯片中集成了四位D/ 全桥驱动器,接受标准A转换器和电机电流传TTL电瓶信号,可以驱感器、固定切断时间的动46v,2A以下电机;斩波放大器等电路, 所此芯片可以有单片机直以LMD18254 很容易完成对电机电流的数字控制,实现步进电机的微步驱动。因此,该芯片主要用于小型直流电机特别是步进电机的控制和驱动上。 驱动中小型直流电机,D 接提供驱动信号。 类功率放大,轴承激励等场合。 综合 考虑L298更适合用在此次课程设计中

首先,Vss(9)是工作电源,最小要4.5V,最大可达36V; VS(4)为驱动电压,最大也是36V,但最好是取Vs大于Vss; GND(8)是接地,ISENA(1)、ISENB(15)好像是用来作反馈的,一般是接地就行;IN1(5)、IN2(7)、IN3(10)、IN4(12)分别对应OUT1(2)、OUT2(3)、OUT3(13)、OUT4(14),即输入高低电平对应,(例如IN1为高则OUT1为高),当然这要是建立在使能端满足的情况下才可以; ENA(6)、ENB(11)为使能端,ENA控制OUT1、OUT2,ENB控制OUT3、OUT4,高电平有效,即在低电平情况下,无论输入为何信号,输出都为低电平; 它

11

的管脚功用及联系大概是这样

图4 L298原理图 封装形式

D95IN240A-L298的封装形式

12

表3

引脚 IN1 0 0 1 1 IN2 0 1 0 1 停 反转 正转 停 L298的部分逻辑功能表 一般来说,应用于显示屏的LED发光材料有以下几种形式: 电机A 精力有限只列举课程设计用到的 2.1.5显示屏的选择 ① LED发光灯(或称单灯) 一般由单个LED晶片,反光杯,金属阳极,金属阴极构成,外包具有透光聚光能力的环氧树脂外壳。可用一个或多个(不同颜色的)单灯构成一个基本像素,由于亮度高,多用于户外显示屏。 ② LED点阵模块 由若干晶片构成发光矩阵,用环氧树脂封装于塑料壳内。适合行列扫描驱动,容易构成高密度的显示屏,多用于户内显示屏。 ③ 贴片式LED发光灯(或称SMD LED) 就是LED发光灯的贴焊形式的封装,可用于户内全彩色显示屏,可实现单点维护,有效克服马赛克现象。 LED之所以受到广泛重视而得到迅速发展,是与它本身所具有的优点分不开的。这些优点概括起来是:亮度高、工作电压低、功耗小、大型化、寿命长、耐冲击和性能稳定。LED的发展前景极为广阔,正朝着更高亮度、更高耐气候性、更高的发光密度、更高的发光均匀性,可靠性、全色化方向发展。LED显示屏广泛应用[2] 在体育场馆、商业应用、银行、证劵、邮政、码头、商场、车站、邮政、电讯、机关、监控、学校、餐厅、酒店、娱乐、等不同户外场所的广告宣传。 就本次课程设计来说LCD1602、12864、LCD5110都是可以选择的,我们着重比较他们的价格。 芯片 价格(元) 稳定性 可靠性 这就是选择LCD1602的原因

LCD1602 5 稳定 可靠 LCD12864 23 稳定 可靠 LCD5110 50+ 稳定 可靠 602采用标准的16脚接口,其中: 第1脚:GND为电源地

第2脚:VCC接5V电源正极

13

第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会 产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。

第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。

第5脚:RW为读写信号线,高电平(1)时进行读操作,

以51为例的简单原理图

低电平(0)时进行写操作。

第6脚:E(或EN)端为使能(enable)端,高电平(1)时读取信息,负跳 变时执行指令。

第7~14脚:D0~D7为8位双向数据端。第15~16脚:空脚或背灯电 源。15脚背光正极,16脚背光负极。 特性

3.3V或5V工作电压,对比度可调

内含复位电路

提供各种控制命令,如:清屏、字符闪烁、光标闪烁、显示移位等多种功能 有80字节显示数据存储器DDRAM

内建有192个5X7点阵的字型的字符发生器CGROM 8个可由用户自定义的5X7的字符发生器CGRAM 特征应用

微功耗、体积小、显示内容丰富、超薄轻巧,常用在袖珍式仪表和低功耗应用系统中。

操作控制 注:关于E=H脉冲——开始时初始化E为0,然后置E为1。 字符集

1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。

在单片机编程中还可以用字符型常量或变量赋值,如'A?。因为CGROM储存的字符代码与我们PC中的字符代码是基本一致的,因此我们在向DDRAM写C51字符代

14

码程序时甚至可以直接用P1=?A?这样的方法。PC在编译时就把'A'先转换为41H代码了。 CGROM中字符码与字符字模关系对照表 字符代码0x00~0x0F为用户自定义的字符图形RAM(对于5X8点阵的字符,可以存放8组,5X10点阵的字符,存放4组),就是CGRAM了。 0x20~0x7F为标准的ASCII码,0xA0~0xFF为日文字符和希腊文字符,其余字符码(0x10~0x1F及0x80~0x9F)没有定义。 以下是1602的16进制ASCII码表地址:读的时候,先读上面那行,再读左边那列,如:感叹号!的ASCII为0x21,字母B的ASCII为0x42(前面加0x表示十六进制)。 指令集 指令码 功能令: 清显示 RS R/W D7 0 D6 0 D5 0 D4 0 D3 0 D2 0 D1 0 D0 1 说明 将DDRAM填满\并且设定DDRAM的地址计数器(AC)到\归位 0 0 0 0 0 0 0 0 1 * 设定DDRAM的地址计数器(AC)到\并且将游标移到开头原点位置;这个指令不改变DDRAM 的内容 显示开关控制指令 进入模式设置指令 0 0 0 0 0 0 1 D C B [D=1: 整体显示 ON],[C=1: 游标ON],[B=1:游标位置反白允许] 0 0 0 0 0 0 0 1 I/D S I/D=1,光标或闪烁向右移动, AC增加1。I/D=0,光标或闪烁向左移动,AC减少1,S整个显示移动 0 0 15

光标或显示移位指令 功能设定 0 0 0 0 0 1 S/C R/L * * 光标或显示移位指令可使光标或显示在没有读写数据的情况下,向左或向右移动,指令不改变DDRAM 的内容 0 0 0 0 1 DL N F * * [DL=0/1:4/8位数据],[N=0/1,单行/双行显示],[F=0/1,5*8/5*10点阵显示模式] 设置CGRAM地址 0 0 0 1 AC5 AC4 AC3 AC2 AC1 AC0 CGRAM地址设置指令设置CGRAM地址指针, 设定DDRAM地址 0 0 1 0 AC5 AC4 AC3 AC2 AC1 AC0 DDRAM地址设置指令设置DDRAM地址。一行地址范围00H~4FH,两行DDRAM地址第一行00H~27H,第二行40H~67H,加上高2位,[一行:80H-A7H],[二行:C0H-E7H] 读忙标志和地址 0 1 BF AC6 AC5 AC4 AC3 AC2 AC1 AC0 BF:忙标志位,BF=1,模块正在进行内部操作,此时模块不接受任何外部指令和数据。BF=0,模块可以接受外部的指令和数据;同时可以读出地址计数器(AC)的值。 写RAM指令 1 0 D7 D6 D5 D4 D3 D2 D1 D0 将数据D7-D0写入到内部的RAM (DDRAM/CGRAM/IRAM/GRAM),将用户自定义的字符写入CGRAM中,D7~D5为000,D4~D0为5点的字模数据 读RAM指令 1 1 D7 D6 D5 D4 D3 D2 D1 D0 从内部RAM读取数据D7——D0(DDRAM/CGRAM/IRAM/GRAM) 16

三、硬件设计

3.1基于L298的直流电机调速系统硬件设计

3.2对系统的各部分功能描述

器件选型及电路结构

电机驱动芯片控制端IN1、IN2连接AT89c51的P3.0、P3.1使能端连接P3.7输出端连接电机和四个二极管,验收时,陈老师问了这四个二极管的作用。那我现在就详细写一下其作用。因为电机是电感负载,当电机开关时势必就会产生感应电动势,我们成为反向峰压,为了给反向峰压提供通道,就接了四个二极管。还有就是L298的高驱动能力弥补了单片机本身的驱动能力,因为单片机本身驱动能力有限,所以,使用L298是明智的

17

选择。其他端口按照原理图来。详见2.2.4

LCD1602的rs、r/w、E控制端口分别接p2.2, p2.1, p2.0功能详见2.4.5

我只说一下接P0口是要接上拉电阻,因为P0口内部是漏及开路输出。

P1口分配为按键接口。

整个电路图分配如上,并留有余地,还可以扩展功能。方便进一步开发,

这也是好的工程师必备的素质。

四、软件设计 4.1流程图

4.1.1主程序流程图

18

开始 硬件初始化 软件初始化 LCD初始化 LCD显示 键盘扫描 是否有按键按下? N 按键处理 Y

19

4.1.2硬件初始化

4.1.3软件初始化

开始 电机停转 指示灯全灭 结束 开始 定时器初始化 中断初始化 结束 20

4.1.4LCD初始化

4.1.5按键扫描

开始 功能设置 显示设置 输入设置 结束 开始 正转? 正传处理 反转? 反转处理 停止? 停转处理 加速? 加速处理 减速? 减速处理 结束 21

4.2LCD部分时序图

LCD1602的时序图解释

不同公司生产的1602液晶的时序图差不多都一样,所以MCU控制程序也差不多,一般都是通用的。下面来看一下它的时序图

4.3PWM产生程序

/************************ * FunctionName:

*Description: 定时器中断产生PWM波 *ENtryparaenter: *REturnValue:

**************************/ void t0() interrupt 1 using 0 { if(tp!=0) { if(count>10) count=0;

22

{ }

if(count>tp) Me=0; else Me=1; }

if(tp==0) if(count>10) count=0; if(count>=tp) Me=0; else Me=1; }

count++;

程序说明:产生可调的PWM波信号,通过改变占空比改变PWM信号。

五、调试过程

5.1软硬件调试及调试问题和解决方法

本次软件调试采用Keil uvision4软件,配置采用默认配置(12MHz晶

振)默认的编译器,仿真器。刚开始使用内部仿真器,后来用外部仿真器(Proteus仿真联调)并使用单步、断点、全速运行等多种手段调试。

硬件仿真使用Proteus仿真,在Proteus中画原理图并仿真。 下面介绍一下解决联调的方法

1:把VDM51.dll这个文件分别复制到Proteus安装文件下的MODELS目录下,以及keil安装文件下的C51\\BIN目录下 2: keil 设置步骤:

(1)用记事本打开C:\\Program Files\\keil 中 toolS.INI文件,添加TDRV9=BIN\\VDM51.DLL (\其中“TDRV9”中的“9”要根据实际情况写,不要和原来的重复。 (2):keil打开DEBUG 选项卡如图设置:

23

a:在出现的对话框里在右栏上部的下拉菜单里选中“Proteus VSM Monitor一51 Driver”。并且还要点击一下“Use”前面表明选中的小圆点

b:再点击“Setting”按钮,设置通信接口,在“Host”后面添上“127.0.0.1”,如果使用的不是同一台电脑,则需要在这里添上另一台电脑的IP地址(另一台电脑也应安装Proteus)。

在“Port”后面添加“8000”。设置好的情形如图所示,点击“OK”按钮即可。最后将工程编译,进入调试状态,并运行 3:protues 设置:

进入Proteus的ISIS,鼠标左键点击菜单“Debug”, 选中“use romote debuger monitor”,如图所示。此后,便可实现KeilC与Proteus连接调试。

5.2调试效果

5.2.1效果图

24

启动初始化 初始化:显示设计者 显示设计者。当然也可以显当然可以显示其他(根据需要) 示其他(根据需要)。

25

没输入的情况

26

正转

27

反转

停转

28

5.2.2仿真与实际的区别及仿真的局限性

仿真有如下几个特点,也是仿真的局限性所在:

a) 仿真芯片不用接电源也可以,电源默认接。比如LCD模块,电机驱动模块芯片

b) 仿真不用接晶振电路。而实际中必须接上,否则不可以使。 c) 仿真不考虑驱动能力。意思就是你直接把电机连到单片机上也可以驱动。而这在实际中是不可能的。也会造成我们的误解。

六、设计总结

其实这次课程设计还是有很大的收获的,首先还是从对单片机的认识谈

起吧,每一次课堂上的学习,包括前两次的大作业,都会使我对51单片机有了更深一步的认识,有时候会有这么一种感觉:单片机还能这么玩!程序还能这么写!我觉得每一次的感悟就有每一次的提高。下面谈谈我对各个软件的理解,再谈谈我对51的浅谈以及本次课设的理解。

先来谈谈Proteus仿真软件,从原理图布图、代码调试到单片机与外围

电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。在编译方面,它也支持IAR、Keil和MPLAB等多种编译器。当然本次课设只用到了原理图仿真。当然了此次课设我还使用了keil与proteus联调的方式来进一步精确的调试。当然我也学到了一些快捷键的使用,比如统一给接口做标号就可以按“a”后,输入“net=p0.#”来依次标p0口

的网络标号。

再说说对keil uvisin4的理解,当然keil也是一个功能非常强大的软件,

29

不管是对程序的编写还是调试,都是相当有效,本次课设用到的并不多,只是用来编写C代码,和调试,keil本身带有51的内部调试器,当然我这次也用了和proteus联调的手段,是调试更方便,更具有目的性。

除了对软件熟练掌握以外,算法思想显得尤为重要,老谭说过:“一

个好的算法是程序的灵魂”。写这个程序就体现了这一点,对于LCD1602的程序部分我是下了功夫,主要是对字符的输入转变,具体实现请参照代码。按键的扫描也是用的两个数组比较来实现检测按键的按下,对此还是颇为自豪。

还有就是编程的思想,在编程的时候应该想到如何是代码更具有可

移植性,这让我皱起了眉头,在对代码整理的时候我意思到了这个问题。 定义放到预编译中 1. 变量尽量在函数中定义

2. 还有变量的名称尽量用英文而不是拼音,也可以放在H文件中包含进来

3. 变量和函数的书写格式也是固定的还可以把模块放到另一个c文件中然后在主文件中包含就可以了 具体实现请参照代码。

30

七、参考文献

【1】Atmel公司AT89C51用户手册

【2】周润景,张丽娜.PROTEUS入门教程.北京:机械工业出版社,2007 【3】Keil Software公司。Keil uvision4用户手册。

【4】张丽娜,刘美玲,姜新华。51系统开发与实践.北京航空航天大学出版社

【5】张毅刚.单片机原理及应用.高等教育出版社

31

附件

代码如下

#include #include #include #include #include #include

#define uchar unsigned char #define uint unsigned int #define LCD_COMMAND 0

#define LCD_DATA 1 #define LCD_CLEAR_SCREEN 0X01 #define LCD_HOMING 0X02 #define LCD_SHOW 0X04 #define LCD_HIDE 0X00 #define LCD_CURSOR 0X02 #define LCD_NO_CURSOR 0X00 #define LCD_FLASH 0X01 #define LCD_NO_FLASH 0X00 #define LCD_AC_UP 0X02 #define LCD_AC_DOWN 0X00 #define LCD_MOVE 0X01

#define LCD_NO_MOVE 0X00 sbit SW0=P1^0; sbit SW1=P1^1;

sbit SW2=P1^2; sbit SW3=P1^3; sbit SW4=P1^4; sbit Mz=P3^0; sbit Mf=P3^1; sbit Me=P3^7; sbit zheng=P1^5; sbit fan=P1^6; sbit ting=P1^7; sbit LcdRs=P2^2;

sbit LcdRw=P2^1; sbit LcdEn=P2^0; uchar last_val[5]={1,1,1,1,1},cur_val[5]={1,1,1,1,1}; uint i; uint count=0;

32

//包含头文件

//写指令 //写数据 //清屏 //回原地 //开显示 //关显示 //显示光标 //不显示光标 //光标闪动 //光标不闪动 //地址计数器加

//画面可平移

//正转开关

//反转开关 //停止开关 //加速开关 //减速开关 //L298芯片控制口

//PWM波输出口 //正转指示灯 //反转指示灯 //LCD控制口

//停转指示灯

//决定按键变化数组 //周期计数

uchar tp=5; uchar str[7]; uchar dis[1];

void keyscan(void); //占空比计数

//按键扫描 void delay1(void); void just(void); void turn(void); void motorstop(void); void speedup(void); void speeddown(void); void delay2();

/************************ * FunctionName: delay *Description: LCD延时程序 *ENtryparaenter: z *REturnValue: 无

**************************/

void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); }

/************************ * FunctionName: LCD_Write

*Description: 当style=1时写数据,等于0时写指令 *ENtryparaenter: style,input *REturnValue: 无

**************************/ void LCD_Write(bit style,uchar input) {

LcdRs=style; P0=input; delay(5); LcdEn=1; delay(5); LcdEn=0;

33

//10ms延时 //正转程序 //反转程序 //停车程序 //加速程序 //减速程序 //100ms延时

}

/************************

* FunctionName: LCD_SetDisplay *Description:

*ENtryparaenter: displaymode *REturnValue:

**************************/

void LCD_SetDisplay(uchar displaymode) { LCD_Write(LCD_COMMAND,0x08|displaymode); }

/************************

* FunctionName: LCD_SetInput *Description:

*ENtryparaenter: InputMode *REturnValue:

**************************/

void LCD_SetInput(uchar InputMode) { LCD_Write(LCD_COMMAND,0x04|InputMode); }

/************************ * FunctionName: LCD_initial *Description: LCD1602初始化 *ENtryparaenter: *REturnValue:

**************************/ void LCD_initial() { LcdEn=0; LCD_Write(LCD_COMMAND,0x38); 行显示 LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); }

/************************ * FunctionName: GotoXY *Description: LCD坐标定位 *ENtryparaenter: x,y *REturnValue:

**************************/

34

//设置功能,8为数据线两

//开显示,无光标 //清屏

//AC递增画面不动

void GotoXY(uchar x,uchar y) { if(y==0) LCD_Write(LCD_COMMAND,0x80|x); 地址80-8FH if(y==1) LCD_Write(LCD_COMMAND,0x80|(x-0x40)); //由于DB7位1所以第一行

//第二行C0-CFH

}

/************************ * FunctionName: Print *Description: 写字符 *ENtryparaenter: *str *REturnValue:

**************************/ void Print(uchar *str) { while(*str!='\\0') { LCD_Write(LCD_DATA,*str); str++; } }

/************************ * FunctionName: Dataconv *Description:

*ENtryparaenter: dat *REturnValue:

**************************/ void Dataconv(uchar dat) { uchar temp; temp=dat; dis[0]=temp+0x30; }

/************************ * FunctionName: welcome *Description: 欢迎界面 *ENtryparaenter: *REturnValue:

**************************/ void welcome() {

35

//输出有效字符

LCD_initial(); GotoXY(0,0); Print(\ Designed\ GotoXY(0,1); Print(\ delay(200); delay2(); }

/************************ * FunctionName:

*Description: 主程序: *ENtryparaenter: *REturnValue:

**************************/ void main() { Mz=0; Mf=0; TMOD=0x02; TH0=0x06; TL0=0x06; TR0=1; ET0=1; EA=1; LcdRw=0; welcome(); 收 delay1(); delay2(); LCD_initial(); while(1) { GotoXY(6,0); Print(\ GotoXY(13,0); Print(\ GotoXY(12,0); Dataconv((uchar) tp); Print(dis); GotoXY(0,1);

36

//电机停转

//定时器0方式2定时 //开启定时器 //允许定时器中断 //总中断允许 //写使能 //显示设计者:袁吉 //延时

//LCD初始化 //大循环

Print(\ GotoXY(11,1); Print(\ keyscan(); } }

/************************ * FunctionName:

*Description: 主程序延时10ms *ENtryparaenter: *REturnValue:

**************************/ void delay1() {

uchar i,j;

for(i=20;i>0;i--) for(j=248;j>0;j--); }

/************************ * FunctionName:

*Description: 按键扫描程序 *ENtryparaenter: *REturnValue:

**************************/ void keyscan() {

last_val[0]=cur_val[0]; cur_val[0]=SW0;

if((last_val[0]!=cur_val[0])&&cur_val[0]==0) {

delay1();

if((last_val[0]!=cur_val[0])&&cur_val[0]==0) just(); }

last_val[1]=cur_val[1]; cur_val[1]=SW1;

if((last_val[1]!=cur_val[1])&&cur_val[1]==0) {

delay1();

if((last_val[1]!=cur_val[1])&&cur_val[1]==0) turn(); }

37

last_val[2]=cur_val[2]; cur_val[2]=SW2;

if((last_val[2]!=cur_val[2])&&cur_val[2]==0) {

delay1();

if((last_val[2]!=cur_val[2])&&cur_val[2]==0) motorstop(); }

last_val[3]=cur_val[3]; cur_val[3]=SW3;

if((last_val[3]!=cur_val[3])&&cur_val[3]==0) {

delay1();

if((last_val[3]!=cur_val[3])&&cur_val[3]==0) speedup(); }

last_val[4]=cur_val[4]; cur_val[4]=SW4;

if((last_val[4]!=cur_val[4])&&cur_val[4]==0) {

delay1();

if((last_val[4]!=cur_val[4])&&cur_val[4]==0) speeddown(); } }

/************************ * FunctionName:

*Description: 定时器中断产生PWM波 *ENtryparaenter: *REturnValue:

**************************/ void t0() interrupt 1 using 0 { if(tp!=0) { if(count>10) count=0; if(count>tp) Me=0; else Me=1; } if(tp==0) {

38

if(count>10) count=0; if(count>=tp) Me=0; else Me=1; } count++; }

void just() { Mz=1; Mf=0; zheng=0; fan=1; ting=1; GotoXY(0,0); Print(\ }

void turn() { Mz=0; Mf=1; zheng=1; fan=0; ting=1; GotoXY(0,0); Print(\ }

void motorstop() { Mz=0; Mf=0; zheng=1; fan=1; ting=0; GotoXY(0,0); Print(\}

39

void speedup() {

if(tp>9) tp=10; else tp++; GotoXY(5,0); Print(\}

void speeddown() {

if(tp<1) tp=0; else tp--;

GotoXY(5,0); Print(\}

void delay2() { uchar a,b,c;

for(c=5;c>0;c--) for(a=200;a>0;a--) for(b=245;b>0;b--); }

40

本文来源:https://www.bwwdw.com/article/kexr.html

Top