仿真是以AT8051的12T指令运行的 STC89C52是6T指令 所有用到延时的延时时间要*2,定时器可以不用改 |
现在仿真可以了,但是同样代码在硬件上不行 |
青青梓衿 发表于 2019-6-26 14:32 仿真可以读出来温度,但是一烧到单片机上就不行了,单片机是STC89C52 |
DS18B20 读时序要求特别高,用实际硬件来调调吧,否则都用定时器 |
先占个位置学习 |
如果你用的是12M的晶振就把复位里的低电平延时30改成70以上 |
我这个例程是使用过的,没有问题。 有程序main.c: /******************************************************************************* * 实验名 :温度显示实验 * 使用的IO : * 实验效果 :1602显示温度 * 注意 : *******************************************************************************/ #include<reg51.h> #include"temp.h" //数码管IO #define DIG P0 sbit LSA=P2^2; sbit LSB=P2^3; sbit LSC=P2^4; unsigned char code DIG_CODE[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; unsigned char Num=0; unsigned int disp[8]={0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f}; void LcdDisplay(int); void Timer0Configuration(); /******************************************************************************* * 函数名 : main * 函数功能 : 主函数 * 输入 : 无 * 输出 : 无 *******************************************************************************/ void main() { Timer0Configuration(); while(1) { LcdDisplay(Ds18b20ReadTemp()); } } /******************************************************************************* * 函数名 : LcdDisplay() * 函数功能 : LCD显示读取到的温度 * 输入 : v * 输出 : 无 *******************************************************************************/ void LcdDisplay(int temp) //lcd显示 { unsigned char datas[] = {0, 0, 0, 0, 0}; //定义数组 float tp; if(temp< 0) //当温度值为负数 { disp[2] = 0x40; //因为读取的温度是实际温度的补码,所以减1,再取反求出原码 temp=temp-1; temp=~temp; tp=temp; temp=tp*0.0625*100+0.5; //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就 //算加上.5,还是在小数点后面。 } else { disp[2] = 0; tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量 //如果温度是正的那么,那么正数的原码就是补码它本身 temp=tp*0.0625*100+0.5; //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就 //算加上0.5,还是在小数点后面。 } // disp[0] = 0; // disp[1] = 0; // disp[3] = DIG_CODE[temp / 10000]; disp[4] = DIG_CODE[temp % 10000 / 1000]; disp[5] = DIG_CODE[temp % 1000 / 100] | 0x80; disp[6] = DIG_CODE[temp % 100 / 10]; disp[7] = DIG_CODE[temp % 10]; } /******************************************************************************* * 函数名 : Timer0Configuration() * 函数功能 : 设置计时器 * 输入 : 无 * 输出 : 无 *******************************************************************************/ void Timer0Configuration() { TMOD=0X02;//选择为定时器模式,工作方式2,仅用TRX打开启动。 TH0=0X9C; //给定时器赋初值,定时100us TL0=0X9C; ET0=1;//打开定时器0中断允许 EA=1;//打开总中断 TR0=1;//打开定时器 } /******************************************************************************* * 函数名 : DigDisplay() interrupt 1 * 函数功能 : 中断数码管显示 * 输入 : 无 * 输出 : 无 *******************************************************************************/ void DigDisplay() interrupt 1 { //定时器在工作方式二会自动重装初,所以不用在赋值。 // TH0=0X9c;//给定时器赋初值,定时1ms // TL0=0X00; DIG=0; //消隐 switch(Num) //位选,选择点亮的数码管, { case(7): LSA=0;LSB=0;LSC=0; break; case(6): LSA=1;LSB=0;LSC=0; break; case(5): LSA=0;LSB=1;LSC=0; break; case(4): LSA=1;LSB=1;LSC=0; break; // case(3): // LSA=0;LSB=0;LSC=1; break; // case(2): // LSA=1;LSB=0;LSC=1; break; // case(1): // LSA=0;LSB=1;LSC=1; break; // case(0): // LSA=1;LSB=1;LSC=1; break; } DIG=disp[Num]; //段选,选择显示的数字。 Num++; if(Num>7) Num=4; } 温度读取程序temp.c: #include"temp.h" /******************************************************************************* * 函数名 : Delay1ms * 函数功能 : 延时函数 * 输入 : 无 * 输出 : 无 *******************************************************************************/ void Delay1ms(unsigned int y) { unsigned int x; for(y;y>0;y--) for(x=110;x>0;x--); } /******************************************************************************* * 函数名 : Ds18b20Init * 函数功能 : 初始化 * 输入 : 无 * 输出 : 初始化成功返回1,失败返回0 *******************************************************************************/ unsigned char Ds18b20Init() { unsigned int i; EA = 0; DSPORT=0; //将总线拉低480us~960us i=70; while(i--);//延时642us DSPORT=1; //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低 i=0; EA = 1; while(DSPORT) //等待DS18B20拉低总线 { i++; if(i>5000)//等待>5MS return 0;//初始化失败 } return 1;//初始化成功 } /******************************************************************************* * 函数名 : Ds18b20WriteByte * 函数功能 : 向18B20写入一个字节 * 输入 : com * 输出 : 无 *******************************************************************************/ void Ds18b20WriteByte(unsigned char dat) { unsigned int i,j; EA = 0; for(j=0;j<8;j++) { DSPORT=0; //每写入一位数据之前先把总线拉低1us i++; DSPORT=dat&0x01; //然后写入一个数据,从最低位开始 i=6; while(i--); //延时68us,持续时间最少60us DSPORT=1; //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值 dat>>=1; } EA = 1; } /******************************************************************************* * 函数名 : Ds18b20ReadByte * 函数功能 : 读取一个字节 * 输入 : com * 输出 : 无 *******************************************************************************/ unsigned char Ds18b20ReadByte() { unsigned char byte,bi; unsigned int i,j; EA = 0; for(j=8;j>0;j--) { DSPORT=0;//先将总线拉低1us i++; DSPORT=1;//然后释放总线 i++; i++;//延时6us等待数据稳定 bi=DSPORT; //读取数据,从最低位开始读取 /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/ byte=(byte>>1)|(bi<<7); // i=4; //读取完之后等待48us再接着读取下一个数 // while(i--); } EA = 1; return byte; } /******************************************************************************* * 函数名 : Ds18b20ChangTemp * 函数功能 : 让18b20开始转换温度 * 输入 : com * 输出 : 无 *******************************************************************************/ void Ds18b20ChangTemp() { Ds18b20Init(); Delay1ms(1); Ds18b20WriteByte(0xcc); //跳过ROM操作命令 Ds18b20WriteByte(0x44); //温度转换命令 // Delay1ms(100); //等待转换成功,而如果你是一直刷着的话,就不用这个延时了 } /******************************************************************************* * 函数名 : Ds18b20ReadTempCom * 函数功能 : 发送读取温度命令 * 输入 : com * 输出 : 无 *******************************************************************************/ void Ds18b20ReadTempCom() { Ds18b20Init(); Delay1ms(1); Ds18b20WriteByte(0xcc); //跳过ROM操作命令 Ds18b20WriteByte(0xbe); //发送读取温度命令 } /******************************************************************************* * 函数名 : Ds18b20ReadTemp * 函数功能 : 读取温度 * 输入 : com * 输出 : 无 *******************************************************************************/ int Ds18b20ReadTemp() { int temp=0; unsigned char tmh,tml; Ds18b20ChangTemp(); //先写入转换命令 Ds18b20ReadTempCom(); //然后等待转换完后发送读取温度命令 tml=Ds18b20ReadByte(); //读取温度值共16位,先读低字节 tmh=Ds18b20ReadByte(); //再读高字节 temp=tmh; temp<<=8; temp|=tml; return temp; } 温度读取头文件temo.h: #ifndef __TEMP_H_ #define __TEMP_H_ #include<reg51.h> sbit DSPORT=P3^7; void Delay1ms(unsigned int ); unsigned char Ds18b20Init(); void Ds18b20WriteByte(unsigned char com); unsigned char Ds18b20ReadByte(); void Ds18b20ChangTemp(); void Ds18b20ReadTempCom(); int Ds18b20ReadTemp(); #endif 适用电路: ![]() ![]() ![]() |