/*********************************************************************************************
* 程序名 * DS18B20温度实验 串口助手显示 小数点后4位精度
* 公司名 * 石家庄芯巢科技
* 编写人 * 何新建
* 日 期 * 2015年7月16日
* 支 持 * STC90C52RC 11.0592MHz(12T)/单倍速
* 接 口 * P2.1接DS18b20
* 说 明 * 实验成功
*********************************************************************************************/
#include<reg52.h>
#include <intrins.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef char int8;
typedef int int16;
uint16 TempDec;//存放小数后4位数
bit fbj;//负号标记
sbit DQ=P2^1; //温度输入口DQ
sbit led=P2^0; //LED
void nops()//延时子函数无返回值 约4us
//误差 -0.202256944444us
{
unsigned char a;
for(a=1;a>0;a--);
}
void delay1us(void) //11.0592MHz(6T)1.0851us误差 -0.000030555556us
{
}
void delay10us(int16 n) //误差 -0.234375us
{
unsigned char a;
int16 b;//变量b如是 unsingned char型,串口助手无显示
for(b=0;b<n;b++)
for(a=5;a>0;a--);
}
void delay1ms(int16 n) //误差 -0.108506944445us
{
unsigned char a,b;
int16 c;//变量c如是 unsingned char型,串口助手无显示
for(c=0;c<n;c++)
for(b=4;b>0;b--)
for(a=113;a>0;a--);
}
/*******************************************
*DS1820复位及存在检测(通过存在脉冲可以判断DS1820是否损坏)
*函数名称:DS1820_Reset()
*说明:函数返回一个位标量(0或1)flag=0存在,反之flag=1不存在
*******************************************/
bit DS18b20_reset()
{
bit flag;
DQ=0;//拉低总线
delay10us(48);//延时480us
DQ=1;//释放总线
delay10us(6);//延时60us
flag=DQ;//对数据脚采样
return(flag);//根据flag的值可知DS1820是否存在或损坏,可加声音告警提示DS1820故障
}
/*
* 18B20写1个字节函数
* 向1-WIRE总线上写一个字节
*/
void write_byte(uint8 val)
{
uint8 i;
for (i=0; i<8; i++)
{
DQ = 1;
delay1us(); //两次传送间隔大于1us
DQ = 0;
nops(); //4us
DQ = val & 0x01; //最低位移出
delay10us(6); //60us (30US)
val >>= 1; //右移一位
}
DQ = 1;
}
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
uint8 read_byte(void)
{
uint8 i, value=0;
for (i=0; i<8; i++)
{
value >>= 1;//让从总线上读到的位数据,依次从高位移动到低位?
DQ=1;
delay1us();//1us
DQ = 0;//将总线拉低,要在1us之后释放总线
nops(); //4us //至少维持了1us,表示读时序开始
DQ = 1;
nops(); //4us
if (DQ)//控制器进行采样
value|=0x80;//若总线为1,即DQ为1,那就把dat的最高位置1;若为0,则不进行处理,保持为0
delay10us(6); //60us
}
DQ=1;
return value;
}
/*
* 启动温度转换
*/
void start_temp_sensor(void)
{
DS18b20_reset(); //DS18b20复位
delay1ms (1); // 延时1毫秒
write_byte(0xCC); // 发Skip ROM命令 写入跳过序列号命令字
write_byte(0x44);// 发转换命令 写入温度转换命令字
}
/*
* 读出温度
*/
int16 read_temp(void)
{
unsigned int value; //存放温度数值
uint8 low, high;//存放温度高低字节
DS18b20_reset(); // 复位
delay1ms (1); // 延时1毫秒
write_byte(0xCC); // 发Skip ROM命令
write_byte(0xBE); // 发读命令 写入读取数据令字
low = read_byte();//连续读取两个字节数据 先读出的是低位数据
high = read_byte();
if(high&0xfc)//判断是正温度还是负温度读数 高8位的前6位是否为1,是为负温度
{//负温度读数求补,取反加1,判断低8位是否有进位
fbj=1;//负号标记
value=((high<<8)|low);//高低字节组合
value=(((~value)+1)*0.0625)+2.6;//求反补1
TempDec=((~low)+1)&0x0f;
TempDec=TempDec*625;
}
else
{
fbj=0;
value=(((high<<8)|low)*0.0625)-2.6;//小数点以前的数2.6是误差
TempDec=(low&0x0f)*625;//小数点以后4位数
}
return value;//返回温度值
}
/**
* UART初始化
* 波特率:9600
*/
void uart_init(void)
{
TMOD = 0x21; // 定时器1工作在方式2(自动重装)T0用于定时,T1用于波特串口初始化函数
SCON = 0x50; // 10位uart,允许串行接受 //01010000设置串行通信方式1 REN=1允许接收
TH1 = 0xfd; //晶振为11.0592波特率为9600,设定的参数为9600,N,8,1
TL1 = 0xfd;
TR1=1; //启动定时器/计数器1
}
//请用实际行动支持宏晶STC大陆本土MCU统一全球市场
/*
void uart_init(void) //9600bps@11.0592MHz
{
TMOD = 0x21; // 定时器1工作在方式2(自动重装)T0用于定时,T1用于波特串口初始化函数
SCON = 0x50; // 10位uart,允许串行接受 //01010000设置串行通信方式1 REN=1允许接收
TH1=0xfd;//9600初值
TL1=0xfd;//9600重装值
TR1=1;//启动定时器
SM1=1;//这1项关闭PC端“串口助手”接收的是乱码
}
*/
/**
* UART发送一字节
*/
void UART_Send_Byte(uint8 dat)
{
SBUF = dat;//数据送发送缓冲区
while (!TI);//等待发送完成同(TI==0)
TI = 0;//清除发送完成标志位
}
/**
* 将数据转换成ASC码并通过UART发送出去
*/
void UART_Send_Dat(uint8 dat) //100度以下温度可用
{
uint8 bw,sw;
UART_Send_Byte(' ');//每行开始发送3个空格,发送一个空格,什么也不显示
UART_Send_Byte(' ');//发送一个空格,什么也不显示
UART_Send_Byte(' ');//发送一个空格,什么也不显示
if(fbj==1)//判断是正温度还是负温度读数 正为0;负为1;
{
UART_Send_Byte('-');//是向串口发送负号
}
bw=dat/100;//取出百位数值
if(bw==0)//如果百位是0
{} //如果百位是0, 什么也不显示
else//否则发送百位数值
{
UART_Send_Byte(dat/100+0x30);//取百位转换为ASCII码
}
sw=(dat%100)/10;//取出十位数值
if(bw|sw==0)//如果百位和十位都是0(bw==0|sw==0)
{}//十位百位都是0,十位0也不显示
else//否则发送十位数值
{
UART_Send_Byte((dat%100)/10+0x30);//取十位转换为ASCII码
}
UART_Send_Byte((dat%100)%10+0x30);//取个为转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte(0x2e);//发送小数点
UART_Send_Byte(TempDec/1000+0x30);//取小数十分位转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte((TempDec%1000)/100+0x30);//取小数百分位转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte(((TempDec%1000)%100)/10+0x30);//取小数千分位转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte(((TempDec%1000)%100)%10+0x30);//取小数万分位转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte(0x60);//发送温度字符
UART_Send_Byte('C');//发送温度字符
}
/*
主函数
*/
void main()
{
int16 ans;//定义变量
bit a;//定义局部位变量
a=DS18b20_reset();//调用复位函数判断DS18b20好坏
if(a==0)led=0;//如果DS18b20是好的发光管亮
uart_init();//调用串口初始化子函数
while(1)
{
start_temp_sensor();//调用温度转换子函数,
led=~led;//熄灭发光管
delay1ms (2000); // 延时1秒
ans=read_temp();//调用读出温度子函数其值赋予ans
UART_Send_Dat(ans); //待发送温度值进行转换并发送
}
}
********************************************************************
*********************************************************************
**********************************************************************
/*********************************************************************************************
* 程序名 * DS18B20温度实验 串口助手显示 小数点后4位精度
* 公司名 * 石家庄芯巢科技
* 编写人 * 何新建
* 日 期 * 2013年9月11日
* 支 持 * STC12LE5608AD3.3V 11.0592MHz
* 接 口 * P2.1接DS18b20 串口助手9600/8/N/1
* 说 明 * 实验通过正负温度显示
*********************************************************************************************/
#include<reg52.h>
#include <intrins.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef char int8;
typedef int int16;
uint16 TempDec;//存放小数后4位数
bit fbj;//负号标记
sbit DQ=P2^1; //温度输入口DQ
sbit led=P2^0; //LED
void nops()//延时子函数无返回值
{
_nop_();
_nop_();
_nop_();
_nop_();
}
void delay_us(uint16 x)//延时子函数有返回值
{
uint16 i;
x=x*5/4;
for(i=0;i<x;i++);
}
void delay_ms(uint16 n)//延时子函数有返回值
{
uint8 m=120;
while (n--)
while (m--);
}
/*******************************************
*DS1820复位及存在检测(通过存在脉冲可以判断DS1820是否损坏)
*函数名称:DS1820_Reset()
*说明:函数返回一个位标量(0或1)flag=0存在,反之flag=1不存在
*******************************************/
bit DS18b20_reset()
{
bit flag;
DQ=0;//拉低总线
delay_us(500);//延时480us
DQ=1;//释放总线
delay_us(60);//延时60us
flag=DQ;//对数据脚采样
return(flag);//根据flag的值可知DS1820是否存在或损坏,可加声音告警提示DS1820故障
}
/*
* 18B20写1个字节函数
* 向1-WIRE总线上写一个字节
*/
void write_byte(uint8 val)
{
uint8 i;
for (i=0; i<8; i++)
{
DQ = 1;
_nop_(); //两次传送间隔大于1us
DQ = 0;
nops(); //4us
DQ = val & 0x01; //最低位移出
delay_us(60); //60us (30US)
val >>= 1; //右移一位
}
DQ = 1;
}
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
uint8 read_byte(void)
{
uint8 i, value=0;
for (i=0; i<8; i++)
{
value >>= 1;//让从总线上读到的位数据,依次从高位移动到低位?
DQ=1;
_nop_();
DQ = 0;//将总线拉低,要在1us之后释放总线
nops(); //4us //至少维持了1us,表示读时序开始
DQ = 1;
nops(); //4us
if (DQ)//控制器进行采样
value|=0x80;//若总线为1,即DQ为1,那就把dat的最高位置1;若为0,则不进行处理,保持为0
delay_us(60); //60us
}
DQ=1;
return value;
}
/*
* 启动温度转换
*/
void start_temp_sensor(void)
{
DS18b20_reset(); //DS18b20复位
delay_ms (1); // 延时1毫秒
write_byte(0xCC); // 发Skip ROM命令 写入跳过序列号命令字
write_byte(0x44);// 发转换命令 写入温度转换命令字
}
/*
* 读出温度
*/
int16 read_temp(void)
{
unsigned int value; //存放温度数值
uint8 low, high;//存放温度高低字节
DS18b20_reset(); // 复位
delay_ms (1); // 延时1毫秒
write_byte(0xCC); // 发Skip ROM命令
write_byte(0xBE); // 发读命令 写入读取数据令字
low = read_byte();//连续读取两个字节数据 先读出的是低位数据
high = read_byte();
if(high&0xfc)//判断是正温度还是负温度读数 高8位的前6位是否为1,是为负温度
{//负温度读数求补,取反加1,判断低8位是否有进位
fbj=1;//负号标记
value=((high<<8)|low);//高低字节组合
value=(((~value)+1)*0.0625)+2.6;//求反补1
TempDec=((~low)+1)&0x0f;
TempDec=TempDec*625;
}
else
{
fbj=0;
value=(((high<<8)|low)*0.0625)-2.6;//小数点以前的数
TempDec=(low&0x0f)*625;//小数点以后4位数
}
return value;//返回温度值
}
/**
* UART初始化
* 波特率:9600
*/
void uart_init(void)
{
TMOD = 0x21; // 定时器1工作在方式2(自动重装)T0用于定时,T1用于波特串口初始化函数
SCON = 0x50; // 10位uart,允许串行接受 //01010000设置串行通信方式1 REN=1允许接收
TH1 = 0xfd; //晶振为11.0592波特率为9600,设定的参数为9600,N,8,1
TL1 = 0xfd;
TR1=1; //启动定时器/计数器1
}
/**
* UART发送一字节
*/
void UART_Send_Byte(uint8 dat)
{
SBUF = dat;//数据送发送缓冲区
while (!TI);//等待发送完成同(TI==0)
TI = 0;//清除发送完成标志位
}
/**
* 将数据转换成ASC码并通过UART发送出去
*/
void UART_Send_Dat(uint8 dat) //100度以下温度可用
{
uint8 bw,sw;
UART_Send_Byte(' ');//每行开始发送3个空格,发送一个空格,什么也不显示
UART_Send_Byte(' ');//发送一个空格,什么也不显示
UART_Send_Byte(' ');//发送一个空格,什么也不显示
if(fbj==1)//判断是正温度还是负温度读数 正为0;负为1;
{
UART_Send_Byte('-');//是向串口发送负号
}
bw=dat/100;//取出百位数值
if(bw==0)//如果百位是0
{} //如果百位是0, 什么也不显示
else//否则发送百位数值
{
UART_Send_Byte(dat/100+0x30);//取百位转换为ASCII码
}
sw=(dat%100)/10;//取出十位数值
if(bw|sw==0)//如果百位和十位都是0(bw==0|sw==0)
{}//十位百位都是0,十位0也不显示
else//否则发送十位数值
{
UART_Send_Byte((dat%100)/10+0x30);//取十位转换为ASCII码
}
UART_Send_Byte((dat%100)%10+0x30);//取个为转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte(0x2e);//发送小数点
UART_Send_Byte(TempDec/1000+0x30);//取小数十分位转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte((TempDec%1000)/100+0x30);//取小数百分位转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte(((TempDec%1000)%100)/10+0x30);//取小数千分位转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte(((TempDec%1000)%100)%10+0x30);//取小数万分位转换为ASCII码+0x30与+'0'同一个事
UART_Send_Byte(0x60);//发送温度字符
UART_Send_Byte('C');//发送温度字符
}
/*
主函数
*/
void main()
{
int16 ans;//定义变量
bit a;//定义局部位变量
a=DS18b20_reset();//调用复位函数判断DS18b20好坏
if(a==0)led=0;//如果DS18b20是好的发光管亮
uart_init();//调用串口初始化子函数
while(1)
{
start_temp_sensor();//调用温度转换子函数,
delay_ms (2000); // 延时1秒
led=1;//熄灭发光管
ans=read_temp();//调用读出温度子函数其值赋予ans
UART_Send_Dat(ans); //待发送温度值进行转换并发送
}
} |