这个小项目自己做了5天,小有成就感。。。感谢前辈们多多提意见。。
12864液晶、DS12C887时钟芯片、DS18B20温度传感器。。。
#define uchar unsigned char
#define uint unsigned int
uint temp;
float f_temp;
sbit Ds=P2^2;
sbit Dula=P2^6;
sbit Wela=P2^7;
sbit LcdCS=P3^5; //寄存器选择输入 通过rs确定是写数据还是写命令
sbit LcdSID=P3^6; //液晶读/写控制 因为不从液晶读取任何数据,所以rw一直为0
sbit LcdSCLK=P3^4; //液晶使能控制 给en一个高脉冲将数据送入液晶控制器
sbit LcdPSB=P3^7; //串并方式控制
sbit DSCS=P1^4; //片选信号,低电平有效
sbit DSAS=P1^5; //地址选通输入端 AS的上升沿将AD0~AD7上出现的地址信息锁存到DS12C887上,下降沿清除地址信息
sbit DSRW=P1^6; //
sbit DSDS=P1^7; //
uchar code table1[]={" CHPAVC 天若海愚"};
uchar code table3[]={"星期一"};
uchar code table4[]={"星期二"};
uchar code table5[]={"星期三"};
uchar code table6[]={"星期四"};
uchar code table7[]={"星期五"};
uchar code table8[]={"星期六"};
uchar code table9[]={"星期日"};
uchar code table10[]={"°C"};
uchar buff[4];
char year,month,day,week,miao,fen,shi;
uchar nyrsfm[17]; //Write_nyrsfm函数中,方法二nyrsfm只需申明成nyrsfm[16]
/***************************************************************
文件名称: wannianli
作者 : 天若海愚
版本号 : V1.0
说明 :
创建时间: 2013年9月17日13:30:38
修改记录: 无
备注 : 在12864液晶屏上显示从DS12C887采集到的年、月、日、时、分数据,并且利用DS18B20采集温度显示在12864上
***************************************************************/
#include
#include
#include
#include
/***********************************
函数名称: Delay()
函数功能: 延时
入口参数: z
备注 :
***********************************/
void Delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
/**********************************
函数名称: Ds_reset()
函数功能: DS18B20复位,初始化函数
入口参数: 无
备注 :
**********************************/
void Ds_reset()
{
uint i;
Ds=1; //书P348,时序图,先将数据线置高电平1
_nop_(); //延时,尽可能短一点
Ds=0;
i=103;
while(i>0)
i--; //当总线停留在低电平超过480us,总线上所以器件都将被复位,这里
//延时约680us总线停留在低电平超过480μs,总线上的所有器件都将被复位
_nop_(); //延时,尽可能短一点
Ds=1;
i=5;
while(i>0)
i--; //释放总线后,如果初始化成功则在15~60us内产生一个由DDS18B20返回的低电平0,据
//该状态可以确定它的存在,但是不能无限制地等
}
/**********************************
函数名称: Ds_read_bit()
函数功能: 读一位数据函数
入口参数: 无
备注 :
**********************************/
bit Ds_read_bit()
{
uint i;
bit dat;
Ds=0; //单片机(微处理器)将总线拉低
_nop_(); //读时隙起始于微处理器将总线拉低至少1us
Ds=1; //拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据
_nop_();
_nop_(); //小延时一下,读取18b20上的数据 ,因为从ds18b20上输出的数据,在读"时间隙"下降沿出现15us内有效
dat=Ds; //主机读从机18b20输出的数据,这些数据在读时隙的下降沿出现15us内有效
i=10;
while(i>0)
i--; //所有读"时间隙"必须60~120us,这里77us
return(dat);
}
/**********************************
函数名称: Ds_read_byte()
函数功能: 读一个字节数据函数
入口参数: 无
备注 :
**********************************/
uchar Ds_read_byte()
{
uchar i,j,dat;
dat=0; //初值不能忘
for(i=1;i<=8;i++) //此句曾写成for(i=0;i<=8;i++),导致程序显示结果出错,细节。。。
{
j=Ds_read_bit();
dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在dat里
}
return(dat);
}
/**********************************
函数名称: Ds_write_byte()
函数功能: 向DS18B20写一个字节函数
入口参数:
备注 :
**********************************/
void Ds_write_byte(uchar dat)
{
uchar i;
uint j;
bit testb;
for(i=1;i<=8;i++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb)
{
Ds=0;
_nop_();
_nop_(); //看时序图,至少延时1us,才产生写"时间隙"
Ds=1; //写时间隙开始后的15μs内允许数据线拉到高电平
j=8;
while(j>0)
j--; //所有写时间隙必须最少持续60us
}
else
{
Ds=0;
j=8;
while(j>0)
j--; //主机要生成一个写0 时间隙,必须把数据线拉到低电平并保持至少60μs,
Ds=1;
_nop_();
_nop_();
}
}
}
/**********************************
函数名称: Ds_change()
函数功能: 18b20开始获取温度并转换
入口参数:
备注 :
**********************************/
void Ds_change()
{
Ds_reset(); //初始化
Delay(1);
Ds_write_byte(0xcc); //跳过ROM.直接向18b20发温度 转换指令,适用于一个从机工作
Ds_write_byte(0x44); //写温度转换指令
}
/**********************************
函数名称: Get_temp()
函数功能: 读取寄存器中存储的温度数
入口参数: 无
备注 :
**********************************/
uint Get_temp()
{
uchar a,b;
Ds_reset();
Delay(1);
Ds_write_byte(0xcc); //写跳过读ROM指令
Ds_write_byte(0xbe); //读暂存器。读内部RAM中9字节的温度数据
a=Ds_read_byte(); //读低8位
b=Ds_read_byte(); //读高8位
temp=b;
temp<<=8; //两个字节组合为一个字
temp=temp|a;
f_temp=temp*0.0625; //得到真实十进制温度值,因为DS18B20可以精确到0.0625 度,所以读回数据的最低位代表的是0.0625 度。
temp=f_temp*10+0.5; //乘以10不是小数点后面只取1位,加0.5是四舍五入
f_temp=f_temp+0.05;
return temp; //temp是整型
}
/**********************************
函数名称: init_com()
函数功能: 串口初始化
入口参数: 无
备注 :
**********************************/
void init_com()
{
TMOD=0x20; //定时器1,方式2
PCON=0x00;
SCON=0x50; //等价于REN=1;SM0=0;SM1=1;
TH1=0xFD;
TL1=0xFD; //设置波特率 9600
TR1=1; //启动定时器1
}
/**********************************
函数名称: comm()
函数功能: 串口发送数据
入口参数:
备注 :
**********************************/
void comm(uchar *parr)
{
do
{
SBUF=*parr++;
while(!TI); //发送完毕,TI由硬件置1
TI=0;
}while(*parr); //保持循环直到字符为'\0'
}
/***********************************
函数名称: Send_byte()
函数功能: 发送一个字节
入口参数: bbyte
备注 :
***********************************/
void Send_byte(uchar bbyte)
{
uchar i;
for(i=0;i<8;i++)
{
LcdSID=bbyte&0x80; //取出最高位
LcdSCLK=1;
LcdSCLK=0; //sclk由低电平变为高电平的瞬间,液晶控制器将sid上数据读入或输出
bbyte<<=1; //左移1位
}
}
/***********************************
函数名称: Write_char()
函数功能: 写数据或写命令
入口参数: start,ddata
备注 :
***********************************/
void Write_char(bit start,uchar ddata)
{
uchar start_data,Hdata,Ldata;
if(start==0)
{
start_data=0xf8; //写指令
}
else
{
start_data=0xfa; //写数据
}
Hdata=ddata&0xf0; //取高4位
Ldata=(ddata<<4)&0xf0; //取低4位
Send_byte(start_data); //发送起始信号
Delay(5); //延时是必须的
Send_byte(Hdata); //发送高4位
Delay(1); //延时是必须的
Send_byte(Ldata);
Delay(1);
}
/***********************************
函数名称: Lcd_pos()
函数功能: 设置显示位置
入口参数: X,Y
备注 :
***********************************/
void Lcd_pos(uchar X,uchar Y)
{
uchar pos;
if(X==0)
{
X=0x80;
}
else if(X==1)
{
X=0x90;
}
else if(X==2)
{
X=0x88;
}
else if(X==3)
{
X=0x98;
}
pos=X+Y;
Write_char(0,pos);
}
/***********************************
函数名称: Lcd_init()
函数功能: 液晶初始化
入口参数: 无
备注 :
***********************************/
void Lcd_init()
{
Delay(5); //启动等待,等LCD进入工作状态
LcdPSB=0; //串口驱动
Write_char(0,0x30); //基本指令操作
Delay(5);
Write_char(0,0x0c); //显示开,关光标,反白关
Delay(5);
Write_char(0,0x01); //清屏,将DDRAM的地址计数器归零
Delay(5);
}
/**********************************
函数名称: Display_temp()
函数功能: 在12864上显示温度
入口参数:
备注 : 小数点后保留一位
**********************************/
void Display_temp()
{
uchar i;
Lcd_pos(2,4);
Write_char(1,buff[0]);
Write_char(1,buff[1]);
Write_char(1,buff[2]);
Write_char(1,buff[3]);
for(i=0;i<3;i++)
{
Write_char(1,table10[i]); //显示符号°C
Delay(5);
}
}
/*********以下是操作DS12C87时钟芯片***********/
/***********************************
函数名称: Write_ds()
函数功能: 写12C8887函数
入口参数: add,date
备注 :
***********************************/
void Write_ds(uchar add,uchar date)
{
DSCS=0;
DSAS=1;
DSDS=1;
DSRW=1;
P0=add;
DSAS=0; //dsas的下降沿将AD0~~AD7上的地址信息锁存到DS12C887上
DSRW=0;
P0=date;
DSAS=1;
DSRW=1; //INTER模式,dsrw的上升沿锁存数据
DSCS=1;
}
/***********************************
函数名称: Read_ds()
函数功能: 读12C8887函数
入口参数: add
备注 :
***********************************/
uchar Read_ds(uchar add)
{
uchar ds_date;
DSAS=1;
DSDS=1;
DSRW=1;
DSCS=0;
P0=add; //先写地址
DSAS=0;
DSDS=0;
P0=0xff;
ds_date=P0; //再读数据
DSDS=1;
DSCS=1;
DSAS=1;
return ds_date;
}
/**********************************
函数名称: Write_nyrsfm()
函数功能: 将年、月、日、时、分显示在12864液晶上
入口参数:
备注 : 不能通过下面的/* 中的函数来实现
**********************************/
void Write_nyrsfm(char year,char month,char day,char shi,char fen)
{
//方法一:
/*uchar i;
Lcd_pos(1,0);
nyrsfm[0]=0x32;
nyrsfm[1]=0x30;
nyrsfm[2]=year/10+0x30;
nyrsfm[3]=year%10+0x30;
nyrsfm[4]='-';
nyrsfm[5]=month/10+0x30;
nyrsfm[6]=month%10+0x30;
nyrsfm[7]='-';
nyrsfm[8]=day/10+0x30;
nyrsfm[9]=day%10+0x30;
nyrsfm[10]=' ';
nyrsfm[11]=shi/10+0x30;
nyrsfm[12]=shi%10+0x30;
nyrsfm[13]=':';
nyrsfm[14]=fen/10+0x30;
nyrsfm[15]=fen%10+0x30;
nyrsfm[16]='\0';
//while(nyrsfm[i]!='\0') //while()循环不显示,是错误的
//{
// Write_char(1,nyrsfm[i]);
// i++;
//}
for(i=0;i<17;i++)
{
Write_char(1,nyrsfm[i]);
Delay(5);
}*/
//方法二:
Lcd_pos(1,0);
nyrsfm[0]=0x32;
Write_char(1,0x32);
nyrsfm[1]=0x30;
Write_char(1,0x30);
nyrsfm[2]=year/10+0x30;
Write_char(1,nyrsfm[2]);
nyrsfm[3]=year%10+0x30;
Write_char(1,nyrsfm[3]);
nyrsfm[4]='-';
Write_char(1,nyrsfm[4]);
nyrsfm[5]=month/10+0x30;
Write_char(1,nyrsfm[5]);
nyrsfm[6]=month%10+0x30;
Write_char(1,nyrsfm[6]);
nyrsfm[7]='-';
Write_char(1,nyrsfm[7]);
nyrsfm[8]=day/10+0x30;
Write_char(1,nyrsfm[8]);
nyrsfm[9]=day%10+0x30;
Write_char(1,nyrsfm[9]);
nyrsfm[10]=' ';
Write_char(1,nyrsfm[10]);
nyrsfm[11]=shi/10+0x30;
Write_char(1,nyrsfm[11]);
nyrsfm[12]=shi%10+0x30;
Write_char(1,nyrsfm[12]);
nyrsfm[13]=':';
Write_char(1,nyrsfm[13]);
nyrsfm[14]=fen/10+0x30;
Write_char(1,nyrsfm[14]);
nyrsfm[15]=fen%10+0x30;
Write_char(1,nyrsfm[15]);
}
/**********************************
函数名称: Write_week()
函数功能: 星期显示
入口参数: xq
备注 :
**********************************/
void Write_week(char xq)
{
uchar i;
Lcd_pos(2,0);
switch(xq)
{
case 1:
i=0;
while(table3[i]!='\0')
{
Write_char(1,table3[i]);
i++;
}
break;
case 2:
i=0;
while(table4[i]!='\0')
{
Write_char(1,table4[i]);
i++;
}
break;
case 3:
i=0;
while(table5[i]!='\0')
{
Write_char(1,table5[i]);
i++;
}
break;
case 4:
i=0;
while(table6[i]!='\0')
{
Write_char(1,table6[i]);
i++;
}
break;
case 5:
i=0;
while(table7[i]!='\0')
{
Write_char(1,table7[i]);
i++;
}
break;
case 6:
i=0;
while(table8[i]!='\0')
{
Write_char(1,table8[i]);
i++;
}
break;
case 7:
i=0;
while(table9[i]!='\0')
{
Write_char(1,table9[i]);
i++;
}
break;
}
}
/**********************************
函数名称: Set_time()
函数功能: DS12C887首次上电初始化时间函数
入口参数: 无
备注 :
**********************************/
void Set_time()
{
Write_ds(2,25);
Write_ds(4,10);
Write_ds(6,3);
Write_ds(7,18);
Write_ds(8,9);
Write_ds(9,13);
}
/***********************************
函数名称: init()
函数功能: 初始化
入口参数: 无
备注 :
***********************************/
void init()
{
uchar i;
i=0;
Wela=0;
Dula=0;
EA=1;
EX1=1;
IT1=1;
Set_time(); //首次上电时使用,只需执行一次
Lcd_pos(3,0);
while(table1[i]!='\0')
{
Write_char(1,table1[i]);
i++;
}
}
/**********************************
函数名称: Main()
函数功能:
入口参数:
备注 :
**********************************/
void Main()
{
init_com(); //串口初始化
Lcd_init(); //LCD初始化
init(); //不能放在Lcd_init()函数前面,,只有在液晶初始化之后才能够显示init()函数的内容
while(1)
{
Ds_change(); //读取寄存器中存储的温度数
Get_temp(); //获取温度并转换
sprintf(buff,"%.1f",f_temp); //将浮点型温度格式化为字符型,并保留一位,需声明#include
Delay(1000);
comm(buff); //串口发送数据,在串口调试助手上显示,这里主要是为了测试buff的内容而加上这句的
Display_temp(); //在12864液晶上显示温度
Delay(5);
year=Read_ds(9); //从DS12C887上读取数据
month=Read_ds(8);
day=Read_ds(7);
week=Read_ds(6);
shi=Read_ds(4);
fen=Read_ds(2);
Write_nyrsfm(year,month,day,shi,fen); //在12864液晶显示
Write_week(week); //显示星期
}
}
上一篇:[51单片机学习笔记FIVE]----独立按键
下一篇:51单片机堆栈深入剖析
推荐阅读最新更新时间:2024-03-16 15:28