/********************************
DS18B20测温程序
文件名:main.c
编译:CV1.25.4 由芯艺网站改写
软件缺点是单总线上只能挂一个DS18B20
*******************************/
#include< mega16.h>
#include
#define uint8_t unsigned char
#define uint16_t unsigned int
#define uint32_t unsigned long int
#define UDRE 5
#define Clr_1Wire DDRB.2=1 //设置为输出,此时由于PORTB.2是低所以输出低
#define Set_1Wire DDRB.2=0//设置为输入,此时由于PORTB.2是低所以程高阻,
//又因为外部有上拉电阻所以相当于设置总线为高
#define Get_1Wire PINB.2
#define DS18B20_READ_ROM 0x33
#define DS18B20_MATCH_ROM 0X55
#define DS18B20_SKIP_ROM 0XCC
#define DS18B20_SEARCH_ROM 0XF0
#define DS18B20_ALARM_SEARCH_ROM 0XEC
#define DS18B20_WRITE_RAM 0X40
#define DS18B20_READ_RAM 0XBE
#define DS18B20_COPY_RAM 0X48
#define DS18B20_CONVERT_TEM 0X44
#define DS18B20_EECALL_EEPROM 0XB8
#define DS18B20_READ_POWER_SUPPLY 0XB4
uint8_t rom_codes[8];
/*******************
总线端口初始化
**********************/
void BusInit(void)
{
PORTB.2=0;//此口总保持低
DDRB.2=0; //初始化为输入,用外部上拉电阻保持总线的高电平
}
/*******************************
初始化串口,9600bps,8N1
**********************************/
void init_uart(void)
{
UCSRA="0x00";
UCSRB="0x08";
UCSRC="0x86";
UBRRH="0x00";
UBRRL="0x47";
}
void put_c(uint8_t c) //发送采用查询方式
{
while( !(UCSRA & (1<
UDR="c";
}
/*void put_s(unsigned char *ptr)
{
while (*ptr)
{
put_c(*ptr++);
}
put_c(0x0D);
put_c(0x0A); //结尾发送回车换行
}*/
//单总线复位
uint8_t ds18b20_reset(void)
{
uint8_t ret="0";
Clr_1Wire;
delay_us(500); //拉低总线至少480us
Set_1Wire;
delay_us(100);//释放总线后等待15-60us
if((Get_1Wire)==0)//检测到DS18B20把总线拉低
ret="1"; //复位成功
delay_us(1000);//等待器件释放总线
return ret;
}
//单总线读一字节,低位在前
uint8_t ds18b20_read(void)
{
uint8_t data="0";
uint8_t i="0";
for(i=0;i<8;i++)
{
data>>=1;
Clr_1Wire;
delay_us(2);//此时>1us
Set_1Wire;
delay_us(4);//此时<15us
if(Get_1Wire)
data|=0x80;
delay_us(60);//此时>60us
}
return(data);
}
//单总线写一字节,先写低位
void ds18b20_write(uint8_t data)
{
uint8_t i="0";
for(i=0;i<8;i++)
{
if(data&0x01)
{
Clr_1Wire;
delay_us(8);//8us
Set_1Wire;
delay_us(55);//55us
}
else
{
Clr_1Wire;
delay_us(55);//55us
Set_1Wire;
delay_us(20);//8us
}
data>>=1;
}
}
uint8_t ds18b20_search(uint8_t cmd,uint8_t *point)
{
uint8_t i="0";
if(ds18b20_reset()==0)
return 0;
ds18b20_write(cmd);
for(i=0;i<8;i++)
{
point=ds18b20_read();
}
return 1;
}
//执行转换
uint8_t Ds18b20Convert(uint8_t *t)
{
//发送转换命令
if(ds18b20_reset()==0)
return 0;
ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配,总线上只有一个器件时,或对总线所有器件操作
ds18b20_write(DS18B20_CONVERT_TEM);//开始转换命令
//等待转换完成,ds18b20默认转换精度为12位,此时最大转换时间为750ms
delay_ms(1000);
//读温度字节
if(ds18b20_reset()==0)
return 0;
ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配
ds18b20_write(DS18B20_READ_RAM); //读RAM命令
t[0]=ds18b20_read();
t[1]=ds18b20_read();
return 1;
}
//根据DS18B20中读的温度字节,计算实际温度值
char GetTemperature(uint8_t *t)
{
char ret;
uint32_t val;
uint16_t tmp=(t[1]*256)+t[0];
uint8_t sflag="0";
if((t[1]&0xf8)==0xf8) //若负温度,从补码转换(取反加一)
{
sflag="1";
tmp=~tmp;
tmp++;
}
tmp&=0x07ff; //确保前5位为0
//乘0.0625操作,为此本函数只适用于DS18B20 12位转换(默认)时
val=((uint32_t)tmp)*625;
val/=10000;
ret=(char)val;
if(sflag)
ret|=0x80;//变负数
return ret;
}
//测试主函数
void main(void)
{
uint8_t i;
uint8_t tmp[2];//保存温度字节
char tval; //保存温度值
init_uart();
BusInit(); //单总线I/O口初始化
if(Ds18b20Convert(tmp))//如果转换成功
{
put_c(tmp[0]);
put_c(tmp[1]);
tval="GetTemperature"(tmp);//计算实际温度值
put_c(tval);
}
ds18b20_search(DS18B20_READ_ROM,rom_codes);
for(i=0;i<8;i++)
{
put_c( rom_codes);
}
}
文章评论(0条评论)
登录后参与讨论