您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 基于51单片机数字示波器设计
第1页,共34页基于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;i10;i++){//采集10次,即10bitADC_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)//串口初始化{第2页,共34页SCON=0x50;//串口工作在方式1,异步模式PCON=0x80;//波特率翻倍TMOD=0x20;//定时器1工作在方式2TH1=0xff;//波特率115200bps,单片机时钟晶振为22.1184MHzTL1=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工程,添加一个主函数,就可以演示了。#includemini51b.h//所有与硬件相关的接口函数定义#includeuart.hvoidmain(){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所示。第3页,共34页图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(number10000){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];第4页,共34页}else{SEG_Q=0xbf;//-SEG_B=0xbf;SEG_S=0xbf;SEG_G=0xbf;}}以上演示源程序keil工程请参考附件【串口调试1】这里我再介绍两款串口绘图软件【MyOsc】和【ComCalWave】,可以直接把串口接收到的数据按X-Y轴绘图,显示结果更直观。主程序这样改:#includemini51b.n//所有与硬件相关的接口函数定义#includeuart.hvoidmain(){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串口绘图软件示例第5页,共34页运行【ComCalWave】,选择正确的串口号和波特率,“OpenCOM”,再设置“WaveShow”,看到了什么?图形!在图形窗口尝试用鼠标右键操作,还可选择特定范围显示,如图1-4所示。图1-4串口绘图软件示例2要看到以上漂亮的波形,还有一些硬件连接要做,需要将信号发生器和Mini51板上ADCin接口连接,注意,TLC1549只能进行0到5V之间的信号转换,你还需要调整信号发生器,产生满足条件的信号才行。以上演示源程序keil工程请参考附件【串口调试2】实际在调试程序中,缺少必要硬件设备的,还可以用正弦表代替实际ADC,这里再介绍一款正弦表生成器软件【正弦表发生器】,软件界面如图1-5所示。图1-5正弦表发生器第6页,共34页【量化阶数】就是ADC位数,例如tlc1549是10阶,ADC0809是8阶;【采样点数】就是在一个正弦周期内,均匀分布多少个采样点,例如在128点的lcd上显示2个以上周期的话,采样点数要小于64点,这里选用30点数来举例,源程序如下。#includemini51b.h//所有与硬件相关的接口函数定义#includeuart.hunsignedcharcodedot[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;i128;i++){uart_put_uchar(dot[i%30]);delay_ms(1);//此处延时当于调节了采样率}}}用以上调试软件同样可以看到漂亮的正弦信号图形。以上调试成功后,是不是感觉很棒,如果你是第一次亲自完成ADC将数据采集,再用软件绘图显示还原信号波形图,一定是一件特别令人激动的事情。第7页,共34页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;//超时跳出}第8页,共34页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
本文标题:基于51单片机数字示波器设计
链接地址:https://www.777doc.com/doc-6356867 .html