平台:Keil 5 + STC89C52
晶振:11.0592MHZ
日期:2024-1-12
#include<reg52.h> //包含头文件
#include<intrins.h>
sbit RS = P2^7; //定义端口
sbit RW = P2^6;
sbit EN = P2^5;
#define DataPort P1
bit LCD_Check_Busy(void);
void LCD_Write_Com(unsigned char com);
void LCD_Write_Data(unsigned char Data);
void LCD_Clear(void);
void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s);
void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data);
void LCD_Init(void);
#define uint8 unsigned char
#define uint16 unsigned int
uint16 temp;
uint8 code STR1[] = "当前温度为:";
uint8 code STR2[] = "°C";
uint8 *p; //指针变量,存储数组元素地址
sbit DQ = P3^7; //DS18B20的数据接口
#define nops(); {_nop_(); _nop_(); _nop_(); _nop_();} //定义空指令
void delay_11us(uint16 n); //函数声明
void delay_ms(uint16 n);
void ds18b20_reset(void);
void write_byte(uint8 val);
uint8 read_byte(void);
void start_convert(void);
uint16 read_temp(void);
void uart_init(void);
void UART_Send_Byte(uint8 dat);
void UART_Send_STR(void);
void UART_Send_Dat(uint8 dat);
/***************************************************
* us延时子函数
* n=1时,约为11us
****************************************************/
void delay_11us(unsigned char n)
{
do {
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
} while (--n);
}
/***************************************************
* ms延时子函数
* n=1时,约为1ms
****************************************************/
void delay_ms(uint16 n)
{
uint8 m=120;
while (n--)
while (m--);
}
/***************************************************
* DS18B20复位子函数
* 总线拉低550us,释放66us
****************************************************/
void ds18b20_reset(void)
{
bit flag=1;
while (flag) //判断初始化是否成功
{
while (flag) //判断DS18B20是否给出反馈
{
DQ = 1;
delay_11us(1); //高电平约11us
DQ = 0;
delay_11us(50); //低电平550us
DQ = 1;
delay_11us(6); //释放66us
flag = DQ; //总线状态采样
}
delay_11us(50); //延时550us
flag = ~DQ; //总线状态采样
}
DQ=1;
}
/***************************************************
* 向总线写入一个字节
****************************************************/
void write_byte(uint8 val)
{
uint8 i;
for (i=0; i<8; i++)
{
DQ = 1; //写时隙准备工作
_nop_();
DQ = 0; //告诉DS18B20,准备采样
nops(); //4us
DQ = val & 0x01; //最低位移出
delay_11us(6); //66us
val >>= 1; //右移一位
}
DQ = 1;
delay_11us(1);
}
/***************************************************
* 从总线读出一个字节
****************************************************/
uint8 read_byte(void)
{
uint8 i, value=0;
for (i=0; i<8; i++)
{
DQ=1; //读时隙准备工作
_nop_();
value >>= 1;
DQ = 0; //告诉DS18B20,准备发送
nops(); //4us
DQ = 1; //释放总线
nops(); //4us
if (DQ) //0和1的判断
value|=0x80;
delay_11us(6); //66us
}
DQ=1;
return(value); //返回采集到的数据
}
/***************************************************
* 温度转换子函数
* 根据操作顺序,发出转换命令
****************************************************/
void start_convert(void)
{
ds18b20_reset();
write_byte(0xCC); // 发Skip ROM命令
write_byte(0x44); // 发转换命令
}
/***************************************************
* 温度读取子函数
* 根据操作顺序,读取温度值
****************************************************/
uint16 read_temp(void)
{
uint8 temp_data[2]; // 读出温度暂放
uint16 temp;
ds18b20_reset(); // 复位
write_byte(0xCC); // 发Skip ROM命令
write_byte(0xBE); // 发读命令
temp_data[0]=read_byte(); //温度低8位
temp_data[1]=read_byte(); //温度高8位
temp = temp_data[1];
temp <<= 8;
temp |= temp_data[0];
return temp;
}
/***************************************************
* UART初始化子函数
* 定时器1,工作方式2,波特率9600
****************************************************/
void uart_init(void)
{
TMOD = 0x20; // 定时器1工作在方式2
SCON = 0x50; // 8位uart,允许串行接受
TH1 = 0xFD; //设置定时器初值
TL1 = 0xFD; //设置定时器初值
TR1 = 1; //启动定时器1
}
/***************************************************
* UART发送一个字节
****************************************************/
void UART_Send_Byte(uint8 dat)
{
SBUF = dat; //送入缓冲寄存器
while (TI == 0); //等待发送完成
TI = 0;
}
/***************************************************
* UART发送一串字符
****************************************************/
void UART_Send_STR(void)
{
while(*p != '\0')
{
SBUF = *p; //送入缓冲寄存器
while (TI == 0); //等待发送完成
TI = 0;
p++; //地址加一
}
}
/***************************************************
* 数值转换子函数
* 将要发送的数转换为ASCII码
****************************************************/
void UART_Send_Dat(uint8 dat)
{
UART_Send_Byte(dat/10 + '0'); //发送十位数
UART_Send_Byte(dat%10 + '0'); //发送个位数
}
/***************************************************
* 判忙子函数
* 读取状态字的STA7位来判断液晶是否忙碌
****************************************************/
bit LCD_Check_Busy(void)
{
unsigned char state;
DataPort= 0xFF;
EN = 0;
RS = 0;
RW = 1;
_nop_();
EN = 1;
state=DataPort;
_nop_();
EN = 0;
return (bit)(state&0x80);
}
/***************************************************
* 写入命令子函数
* 先判断液晶是否忙碌,不忙则写入
****************************************************/
void LCD_Write_Com(unsigned char com)
{
while(LCD_Check_Busy()); //忙则等待
EN = 0;
RS = 0;
RW = 0;
_nop_();
EN = 1;
DataPort= com;
_nop_();
EN = 0;
}
/***************************************************
* 写入数据子函数
* 先判断液晶是否忙碌,不忙则写入
****************************************************/
void LCD_Write_Data(unsigned char Data)
{
while(LCD_Check_Busy()); //忙则等待
EN = 0; //默认低电平
RS = 1;
RW = 0;
_nop_();
EN = 1;
DataPort= Data;
_nop_();
EN = 0;
}
/***************************************************
* 清屏子函数
* 通过调用写入命令子函数来实现
****************************************************/
void LCD_Clear(void)
{
LCD_Write_Com(0x01);
}
/***************************************************
* 写入字符串子函数
* 使用字符型指针做为形参
****************************************************/
void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
{
if (y == 0)
LCD_Write_Com(0x80 + x); //表示第一行
else
LCD_Write_Com(0xC0 + x); //表示第二行
while (*s) // “/0”
{
LCD_Write_Data( *s);
s ++;
}
}
/***************************************************
* 写入字符子函数
* 先输入地址,后输入字符
****************************************************/
void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data)
{
if(y == 0)
LCD_Write_Com(0x80 + x);
else
LCD_Write_Com(0xC0 + x);
LCD_Write_Data( Data);
}
/***************************************************
* 初始化子函数
* 参照1602datasheet
****************************************************/
void LCD_Init(void)
{
LCD_Write_Com(0x38);
LCD_Write_Com(0x08); /*显示关闭*/
LCD_Write_Com(0x01); /*显示清屏*/
LCD_Write_Com(0x06); /*显示光标移动设置*/
LCD_Write_Com(0x0C); /*显示开及光标设置*/
}
//主程序
main()
{
uint16 wendu;
uart_init(); //串口初始化
while (1)
{
start_convert(); //启动温度转换
delay_ms (1000); // 延时1秒
wendu=read_temp(); //读取暂存器中的温度数据
if (wendu > 60000) //判断温度正负
{
LCD_Write_Char(5,1,'-');
UART_Send_Byte('-'); //添加负号
wendu = ~wendu; //按位取反
wendu++; //加一,得到补码
}
temp=wendu;
a[0]=temp/10;
a[1]=temp%10;
wendu >>= 4; //忽略掉小数位
LCD_Init(); //屏幕初始化
LCD_Clear(); //清屏
LCD_Write_String(0,0,"temperture");
LCD_Write_Char(6,1,wendu/10+'0');
LCD_Write_Char(7,1,wendu%10+'0');
LCD_Write_String(9,1,"oc");
}
}