单片机技术及应用(C语言版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第二单元 单片机系统的显示界面

综合教学目标

学习单片机编程常用软件的操作;掌握单片机系统中常用显示模块的程序设计。

主要内容

项目2.1流水灯、项目2.2电子秒表、项目2.3电子钟、项目2.4两级菜单的显示界面。分别介绍了发光二极管、数码管、字符型液晶显示器RTC1602、点阵型液晶显示器TG12864。

岗位技能综合职业素质要求:学会操作相关软件,处理烧录芯片时的问题。

单片机系统的显示界面主要用于显示系统的参数设置界面、输出结果界面、系统运行中的报警界面等。友好的人机界面将使产品大受欢迎。

本教材中选用“YL-236型单片机控制功能实训考核装置”作为项目实训平台。

YL-236装置将单片机系统中的常用显示模块集中在MCU04显示模块上,其照片如图2-1所示。其中包含有:8个发光二极管LED0~LED7(左下)、8个数码管显示器(右下)、1个RTC1602液晶显示器(左中)、1个TG12864液晶显示器(左上)、点阵显示器(右上)。

图2-1 YL-236装置中的MCU04显示模块

项目实训中可以根据需要选择其中某个或多个显示器来使用。

项目2.1 流水灯

2.1.1 项目描述

本项目要求采用显示模块MCU04中的发光二极管(LED),完成下述任务。

任务2-1-1:点亮一个发光二极管。

① 了解发光二极管工作原理。

② 点亮第一个发光二极管。

③ 掌握51单片机仿真器的使用,以及MedWin软件操作。

任务2-1-2:实现二极管闪烁。

① 了解ms级延时C51函数。

② 用单片机控制发光二极管闪烁。

③ 掌握双龙下载器的使用。

任务2-1-3:实现流水灯。

2.1.2 项目分析

通过项目描述,实现本项目需完成以下两方面工作。

①硬件电路的设计:以单片机为控制中心,通过其I/O口与MCU04显示模块中的发光二极管连接,构成单片机控制LED电路。

② 程序的设计:用C51语言编写单片机控制LED程序。

2.1.3 任务2-1-1 点亮一个发光二极管

一、发光二极管的工作原理

在YL-236装置的MCU04显示模块中,发光二极管部分的照片如图2-2(a)所示。

LED显示电路工作原理分析:如图2-2(b)所示,当LED0端口为低电平时,发光二极管D1正向导通,有电流通过D1,D1发光;当LED0端口为高电平时,发光二极管D1无法导通,D1熄灭。将单片机某I/O口与LED0端口相连,通过软件控制该I/O输出高或低电平就可以使D1灭或亮。图2-2(b)中,电阻R1起限流作用,调整R1阻值大小就可以调节LED的亮度。

图2-2 MCU04显示模块中的发光二极管照片与电路原理图

二、任务2-1-1的实施

1.硬件电路的设计

本任务需要使用YL-236装置中的三个模块:MCU01主机模块、MCU02电源模块、MCU04显示模块。模块接线图如图2-3所示,其中主机模块的P0.0~P0.7用排线接到显示模块的LED0~LED7;主机模块、显示模块的+5V电源端子接到电源模块的+5V端口;主机模块、显示模块的GND端子接到电源模块的GND端口。

图2-3 单片机控制LED显示的模块接线图

2.点亮LED0的程序设计

(1)单片机P0.0的输出电平与LED0状态关系表

由LED工作原理可知,单片机P0.0的输出电平与LED0状态关系见表2-1。

表2-1 P0.0的输出电平与LED0状态关系表

(2)用C51语言指令控制单片机I/O口输出

在C51语言中,使单片机P0.0输出低电平,只需要写语句“P0^0=0;”;使单片机P0.0输出高电平,只需要写语句“P0^0=1;”。

任务2-1-1的程序清单

            #include<at89x52.h>  //头文件包含
            sbit LED0=P0^0;        //定义符号LED0为单片机的P0.0引脚
            void main()
            {
        LED0=0;           //P0.0输出低电平,灯亮;P0.0输出高电平,灯熄灭
        while(1);       //死循环
            }

【知识链接一】C程序的基础知识

1.C程序的基本结构

(1)C程序是由函数构成的。一个C源程序至少且仅包含一个main函数,也可以包含一个main函数和若干其他函数。函数体的内容由一对{}括起来,{}必须成对出现。

(2)main为“主函数”,一个C程序总是从main函数开始执行,而且不论main函数在整个程序中的位置如何。

(3)C程序书写格式自由,一行内可以写几条语句,一条语句可以分写在多行上。

(4)每条语句和数据声明的最后必须有一个分号,分号是C语句的必要组成部分,不可缺少。既使程序中最后一条语句也应包含分号。

2.文件包含

“文件包含”是指一个文件将另外一个文件的内容全部包含进来。其格式为:

① #include<文件名称>

② #include"文件名称"

两者区别在于""和< >。< >表示头文件在编译器(KeilC51)的安装目录下,一般都是编译器自带的头文件;""表示头文件在当前工程的目录下,一般都是自己写的头文件,编译器将首先查找当前目录,如果没找到,则在由菜单选择项所确定的目录中查找。

任务2-1-1的程序中,文件at89x52.h在路径“C:\Keil\C51\INC\Atmel”中,是编译器自带的头文件,它主要定义了ATMEL公司的52单片机内部相关资源名称,以方便使用。

3.KeilC51单片机集成开发环境

KeilC51是目前使用最广泛的基于51单片机内核的开发平台之一,其编译器性能较好。

4.使用KeilC的关键字sbit来定义位变量

第一种方法:sbit位变量名=位地址值

第二种方法:sbit位变量名=字节名称^序号

第三种方法:sbit位变量名=字节地址值^序号

例如:sbitOV=PSW^2。

三、单片机仿真器及其软件的使用

YL-236装置中配备的仿真器为南京万利公司的“insight”51单片机仿真器。YL-236装置的主机模块与仿真器模块的照片如图2-4所示。先将主机模块上的AT89S52芯片取下,将仿真头的引脚插在主机模块的卡座上并卡紧,注意仿真头上的弧形标识对准卡座的上方,方向不能插反;然后按照图2-3连接好系统接线,并接通仿真器的电源与USB线等。

图2-4 主机模块与仿真器模块照片

“insight”51单片机仿真器的配套软件为MedWin3.0,它是一个国产的中文界面单片机集成开发平台,比KeilC51更好操作,但其自身不带C51编译器,需要调用KeilC编译器。操作步骤如下。

(1)启动MedWin3.0,创建项目,命名后保存。

启动MedWin3.0后,在菜单“项目管理”中选择“新建项目”,如图2-5所示。

图2-5 新建项目

弹出对话框如图2-6所示。点击其中“设备驱动程序名”后的下拉按钮,出现若干选项:第一项“InsightME-52HUFamilyEmulator”为上述万利仿真器,使用仿真器时应选此项;第二项“80C51SimlatorDriver”为软件仿真,若不连接仿真器,只是使用MedWin编译源程序产生机器码,可以选此项。这里选中第一项,点击“下一步”按钮。

图2-6 选择驱动程序

在第2步的对话框中,选择如图2-7所示编译工具,然后点击“下一步”按钮。

图2-7 选择编译工具

然后,在图2-8所示对话框中输入项目名称led0,然后点击“下一步”按钮。其存储位置一般默认在计算机最后一个盘符根目录的“WorkDir”文件夹下。也可点击“浏览”按钮自行设定存储路径。

图2-8 输入项目名称

然后,在图2-9所示对话框中,设置有关参数。点击“片内RAM长度”选项后的下拉按钮,选择“256”,可以充分使用AT89S52的256字节RAM空间;若单片机为AT89S51,则选择“128”。

图2-9 设置有关参数

点击“操作系统内核”选项后的下拉按钮,出现3个选项:① None(无操作系统);② RTX_51Tiny(RTX_51操作系统精简版);③ PTX_51Full(RTX_51操作系统完整版)。本项目没有采用操作系统,因此选①。

在图2-9中,点击“完成”按钮后,项目led0就创建完毕,如图2-10所示。

图2-10 新建项目完成

(2)创建源程序文件并命名保存。

选中菜单“文件/新建”,创建源程序文件,如图2-11所示。

图2-11 创建源程序文件

选中菜单“文件/另存为”,保存为C语言程序文件格式,如图2-12所示。

图2-12 另存为C语言程序文件格式

(3)导入/添加C文件到项目中。

用鼠标右键单击源文件组,在弹出的菜单中选择“导入/添加文件”,如图2-13所示。

图2-13 导入C文件(一)

找到之前保存的C文件,并添加到项目工程的源文件组中去,如图2-14所示。

导入源程序文件后,源文件组将出现该文件,如图2-15所示。

(4)在刚导入的C文件中编写C51程序。

在程序编辑区输入C51源程序,如图2-16所示。

图2-14 导入C文件(二)

图2-15 文件导入完成

图2-16 输入C51程序

(5)编译C51程序。

由于MedWin3.0自身不带编译器,因此选中菜单“设置/设置编译工具”,如图2-17所示。

图2-17 设置编译工具(一)

在如图2-18所示的对话框中,设置编译工具及相关文件路径后,点击“确定”按钮。

图2-18 设置编译工具(二)

选中菜单“项目管理/重新产生代码并装入”,如图2-19所示。

用软件编译C51源程序,如果编译链接无误,将产生机器码,并装入仿真器;若编译链接中发现错误(主要为语法错误),则会在构建窗口中提示错误种类,无法产生机器码,此时应该改正程序中的错误,重新产生代码并装入,正确后,才能进行下一步。

图2-19 重新产生代码并装入

(6)调试C51程序。

如图2-20所示,点击菜单“调试”后出现的下拉菜单中,可选择以“单步”或“全速运行”等方式运行程序,并在系统中查看程序运行结果。若结果有错(主要为逻辑错误),则应改正程序错误,重新编译、调试,直至程序运行结果完全正确。

图2-20 调试C51程序

本任务中,以“全速运行”方式运行程序后,将会看到LED0亮。在“调试”状态下,选中菜单“调试/返回监控”,将退出“调试”状态。

2.1.4 任务2-1-2 实现二极管闪烁

一、任务要求

本任务要求单片机控制LED0间隔1s闪烁,就是让LED0灯亮1s,然后熄灭1s,反复循环不止。

二、任务2-1-2的实施

1.硬件电路的设计

硬件电路的设计与任务2-1-1相同。

2.程序的设计

(1)下面函数为ms级延时函数。

            void delayms(uintx)  //当晶振为12MHz,延时xms,
            {                     //用MedWin3.0的 “查看/工具栏/时间”功能测试结果:
        uchar i;          //x小于500(ms)时,最大误差为17μs;
        while(x--)      //x为1000、2000、3000(ms)时,误差分别为19、23、27μs。
        for(i=0;i<123;i++);
            }                     //当晶振为11.0592MHz,延时12x/11ms。

(2)单片机控制LED0闪烁的程序流程图如图2-21所示。

图2-21 单片机控制LED0闪烁的程序流程图

任务2-1-2的程序清单

            #include<at89x52.h>
            #define uintunsignedint        //定义uint=unsignedint(无符号整型)
            #define ucharunsignedchar      //定义uchar=unsignedchar(无符号字符型)
            sbit LED0=P0^0;               //定义符号LED0为单片机的P0.0引脚
            void delayms(uintx)          //函数省略,请参考上文
            void main()
            {
        while(1)                //另一种解法
        {
            LED0=0;              //LED0亮1s
            delayms(922);      //实际晶振11.0592MHz,1000*11.0592/12=922
            LED0=1;              //LED0灭1s
            delayms(922);
        }
        /*
        while(1)                //另一种解法
        {
            LED0=!LED0;         //LED0亮1s,灭1s。效果同上
            delayms(922);
        }*/
            }

正确连接好仿真器,在MedWin3.0中建立名为led1项目,输入上面的源程序,编译、连接正确后,全速运行,可以看到发光二极管LED0亮1s、灭1s,不停闪烁。

【知识链接二】程序流程图与程序的构成等

1.程序流程图

程序流程图是用一些图框来表示各种操作,直观形象,易于理解。美国国家标准化协会ANSI(AmericanNationalStandardInstitute)规定的一些常用的流程图符号如知识链接图2-1所示。

知识链接图2-1

2.程序的构成

程序=数据结构+算法

① 对数据的描述,在程序中指定数据的类型和数据的组织形式,即数据结构。

② 对操作的描述,即操作步骤,也就是算法。

3.逻辑运算符“!”的作用

!为逻辑非运算符,其作用是将逻辑量或位变量的值取反,即原来为1的,变为0;原来为0的,变为1。

三、单片机程序的烧录

程序调试成功后,下一步要把程序代码下载(烧录)到单片机芯片AT89S52中。

YL-236装置中配备了双龙ISP下载器。按照其光盘里产品说明书上的步骤,安装好相关软件后,第一次用USB线连接双龙ISP下载器和计算机时,会在电脑屏幕上看到“已经找到新硬件”的提示,选择“自动安装软件”,计算机会自动安装好新增的设备。

单片机程序烧录的操作步骤如下。

① 下载程序前,首先关闭系统电源,将仿真头取下;然后将AT89S52的引脚插在主机模块的卡座上并卡紧,注意单片机芯片上的弧形标识对准卡座的上方,方向不能插反。

② 用排线连接双龙ISP下载器与主机模块后,再接通双龙ISP下载器的USB线。

③ 启动双龙ISP下载器软件后,出现如图2-22所示界面。

图2-22 双龙ISP下载器软件界面

④ 如图2-22所示,首先在界面上部各选项中,正确选择“下载端口”、“下载速度”、“芯片型号”等,然后点击“FLASH存贮器”选项右边的“Flash”按钮,添加要烧录的机器码文件(一般为HEX文件),如图2-23所示。

⑤ 添加HEX文件后,点击图2-22中的“编程”按钮,软件会自动烧录机器码程序到AT89S52单片机中。但烧录有时会失败,可能是由于在设计的目标系统电路中,P1.5、P1.6、P1.7的电平被钳制住(例如:作为输入端口,而从外界输入电平为0V等),ISP下载器无法通过这3个引脚下载程序,这时,可以将主机模块上P1.5、P1.6、P1.7端子上的导线拔除,再下载程序。下载失败,有时是因为目标系统自身电源未供应,这时可以通过ISP下载器给目标系统供电,然后再完成下载,相关设置操作如图2-24所示。

图2-23 添加机器码文件

图2-24 给目标系统供电

⑥ 本任务中,正确烧录“LED0闪烁”的程序代码后,先断开双龙ISP下载器的USB线,再断开双龙ISP下载器与主机模块的排线,打开系统电源后,即可看到LED0不停闪烁。

2.1.5 任务2-1-3 实现流水灯

一、任务要求

单片机控制8个发光二极管从LED0到LED7间隔1s依次点亮(亮1s后熄灭,下一个LED点亮),当LED7亮1s后,又从LED0开始点亮,如此循环不止,视觉效果上像一个亮的灯从右到左流动。

二、任务2-1-3的实施

1.硬件电路的设计

硬件电路的设计与任务2-1-1相同。

2.程序的设计

(1)流水灯形成原理。

LED形成流水灯的效果实质是按顺序依次点亮发光二极管,其发光过程见表2-2。

表2-2 流水灯发光过程表

注:表中数据0或1,表示该引脚输入低或高电平,以使相应LED亮或灭。

(2)本教材提供两种方法实现单片机控制LED流水灯的程序清单,方法二的流程图如图2-25所示。

图2-25 单片机控制LED流水灯的程序流程图

任务2-1-3的程序清单

            #include<at89x52.h>
            #define uintunsignedint             //定义uint=unsignedint(无符号整型)
            #define ucharunsignedchar           //定义uchar=unsignedchar(无符号字符型)
            sbit LED0=P0^0;                    //定义符号LED0为单片机的P0.0引脚
            sbit LED1=P0^1;                    //定义符号LED1为单片机的P0.1引脚
            sbit LED2=P0^2;                    //定义符号LED2为单片机的P0.2引脚
            sbit LED3=P0^3;                    //定义符号LED3为单片机的P0.3引脚
            sbit LED4=P0^4;                    //定义符号LED4为单片机的P0.4引脚
            sbit LED5=P0^5;                    //定义符号LED5为单片机的P0.5引脚
            sbit LED6=P0^6;                    //定义符号LED6为单片机的P0.6引脚
            sbit LED7=P0^7;                    //定义符号LED7为单片机的P0.7引脚
            void delayms(uintx)               //函数省略,请参考任务2-1-2
            void main()                       //方法一
            {
        while(1)                     //方法一比较容易想到
        {
            P0=0xff;                  //熄灭所有的LED
            LED0=0;                   //点亮LED0
            delayms(922);           //实际晶振为11.0592MHz,延时1s
            P0=0xff;
            LED1=0;                   //点亮LED1
            delayms(922);
            P0=0xff;
            LED2=0;                   //点亮LED2
            delayms(922);
            P0=0xff;
            LED3=0;                   //点亮LED3
            delayms(922);
            P0=0xff;
            LED4=0;                   //点亮LED4
            delayms(922);
            P0=0xff;
            LED5=0;                   //点亮LED5
            delayms(922);
            P0=0xff;
            LED6=0;                   //点亮LED6
            delayms(922);
            P0=0xff;
            LED7=0;                   //点亮LED7
            delayms(922);
        }
            }
            void main()                       //方法二
            {
        uchar num,i;                  //定义2个变量
        while(1)                     //方法二比较简洁
        {
            num=0xfe;                 //准备点亮第一个灯(LED0)
            for(i=0;i<8;i++)      //8个LED,共循环8遍
            {
                P0=num;               //点亮某个LED
                delayms(922);       //延时1s
                num=num<<1|0x01;    //准备下一个LED
            }
        }
            }
            //0xfe:点亮LED0,0xfd:点亮LED1,0xfb:点亮LED2,0xf7:点亮LED3,
            //0xef:点亮LED4,0xdf:点亮LED5,0xbf:点亮LED6,0x7f:点亮LED7

正确连接好仿真器,在MedWin3.0中建立名为led2的项目,输入上面的源程序(main函数在方法一与方法二中选一个),编译、连接正确后,全速运行,可以看到一个亮的灯从右至左流动。关闭系统电源后,正确烧录“流水灯”的程序代码到单片机中,取下双龙ISP下载器,打开系统电源后,即可看到同样的结果。

在本书后面各任务中,请参考任务2-1-1~2-1-2中介绍的方法正确使用仿真器和双龙ISP下载器调试和下载程序,只有程序下载到单片机中并运行正确后,方为任务完成。

【知识链接三】C51的数据结构

一、常量与变量

C语言的基本数据类型,按其取值是否可改变分为常量和变量两种。在程序执行过程中,其值不发生改变的量称为常量,取值可变的量称为变量。

1.数值常量

数值常量也称为常数,例如12、-5.3、′c′、′abc′等。其中12为整型常量,-5.3为浮点型常量,′c′为字符型常量,"abc"为字符串常量。

2.符号常量

在C语言中,可以用一个标识符(标识符的定义见下文)来表示一个常量,称之为符号常量。符号常量在使用之前必须先定义,其一般形式为:“#define标识符 常量”。

其中,#define也是一条预处理命令,称为宏定义命令,其功能是把该标识符定义为其后的常量值。一经定义,以后在程序中所有出现该标识符的地方均代之以该常量值。

二、变量

值可以改变的量称为变量。一个变量应该有一个名字,在内存中占据一定的存储单元,在该存储单元中存放变量的值。请注意:变量名与变量值的区别如知识链接图2-2所示。

知识链接图2-2

在C语言中,要求对所有用到的变量做强制定义,也就是“先定义,后使用”。

在C语言中用来标识变量名、符号常量名、函数名、数组名、类型名等的有效字符序列称为标识符。简单地说,标识符就是一个名字。

C语言规定标识符只能由字母、数字和下划线三种字符组成,且第一个字符必须为字母或下划线。要注意的是,C语言中大写字母与小写字母被认为是两个不同的字符,即Sum与sum是两个不同的标识符。

1.整型变量

整型变量的基本类型符为int,在int之前可以根据需要分别加上修饰符。在KeilC中规定,基本整型数据在存储器中占用2个字节(即16bit)、长整型占用4个字节的存储空间。知识链接表2-1列出了各种整型数据的有关数据。

知识链接表2-1 整数类型的有关数据

2.字符型变量

字符型变量的基本类型符为char,其表达的范围是-128~+127;字符型变量只有一个修饰符unsigned,即无符号数,而加上了unsigned后,其表达的范围变为0~255。

3.浮点型变量

在8位单片机中,尽量不要用浮点型数据,这里不做介绍。

4.KeilC51特有的变量类型

(1)位型变量

位型变量是使用一个二进制位来存放数据,其值只有“0”和“1”两种。位型变量的定义和其他数据类型一样,关键字为bit。例如:

            bita=0;     //定义一个位变量,并赋初值为0

(2)sfr型变量

80C51内部有一些特殊功能寄存器(sfr)。为定义、存取这些特殊功能寄存器,C51增加了sfr型数据,相应也增加了sfr、sfr16和sbit这3个关键字。例如:

            sfrP0=0x80;       //定义8位特殊功能寄存器P0
            sfr16DPTR=0x82;   //定义16位特殊功能寄存器DPTR

三、变量的存储类型

在变量前加一个修饰符可以指定变量的存储器类型。

① data:片内RAM低128B,直接寻址访问,存储类型默认为data。② bata:片内RAM中20H~2FH,可以位寻址。

③ idata:片内RAM中256B,间接寻址访问。

④ xata:片外RAM中或片外I/O口扩展。

⑤ code:ROM中一般为固定数据表格,用MOVC指令查表访问。

例如:

            unsignedcharbdataflag;
            sbit F0=flag0;
            sbit F1=flag1;