📄 wend.c
字号:
#include<reg52.H> //使用1602LCD显示DS18B20转换的温度值,12MHz,程序已经好使
#include<intrins.H>
#include<math.H>
#define uchar unsigned char //定义无符号字符为 uchar,方便书写
#define uint unsigned int
sbit RS=P3^3; // 数据/命令选择端(H/L)
sbit LCDEN=P3^5;//使能端,RW读写端接地
void delayUs()
{
_nop_();
}
//写命令:RS=0, RW=0;
//第一行开始地址为0x80, 第二行开始地址为0xc0;
void delayMs(uint a)
{
uint i,j;
for(i=a;i>0;i--)
for(j=100;j>0;j--);
}
void writeComm(uchar comm)
{
RS=0;
P1=comm;
LCDEN=1;
delayUs();
LCDEN=0;
delayMs(1);
}
// 写数据:RS=1, RW=0;
void writeData(uchar dat)
{
RS=1;
P1=dat;
LCDEN=1;
delayUs();
LCDEN=0;
delayMs(1);
}
//初始化
void init()
{
writeComm(0x38); //显示模式,固定指令为00111000=0x38, 16*2显示, 5*7点阵,8位数据接口
writeComm(0x0c); //开显示, 关光标,指令1: 00001DCB : D:开显示/关显示(H/L);
//C:显示光标/不显示(H/L), B:光标闪烁/不闪烁(H/L)
writeComm(0x06); //写字符后地址加1, 光标加1
writeComm(0x01); //清屏
}
void writeString(uchar * str,uchar length)
{
uchar i;
for(i=0;i<length;i++)
{
writeData(str[i]);
}
}
sbit ds=P3^7;
//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
//初始化DS18B20
void dsInit()
{
unsigned int i; // 对于12MHz时钟, unsigned int型的i, 作一个i++操作的时间大约为8us
ds=0;
i=100; // 拉低约800us, 符合协议要求的480us以上
while(i>0)i--; //产生一个上升沿, 进入等待应答状态
ds=1;
i=4;
while(i>0)i--;
}
void dsWait()
{
unsigned int i;
while(ds);
while(~ds);//检测到应答脉冲
i=4;
while(i>0)i--;
}
// 向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
bit readBit()
{
unsigned int i;
bit b;
ds=0;
i++; //延时约8us, 符合协议要求至少保持1us
ds=1;
i++;i++;//延时约16us, 符合协议要求的至少延时15us以上
b=ds;
i=8;
while(i>0)i--; //延时约64us, 符合读时隙不低于60us要求
return b;
}
//读取一字节数据, 通过调用readBit()来实现
unsigned char readByte()
{
unsigned int i;
unsigned char j,dat;
dat=0;
for(i=0;i<8;i++)
{
j=readBit(); //最先读出的是最低位数据
dat=(j<<7)|(dat>>1);
}
return dat;
}
//向DS18B20写入一字节数据
void writeByte(unsigned char dat)
{
unsigned int i;
unsigned char j;
bit b;
for(j=0;j<8;j++)
{
b=dat&0x01;
dat>>=1; //写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
if(b)
{
ds=0;
i++;i++; // 拉低约16us, 符号要求15~60us内
ds=1;
i=8;while(i>0)i--; //延时约64us, 符合写时隙不低于60us要求
}
else //写"0", 将DQ拉低60us~120us
{
ds=0;
i=8;while(i>0)i--; // 拉低约64us, 符号要求
ds=1;
i++;i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
}
}
}
// 向DS18B20发送温度转换命令
void sendChangeCmd()
{
dsInit(); // 初始化DS18B20, 无论什么命令, 首先都要发起初始化
dsWait(); //等待DS18B20应答
delayMs(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0x44); // 写入温度转换命令字 Convert T
}
// 向DS18B20发送读取数据命令
void sendReadCmd()
{
dsInit();
dsWait();
delayMs(1);
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0xbe); //写入读取数据令字 Read Scratchpad
}
// 获取当前温度值
int getTmpValue()
{
unsigned int tmpvalue;
int value; // 存放温度数值
float t;
unsigned char low,high;
sendReadCmd(); //连续读取两个字节数据
low=readByte();
high=readByte();
tmpvalue=high; // 若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
tmpvalue<<=8;
tmpvalue|=low; //计算机中对于负数是利用补码来表示的
value=tmpvalue; //将高低两个字节合成一个整形变量,将高低两个字节合成一个整形变量
t=value*0.0625; //使用DS18B20的默认分辨率12位, 精确度为0.0625度,
// 即读回数据的最低位代表0.0625度
value=t*100+(value>0?0.5:-0.5); //将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
// 如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
//如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度大于0加0.5, 小于0减0.5
return value;
}
void display(int v)
{
unsigned char count;
unsigned char datas[]={0,1,2,3,4};
unsigned int tmp=abs(v);
datas[0]=tmp/10000; //最高位
datas[1]=tmp%10000/1000;
datas[2]=tmp%1000/100;
datas[3]=tmp%100/10;
datas[4]=tmp%10; //最低位
writeComm(0xc0+1); //0xc0=1100 0011 ->DDRAM地址设置,两行显示,第二行开始地址,距头1个距离
if(v<0) //温度的符号判断
{
writeString("- ",2); //注意符号后有一个空格
}
else
{
writeString("+ ",2);
}
if(datas[0]!=0)
{
writeData('0'+datas[0]); //输入字符0,1,2,3,4,5,6,7,8,9
}
for(count=1;count!=5;count++) // 依次显示由高到低位
{
writeData('0'+datas[count]);
if(count==2) //两高位之后小数点
{
writeData('.');
}
}
}
void main()
{
uchar table[]="Now Temperature:";
sendChangeCmd(); //先放入温度传感指令再液晶驱动,将顺序执行,没有检测到温度传感则无数据输出
init();
writeComm(0x80);
writeString(table,16);
while(1)
{
delayMs(1000); //温度转换时间需要750ms以上
writeComm(0xc0);
display(getTmpValue());
sendChangeCmd();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -