由于DS18B20是单线操作,所以必须严格遵守它的时序要求才能正常与之建立联系并实现读写操作。
网上见到的程序多是在主程序中以延时的方式实现,而且要求关中断,以实现18B20对时序的要求。但是实际应用中,测温操作一般是作为辅助功能,主要任务是通信及数据处理等其他操作,这样一来,如果将DS18B20的程序代码放在主程序中,势必影响其他需要实时处理的中断。
前些天用到DS18B20,就尝试以51定时中断的方法实现DS18B20时序,在面包板上成功跑了起来。
用的单片机是STC11F16XE,使用外部晶振24MHz。下面的程序中不仅有DS18B20的操作,还包含了数码管显示、按键检测、EEPROM的操作。定时器T1专门用于DS18B20时序产生,定时器T0用于按键检测、数码管显示,主函数中做EEPROM及其他的操作。程序中有些注释是调试过程中加的,并且有些代码部分在调试中修改过,先前的注释并没有同时删去,所以看下面的代码的时候,不要被注释误导了。
代码如下:
#include "REG51.H"
#include "INTRINS.H"
typedef unsigned char BYTE;
typedef unsigned int WORD;
sfr P1M0 = 0x92; //
sfr P1M1 = 0x91; //
sfr P3M0 = 0xB2;
sfr P3M1 = 0xB1;
sfr P2M0 = 0x96;
sfr P2M1 = 0x95;
/*sfr associated with the IAP*/
sfr IAP_DATA = 0xc2;
sfr IAP_ADDRH = 0xc3;
sfr IAP_ADDRL = 0xc4;
sfr IAP_CMD = 0xc5;
sfr IAP_TRIG = 0xc6;
sfr IAP_CONTR = 0xc7;
/*ISP/IAP/EEPROM command*/
#define CMD_IDLE 0
#define CMD_READ 1
#define CMD_PROGRAM 2
#define CMD_ERASE 3
#define ENABLE_IAP 0x80 //if SYSCLK<30MHz
//#define ENABLE_IAP 0x81//if SYSCLK<24MHz
//start address for STC11/10xx series EEPROM
#define IAP_ADDRESS0x0000
void Delay(BYTE N);
void IapIdle();
BYTE IapReadByte(WORD addr);
void IapProgramByte(WORD addr, BYTE val);
void IapEraseSector(WORD addr);
#define MINUTE 8400 //60*140=8400 interrupts per minute
#define DAY3S 4320 //there are 72*60*8400=4320*8400 interrupts in 72 hours
//
sbit shi = P3^7;
sbit ge = P3^2;
//sbit led = P1^5;
sbit key1 = P3^3;
sbit key2 = P3^4;
sbit key3 = P3^5;
sbit heat = P2^7;
sbit water = P2^5;
sbit beep = P2^0;
unsigned char code digit[11] ={
0xbf,//0
0x83,//1
0xed,//2
0xeb,//3
0xd3,//4
0xfa,//5
0xfe,//6
0xa3,//7
0xff,//8
0xfb,//9
0xc0//nfinished
};
unsigned char code cmd[4] = {0xcc,0x44,0xcc,0xbe};
unsigned int cmd_n;
bit nodevice,cunz;
unsigned char saom;
unsigned int num,t1_num;
unsigned char temp,led;
unsigned int jiaoshui,jiaoshui_t,jiaoshui_tt;
unsigned char wendu,cishu;
unsigned int ds18b20;
unsigned char menu,inc,dec;
BYTE kflag; //
bit adjust;
bit updateEEP;
unsigned int heat_t;
sbit DQ = P3^1; //DS18B20?????P3.3
BYTE TPH; //?????????
BYTE TPL; //?????????
BYTE dat;
void main()
{
updateEEP = 0;
num = 0;
temp = 0;
saom = 0;
led = 0x00;
nodevice = 0;
menu = 0;
inc = 0;
dec = 0;
kflag = 0x00;
adjust = 0;
wendu = 50;
cishu = 72;
heat = 1;
water = 1;
jiaoshui = 0;
jiaoshui_t = 1;
jiaoshui_tt = 0;
P2M0 = 0x01;
P2M1 = 0x00;
beep = 0;
P1M0 = 0xff; //
P1M1 = 0x00; //
// P1 = digit[0];
P3M0 = 0x84; //
P3M1 = 0x84;
P3 = 0X0;
TMOD = 0x11; //TMOD = 0x1;
TH0 = 0x00;
TL0 = 0xff;
TR0 = 1;
ET0 = 1;
TH1 = 0xff;
TL1 = 0x88;//256-120=136=0x88
TR1 = 0;
ET1 = 1; // enable T1 interrupt
PT0 = 0;
PT1 = 1; // T1优先级高
EA = 1;
//read wendu and cishu value from EEPROM
Delay(10);
wendu = IapReadByte(0x0002);
cishu = IapReadByte(0x0003);
jiaoshui = 8400/cishu;
//
while (1)
{
if(updateEEP == 1)
{
updateEEP = 0;
IapEraseSector(0x0000);
IapProgramByte(0x0002,wendu);
IapProgramByte(0x0003,cishu);
jiaoshui = 8400/cishu;
}
beep= (ds18b20>30)? 1:0;
heat= (ds18b20>30)? 0:1;
water=(jiaoshui_t<420)? 0:1;
// beep= (jiaoshui_t<420)? 1:0;
}
}
/
void it_timer0(void) interrupt 1
{
TH0 = 0xc8; //定时时间是1/140s
TL0 = 0x32;
num++;
/*
if(jiaoshui_t
0) wendu--;
else wendu=0;
kflag = 0x00; break;}
else if(menu==2)
{if(cishu>0) cishu--;
else cishu=0;
kflag = 0x00; break;}
else break;
default ://??????????????
break;
}
// P1M0 = 0xff;
// P1M1 = 0x00;
//显示
saom++;
saom = saom%3;
switch(menu)
{
case 0 : temp = ds18b20; led = 0x00; break;
case 1 : temp = wendu; led = 0x02; break;
case 2 : temp = cishu; led = 0x01; break;
default : temp = ds18b20; break;
}
if(nodevice)
{
shi = 0;
ge = 0;
P1 = digit[10];
}
else
switch(saom)
{
case 0 :
shi = 0;
ge = 1;
P1 = digit[temp/10];
break;
case 1 :
shi = 1;
ge = 0;
P1 = digit[temp%10];
break;
case 2 :
shi = 1;
ge = 1;
if(num < 80) P1 = led;
else P1 = 0x80;
break;
default : break;
}
/*
//加热定时
if(ds18b20>30) {heat = 1; heat_t++;}
if((heat_t > 0) && (heat_t < 1400))
{heat_t++;}
else {heat_t = 0; heat = 0;}
*/
//采集18B20
if(num>=140)
{
num = 0;
t1_num = 0; cmd_n = 0; nodevice = 0;
TR1 = 1;
}
}
void it_timer1(void) interrupt 3
{
switch(t1_num)
{
case 0 :
case 33 :
cunz = 1; DQ = 0; break;
case 8 :
case 41 :
DQ = 1; break;
case 9 :
case 42 :
cunz = DQ; break;
case 16 : //写字节 第一位
case 49 :
if(cunz) {/*ET1 = 0;*/TR1 = 0; nodevice = 1; break;}
else
{
dat = cmd[cmd_n++]; DQ = 0; _nop_(); _nop_();
dat >>= 1; DQ = CY; break;
}
case 17 : //cmd[0]
case 18 :
case 19 :
case 20 :
case 21 :
case 22 :
case 23 :
case 25 : //cmd[1]
case 26 :
case 27 :
case 28 :
case 29 :
case 30 :
case 31 :
case 50 : //cmd[2]
case 51 :
case 52 :
case 53 :
case 54 :
case 55 :
case 56 :
case 58 : //cmd[3]
case 59 :
case 60 :
case 61 :
case 62 :
case 63 :
case 64 :
DQ = 1; _nop_(); _nop_(); //恢复数据线,恢复时间
DQ = 0; _nop_(); _nop_(); //开始下一位
dat >>= 1; DQ = CY; break;
case 24 :
case 57 :
DQ = 1; _nop_(); _nop_(); //写第一个字节结束
dat = cmd[cmd_n++]; //填充dat
DQ = 0; _nop_(); _nop_(); //写第二个字节
dat >>= 1; DQ = CY; break;
case 32 :
DQ = 1; _nop_(); _nop_(); //写第二个字节结束 0x44
_nop_(); _nop_();
case 65 :
DQ = 1; _nop_(); _nop_(); //0xbe 命令发完
dat = 0; //读TPL
dat >>= 1;
DQ = 0; _nop_(); _nop_();
DQ = 1; _nop_(); _nop_();
if(DQ) dat |= 0x80;
break;
case 66 :
case 67 :
case 68 :
case 69 :
case 70 :
case 71 :
case 72 :
case 74 :
case 75 :
case 76 :
case 77 :
case 78 :
case 79 :
case 80 :
dat >>= 1;
DQ = 0; _nop_(); _nop_();
DQ = 1; _nop_(); _nop_();
if(DQ) dat |= 0x80;
break;
case 73 :
TPL = dat;
dat = 0; //读TPH
dat >>= 1;
DQ = 0; _nop_(); _nop_();
DQ = 1; _nop_(); _nop_();
if(DQ) dat |= 0x80;
break;
case 81 :
TPH = dat;
TPL = (TPL>>4) & 0x0f;
TPH = (TPH<<4) & 0xf0;
ds18b20 = TPL | TPH;
if(ds18b20>99 | ds18b20 <=0)
nodevice = 1;
TR1 = 0;
break;
default : break;
}
t1_num++;
TH1 = 0xff;
TL1 = 0x88;//256-120=136=0x88
}
//
void Delay(BYTE n)
{
WORD x;
while(n--)
{
x = 0;
while(++x);
}
}
void IapIdle()
{
IAP_CONTR = 0;
IAP_CMD = 0;
IAP_TRIG = 0;
IAP_ADDRH = 0xff;
IAP_ADDRL = 0xff;
}
BYTE IapReadByte(WORD addr)
{
BYTE rdval;
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_READ;
IAP_ADDRL = addr;
IAP_ADDRH = addr >> 8;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
rdval = IAP_DATA;
IapIdle();
return rdval;
}
void IapProgramByte(WORD addr, BYTE val)
{
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_PROGRAM;
IAP_ADDRL = addr;
IAP_ADDRH = addr >> 8;
IAP_DATA = val;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
IapIdle();
}
void IapEraseSector(WORD addr)
{
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_ERASE;
IAP_ADDRL = addr;
IAP_ADDRH = addr >> 8;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
IapIdle();
}
上一篇:单片机_LCD12864显示自己制作的图片(时钟为例)
下一篇:基于单片机的电梯(四层)控制系统设计
推荐阅读

推荐帖子
- 一种低功耗的热释电人体感应模块
- GH-718人体感应模块 [■应用范围 ■安防产品■人体感应玩具■人体感应灯具■工业自动化控制等 主要技术参数: 1使用工作电压:DC4.5~20V 2静态电流:50uA 3电平输出:高3.3V低0V 4保持时间:3-900秒可调 5感应角度:110度 6感应距离:7M 详细资料下载 [本帖最后由珊珊于2008-12-1410:30编辑]一种低功耗的热释电人体感应模块
-
珊珊
安防电子
- 使用BBB的IO口
- 本帖最后由wytalfred于2014-3-821:40编辑 从Terminal直接控制IO口的方法如下:root@beaglebone:~#cd/sys/class/gpio root@beaglebone:/sys/class/gpio#ls-l total0 --w-------1rootroot4096Jan100:00export lrwxrwxrwx1rootroot0Jan100:00gpiochip0->../../dev
-
wytalfred
DSP 与 ARM 处理器
- 体贴的戒指闹钟
- 前些时体贴的戒指闹钟 间我发了一个帖子问有没有给一个人的闹钟。现在有了[体贴的戒指闹钟 ],情侣双方很多时候可能会遇到起床时间不同,设计不同时间的闹钟的话会打扰到对方,可这款设计不会像普通闹钟一样靠刺耳的声音催人起床,而是通过另一种温柔的方式让人慢慢醒来。看来和我想法一样的人还大有人在啊体贴的戒指闹钟
-
xyh_521
创意市集
- 请问这个应该调用何函数?
- 我用监视器在串口上获得串口请求如下,请问调用哪2个API才能得到下面的请求呢? IOCTL_SERIAL_SET_WAIT_MASK IOCTL_SERIAL_WAIT_ON_MASK PS:比如,调用ReadFile,获得的请求为IRP_MJ_READ; WriteFile为IRP_MJ_WRITE; ClearCommError为IOCTL_SERIAL_GET_COMMSTATUS。 非常感谢!!!!!!!!!请问这个应该调用何函数?
-
xtaccount
嵌入式系统
- 2013f题复测
- 本帖最后由paulhyde于2014-9-1503:06编辑2013f题复测 2013f题复测
-
2357470983
电子竞赛
- 【行空板 Python编程学习主控板测评】开发环境与开机配置
- 本帖最后由jinyi7016于2022-10-3110:59编辑 首先感应EEWORLD与DFRobot选择我进行这些行空板的试用。收到开发板后,第一时间开箱开机开发板有两种配件,一个是一条Type-c的USB线,这条线是两用的,还可以连接microusb接口,还有一些ph2.0的3P与4P的连接线,可以连接DFRobot的一些模块。行空板的教程,都可以在这里找到:行空板官方教程-wiki.unihiker.com一、芯片组行空板的硬件资源很丰富,如下所示:
-
jinyi7016
嵌入式系统
设计资源 培训 开发板 精华推荐
最新视频课程更多
- 用VS2005开发WINCE程序,安装WinCE 5.0 Device Emulator时,提示要WIN2000 SP4或者WINXP SP1才能安装,我是WI
- 今天把文件系统成功移植到STM32上了
- 说说多核DSP C6678 SRIO借口调试记录
- 晒WEBENCH设计的过程+输出5V电压1A电流电源适配器方案
- 什么时候我能看懂这个坛子里面大部分的贴?
- 形象化的理解STM32的NVIC.请版主和高手指正.
- wince和mobile交流群2 群号:68385705,欢迎做Wince和Mobile方面的底层和上层的软件开发的相关人员加入,现还有部分名额
- 关于工控论坛的IGBT问题。。。
- EEWORLD大学堂----test
- 过来人能给电子,自动化专业学习者一点经验?