个人成长笔记–使用89C52在1602液晶屏上显示日期和温度
LCD1602配置过程:
#include "config.h"
#include "Lcd1602.h"
//首先判断1602忙不忙
void Read_Busy()
{
uint8 busy;
LCD_DB = 0xFF;//首先复位数据总线
LCD_RS = 0;
LCD_RW = 1;
do
{
LCD_EN = 1;//先使能,才可以发送数据
busy = LCD_DB;//发送数据
LCD_EN = 0;//拉低使能,以便下一次产生上升沿
}while(busy & 0x80);//与D7相与,为1表示忙,程序一直循环等待
//while(busy |= 0x01);//错了,D7是最高位,所以选择要与最高位相比较
}
//写命令
void Write_Cmd_Byte(uint8 cmd)
{
Read_Busy();//记住先判断忙不忙
LCD_RS = 0;
LCD_RW = 0;
LCD_DB = cmd;//写入指令
LCD_EN = 1;//使能
LCD_EN = 0;//每次都要记得拉低使能位,方便下次产生上升沿
}
//写数据
void Write_Data_Byte(uint8 dat)
{
Read_Busy();//记住先判断忙不忙
LCD_RS = 1;
LCD_RW = 0;
LCD_DB = dat;//写入数据
LCD_EN = 1;//使能
LCD_EN = 0;//每次都要记得拉低使能位,方便下次产生上升沿
}
//清屏
void Clear_Screen()
{
Write_Cmd_Byte(0x01);//清除数据
}
//打开光标闪烁
void Open_Cursor()
{
Write_Cmd_Byte(0x0F);//打开光标
}
//关闭光标
void Close_Cursor()
{
Write_Cmd_Byte(0x0C);//关闭光标
}
//设置指令在哪个位置显示
void Set_Cursor(uint8 x,uint8 y)
{
if(y)
{
x |= 0x40;//如果y=1;就在第二行显示,x等于多少就在多少列显示
}
x |= 0x80;//否则,在第一行显示,
//还要写指令,不然怎样显示
Write_Cmd_Byte(x);
}
//在指定位置显示一个字符串
void Dis_OneChar(uint8 x,uint8 y,uint8 dat)
{
Set_Cursor(x,y);
Write_Data_Byte(dat);
}
//在指定位置显示字符串
void Dis_Str(uint8 x,uint8 y,uint8 *str)
{
Set_Cursor(x,y);
while(*str != '\0')
{
Write_Data_Byte(*str++);
}
}
//1602初始化
void LCD1602_Init()
{
Write_Cmd_Byte(0x38);//显示模式设置
Write_Cmd_Byte(0x0C);//开显示,关闭光标
Write_Cmd_Byte(0x06);//读写一字节后地址指针加1
Write_Cmd_Byte(0x01);//显示清屏
}
DS18B20配置过程:
#include "config.h"
#include "DS18B20.h"
//前提是晶振在11.0952情况下
//us延时函数,执行一次us---所需6.5us进入一次函数需要11.95us
void Delay_us(uchar us)
{
while(us--);
}
//单总线初始化时序
bit Ds_Init()
{
bit i;
EA = 0;//禁止总中断
DS18B20_IO = 1;//先置高释放一下总线
_nop_();//延时5us,稳定一下
DS18B20_IO = 0;//再把总线置低,开始复位
Delay_us(75);//至少拉低480us,总线将全部被复位,75*6.5+11.95=499.45us
DS18B20_IO = 1;//释放总线
Delay_us(4);//延时4*6.5+11.95=37.95us,等待18B20发回存在信号
i = DS18B20_IO;//把返回值赋值给i
Delay_us(20);//延时20*6.5+11.95=141.95us,读取存在信号的时间
DS18B20_IO = 1;//释放总线
_nop_();//延时5us,稳定一下
EA = 1;//使能总中断
return(i);//如果i=0则存在总线上,并且DS18B20已经准备好了。
}
//写一个字节
void Write_Byte(uchar dat)
{
//一次只能写一位,一个字节8位,所以循环8次
uchar i;
EA = 0;//禁止总中断
for(i=0;i<8;i++)
{
DS18B20_IO = 0;//初始化化的时候已经释放总线了,现在直接拉低
_nop_();//延时大于1us产生写时序
DS18B20_IO = dat & 0x01;//从最低位开始写
Delay_us(10);//10*6.5+11.95=76.95us,写0时需要60~120us。写1时需要60us以上,所以都符合
DS18B20_IO = 1;//释放总线
_nop_();//两个周期之间需要间隔大于1us
dat>>=1;//把读到最低位放进高位,然后在把低位放高位,最后最低位就会到最低位
}
EA = 1;//使能总中断
}
//读一个字节
uchar Read_Byte()
{
//一次只能读一位,一个字节8位,所以循环8次
uchar i,j,dat;
EA = 0;//禁止总中断
for(i=0;i<8;i++)
{
DS18B20_IO = 0;//初始化化的时候已经释放总线了,现在直接拉低
_nop_();//延时大于1us产生读时序
DS18B20_IO = 1;//释放总线,交给18B20控制
_nop_();
j = DS18B20_IO;//从最低位读取,一个读一个位
Delay_us(10);//10*6.5+11.95=76.95us,读一位需要延时60~120us
DS18B20_IO = 1;//释放总线
_nop_();//两个周期之间需要间隔大于1us
dat = (j<<7) | (dat>>1);//j把读到最低位左移7位到达dat最高位,dat在整体左移一位
}
EA = 1;//使能总中断
return(dat);
}
//启动一次18B20温度转换
bit Start_DS18B20()
{
bit ack;
ack = Ds_Init();//获取18B20应答
if(ack == 0)//如果ack值为0,则应答,if语句就为真
{
Write_Byte(0xCC);//总线上只有一个18B20,所以跳过ROM操作
Write_Byte(0x44);//启动一次温度转换
}
return ~ack;//ack等于0就是应答,取反就是1,返回1就代表启动成功
}
//读取DS18B20转换温度值
bit Get_DS18B20_Temp(int16 *temp)
{
bit ack;
uint8 LSB,MSB;//16位的温度值的低字节和高字节
ack = Ds_Init();//获取18B20应答
if(ack == 0)//如果ack值为0,则应答,if语句就为真
{
Write_Byte(0xCC);//总线上只有一个18B20,所以跳过ROM操作
Write_Byte(0xBE);//发送读命令
LSB = Read_Byte();//先读低位,一共8位,低位数据存在最低位
MSB = Read_Byte();//在读高位,一共8位,高位数据存在最高位
*temp = ((int16)MSB << 8) + LSB;//把MSB强制转换成16位,MSB左移8位,把高8位存到高八位,加LSB的低8位,正好转换成整型16位
}
return ~ack;//ack等于0就是应答,取反就是1,返回1就代表获取成功
}
然后再应用写调用函数:
//获取温度,并显示到液晶屏上
//ops:为0时,只有温度变化才刷新,非0则立即刷新
void RefreshTemp(uint8 ops)
{
int16 temp;
uint8 pdata str[6];
static int16 backup = 0;
Get_DS18B20_Temp(&temp);//获取当前温度值
Start_DS18B20();//启动下一次转换
temp >>= 4;//舍弃4位小数位
if((backup!=temp) || (ops!=0))//按照需要刷新液晶显示
{
str[0] = (temp/10) + '0';//十位转ASCII码
str[1] = (temp%10) + '0';//个位转ASCII码
str[2] = '\'';//用'C代替°C
str[3] = 'C';
str[4] = '\0';//字符串结束符
Dis_Str(12,1,str);//显示到液晶上
backup = temp;//刷新上一次温度值
}
}
结果显示:
这里以上代码对温度的显示,日期和时间是之前所写。