这是我的启蒙设计
用的语法都比较简单希望能帮到大家
仿真和源代码在最后面
//ad0808(仿真)对应实物为adc0809采样电压数据并转化成十进制在LCD1602上面显示出来精确度为5/255约等于0.02
//1.头文件,宏定义,定义管脚等:
#include <REGX52.H>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define uchar unsigned char
#define uint unsigned int
//1602的使能,读写的三个端口
sbit EN=P3^2;
sbit RW=P3^3;
sbit RS=P3^4;
sbit clk=P2^4; //时钟,adc0809工作时要有时钟
sbit START=P2^5; //产生一个脉冲后adc0808开始工作
sbit ad_busy=P2^6; //转换完成会反转
sbit OE=P2^7; //adc的开关
uint tmp;
uint tmp1;
uint tmp2;
uint tmp3;
//sbit P2_0=P2^0;
//sbit P2_1=P2^1;
//sbit P2_2=P2^2;
//sbit P2_3=P2^3;
uchar code table[]={'0','1','2','3','4','5','6','7','8','9'}; //此条语句为显示字符串时定义的字符串数组
//2.延时子程序:
void delay(uint c) //功能为提供初始化等其他子程序中的延时
{
uint a,b;
for(a=0;a<c;a++)
for(b=0;b<120;b++);
}
//3.LCD1602基本初始化子程序:
void LCD1602()
{
EN=0;
RS=1;
RW=1;
P0=0xff; //这里P0为与LCD D0~D7相连的I/O口
}
//4.读忙子程序:实物连接可以不用屏蔽,但是仿真必须屏蔽
//void read_busy()
//{
// P0=0xff;
// RS= 0;
// RW=1;
// EN=1;
// while(P0&0x80); //P0和10000000相与,D7位若不为0,停在此处
// EN=0; //若为0跳出进入下一步;这条语句的作用就是检测D7位}
//}
//5.写指令写数据子程序:
void write(uchar a,bit b)
{
// read_busy(); //读忙函数仿真要屏蔽
delay(10);
P0=a;
RS=b; //其中a=0,写指令;b=1,写数据;
RW=0;
EN=1;
EN=0;
}
//6.LCD1602初始化子程序:
void init() //完全按照要求初始化流程来,中间省略了一步写指令38H
{
delay(15);
write(0x38,0);
delay(5);
write(0x38,0);
write(0x08,0);
write(0x01,0);
write(0x06,0);
write(0x0c,0);
}
//7.定时器T0外部中断1用于adc0809
void Interrupt() interrupt 1
{
TH0 = (65536 - 50) / 256; //触发中断时重新装填计时
TL0 = (65536 - 50) % 256;
clk = ~clk;
}
//8.显示单个字符子程序:
void display_lcd_byte(uchar y,uchar x,uchar z) //Y=0,1(起始行)X=0~15(起始列)Z=想写字符的ASCII码
{
if(y) //是否显示在第二行(若在第一行Y=0,不进入IF语句,若在第二行,进入IF语句
{
x+=0x40; //第二行起始地址加上列数为字符显示地址
}
x+=0x80; //设置数据指针位置
write(x,0);
write(z,1); //写入数据
}
//9.显示字符串子程序:
void display_lcd_text(uchar y,uchar x,uchar table[]) //Y,X同上字符显示,table[]字符串数组
{
uchar z=0;
uchar t;
t=strlen(table)+x; // 求得字符串长度加上起始列位置
while(x<t) //功能为LCD显示到字符串最后一个字符,防止字符串
{ //没有16个字符,从而不够位产生乱码;
display_lcd_byte(y,x,table[z]); //逐位显示数组内字符
x++;
z++;
}
}
//10.将8位的ADC转换成十进制并逐次显示出来,这里可以使用sprintf函数来转换只要添加相应的头文件(有时间我会去改改),为了更直观的理解采用以下的方法
void mul_adc(uint a,uint b,uint c)
{
#if 1 //将1改成0就可以用下面的方式了
uint i; //0 - 255.例如当1.25V时 x/255=1.25/5 x=63.75
c=c/0.051; //小数点去掉,应为64左右。同理得出输入2V时,输出转
i=c/1000; //换数据为102.out=x*5/255.out=out*1000(保留3位小数).
display_lcd_byte(a,(b),table[i]);
delay(10);
display_lcd_byte(a,(b+1),'.');
delay(10);
i=c/100%10;
display_lcd_byte(a,(b+2),table[i]);
delay(10);
i=c/10%10;
display_lcd_byte(a,(b+3),table[i]);
delay(10);
#else
//sprintf的实现将上面的uint i;到delay(10);都屏障了,以下的四条语句即可实现上述功能并且更加灵活
char n[10]; //定义一个缓存
float i=c/51.0;//将c的值即采样的值转化成float型的电压值即实际电压值
sprintf(n,"%.2f",i);//将电压值转化成字符串的形式
display_lcd_text(a,b,n);//直接在坐标(a,b)位置打印
#endif
}
//11.显示数据的位置
void show ()
{
mul_adc(0,3,tmp);
mul_adc(1,3,tmp1);
mul_adc(0,11,tmp2);
mul_adc(1,11,tmp3);
}
//12.主程序:主程序里除了放入初始化程序外就是加入自己编写的显示子程序
void main()
{
LCD1602();
delay(50);
init();
clk = 0xff; //初始化clk
TMOD = 0x01; //初始化TMOD,定时器0,方式1
EA = 1; //开放所有中断
ET0 = 1; //开放定时器0中断控制位
TR0 = 1; //定时器0开始计时
while(1)
{
P2_0=0; //ADC通道0打开 P2_1,P2_2接地,ADD(ABC)=000;
P2_1=0;
START=0;
START=1; //0 1 0为一个脉冲
START=0; //ADC开始工作
while(ad_busy==1); //ADC转换完成标志
OE=0; //
delay(20); //0->1上升沿开 adc必须有延时否则单片机反应不过来
OE=1; //
tmp=P1;
OE=0; //1->0下降沿关
P2_0=1;//ADC通道1打开ADD(ABC)=001;
P2_1=0;
START=0;
START=1;
START=0;
while(ad_busy==1);
delay(20);
OE=1;
tmp1=P1;
OE=0;
P2_0=0;//ADC通道2打开ADD(ABC)=010;
P2_1=1;
START=0;
START=1;
START=0;
while(ad_busy==1);
delay(20);
OE=1;
tmp2=P1;
OE=0;
P2_0=1; //ADC通道3打开ADD(ABC)=011;
P2_1=1;
START=0;
START=1;
START=0;
while(ad_busy==1);
delay(20);
OE=1;
tmp3=P1;
OE=0;
display_lcd_text(0,0,"U0:"); // 显示字符串
display_lcd_byte(0,7,'V'); // 显示一个字符
display_lcd_text(0,8,"I0:"); // 显示字符串
display_lcd_byte(0,15,'A'); // 显示一个字符
display_lcd_text(1,0,"U1:"); // 显示字符串
display_lcd_byte(1,7,'V'); // 显示一个字符
display_lcd_text(1,8,"I1:"); // 显示字符串
display_lcd_byte(1,15,'A'); // 显示一个字符
show();
}
}
链接:https://pan.baidu.com/s/1e2lt4N2GCB9CCKAIhVUT1Q
提取码:zq4g