您的当前位置:首页正文

实验十:综合实验-基于单片机的示波器实现(超级详细)

2021-02-07 来源:伴沃教育
微机原理与接口实验

综合实验

基于LCD的简易示波器实现

实验人:*** 学号:**** 院系:信息学院微电子学系

1

实验十、综合实验

目录

实验目的 ................................................................................................. 1 实验思路 ................................................................................................. 1 实验原理 ................................................................................................. 3 实验设计 ............................................................................................. 7 电原理图 ............................................................................................. 7 流程图 ................................................................................................. 8 各模块流程图 ...................................................................................... 9 实验仿真结果 ................................................................................................. 12 实验遇到的问题及改进 ...................................................................... 17 改写后的C语言代码 ......................................................................... 19 实验结果及展示 ................................................................................. 38 实验总结 ............................................................................................ 42

2

实验十、综合实验

【实验目的】

利用本学期学习的单片机及其接口知识,使用实验板上的外部设备自行设计一个实验。 【实验思路】

个人计划利用LCD液晶显示屏,制作一个示波器,所用的设备主要有51单片机,单片机片外存储器,LCD显示屏,AD芯片TLC549。预期实现功能为在LCD显示屏右侧显示自己的姓名或者示波器三个字,在屏幕左边的方框内显示信号源输入的波形。同时仿照我们实际使用的示波器设计波形的上/下平移,幅值压缩/拉伸,以及波形的展宽/压缩,并且能够测量输入波形的幅度,绝对误差精度在0.1V以下。

对于这个实验的难点,我个人认为主要在一下几个方面: 1. LCD的使用;

2. 对于获取到的ADC数据的存储与处理;

3. 将离散的ADC采样的数据进行连接,构成平滑的曲线。 4. 对输入波形幅度测量与显示

关于LCD的使用,将在后面的实验原理中进一步介绍,这里主要就后两个难点进行讨论:

根据LCD屏的大小为128*64,设计搭建一个90*60的方框作为波形显示窗口,考虑到在LCD显示时,每个显示Byte为8*1的一列(每128个组成一页),所以简化设计,将第一页的最下面一行,以及第八页的最上面一行作为显示方框的上下边界,从而中间的六页为波形显示区域,占用的点数为90*48。

考虑到需要采集90个样本,故设计使用片外存储器,依次存储90个数据。对于数据的处理,因为每个数据样本在显示时对应不同的时间点,所以为单独的一列,主要难度是将定位到对应列的确切的点上,所以需要自行设计一个函数能够把确切的点显示到对应的列上。

横坐标是90个点,纵坐标是48个点,所以在AD转换后还需要进行数据处理,因为AD转换后的值是在00-FFH之间,所以需要把FFH/6=256/6=43个点。因此,形成一个缩小的映射,由于LCD的分辨率的原因,这个将是在LCD的情况下最大的分辨率。具体的对应的位置可以通过如下方法算出:00-FFH的值被映射到00-2BH(0-43)的空间,所以,当被测信号电压大于等于参考电压,AD转

1

实验十、综合实验

换过来的值是FFH,则被对应为2BH,由于LCD的行是从上往下递增的,所以AD转换过来的值还需要进一步处理,用一个参考值减去转换值,得到显示的行值,即显示行值=参考值-AD转换映射值。而对参考值的改变,就可以改变显示波形的上下位置。因为0-256个AD转换值被映射到0-43个映射值,所以每5.9个点近似对应一行,初始设定每6个点对应一行,这样即可确定每个点所对应的行号,在根据其行号,可以推出其应该在哪一页中的哪一个位置,从而可以通过对01H或是80H的循环移位得到该点在对应页中的准确位置。

而如何将离散的点连成平滑的曲线,在这个计算中,我认为最重要的是不可出现如下图左边出现的情况。这样会造成显著的视觉上有台阶的感觉。所以在补充两个点之间的间隙时,我选择的方法是先判断下一个补充的点是否会与前一列的点在一行上,如果是的话,就不再补充,这样可以使得补充出来的曲线更加的平滑。这样的好处在显示方波的时候最为有效。

2

实验十、综合实验

【实验原理】

一、AD芯片原理 TLC549 8位串行A/D:

TLC549是美国德州仪器(TI)公司生产的8位串行逐次比较型A/D转换芯片。通用微处理器通过串行控制线可实现对该芯片的控制。该芯片具有4MHz片内系统时钟和软、硬件控制电路,转换时间最长17μs, 转换速度为40 000次/s。总失调误差最大为±0.5LSB,典型功耗值为6mW。

器件如左图所示:其中1、3脚为参考电压输入,其中1脚REF+,3脚REF-,通常为保证器件工作良好,REF+电压应高于REF-电压至少1V,为减少误差,建议相差4.75V以上

TLC549的工作时序图如下:

从图中可以看出,其控制时序有如下特点:

1. 将CS置低。内部电路在测得CS下降沿后,等待ten后自动将前一次转换结果的最高位(D7)位输出到DATA OUT端上。

2. 前四个IO_CLOCK 周期的下降沿依次移出第2、3、4 和第5 个位(D6、D5、

D4、D3),片上采样保持电路在第4个IO_CLOCK 下降沿开始采样模拟输入。 3. 接下来的3个IO_CLOCK 周期的下降沿移出第6、7、8(D2、D1、D0)个转换位。

4. 最后,片上采样保持电路在第8个I/O CLOCK 周期的下降沿后,开始A/D转换。第8个IO_CLOCK后,CS 必须为高,或IO_CLOCK保持低电平,这种状态

二、LCD显示屏的工作原理

3

实验十、综合实验

LCD12864 分为两种,带字库和不带字库的,不带字库的显示汉字的时候可以选择字体,而带字库的液晶,只能显示GB2312 的宋体,当然也可以显示其他的字体,不过不是液晶本身字库中带的了,而是用图片的形式显示。

由于该实验用的是带字库的LCD12864,所以这里主要介绍这一类。 字库型液晶显示可以分为串行方式和并行方式两种,通过引脚PSB 进行选择,它只有一个驱动芯片, 不像Proteus 中无字库液晶有两个驱动芯片。显示是整体显示,而不是左右屏的显示。

LCD结构图如上所示:

4

实验十、综合实验

这类LCD的引脚如上图所示。

本次实验所用的是周立功的实验箱,其LCD管脚内部已经固定连接好了,并运用并行的方式。

从图中可以看出LCD12864的输入管件有14个,其中D0-D7直接与单片机的P0口相连,D/-I管脚为数据/命令判断管脚,R/-W管脚为读/写判断管脚,E为用于锁存数据与指令使能管脚,CS1/CS2为LCD左右屏片选管脚,RST为复位管脚且低电平有效。

LCD显示屏主要有以下几种操作:读信号,写信号,读数据,写数据(这里的数据为显示缓冲区中的数据)。其中在这里实验里主要使用的是读信号,写信号,写数据这三种操作,其对端口的输入要求如下:

操作 读指令 写指令 读数据 LCD的显示原理:

5

R/-W 1 0 0 D/-I 0 0 1 E 1 下降沿 下降沿 实验十、综合实验

LCD指令中有开显示指令和关显示指令,LCD显示与否受控于这个软件控制开关,需要显示时向LCD中写入开显示指令即可开显示,也可以通过指令关闭LCD显示。因此实际应用中只需将待显示的内容写入显示缓冲区DDRAM后,打开显示开关即可。

显示缓冲区地址与内容关系如下:

行地址X称为页地址 列地址Y具有地址计数器,在读写数据后有自动加一功能,从而指向下一个DDRAM。

显示器常用的指令码如下:

D7 D6 D5 D4 D3 D2 D1 D0 功能描述 0 0 1 1 1 1 1 1 开显示 0 0 1 1 1 1 1 0 关显示 1 1 设置显示起始行(0-63) 指定显示屏从DDRAM哪一行开始显示 1 0 1 1 1 0-7 0 1 (0-63)

6

设置页地址 设置列地址 实验十、综合实验

【实验设计】 一、电原理图:

7

实验十、综合实验

二、实验流程图:

因为这个实验中设计的模块比较多,故分模块进行流程图表示,其中AD芯片驱动以及延时模块比较简单不做涉及。

主模块(MAIN):实现各模块的调用

调用LCD初始化模块开始 调用清屏函数 调用汉字显示模块 调用边框显示模块 调用数据处理波形并显示波形 调用显示被测波形幅值模块 结束 8

实验十、综合实验

LCD初始化模块:

该模块包含LCD_INIT,LCD_CMD(写命令函数),LCD_WRITE(写数据函数),BUSY(检查是否处于忙状态函数),SCREEN_CHOOSE(LCD屏幕选择函数),CLEAN_SCREEN(清屏函数)。

RST置位,开启LCD 等待5ms,LCD预热 输入开显示命令3FH 设置初始显示行 设置初始存储行地址 设置初始存储列地址 判断LCD忙 NO 调用指令输入函数 RS,RW清零,对P0传输命令 EN复位等待几个周期后置位,命令传输完成 RS清零,RW置位,进行读指令 YES EN先清零后置位,读取P0数据 YES P0.7=1 NO 汉字显示模块:

汉字显示中用的行列,与单字节显示中所用的行列不同,单字节中的行列为具体的存储单元位置,汉字显示模块中的行列为16*16的一个汉字显示区域在128*64的点

阵中的位置。

输入汉字显示所在的行,列,以及字符库中显示汉字的位置 根据输入的汉字所在位置,确定汉字存储的首字节的地址 根据输入的行地址,确定实际字节显示的行地址 根据输入的列地址,确定实际字节显示的列地址 向LCD输入行列地址 向LCD输入数据 NO 是否输入16次 YES 行地址加1,列地址复原,再操作一遍 9 实验十、综合实验

单字节显示模块:

与汉字显示模块基本一致,为单字节显示,即依次调用写指令函数(确定行地址和列地址)和写数据函数。

边框显示模块:

定义显示屏宽度为90,高度为48,即可显示90个采样点的数据构成的波形。行地址从0B8H-0BEH,列地址从第一个屏幕的41H-7F,第二个显示屏的40H-5CH。

设置输入行地址为0B8H,列地址为40H,数据为0FFH(绘制小竖线) R0赋值为6 增加行地址,R0减一 YES 行地址加1,列地址为加1,数据为01H(边框底部横线,屏幕1) R0赋值为3EH 增加列地址,R0减一 YES R0==0 NO R0==0 NO 余下的边框绘制…

数据处理波形显示模块:

该模块为示波器实验的核心模块,设计ADC数据采集和读取,根据外部按键情况进行数据操作,将数据转换成波形等等,下面将把该模块中的几大重要函数进行流程图分析

外部开关判断 Button1(UP)按下:显示波形上移 Button2(DOWN)按下:显示波形下移 Button3(INSERT)按下:显示波形横向变窄(采样率下降) Button4(MULTI)按下:显示波形幅度减小 预采样一个值,且等待50us(fs=20kHz) 调用ADC采样函数 ADC采样及处理 MULTI==1 大于1 YES 取下一个采样点 小于1 在当前采样点与前一个点之间加入其平均值 将采样点存入片外存储器中 10

实验十、综合实验

将ADC输出数据幅值给DDATA DDATA==7FH 大于 DDATA减去7FH YES 小于 7FH减去DDATA 数据移位量计算 根据前面所得的数据点信息进行波形绘制

将得到的结果除以5,可以得到需要移动的格数 根据需要移动的格数进行分类,确定该点在LCD中对应的行号和在所在byte的数据值 判断当前点与前一个点是否在同一行 YES 通过循环补1移位,填NO 补当前点与前一点之间将当前点与前一点之间的空白的空白点 补上,此处需要判断当前点在前一点的上面还是下面 判断是否输出了90个点,如果输出满了90个点,则返回模块开始阶段,重新取数 11

实验十、综合实验

【实验仿真结果】 1方波

2三角波

3正弦波

12

实验十、综合实验

4波形幅度压缩

5波形横向压缩

13

实验十、综合实验

6波形上移

7波形下移

14

实验十、综合实验

8 测量输入波形幅度峰峰值

15

实验十、综合实验

9 可测波形的频率范围 fin=10Hz

fin=20Hz

fin=30Hz

正弦波形开始出现调制波的波形,即波幅出现正弦的轮廓,这个时候说明采样频率小于等于被测波形频率的两倍了。也就是示波器测量波形频率的极限,这就是没有外部存储器的单片机示波器的最大测量频率。

后来经过调整代码,把采样和显示分开来,提高了采样率,因此被测波形的频率上限就提高了。

fin=1000Hz

16

实验十、综合实验

【实验中遇到的困难】

在实际设计中遇到了如下问题,需要对代码进行修改,故说明如下: 1. 发现自己根据LCD原理编写的LCD驱动并不可行,而只有使用周立功编写的教材中的实例才可以进行。由于周立功实验箱的原因,对于这个问题的具体原因,我和几个同学讨论下来也不是很清楚,应该是与电路中的延时有关,因为我们对电路中的每个管脚的作用都进行了分析,分析结果是实际电路中的A0,A1,A2与我们设计时定义的P1口的输出管脚的实际作用是一样的,但是由于在LCD的连接上增加了一串组合逻辑,最终可能导致了时序上的问题。

2. 没有能够成功的使用片外存储器,读取到的变量均为0FFH,在使用在线debug模式调整时,观察到Xdata中没有能够写入需要存储的数据。在经过和实验老师的交流后,确认了实验箱是没有外部数据存储器的,所以在对AD转换的实验流程和代码需要更改。这样的修改造成了采样频率的极端下降,因为每次要AD采样一个点以后,要经过数据处理及显示,以及波形圆滑判断后才能继续下一个点的采样。所以,由于没有外部存储器,使得采样频率变得很低。不过这完全不影响这个实验的功能实现,只是在实验的可拓展性上限制多了一点。

根据以上的问题,对代码进行如下修改:

1. 采用周立功教材的驱动,故用C语言对自己的代码进行重新编写。 2. 不采用记录90个数据的方法,而是每次只记录存储一个数据,并对其进

行操作和显示,这样造成的缺点是采样率会变得很低,因为对数据的操作中有很多循环语句,而且还有要调用一列显示模块,以及波形是否圆滑的条件判断语句,会占用很多的运行时间,从而造成采样率低下。但就一开始的设计目标而言,并不会有影响,只是减少了这个设计的可拓展性,使得频率测量的范围缩小了很多。 3. 对实验数据处理框图进行了修改,如下

17

实验十、综合实验

按键判断UP键为0,Level--,则使波形向上移动UP/DOWN/LENGTH/MULTI键是否按下YN清除该列点坐标数据DOWN键为0,Level++,则使波形向下移动LENGTH为0,insert++,则使采样频率减小,横向压缩波形MULTI为0,multi++,则纵向压缩波形调用adc模块,获得一个采样点的值若数据超过原有的最大值或者低于原有的最小值,更新数据的最大值和最小值采样数据缩小映射并调整为显示的行坐标调用显示点函数,显示该点判断是否为第一列Y显示该点,把该点的行信息更新到前一列行值中N判断该点是否与前一个点同一行YNY判断该列点是否在前一列之下调用画线函数,显示该点到前一列行坐标值N判断该列点是否在前一列之上Y调用画线函数,显示该点到前一列行坐标值N显示该点,并更新前一列坐标值调用显示峰峰值模块

4. 后来由于内部数据存储器所剩空间不多,为了想要提高采样率,提高对

于测量波形频率上限的提高,遂利用剩下的60个Byte的数据存储器字节空间,形成一个数组,把每次采样的点存入这个数组中,在由这个数组的内容去显示,这样做的目的是可以大大提高被测波形的频率上限,从原来的30Hz到现在的1000Hz。这样就可以把采样率提到最高。以后如果还想要提高采样率,则必须从AD转换器件入手,因为AD的转换速度是限制采样率的主要因素。不过这样做会有限制,就是单片机为数不多的内部存储器很小,知道导致一次采样60个点,没有把LCD的屏填满,

18

实验十、综合实验

因此这样显示的宽度就不是很宽。所以如果有外部存储器,则可以把每次采样的数据存入外部存储器,这样就没有宽度上的限制了。

5. 后来经过改进又加入了一些功能按键。如下所示: sbit UP = P2^0 ; sbit DOWN = P2^1 ;

//增加,波形上移 //减少,波形下移

sbit LENGTH = P2^2 ; //波形横向压缩 sbit LENGTH_= P2^3 ; sbit MULTI = P2^4 ; sbit MULTI_= P2^5 ;

//波形横向拉伸 //幅值变小 //幅值变大

sbit LENGTH__ = P2^6 ; //波形大幅横向压缩(针对低频率波形) sbit STOP = P2^7 ;

三、实验代码

由于程序过长,在实验之前设计的C程序代码在前面就不写出来了,下面是最后经过实验调试过后的C语言程序代码。 C语言代码设计:

主要文件有:

头文件:config.h(配置文件,定义变量) adc.h(adc函数头文件) LCM_DRIVE.h(驱动函数头文件)

C语言文件:adc.c(adc驱动函数)

LCM_DISP.c(主函数,实现了汇编语言中汉字显示,方框绘制,波形处理及显示等功能。) LCM_DRIVE.c(驱动函数文件)

//暂停

19

实验十、综合实验 【config.h】

/**************************************************************************** * 文件名:CONFIG.H

* 功能:配置文件,用于LCM_DISP项目。(目的在于方便项目管理) * 说明:所有项目C程序文件包含此头文件即可。

****************************************************************************/ #ifndef CONFIG_H #define CONFIG_H

#ifndef uint8 #define uint8 #endif

#ifndef uint16 #define uint16 #endif

/* 定义LCM像素数宏 */ #define LCM_XMAX 128 #define LCM_YMAX 64

/* 包含头文件 */ #include #include #include \"LCM_DRIVE.H\" #endif

【adc.h】

/********定义函数adc***********/ #ifndef ADC_H #define ADC_H

extern uint8 adc(void);

【LCM_DRIVE.h】 /该函数为周立功教程中的函数/

/**************************************************************************** * 文件名:LCM_DRIVE.H

* 功能:图形液晶TG12864B-2驱动程序。(头文件)

20

unsigned int

unsigned char

实验十、综合实验

****************************************************************************/ #ifndef LCMDRIVE_H #define LCMDRIVE_H

/* 定义LCM操作地址 */

#define LCMCS1W_COM (*((uint8 volatile xdata *) 0x2004)) #define LCMCS1W_DAT (*((uint8 volatile xdata *) 0x2005)) #define LCMCS2W_COM (*((uint8 volatile xdata *) 0x2000)) #define LCMCS2W_DAT (*((uint8 volatile xdata *) 0x2001))

/* 定义LCM操作的命令字 */ #define LCM_DISPON #define LCM_STARTROW

0x3f /* 打开LCM显示 */

0xc0 /* 显示起始行0,可以用LCM_STARTROW+x设置起始行。(x<64) */

#define LCM_ADDRSTRY 0xb8 /* 页起始地址,可以用LCM_ADDRSTRX+x设置当前页(即行)。(x<8) */ #define LCM_ADDRSTRX 0x40 /* 列起始地址,可以用LCM_ADDRSTRY+x设置当前列(即更)。(x<64) */

/* 定义宏函数 */

#define LCM_DispClr() LCM_DispFill(0x00) /* 清屏函数,清屏后设置显示起始行为0 */

extern uint8 xdata disp_buf[LCM_YMAX/8][LCM_XMAX];

/*********************************************************************** * 名称:LCM_DispIni() * 功能:LCM显示初始化 * 入口参数:无 * 出口参数:无

* 注:初化显示后,清屏并设置显示起始行为0。

***********************************************************************/ extern void LCM_DispIni(void);

/*********************************************************************** * 名称:LCM_WriteByte()

* 功能:向指定点写数据(一字节)。 * 入口参数:x *

x坐标值(0-127)

y y坐标值(0-63)

* wrdata 所要写的数据 * 出口参数:无

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

21

实验十、综合实验

extern void LCM_WriteByte(uint8 x, uint8 y, uint8 wrdata, uint8 screen);

/*********************************************************************** * 名称:LCM_DispFill() * 功能:向显示屏填充数据

* 入口参数:filldata 要写入LCM的填充数据 * 出口参数:无

***********************************************************************/ extern void LCM_DispFill(uint8 filldata);

/*********************************************************************** * 名称:LCM_DispChar() * 功能:指定地址显示字符。 * 入口参数:disp_cy * *

disp_cx

y值(0-7)

Y值(0-15)

所要显示的字符(ASCII码)

dispdata

* 注:支持显示字符0-9、A-Z、a-z及空格,字符显示模式为5*7,模为8*8,所以 * 屏幕显示为8*16(共8行,每行16个字符)。

***********************************************************************/ extern void LCM_DispChar(uint8 disp_cy, uint8 disp_cx, char dispdata);

/*********************************************************************** * 名称:LCM_DispStr() * 功能:字符串显示输出。 * 入口参数:disp_cy * *

X值(0-7)

disp_cx Y值(0-15) disp_str 字串指针

* 出口参数:无

* 注:支持显示字符0-9、A-Z、a-z及空格,字符显示格式为5*7,模为8*8,所以屏幕显示 * 为8*16(共8行,每行16个字符)。

***********************************************************************/ extern void LCM_DispStr(uint8 disp_cy, uint8 disp_cx, char *disp_str); #endif

22

实验十、综合实验 C语言函数:

【adc.c】

//ADC:REF+连基准源的+5V(通过可调电阻调整),CLK、DAT和-CS分别连P11、P12和P13。信号发生源的输出连ANIN

#include \"CONFIG.H\" sbit csadc=P1^3; sbit dat=P1^2; sbit clk=P1^1; uint8 adc() {

uint8 e,b; b=0; clk=0; csadc=0;

for (e=0;e<8;e++) { clk=1;

b=(b<<1)|dat; //将adc输出数据移位传输进b clk=0;

; } csadc=1; clk=1; return b; }

【LCM_DRIVE.c】

/*********************************************************************** * 文件名:LCM_DRIVE.C

* 功能:图形液晶TG12864B-2驱动程序。

* 说明:在LCM_DRIVE.H文件中定义了LCM操作地址,左半屏的写命令操作地址为2004H,写 * 数据操作地址为2005H,右半屏的写命令操作地址为2000H,写数据操作地址为2001H; * 由于GRAPHICS.C中使用了disp_buf作为作图缓冲区,所以LCM_WriteByte()、LCM_ * DispFill()均要更新disp_buf。

***********************************************************************/ #include \"CONFIG.H\"

23

实验十、综合实验

/* LCM复位控制脚定义 */ sbit LCM_RST

= P1^0;

/*********************************************************************** * 名称:LCM_Wr1Command()

* 功能:写命令子程序,所选屏为左半屏(CS1)。 * 入口参数:command 要写入LCM的命令字

***********************************************************************/ #define LCM_Wr1Command(command)

/*********************************************************************** * 名称:LCM_Wr2Command()

* 功能:写命令子程序,所选屏为右半屏(CS2)。 * 入口参数:command 要写入LCM的命令字

***********************************************************************/ #define LCM_Wr2Command(command)

/*********************************************************************** * 名称:LCM_Wr1Data()

* 功能:写数据子程序,所选屏为左半屏(CS1)。 * 入口参数:wrdata

要写入LCM的数据

LCMCS2W_COM = command LCMCS1W_COM = command

***********************************************************************/ #define LCM_Wr1Data(wrdata)

/*********************************************************************** * 名称:LCM_Wr2Data()

* 功能:写数据子程序,所选屏为右半屏(CS2)。 * 入口参数:wrdata

要写入LCM的数据

LCMCS1W_DAT = wrdata

***********************************************************************/ #define LCM_Wr2Data(wrdata)

/*********************************************************************** * 名称:LCM_DispIni()

* 功能:LCM显示初始化。使能显示,设置显示起始行为0并清屏。 * 入口参数:无 * 出口参数:无

***********************************************************************/ void LCM_DispIni(void)

24

LCMCS2W_DAT = wrdata

实验十、综合实验 { uint16 i;

LCM_RST = 0;

// 复位驱动芯片

for(i=0; i<500; i++); LCM_RST = 1;

LCM_Wr1Command(LCM_DISPON);

// 打开显示

LCM_Wr1Command(LCM_STARTROW); // 设置显示起始行为0 LCM_Wr2Command(LCM_DISPON); LCM_Wr2Command(LCM_STARTROW); LCM_DispClr();

LCM_Wr1Command(LCM_ADDRSTRY+0); LCM_Wr1Command(LCM_ADDRSTRX+0); LCM_Wr2Command(LCM_ADDRSTRY+0); LCM_Wr2Command(LCM_ADDRSTRX+0); }

/*********************************************************************** * 名称:LCM_WriteByte()

* 功能:向指定点写数据(一字节)。 * 入口参数:x *

x坐标值(0-127)

// 设置页(行)地址 // 设置列地址,即列

// 清屏

y y坐标值(0-63)

* wrdata 所要写的数据 * 出口参数:无

* 说明:会更新disp_buf相应存储单元

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

/***********说明*************

*对该函数进行修改以适应自己编写的C语言的程序要求,输入变量与之前汇编语言中一样,为实际的 *页号和列号,而不是之前周立功教程中的无偏移地址的具体的行号和列号。 *同时在实验中发现屏幕有闪烁的情况,所以在程序中增加for语句来实现延时。/ void LCM_WriteByte(uint8 x, uint8 y, uint8 wrdata, uint8 screen) { int j;

disp_buf[y][x] = wrdata; if(screen==1)

// 选择液晶控制芯片(即CS1--控制前64个点,CS2--控制后64个

25

实验十、综合实验 点) {

LCM_Wr1Command(x); for (j=0;j<10;j++);

// 设置当前列地址,即x坐标

LCM_Wr1Command(y);

// 设置当前页地址,即y坐标

for (j=0;j<10;j++);

// 短延时

for(j=0; j<5; j++); LCM_Wr1Data(wrdata);

for (j=0;j<10;j++);

} else {

// 调整x变量值

LCM_Wr2Command(x);

for (j=0;j<10;j++);

LCM_Wr2Command(y);

for (j=0;j<10;j++);

for(j=0; j<5; j++); LCM_Wr2Data(wrdata);

for (j=0;j<10;j++);

} }

/*********************************************************************** * 名称:LCM_DispFill() * 功能:向显示屏填充数据

* 入口参数:filldata 要写入LCM的填充数据 * 出口参数:无

* 说明:会更新disp_buf相应存储单元

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

void LCM_DispFill(uint8 filldata) { uint8 x, y;

LCM_Wr1Command(LCM_STARTROW); // 设置显示起始行为0 LCM_Wr2Command(LCM_STARTROW);

26

实验十、综合实验 for(y=0; y<8; y++)

{ LCM_Wr1Command(LCM_ADDRSTRY+y); // 设置页(行)地址 LCM_Wr1Command(LCM_ADDRSTRX); // 设置列地址 LCM_Wr2Command(LCM_ADDRSTRY+y); LCM_Wr2Command(LCM_ADDRSTRX);

for(x=0; x<64; x++) { LCM_Wr1Data(filldata); LCM_Wr2Data(filldata); disp_buf[y][x] = filldata; disp_buf[y][x+64] = filldata; } } }

【LCM_DISP.c】 /*

* 文件名: main.c * 作者: * 功能: */

#include \"CONFIG.H\" #include \"adc.H\" #include \"lcm_drive.H\" #define uint unsigned int #define uchar unsigned char sbit UP = P2^0 ; //增加,波形上移 sbit DOWN = P2^1 ;//减少,波形下移 sbit LENGTH = P2^2 ; //波形横向压缩 sbit LENGTH_= P2^3 ; sbit MULTI = P2^4 ; sbit MULTI_= P2^5 ;

//波形横向拉伸 //幅值变小

//幅值变大

Andy-JING main函数

sbit LENGTH__ = P2^6 ; //波形大幅横向压缩 sbit STOP = P2^7 ;

uint8 col,pag,num,ddata,ad,screen; 幕选择

27

//列号,行号,汉字库中的位置,字节显示数据,偏移量,屏

//暂停

实验十、综合实验

uint8 multi,insert,insert_,level;

uchar code table[]={

//幅值变化量,波形展宽或压缩量,波形上下移动量

0x40,0x20,0x40,0x10,0x42,0x08,0x42,0x06,0x42,0x00,0x42,0x40,0x42,0x80,0xC2,0x7F,// 0x42,0x00,0x42,0x00,0x42,0x00,0x42,0x02,0x42,0x04,0x40,0x08,0x40,0x30,0x00,0x00,//\"示\

0x10,0x04,0x60,0x04,0x02,0x7C,0x0C,0x03,0xC0,0x80,0x00,0x60,0xF8,0x1F,0x88,0x80,// 0x88,0x43,0x88,0x2C,0xFF,0x10,0x88,0x28,0x88,0x46,0xA8,0x81,0x18,0x80,0x00,0x00,//\"波\

0x80,0x08,0x80,0x08,0x9E,0xF4,0x92,0x94,0x92,0x92,0x92,0x92,0x9E,0xF1,0xE0,0x00,// 0x80,0x01,0x9E,0xF2,0xB2,0x92,0xD2,0x94,0x92,0x94,0x9E,0xF8,0x80,0x08,0x00,0x00,//\"器\};

uchar code table1[]={

0x00,0x00,0xF0,0x1F,0x00,0x10,0xFF,0x0F,0x00,0x08,0xF0,0x1F,0x80,0x10,0x90,0x10,// 0x4C,0x15,0x57,0x15,0xA4,0xFF,0x54,0x15,0x4C,0x15,0x84,0x10,0x80,0x10,0x00,0x00,//\"峰\

0x00,0x00,0xF0,0x1F,0x00,0x10,0xFF,0x0F,0x00,0x08,0xF0,0x1F,0x80,0x10,0x90,0x10,// 0x4C,0x15,0x57,0x15,0xA4,0xFF,0x54,0x15,0x4C,0x15,0x84,0x10,0x80,0x10,0x00,0x00,//\"峰\

0x00,0x01,0x80,0x00,0x60,0x00,0xF8,0xFF,0x07,0x40,0x04,0x40,0xE4,0x7F,0xA4,0x4A,// 0xA4,0x4A,0xBF,0x4A,0xA4,0x4A,0xA4,0x4A,0xE4,0x7F,0x04,0x40,0x00,0x40,0x00,0x00,//\"值\};

uchar code number[]={

0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//\"0\

0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//\"1\

0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//\"2\

0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//\"3\

0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//\"4\

0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//\"5\

0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//\"6\

28

实验十、综合实验

0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//\"7\

0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//\"8\

0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//\"9\

0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//\"V\0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };

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

* 名 称:DelayS() * 功 能:长软件延时。 * 入口参数:delayno

延时时间控制

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

void DelayS(uint16 delayno) { }

void display_byte() {

LCM_WriteByte(col, pag, ddata, screen); }

void display_pageclmbyte(unsigned char page, unsigned char clm, unsigned char wdata) {

if(clm<64)

{LCM_WriteByte(0x40+clm,0xb8+page,wdata,1);} else

{clm=clm-64;

LCM_WriteByte(0x40+clm,0xb8+page,wdata,2);

29

//单字节显示

uint16 i;

for(; delayno > 0; delayno --) { }

for(i = 0; i < 1000; i ++);

实验十、综合实验 }

}

//给出行列坐标,显示一个点(每一列在同一页内只能显示一个点) void display_dot(unsigned char hang, unsigned char lie) { }

//给出行起始和终止坐标,列坐标,画竖线

void display_line(unsigned char hang0, unsigned char hang, unsigned char lie) { }

void display_SBQ() {

30

unsigned char page0,page,i,j,wdata=0,wei0,wei; page0=hang0/8; page=hang/8; wei0=hang0%8; wei=hang%8; j=page-page0;

if(page0==page) //同页内 { }

if(page>page0) { }

for(;wei0<=7;wei0++)

{wdata|=(1<//相邻页,不同页

for(;wei0display_pageclmbyte(page,lie,wdata); unsigned char i,wdata,page; i=hang%8; wdata=1<>3;

display_pageclmbyte(page,lie,wdata);

display_pageclmbyte(page0,lie,wdata); wdata=0;

for(i=0;idisplay_pageclmbyte(page,lie,wdata);

实验十、综合实验 uint k,l,r; l=0xb8; }

void display_FFZ() {

uint k,l,r; l=0xb8;

screen=2;

for(k=0;k<3;k++) //显示三个字 { pag=l; {

ddata=table1[2*r+32*k]; }

pag=l+0x01; //显示下半个字

display_byte(); col++; col=0x60; screen=2;

for(k=0;k<3;k++) //显示三个字 { pag=l; { }

ddata=table[2*r+32*k]; }

pag=l+0x01; //显示下半个字 col=0x70;

display_byte(); col++; col=0x70;

for(r=0;r<16;r++) //显示上半个字的16个字节

for(r=0;r<16;r++) //显示下半个字的16个字节 { }

l=l+0x02;

ddata=table[2*r+1+32*k]; display_byte(); col++;

for(r=0;r<16;r++) //显示上半个字的16个字节

31

实验十、综合实验 col=0x60;

for(r=0;r<16;r++) //显示下半个字的16个字节 { ddata=table1[2*r+1+32*k]; display_byte(); col++;

}

l=l+0x02;

}

}

void display_frame() //显示方框

{

screen=1; col=0x40; for(pag=0xb8;pag<0xbf;pag++) { ddata=0xff; display_byte();

}

pag=0xb8;

for(col=0x40;col<=0x7d;col++) { ddata=0x80; display_byte();

}

pag=0xbf;

for(col=0x40;col<=0x7d;col++) { ddata=0x01; display_byte();

}

col=0x7d;

for(pag=0xb9;pag<=0xbe;pag++) {

ddata=0xff; display_byte(); }

}

//显示左边的竖线

//显示左屏幕方框上方实线

//显示左屏幕方框下方实线

//显示右屏幕右侧实线

32

实验十、综合实验 void refresh() {

uchar i,j; for(i=1;i<7;i++) {for(j=1;j<91;j++)

//对于当前点所在行进行清空,刷行

//将示波器方框中内容清空

{display_pageclmbyte(i,j,0x00);} } }

void refresh1(unsigned char lie) {

uchar i;

for(i=1;i<7;i++)

{display_pageclmbyte(i,lie,0x00);} }

void display_fengfengzhi(unsigned char dmax,unsigned char dmin) {

float Vdis,Vref=0.0193;

//单位参考电压值=输入的参考电压值

/256**********************

uchar V1,V2,V3,j; Vdis=Vref*(dmax-dmin); V1=(unsigned char)Vdis; Vdis=10*(Vdis-V1); V2=(unsigned char)Vdis; V3=10*(Vdis-V2); screen=2; pag=0xBE;

for(col=0x5D,j=0;col<=0x64;col++,j++) //显示峰峰值,个位 {

ddata=number[V1*16+j]; display_byte(); }

pag=0xBF;

for(col=0x5D,j=8;col<=0x64;col++,j++) {

ddata=number[V1*16+j]; display_byte(); }

display_dot(62,101);

//显示小数点 33

实验十、综合实验 }

pag=0xbe;

for(col=0x66,j=0;col<=0x6D;col++,j++) //显示峰峰值,十分位 {

ddata=number[V2*16+j]; display_byte(); }

pag=0xBF;

for(col=0x66,j=8;col<=0x6D;col++,j++) {

ddata=number[V2*16+j]; display_byte(); }

pag=0xbe;

for(col=0x6E,j=0;col<=0x76;col++,j++) //显示峰峰值,百分位 {

ddata=number[V3*16+j]; display_byte(); }

pag=0xBF;

for(col=0x6E,j=8;col<=0x76;col++,j++) {

ddata=number[V3*16+j]; display_byte(); }

pag=0xbe;

for(col=0x76,j=0;col<=0x7E;col++,j++) //显示峰峰值,单位 {

ddata=number[160+j]; display_byte(); }

pag=0xBF;

for(col=0x76,j=8;col<=0x7E;col++,j++) {

ddata=number[160+j]; display_byte(); }

void delay_5ms() //adc延时设计,insert决定延时长度,insert初始为15,可以延时3ms,从而控制采样率,实现波形展宽和压缩

34

实验十、综合实验 {

uchar j; uchar k; k=insert_; for(;k>0;k--)

for(j=3*insert;j>0;j--) ; }

void delay_1ms() //adc延时设计,insert决定延时长度,insert初始为15,可以延时3ms,从而控制采样率,实现波形展宽和压缩 {

uchar j;

for(j=insert*2;j>0;j--) ; }

void check() {

if(!UP) {level--;}

//检查UP键是否下推为0,若为0,则使波形向上移动 //检查DOWN键是否下推为0,若为0,则使波形向下移动

//判断波形展宽压缩键是否下推为0,若为0,则使采样频率减小,

if(!DOWN){level++;} if(!LENGTH){insert++;} 横向压缩波形

if(!LENGTH_){insert--;} if(!MULTI) {multi++;} 波形

if(!MULTI_) {multi--;}

//判断波形幅值压缩拉伸键是否下推为0,若为0,则纵向压缩

if(!LENGTH__){insert_++;} if(!STOP) {

while(!STOP) { }

delay_5ms();

} }

void main() {

uchar d,dh,dh0,j,dmax,dmin,V1,V2; uchar dx[60]={0};

35

实验十、综合实验

multi=6; level=55;

//初始设定multi,level,insert,multi是调节波形的显示幅度 //level是调节波形的上下位置

//insert调节采样时间,值越大,采样频率越小,波形显示越窄(要想提高采样率

insert=0;

和速度,减小insert的值)

while(1)

{

check();

for(j=0;j<60;j++) {

dx[j]=adc(); }

for(j=1;j<61;j++) {

refresh1(j); d=dx[j-1];

if(d>dmax) {dmax=d;} if(d//数据处理

//采样数据显示的行数

delay_5ms();

//采样

LCM_DispIni(); LCM_DispClr(); display_SBQ(); display_FFZ();

display_frame(); //显示边框

//LCD初始化 //LCD清屏 //显示汉字

dh=level-d;

// display_dot(dh,j); if(j==1)

//判断是否为第一列,若是,则不用与前一列比较

{display_dot(dh,j); dh0=dh;}

else {

if(dh==dh0) //如果前一列与该列行数相同 {

display_dot(dh,j); }

if(dh>dh0) {

display_line(dh0,dh,j);

36

//如果该列点在前一列之下

实验十、综合实验 dh0=dh; }

if(dh//如果该列点在前一列之上

display_line(dh,dh0,j); dh0=dh;

}

}

//delay_5ms();

}

display_fengfengzhi(dmax,dmin); }

}

37

实验十、综合实验

【实验结果及展示】 1方波

2三角波

3正弦波

4波形幅度压缩

38

实验十、综合实验

5波形横向压缩

6波形上移

7波形下移

39

实验十、综合实验

8 测量输入波形幅度峰峰值

9 可测波形的频率范围(可测波形频率上限)

40

实验十、综合实验

在输入波形频率到达800Hz的时候,可以看到LCD上显示的波形已经开始出现调制现象,说明采样率已经开始低于被测波形的频率的两倍。所以这个建议示波器的最大被测波形频率上限为800Hz。

41

实验十、综合实验

【实验总结】

这是本学期最后一次实验了,也是我编写的最长的一些,调试时间最长的一次了,一开始想用LCD读的功能设计一个游戏,然后自己研究LCD,折腾了很久,最后把游戏的代码页编写完成,但是却发现实验的板子是没有外部存储器的,所以这个读外存的函数不能用,导致这个游戏没有被实现。于是我重新想了一个实验项目,只用LCD写函数,并且联系之前学过的AD原理,研究了很久,但最后还是搞出来了,个人还是比较满意的。这学期确实学到了很多东西,感谢老师对我实验上的帮助。

42

因篇幅问题不能全部显示,请点此查看更多更全内容