数字示波器完整设计过程.docx

上传人:b****4 文档编号:5891232 上传时间:2023-05-09 格式:DOCX 页数:51 大小:381.70KB
下载 相关 举报
数字示波器完整设计过程.docx_第1页
第1页 / 共51页
数字示波器完整设计过程.docx_第2页
第2页 / 共51页
数字示波器完整设计过程.docx_第3页
第3页 / 共51页
数字示波器完整设计过程.docx_第4页
第4页 / 共51页
数字示波器完整设计过程.docx_第5页
第5页 / 共51页
数字示波器完整设计过程.docx_第6页
第6页 / 共51页
数字示波器完整设计过程.docx_第7页
第7页 / 共51页
数字示波器完整设计过程.docx_第8页
第8页 / 共51页
数字示波器完整设计过程.docx_第9页
第9页 / 共51页
数字示波器完整设计过程.docx_第10页
第10页 / 共51页
数字示波器完整设计过程.docx_第11页
第11页 / 共51页
数字示波器完整设计过程.docx_第12页
第12页 / 共51页
数字示波器完整设计过程.docx_第13页
第13页 / 共51页
数字示波器完整设计过程.docx_第14页
第14页 / 共51页
数字示波器完整设计过程.docx_第15页
第15页 / 共51页
数字示波器完整设计过程.docx_第16页
第16页 / 共51页
数字示波器完整设计过程.docx_第17页
第17页 / 共51页
数字示波器完整设计过程.docx_第18页
第18页 / 共51页
数字示波器完整设计过程.docx_第19页
第19页 / 共51页
数字示波器完整设计过程.docx_第20页
第20页 / 共51页
亲,该文档总共51页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

数字示波器完整设计过程.docx

《数字示波器完整设计过程.docx》由会员分享,可在线阅读,更多相关《数字示波器完整设计过程.docx(51页珍藏版)》请在冰点文库上搜索。

数字示波器完整设计过程.docx

数字示波器完整设计过程

基于Mini51板的数字示波器设计

基于Mini51板硬件资源,构思数字示波器的方案已经思考很久了,总是没有集中的时间,一个稍微复杂的设计完成创作需要集中的时间才能完成,这次利用学期结束的一段集中时间,完成了基于LCD12864显示的数字示波器程序设计,现在将文档写出来供大家交流学习用。

在此声明,这个教程是写给初学者看的,我会从简单到复杂一步一步详细介绍设计过程,甚至是调试的过程,还包括一些经验总结,特别是提供了完整的keil工程附件。

希望读者立足示波器项目,学到更多关于软硬件开发的一些经验技巧。

1简易数字示波器原理

数字示波器基本原理可以简单理解为:

数据采集+图形显示,该过程循环进行,如图1-1所示。

首先是数据采集,这一版我们直接用Mini51板上的ADC“TLC1549”。

(如果你没有ADC,也可能没有信号发生器,后面会介绍一种正弦表调试方法。

TLC1549驱动函数unsignedintread_adc(void)。

图1-1简易数字示波器流程图

unsignedintread_adc(void)

{

unsignedchari;

unsignedinttemp=0;

ADC_CS=0;//开启控制电路,使能DA和CKIO引脚

for(i=0;i<10;i++){//采集10次,即10bit

ADC_CK=0;

temp<<=1;

if(ADC_DA)temp++;

ADC_CK=1;

}

ADC_CS=1;

return(temp);

}

注:

带背景色的源码都是直接从演示程序中拷贝的。

以上是是驱动TLC1549的函数,如果你还想彻底弄清TLC1549的各种参数,请参考数据手册TLC1549.pdf,使用该函数需要注意的是,两次调用该函数之间的间隔要超过21us,AD转换是要一段时间的,在高速系统中时间控制尤其关键。

Mini51板单片机在22.1184M晶振时钟频率下运行,连续两次AD采集数据并将数据写入外部扩展RAM变量缓冲区,之间的时间间隔实测略小于21us的,需要适当延时。

这在高速档数据采集时增加了一定延时等待就是这个原因。

图形显示有很多种,LCD显示稍难,ADC得到的结果如何在LCD上描点,这确实是一个难点,涉及LCD驱动问题,需要花费很大篇幅才能完成。

最初调试我们可以选用串口来做,借助他人现成的工具软件。

下面介绍基于串口和上位机工具软件的波形显示程序设计。

串口初始化函数rs232_port_init(void)。

voidrs232_port_init(void)//串口初始化

{

SCON=0x50;//串口工作在方式1,异步模式

PCON=0x80;//波特率翻倍

TMOD=0x20;//定时器1工作在方式2

TH1=0xff;//波特率115200bps,单片机时钟晶振为22.1184MHz

TL1=0xff;

TR1=1;//开启时钟

RI=0;//清空接受标志位

TI=0;//清空发送标志位

}

往串口写1字节函数voiduart_put_uchar(unsignedcharc)。

voiduart_put_uchar(unsignedcharc)//往串口写1字节无符号数据

{

SBUF=c;

while(!

TI);

TI=0;

}

从串口读1字节函数unsignedcharuart_get_uchar()。

unsignedcharuart_get_uchar()//从串口读1字节无符号数据

{

while(!

RI);

RI=0;

returnSBUF;

}

以上这几个函数是学单片机的人一定要掌握的,能够随手拿来就用,通过串口调试程序,很方便。

有了以上4个函数,再建一个keil工程,添加一个主函数,就可以演示了。

#include"mini51b.h"//所有与硬件相关的接口函数定义

#include"uart.h"

voidmain()

{

rs232_port_init();//串口初始化

read_adc();//首个ADC数据丢失

while

(1){

if(uart_get_uchar()==0x55)uart_put_uchar(read_adc()/4);//10bit/4变8bit

}

}

在主程序循环中,接收到上位机下发的数据0x55后,读取ADC数据并发送一次,在串口调试助手(例如SSCOM)里,设置相关端口和波特率后,发送0x55,注意HEX(十六进制格式)选项,就可以看到ADC的结果,如图1-2所示。

图1-2串口调试ADC

调试ADC还有一种更方便的方法,结果直接在Mini51板上的数码管上显示出来,不管你对数码管硬件熟悉不熟悉,只要使用模板程序提供的数码管驱动函数led_disp(uintnumber)即可。

Mini51板数码管驱动函数led_disp(unsignedint)。

voidled_disp(uintnumber)//Mini51板数码管显示函数,传入整数0~9999

{

unsignedcharcodetab1[20]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,};

unsignedchartemp,flag=0;

if(number<10000){

temp=number/1000%10;//千位数码管

if(temp){

SEG_Q=tab1[temp];

flag=1;

}

else{

SEG_Q=0xff;//数码管熄灭

flag=0;

}

temp=number/100%10;//百位数码管

if(flag|temp){

SEG_B=tab1[temp];

flag=1;

}

else{

SEG_B=0xff;//数码管熄灭

flag=0;

}

temp=number/10%10;//十位数码管

if(flag|temp)SEG_S=tab1[temp];

elseSEG_S=0xff;//数码管熄灭

temp=number%10;//个位数码管

SEG_G=tab1[temp];

}

else{

SEG_Q=0xbf;//"-"

SEG_B=0xbf;

SEG_S=0xbf;

SEG_G=0xbf;

}

}

以上演示源程序keil工程请参考附件【串口调试1】

这里我再介绍两款串口绘图软件【MyOsc】和【ComCalWave】,可以直接把串口接收到的数据按X-Y轴绘图,显示结果更直观。

主程序这样改:

#include"mini51b.n"//所有与硬件相关的接口函数定义

#include"uart.h"

voidmain()

{

rs232_port_init();

read_adc();

delay_ms

(1);

while

(1){

uart_put_uchar(read_adc()/4);

//seg7_disp(read_adc());

delay_ms

(1);//这里的延时起到调节采样率的作用

}

}

运行【MyOsc】,设置串口和波特率后“OPEN”,适当调节输入信号频率后可以看到如图1-3所示的图案。

图1-3串口绘图软件示例

运行【ComCalWave】,选择正确的串口号和波特率,“OpenCOM”,再设置“WaveShow”,看到了什么?

图形!

在图形窗口尝试用鼠标右键操作,还可选择特定范围显示,如图1-4所示。

图1-4串口绘图软件示例2

要看到以上漂亮的波形,还有一些硬件连接要做,需要将信号发生器和Mini51板上ADCin接口连接,注意,TLC1549只能进行0到5V之间的信号转换,你还需要调整信号发生器,产生满足条件的信号才行。

以上演示源程序keil工程请参考附件【串口调试2】

实际在调试程序中,缺少必要硬件设备的,还可以用正弦表代替实际ADC,这里再介绍一款正弦表生成器软件【正弦表发生器】,软件界面如图1-5所示。

图1-5正弦表发生器

【量化阶数】就是ADC位数,例如tlc1549是10阶,ADC0809是8阶;

【采样点数】就是在一个正弦周期内,均匀分布多少个采样点,例如在128点的lcd上显示2个以上周期的话,采样点数要小于64点,这里选用30点数来举例,源程序如下。

#include"mini51b.h"//所有与硬件相关的接口函数定义

#include"uart.h"

unsignedcharcodedot[30]={//正弦表,注意数据类型是“code”,存放在rom当中

0x80,0x9a,0xb4,0xcb,0xdf,0xee,0xf9,0xff,0xff,0xf9,

0xee,0xdf,0xcb,0xb4,0x9a,0x80,0x65,0x4c,0x34,0x21,

0x11,0x6,0x0,0x0,0x6,0x10,0x20,0x34,0x4b,0x65,

};

voidmain()

{

unsignedchari;

rs232_port_init();

delay_ms

(1);

while

(1){

for(i=0;i<128;i++){

uart_put_uchar(dot[i%30]);

delay_ms

(1);//此处延时当于调节了采样率

}

}

}

用以上调试软件同样可以看到漂亮的正弦信号图形。

以上调试成功后,是不是感觉很棒,如果你是第一次亲自完成ADC将数据采集,再用软件绘图显示还原信号波形图,一定是一件特别令人激动的事情。

2图形液晶LCD12864绘图驱动设计基础

下面我们学习如何在LCD12864上显示同样的正弦波形。

关于LCD的硬件接口电路,在前面的教程中有详细介绍,涉及单片机总线知识和CPLD内部电路,需要专门学习,这里我们借助现成的驱动函数,重点讲解LCD绘图程序设计。

LCD12864的电路接口在【mini51b.h】头文件中定义。

#defineLCD_LCWXBYTE[0xf4ea]//左屏命令写入

#defineLCD_LDWXBYTE[0xf5ea]//左屏数据写入

#defineLCD_LCRXBYTE[0xf6ea]//左屏命令读出

#defineLCD_LDRXBYTE[0xf7ea]//左屏数据读出

#defineLCD_RCWXBYTE[0xf8ea]//右屏命令写入

#defineLCD_RDWXBYTE[0xf9ea]//右屏数据写入

#defineLCD_RCRXBYTE[0xfaea]//右屏命令读出

#defineLCD_RDRXBYTE[0xfbea]//右屏数据读出

后面所有对LCD的编程操作都是基于以上接口定义(总线编址)进行的读写操作。

首先来看LCD点阵结构图,这里以不带字库的LCD12864来讲解,如图2-1所示。

图2-1LCD点阵分布结构图

此LCD屏由水平128列,垂直64行组成。

水平128列分左右各64列两个半屏构成。

垂直64行又分8页,每页8行(1列8点刚好1字节)。

程序每次对LCD的绘图操作就是以最小单位1字节进行操作的。

理解这点至关重要。

也就是每次只能针对8点进行操作,而不是1点进行操作。

左右屏由单独地址线控制(前面的接口定义就是分左右屏定义的)。

实际打点只需往指定“位置”写入数据,“1”亮,“0”暗。

LCD驱动函数:

忙检测函数voidloop_lcd12864_is_busy(unsignedcharright)。

voidloop_lcd12864_is_busy(unsignedcharright)

{

unsignedchartmp,counter=0;

do{

if(right)tmp=LCD_RCR;

elsetmp=LCD_LCR;

if(counter++>50)break;//超时跳出

}

while((tmp|0x7f)==0xff);//bit7为1则表示LCD内部执行命令,处于“忙”状态

}

对LCD进行读写操作时,需要进行“忙”检测,LCD内部也是由控制器来完成一些列LCD屏显示操作的,执行各种操作都是需要一定的时间的,也就是说不是任何时候外部控制器都可以操作LCD的,只有LCD为空闲状态时才可以操作,忙检测就是循环读取LCD状态标志位,判断是否空闲,关于命令的细节请参考数据手册。

命令写入函数voidlcd_cmd_wr(unsignedcharcmd,right)。

voidlcd_cmd_wr(unsignedcharcmd,right)

{

loop_lcd12864_is_busy(right);//忙检测

if(right)LCD_RCW=cmd;//右屏命令写入

elseLCD_LCW=cmd;//左屏命令写入

}

数据写入函数voidlcd_dat_wr(unsignedchardata,right)。

voidlcd_dat_wr(unsignedchardata,right)

{

loop_lcd12864_is_busy(right);

if(right)LCD_RDW=data;

elseLCD_LDW=data;

}

lcd_cmd_wr()和lcd_dat_wr()两个函数分别是给LCD写命令和写数据函数,通过写命令函数设定地址。

每个函数都分左右屏,用0,非0选择。

读数据函数unsignedcharlcd_dat_rd(unsignedcharright)。

unsignedcharlcd_dat_rd(unsignedcharright)

{

loop_lcd12864_is_busy(right);

if(right)return(LCD_RDR);

elseretuen(LCD_LDR);

}

该函数完成对LCD已显示的数据读出,首次操作需要读2次数据才有效。

LCD清屏函数voidlcd12864_clr(void)。

voidlcd12864_clr(void)

{

unsignedchari,j;

for(i=0;i<8;i++){//从0到7共8页

lcd_cmd_wr(ORGX,0);//分页设定左屏0点地址

lcd_cmd_wr(ORGY+i,0);

lcd_cmd_wr(ORGX,1);//分页设定右屏0点地址

lcd_cmd_wr(ORGY+i,1);

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

lcd_data_wr(0,0);

lcd_data_wr(0,1);

}

}

}

该函数对LCD所有点阵写0,完成一次清屏操作。

这里的ORGY,PRGX是设定光标的命令,光标指向(0,0)字节,是一个固定值。

实际在执行数据写入的时,x坐标范围从0到63,在连续写入过程中能够实现自动加1,y轴页地址范围从0到7,需要逐页设定。

LCD初始化函数voidlcd12864_init(void)。

voidlcd12864_init(void)

{

lcd_cmd_wr(DISPON,0);//显示开启

lcd_cmd_wr(DISPFIRST,0);//设定显示首行地址

//修改首行地址可以实现屏幕滚动显示效果

lcd_cmd_wr(ORGY,0);//设定初始光标

lcd_cmd_wr(ORGX,0);

lcd_cmd_wr(DISPON,1);//初始另外一半

lcd_cmd_wr(DISPFIRST,1);

lcd_cmd_wr(ORGY,1);

lcd_cmd_wr(ORG,1);

lcd12864_clr();//执行清屏,非必须操作

}

该函数用来初始化LCD,设置显示模式,光标位置等,在对LCD绘图时,最多的命令就是设定当前光标位置,通过光标位置来指定将要操作的LCD显示点。

在对LCD编程操作以前,一定要执行此函数对LCD进行初始化操作。

例如给左半屏(0,0)首字节写入数据0x55,应该执行以下程序。

lcd12864_init();//LCD初始化

lcd_cmd_wr(ORGX,0);//设定水平轴X地址

lcd_cmd_wr(ORGY,0);//设定垂直轴Y地址

lcd_dat_wr(0x55,0);//写入数据,从下至上为01010101

lcd_dat_wr(0xaa,0);//写入数据,从下至上为10101010,连续写入,X地址自动加1

这样在如图0字节和1字节就将交替有4点亮,4点暗,构成如图2-2所示图案。

图2-2LCD显示示例图2-3LCD显示示例

又如执行程序:

lcd12864_init();

lcd_cmd_wr(ORGX,1);

lcd_cmd_wr(ORGY,1);

lcd_dat_wr(0x55,1);

显示效果如图2-3所示。

如果执行以下程序:

lcd12864_init();

lcd_cmd_wr(ORGX+1,0);

lcd_cmd_wr(ORGY+1,0);

lcd_data_wr(0x55,0);

显示效果如图2-4所示。

图2-4LCD显示示例图2-5LCD显示示例

从驱动函数可见,一次对LCD写入数据是以字节为单位,通过写命令确定坐标,Y坐标从0页到7页,X坐标从0列到63列,分左右屏,左上角为坐标(0,0)点,这和我们习惯的左下角为(0,0)坐标轴是不一样的。

因为每次操作LCD是一个字节为单位,对应8点,如果我们希望以任意点为坐标显示,还得另外寻找别的办法编程实现真正“点”显示。

如图2-5所示,在屏幕上指定位置画点,水平轴就是x,与lcd坐标一致,y轴需要将点坐标变成字节为单位的坐标,我们先按习惯将y轴64点从下至上编号0到63,其中0到7点为字节0,8到15点为字节1,依此类推对应8字节。

第一点Y轴为30,应该是哪字节哪bit呢?

30/8取整为3,前3字节(0,1,2三字节)对应0到23点跳过,实际30点应该在第4字节(24到31)的bit6上,这就要用算法计算出字节数和bit位,前面30/8=3,这里的3似乎就是要找的字节数,那么30%8(30除8取余数)呢,余数是6,不是刚好是bit位吗?

所以可以这样将y值映射到某字节的某点上,如果Y轴64点对应8字节变量Da[n],n从0到7,则:

da[y/8]=1<<(y%8);或

da[y>>3]=0x01<<(y&0x07);后一种算法更优。

通过总结规律,用以上算法可以将任意0到63之间的数据作为坐标描点到对应的8个字节中,然后将8个字节全部写入LCD,则通过刚才算法就会有一点与所给坐标一致。

第一点:

da[30/8]=1<<30%8;即da[3]=0x40;

第二点:

da[10/8]=1<<10%8;即da[1]=0x04;

下面我们来设计的函数。

总结以上算法,编写出在LCD任何坐标位置上描点绘图函数voidlcd_disp(unsignedcharx,y)。

列更新子函数lcd_row_wr(unsignedcharx,unsignedchar*da)。

voidlcd_row_wr(unsignedcharx,unsignedchar*da)//x是列坐标,*da是8字节列数据

{

unsignedcharj;

if(x<64){//根据列坐标选择左右半屏

for(j=0;j<8;j++){//写左半屏

lcd_cmd_wr(ORGY+j,0);

lcd_cmd_wr(ORGX+x,0);

lcd_data_wr(da[j],0);

}

}

else{

x-=64;//坐标调整

for(j=0;j<8;j++){//写右半屏

lcd_cmd_wr(ORGY+j,1);

lcd_cmd_wr(ORGX+x,1);

lcd_data_wr(da[j],1);

}

}

}

voidlcd_disp(unsignedcharx,y)//x水平坐标,y垂直坐标

{

unsignedchardat[8];

unsignedcharj;

for(j=0;j<8;j++)dat[j]=0x0;

dat[y/8]|=0x01<<(y&0x07);

lcd_row_wr(x,dat);

}

以上函数能够在指定坐标(x,y)上描点,例如执行程序:

lcd_init();

lcd_disp(0,0);

lcd_disp(1,1);

lcd_disp(2,2);

lcd_disp(3,3);

lcd_disp(4,4);

lcd_disp(5,5);

lcd_disp(6,6);

lcd_disp(7,7);

lcd_disp(70,10);

lcd_disp(71,20);

lcd_disp(72,30);

lcd_disp(73,40);

效果如图2-6所示。

图2-6LCD显示示例图2-7LCD显示示例

以上演示源程序keil工程请参考附件【LCD驱动exa1】。

如图2-6所示效果,Y轴“反了”,是的,这很好办,在lcd_disp()函数中增加一句:

y=63-y;就可以实现。

在下面的例子中将做到与我们习惯的坐标一致。

voidmain()

{

unsignedchari;

lcd_init();

for(i=0;i<128;i++){

lcd_disp(i,i/2);

}

while

(1);

}

效果如图2-7所示。

以上演示源程序keil工程请参考附件【LCD驱动exa2】。

如果将正弦表的数据送LCD显示,程序:

voidmain()

{

unsignedchari;

lcd_init();

for(i=0;i<128;i++){lcd_disp(i,dot[i%30]/4);//除以4是变8bit为6bit(0-63)进行LCD映射

}

while

(1);

}

效果如图2-8所示。

图2-8LCD显示示例图2-9矢量绘图示例

以上演示源程序keil工程请参考附件【LCD驱动exa3】。

以上是逐点绘图,其实矢量绘图效果会更好,矢量绘图

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2