打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
51单片机示波器制作(12864显示带字库)
首先说明:我才接触51单片机3个星期(6月8号才高考完),对C语言还很陌生。我就是一个萌新,还希望大佬们多多指导。
12864(带字库st7920驱动)为显示器,XPT2046为AD转换芯片。(不要问我为什么用这个芯片,开发板自带的坑货。我在网上下载的示波器程序大多以ADC0832或ADC0808为AD转换芯片,结果我都用不了,所以才被迫自写程序。)
示波器程序由main.c XPT2046.c XPT2046.h三个子文件构成,main.c是我根据网上的一个12864画图程序改编而成我也加了一些注释,后面两个文件取自开发板自带的例程并进行了修改。所以说这个程序基本上不是我编写的,也有很多问题和不足之处还请指正。
下面是效果图。
首先是方波。
再是正弦波。
由于没有函数发生器,就只能通过手机播放只做好的正弦音频,再检测手机耳机接口信号。
不知道为什么,正弦波有一半不见了,似乎是由于不能检测到负电压还是什么的。。。
下面贴出main.c的代码。
#include <reg52.h>
#include"XPT2046.h"
#define uint unsigned int
#define uchar unsigned char
sbit RS=P2^6; //LCD数据或命令选择端
sbit RW=P2^5; //LCD写入或读出选择端
sbit RST=P1^0; //LCD复位端口
sbit LCDE=P2^7; // LCD使能端
sbit PSB=P3^2;//串行或并行选择端
void delay(uchar i)
{
while(i--);
} //延时函数,i=1时延时约10微秒(12M晶振)
void SPI_Start()
{
CLK = 0;
CS  = 1;
DIN = 1;
CLK = 1;
CS  = 0;
} //ADC芯片(XPT2046)初始化函数
void lcd_busy()
{
RS=0;
RW=1;
P0=0XFF;
LCDE=1;
delay(14);
while((P0&0x80)==0x80);
LCDE=0;
}//LCD12864(st7920驱动)查忙函数
void write_com(uchar com)
{
lcd_busy();RS=0;
RW=0;
LCDE=0;
P0=com;
delay(9);
LCDE=1;
delay(9);
LCDE=0;
}//LCD写指令函数
void write_num(uchar num)
{
lcd_busy();
RS=1;
RW=0;
LCDE=0;
P0=num;
delay(7);
LCDE=1;
delay(9);
LCDE=0;
}//LCD写数据函数
uchar read_data()
{
uchar read;
lcd_busy();
RS=1;
RW=1;
LCDE=0;
delay(7);
LCDE=1;
delay(9);
read=P0;
LCDE=0;
delay(11);;
return read;
} //LCD读数据函数
void clear_lcd()
{
uchar i,j;
write_com(0x34);
for(i=0;i<32;i++)             //因为LCD有纵坐标32格所以写三十二次
{
write_com(0x80+i);         //先写入纵坐标Y的值
write_com(0x80);         //再写入横坐标X的值
for(j=0;j<32;j++)         //横坐标有16位,每位写入两个字节的的数据,也就写入32次
{                         //因为当写入两个字节之后横坐标会自动加1,所以就不用再次写入地址了。
write_num(0x00);
}
}
write_com(0x36);
write_com(0x30);
} //LCD清屏函数
void put_point(uchar x,uchar y)
{
uint bt=0,read=0;
uchar x_adr,y_adr,h_bit,l_bit;
y_adr=0x80+y%32;            //计算Y轴的地址,应为纵坐标有64个,所有对32求余,当Y大于31时,Y的坐标是下半屏的。
if(y>31) //计算X轴的地址当Y大于31时X的地址在下半屏,从0X88开始,小于31时X的地址是在上半屏,从0X80开始
x_adr=0x88+x/16;
else
x_adr=0x80+x/16;
bt=0x8000>>(x%16); //求这个点到底是在哪个点
write_com(0x34);
write_com(0x34);
write_com(y_adr);     //读取数据的时候要先写入所取数据的地址
write_com(x_adr);
read_data();         //读取的第一个字节不要,
read=read_data();     //从第二个字节开始接收。
read<<=8;
read|=read_data();
bt=bt|read;
h_bit=bt>>8;
l_bit=bt;
write_com(y_adr);     //写入点的时候,重新写入地址,因为地址已经改变。
write_com(x_adr);
write_num(h_bit);
write_num(l_bit);
write_com(0x36); //开显示
write_com(0x30);     //转回基本指令集
}//LCD画点函数
/*
液晶初始化
*/
void lcd_init()
{
PSB=1;
RST=1;
write_com(0x30);     //基本指令操作
write_com(0x0c);     //开显示
write_com(0x01);     //清除LCD显示
}
void main()
{
float i;
uchar x,n,y;
lcd_init();
clear_lcd();
while(1)
{
SPI_Start();
write_com(0x34);
write_com(0x34);
write_com(0x80);
write_com(0x88);
for(i=16;i>0;i--) //画出X轴
{
write_num(0xff);
}
for(i=0;i<64;i++) //画出Y轴
{
put_point(0,i);
}
for(i=0;i<128;i++)
{
x=i;//使横坐标自动向前移
n = Read_AD_Data(0xE4);//接收返回的AD值
y=32-(n/10);//确定点的纵坐标(纵坐标是AD值,不是电压。)
put_point(x,y);
delay(100);
}
write_com(0x36);
write_com(0x30);
while(1);
}
}//主函数
复制代码
全部资料下载地址:
 示波器(自制).zip (38.06 KB, 下载次数: 28)
 xpt2046中文.pdf (1.26 MB, 下载次数: 18)
blink 发表于 2017-6-29 20:04
这个是可以测频率的吗
不可以,就只能显示波形。不过我参考别人写的程序后觉得加装LM393再修改一下程序也许就能测频率。我现在没有LM393,也许你可以试一试。
补充一下:这个程序在测量时需要在信号源内加入一定的直流偏置,否则有部分波形无法正常显示。(就像开始测正弦波时只显示了波形的一半。)
这几天我又对程序进行了修改——将AD检测过程与屏幕刷新过程分离,大大提高了检测速度。(此外我将程序修改为5秒自动刷新,以方便观察。)
修改后的main.c如下。
#include
#include"XPT2046.h"
#define uint unsigned int
#define uchar unsigned char
uchar xdata a[128];
sbit RS=P2^6; //这个是LCD的数据命令选择端
sbit RW=P2^5; //这个是LCD的写入或是读出选择端
sbit RST=P1^0; //这个是LCD的复位端口
sbit LCDE=P2^7; // 这个是LCD的使能端
sbit PSB=P3^2;
void delay(uchar i)
{
while(i--);
}
void delayms(uint c)   //误差 0us
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
void lcd_busy()
{
RS=0;
RW=1;
P0=0XFF;
LCDE=1;
delay(14);
while((P0&0x80)==0x80);
LCDE=0;
}
void write_com(uchar com)
{
lcd_busy();RS=0;
RW=0;
LCDE=0;
P0=com;
delay(9);
LCDE=1;
delay(9);
LCDE=0;
}
void write_num(uchar num)
{
lcd_busy();
RS=1;
RW=0;
LCDE=0;
P0=num;
delay(7);
LCDE=1;
delay(9);
LCDE=0;
}
uchar read_data()
{
uchar read;
lcd_busy();
RS=1;
RW=1;
LCDE=0;
delay(7);
LCDE=1;
delay(9);
read=P0;
LCDE=0;
delay(11);;
return read;
}
void clear_lcd()
{
uchar i,j;
write_com(0x34);
for(i=0;i<32;i++)             //因为LCD有纵坐标32格所以写三十二次
{
write_com(0x80+i);         //先写入纵坐标Y的值
write_com(0x80);         //再写入横坐标X的值
for(j=0;j<32;j++)         //横坐标有16位,每位写入两个字节的的数据,也就写入32次
{                         //因为当写入两个字节之后横坐标会自动加1,所以就不用再次写入地址了。
write_num(0x00);
}
}
write_com(0x36);
write_com(0x30);
}
void put_point(uchar x,uchar y)
{
uint bt=0,read=0;
uchar x_adr,y_adr,h_bit,l_bit;
y_adr=0x80+y2;            //计算Y轴的地址,应为纵坐标有64个,所有对32求余,当Y大于31时,Y的坐标是下半屏的。
if(y>31) //计算X轴的地址当Y大于31时X的地址在下半屏,从0X88开始,小于31时X的地址是在上半屏,从0X80开始
x_adr=0x88+x/16;
else
x_adr=0x80+x/16;
bt=0x8000>>(x); //求这个点到底是在哪个点
write_com(0x34);
write_com(0x34);
write_com(y_adr);     //读取数据的时候要先写入所取数据的地址
write_com(x_adr);
read_data();         //读取的第一个字节不要,
read=read_data();     //从第二个字节开始接收。
read<<=8;
read|=read_data();
bt=bt|read;
h_bit=bt>>8;
l_bit=bt;
write_com(y_adr);     //写入点的时候,重新写入地址,因为地址已经改变。
write_com(x_adr);
write_num(h_bit);
write_num(l_bit);
write_com(0x36); //开显示
write_com(0x30);     //转回基本指令集
}
/*
液晶初始化
*/
void lcd_init()
{
PSB=1;
RST=1;
write_com(0x30);     //基本指令操作
write_com(0x0c);     //开显示
write_com(0x01);     //清除LCD显示
}
void main()
{
while(1)
{
uchar x,i,y;
lcd_init();
clear_lcd();
write_com(0x34);
write_com(0x34);
write_com(0x80);
write_com(0x88);
for(i=16;i>0;i--) //画出X轴
{
write_num(0xff);
}
for(i=0;i<64;i++) //画出Y轴
{
put_point(0,i);
}
for(i=0;i<128;i++)
{
a[i] = Read_AD_Data(0xE4);
}
for(i=0;i<128;i++)
{
x=i;
y=32-(a[i]/10);
put_point(x,y);
}
write_com(0x36);
write_com(0x30);
delayms(5000);
}
}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
1602精简的四线控制方法,值得一看
51单片机液晶显示(含lcd12864和lcd1602)时钟_liutao2588的空间_...
LCD1602液晶显示带汉字的万年历程序(51单片机)
求指导 51单片机控制 57步进电机|我爱单片机
源程序C代码:篮球比赛应用系统
1602显示程序
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服