📄 18b20_1602.c
字号:
#include <at89x52.h>
#include <absacc.h>
#include <intrins.h>
#include <math.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD_COMMAND 0 //1602写命令或数据参数
#define LCD_DATA 1
#define RS P2_0 //1602控制端口
#define RW P2_1
#define EN P2_2
#define DBport P0 //1602数据命令口
#define DO P1_0 //18b20总线接口
uchar temp_l = 0; //温度值存储低位字节
uchar temp_h = 0; //温度值存储高位字节
uchar tempsign = 0; //温度值符号位
uchar temp_integer[4]; //温度整数存储数组
uchar temp_dicimal[5]; //温度小数存储数组
/*延时以ms为单位的t时间*/
void Delay(uint t)
{
uint i;
while(t--)
{
for(i=0; i<125; i++)
{ }
}
}
/**********************************************************
等待程序
**********************************************************/
uchar LCD_Wait(void)
{
RS = 0;
RW = 1; _nop_();
EN = 1; _nop_();
//while(DBport & 0x80); _nop_();
EN = 0; _nop_();
return DBport;
}
/**********************************************************
写指令/数据
**********************************************************/
LCD_Write(bit style, uchar input)
{
RW = 0;
RS = style;
EN = 0; _nop_();
DBport = input; _nop_();
EN = 1; _nop_();
EN = 0; _nop_();
LCD_Wait();
}
/**********************************************************
设置屏幕初始模式
**********************************************************/
#define LCD_SHOW 0x0C //显示开
#define LCD_HIDE 0x08 //显示关
#define LCD_CURSOR 0x0A //显示光标
#define LCD_NO_CURSOR 0x08 //无光标
#define LCD_FLASH 0x09 //光标闪动
#define LCD_NO_FLASH 0x08 //光标不闪动
void LCD_SetDisplay(unsigned char DisplayMode)
{
LCD_Write(LCD_COMMAND, DisplayMode);
}
/**********************************************************
设置写完1byte数据后显示模式(输入每个字符后屏幕变化)
**********************************************************/
#define LCD_CURSOR_LEFT 0x04 //每写完一个字节光标左移,且AC减1
#define LCD_CURSOR_RIGHT 0x06 //每写完一个字节光标右移,且AC加1
#define LCD_CHAR_RIGHT 0x05 //每写完一个字节字符右移
#define LCD_CHAR_LEFT 0x07 //每写完一个字节字符左移
void LCD_Setinput(unsigned char InputMode)
{
LCD_Write(LCD_COMMAND, InputMode);
}
/**********************************************************
设定显示功能
**********************************************************/
#define LCD_DISPLAY_FUNCTION 0x38 //8位两行显示,5×7字型
void LCD_Setfunction(unsigned char Display_function)
{
LCD_Write(LCD_COMMAND, Display_function);
}
/**********************************************************
做完上面的设置,现在可以初始化LCD了
**********************************************************/
#define LCD_SCREEN_CLEAR 0x01
void Initial_LCD(void)
{
EN = 0;
LCD_Setfunction(LCD_DISPLAY_FUNCTION);
LCD_Setfunction(LCD_DISPLAY_FUNCTION);
//这几句顺序很重要,我随便改变了一下,竟然就没有显示了
LCD_SetDisplay(LCD_SHOW | LCD_NO_CURSOR);
LCD_Write(LCD_COMMAND, LCD_SCREEN_CLEAR);
LCD_Setinput(LCD_CURSOR_RIGHT);
}
/**********************************************************
令字符左移
*********************************************************
#define SCREEN_RIGHT_MOVE 0x18
#define SCREEN_LEFT_MOVE 0x1C
void LCD_SCREEN_MOVE(uchar Move_Director)
{
LCD_Write(LCD_COMMAND, Move_Director);
}*/
/**********************************************************
设定显示位置程序(即字符在什么位置显示出来)
**********************************************************/
void GotoXY(uchar x, uchar y)
{
if(y == 0)
{LCD_Write(LCD_COMMAND, 0x80|x);} //1602地址为第一行00H~0FH,第二行为40H~4FH,
if(y == 1) //而且写入地址命令格式为1xxx xxxx,
{LCD_Write(LCD_COMMAND, 0x80|(x-0x40));} //所以这里的0x80|(x-0x40)就是如此得出
}
/**********************************************************
写字符程序
**********************************************************/
void Print(uchar *str, uchar j)
{
uchar i = 0;
for(i=0; i<j; i++)
{
LCD_Write(LCD_DATA, *str);
str++;
}
}
/*us级延时,延时时间约4+2*i*/
void Delayus(uchar i)
{
while(--i);
}
/*产生复位脉冲,等待应答信号*/
bit Resetpaulse()
{
DO = 0; //拉低约600us
Delayus(150);
Delayus(150);
DO = 1;//产生上升沿,延时约15~60us
Delayus(30);
return(~DO); //等待应答信号
}
/*读取数据一位*/
bit Readbit()
{
uint i = 0;
bit b = 0;
DO = 0; //产生读时隙
i++; //维持低电平至少1us
DO = 1; //1us以上后拉高
Delayus(2); //延时8us,DO下降沿15内ds18b20输出的数据才有效
b = DO; //读取数据
Delayus(40); //每个读时隙至少持续60us
return(b);
}
/*读取一个字节*/
uchar Readbyte()
{
uchar byte_read = 0;
uchar i, j;
for(i=0; i<8; i++)
{
j = Readbit();
byte_read = (j<<i) | byte_read; //低位读起
}
return(byte_read);
}
/*写一个字节*/
void Writebyte(uchar byte_to_write)
{
uchar i = 0;
uchar j = 0;
bit write_bit = 0;
for(j=0; j<8; j++)
{
write_bit = (byte_to_write & 0x01);
if(write_bit == 1) //写1
{
DO = 0; //产生写时隙
Delayus(3); //延时15us
DO = 1; //写1
Delayus(40); //延时,写时隙不得低于60us
}
else
{
DO = 0; //产生写时隙
Delayus(50); //延时,保持低约60us~120us
DO = 1;
i++;
}
byte_to_write = byte_to_write >> 1;
}
}
/*启动温度转换*/
void StartConvert()
{
Resetpaulse(); // 发出复位脉冲,每次操作都从复位开始
Delay(1);
EA = 0;
Writebyte(0xcc); //skip room命令
Writebyte(0x44); //启动温度转换命令
EA = 1;
}
/*读取温度值*/
void ReadTempreture()
{
EA = 0;
Resetpaulse(); // 发出复位脉冲,每次操作都从复位开始
Delay(1);
Writebyte(0xcc); //skip room命令
Writebyte(0xbe); //读取暂存器命令
temp_l = Readbyte(); //存储温度低字节值 (整数部分低四位和小数部分)
temp_h = Readbyte(); //存储温度高字节值 (其中高五位为符号位)
EA = 1;
}
/*数据处理程序*/
void Digital_process()
{
uchar total = 0;
uchar low = 0;
uint dicimal = 0;
tempsign = (temp_h >> 7) & 0x01; //得出符号位
total = ((temp_h << 4)&0xf0) | ((temp_l >> 4)&0x0f); //取整数位
low = temp_l & 0x0f; //取小数位
if(tempsign == 0)
{
temp_integer[0] = total / 100 + '0'; //计算百、十、个位
temp_integer[1] = (total%100)/10 + '0';
temp_integer[2] = (total%100)%10 + '0';
temp_integer[3] = '\0';
if(temp_integer[0] == '0')
{
if(temp_integer[1] != '0')
{
temp_integer[0] = '\0'; //百位零消隐
}
else if(temp_integer[1] == '0')
{
temp_integer[0] = '\0'; //百位,十位零都消隐
temp_integer[1] = '\0';
}
}
dicimal = low * 625; //计算小数
temp_dicimal[0] = dicimal / 1000 + '0'; //十分位
temp_dicimal[1] = dicimal % 1000 /100 + '0'; //百分位
temp_dicimal[2] = dicimal % 100 / 10 + '0'; //千分位
temp_dicimal[3] = dicimal % 10 + '0'; //万分位
temp_dicimal[4] = '\0'; //数组加一个空字符(好像系统也会自动加上的?)
}
else if(tempsign == 1) //负数处理
{
if(low == 0x00) //负数要取反加一再乘以0.0625就是实际温度值了,我这里没有设那么多int型变量,
{
total = ~total + 1; //所以就用了这么一个计算方法
low &= 0x0f;
} /*具体一点讲,小树低四位为全零时取反加一要有进位,此时只要整数位取反加一即可,
小数位不用理会,其余情况整数位取反,小数位取反加一*/
else
{
total = ~total ;
low = (~low) + 1;
low &= 0x0f; //注意高四位要变成零
}
temp_integer[1] = (total%100)/10 + '0'; //计算十、个位
temp_integer[2] = (total%100)%10 + '0';
temp_integer[3] = '\0';
if(temp_integer[1] == '0')
{
temp_integer[1] = '\0';
}
dicimal = low * 625;
temp_dicimal[0] = dicimal / 1000 + '0';
temp_dicimal[1] = dicimal % 1000 /100 + '0';
temp_dicimal[2] = dicimal % 100 / 10 + '0';
temp_dicimal[3] = dicimal % 10 + '0';
temp_dicimal[4] = '\0';
}
}
void main()
{
bit palse = 0;
Initial_LCD();
GotoXY(0,0);
Print("CHECKING...",12);
Delay(3000);
palse = Resetpaulse(); //检测DS18B20是否响应
if(palse)
{
Initial_LCD();
GotoXY(0,0);
Print("DS18B20 OK",11);
}
else
{
Initial_LCD();
GotoXY(0,0);
Print("DS18B20 ERROR",13);
while(1);
}
do{
Delay(1);
StartConvert();
Delay(1020);
ReadTempreture();
Digital_process();
if(tempsign == 0) //显示正值温度
{
GotoXY(0,1);
Print("TEMP:",5);
GotoXY(5,1);
Print(temp_integer,3);
GotoXY(8,1);
Print(".",1);
GotoXY(9,1);
Print(temp_dicimal,4);
}
else //显示负值温度
{
GotoXY(0,1);
Print("TEMP:",5);
GotoXY(5,1);
Print("-",1);
GotoXY(6,1);
Print(temp_integer + 1,2);
GotoXY(8,1);
Print(".",1);
GotoXY(9,1);
Print(temp_dicimal,4);
}
}
while(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -