单总线协议简介
- 单总线延时函数
//单总线延时函数,此处延时函数很重要,根据自己的时钟频率而定
void Delay_OneWire(unsigned int t) //Y5指令集,FOSC:11059200L,软件延时15us(t=1)
{
unsigned char i;
for(;t>0;t--)
{
i = 39;
while(--i);
}
}
- 单总线写时序
//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(2);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(2);
}
- 单总线读时序
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(2);
}
return dat;
}
ds18b20初始化
//DS18B20设备初始化
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(2);
DQ = 0;
Delay_OneWire(36);
DQ = 1;
Delay_OneWire(2);
initflag = DQ;
Delay_OneWire(6);
return initflag;
}
ds18b20读取温度函数
//读取温度
float rd_temperature(void)
{
unsigned int temp;
float temperature;
unsigned char low,high;
init_ds18b20();
Write_DS18B20(0xCC); //忽略ROM指令
Write_DS18B20(0x44); //启动温度转换
Delay_OneWire(100); //1ms->等待温度转换 ---MAX(750ms)
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE); //读取寄存器
low = Read_DS18B20();
high = Read_DS18B20();
/**精度为0.0625摄氏度**/
temp = high;
temp <<= 8;
temp |= low;
temperature = (float)temp*0.0625;
return temperature;
}
主函数部分
- 此处有些杂乱
#include "reg52.h"
#include "ds18b20.h"
#define FOSC 11059200L
#define T1MS (65536-FOSC/1000) //1T模式
#define N 10
sfr AUXR = 0x8e;
sbit N_RELAY = P0^4;
sbit N_BUZZ = P0^6;
sbit LED_1 = P0^0;
sbit LED_2 = P0^1;
unsigned char code Duan[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //共阴极段选0~9
unsigned char code Wei[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //共阴极位选 1--8
unsigned char c[N];
unsigned char SMG_chai(unsigned int t);
float temperature = 0;
unsigned int t = 58;
unsigned char s=0,i1=0;
void T0Init()
{
AUXR |= 0x80; //定时器0为1T模式
// AUXR &= 0x7f; //定时器0为12T模式
TMOD = 0x00; //设置定时器为模式0(16位自动重装载)
TL0 = T1MS; //初始化计时值
TH0 = T1MS >> 8;
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
}
void main()
{
T0Init();
P2 = 0xa0; N_BUZZ=0; N_RELAY=0; P2 = 0x00;
P2 = 0x80; P0=0xff; P2 = 0x00;
while(1)
{
if(temperature < 28)
{
P2 = 0x80; P0=0xff; LED_1=0; LED_2=0; P2 = 0x00;
}
else
{
P2 = 0x80; P0=0xff; LED_2=0; P2 = 0x00;
}
i1 = SMG_chai(temperature);
//注释:锁存器真麻烦
// P0=0x00; P2 = 0xc0; P2 = 0x00; //关闭下位选,达到消隐的目的。
P0=0xff; //关闭下段选,达到消隐的目的。
P2 = 0xe0; P0=~Duan[c[s]]; P2 = 0x00;
P0=0x00; //进入位选前先把P0清零,禁止选通数码管。
P2 = 0xc0; P0=~Wei[7-s]; P2 = 0x00;
P0=0xff;
}
}
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1
{
static int count = 1000;
if(s<i1)
{
s++;
}
else
s=0;
if(count-- == 0)
{
count = 1000;
temperature = rd_temperature();
}
}
unsigned char SMG_chai(unsigned int t)
{
unsigned char i=0;
if(t<10)
c[i]=t;
else
{
while(1)
{
c[i]=t%10;
t=t/10;
i++;
if(t<10)
break;
}
c[i]=t;
}
return i;
}
小结
-
程序还有许多可改进之处,欢迎各路大神批评指正。
-
单总线协议对时序要求严格,一定按照datasheet给的时序一步一步写;读取到错误值4095或者没有值,一定先检查时序。
-
CT107D开发板的锁存器可能有其独到之处,首先节省了IO口,其次作为驱动使用,但是在使用之时注意何时开何时关。
-
写程序逻辑和时序很重要。
-
溜了溜了~~~