天天看點

單片機的ds18b20程式

ds18b20對時序要求很高,是以一定要注意延時

下面是32單片機的程式

//複位DS18B20
void DS18B20_Rst(void)	   
{                 
	DS18B20_IO_OUT(); 	//SET PG11 OUTPUT
    DS18B20_DQ_OUT=0; 	//拉低DQ
    delay_us(750);    	//延時750us
    DS18B20_DQ_OUT=1; 	//DQ=1 
	delay_us(15);     	//15US
}

//等待DS18B20的回應
//傳回1:未檢測到DS18B20的存在
//傳回0:存在
u8 DS18B20_Check(void) 	   
{   
	u8 retry=0;
	DS18B20_IO_IN();	//SET PG11 INPUT	 
    while (DS18B20_DQ_IN&&retry<200)
	{
		retry++;
		delay_us(1);
	};	 
	if(retry>=200)return 1;
	else retry=0;
    while (!DS18B20_DQ_IN&&retry<240)
	{
		retry++;
		delay_us(1);
	};
	if(retry>=240)return 1;	    
	return 0;
}

//從DS18B20讀取一位
//傳回1/0
u8 DS18B20_Read_Bit(void) 	 
{
    u8 data;
	DS18B20_IO_OUT();	//SET PG11 OUTPUT
    DS18B20_DQ_OUT=0; 
	delay_us(2);
    DS18B20_DQ_OUT=1; 
	DS18B20_IO_IN();	//SET PG11 INPUT
	delay_us(12);
	if(DS18B20_DQ_IN)data=1;
    else data=0;	 
    delay_us(50);           
    return data;
}

//從DS18B20讀取一個位元組
u8 DS18B20_Read_Byte(void)     
{        
    u8 i,j,dat;
    dat=0;
	for (i=1;i<=8;i++) 
	{
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }						    
    return dat;
}

//寫一個位元組到DS18B20
void DS18B20_Write_Byte(u8 dat)     
 {             
    u8 j;
    u8 testb;
	DS18B20_IO_OUT();	//SET PG11 OUTPUT;
    for (j=1;j<=8;j++) 
	{
        testb=dat&0x01;
        dat=dat>>1;
        if (testb) 
        {
            DS18B20_DQ_OUT=0;	// Write 1
            delay_us(2);                            
            DS18B20_DQ_OUT=1;
            delay_us(60);             
        }
        else 
        {
            DS18B20_DQ_OUT=0;	// Write 0
            delay_us(60);             
            DS18B20_DQ_OUT=1;
            delay_us(2);                          
        }
    }
}

//開始溫度轉換
void DS18B20_Start(void) 
{   						               
    DS18B20_Rst();	   
	DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	// skip rom
    DS18B20_Write_Byte(0x44);	// convert
} 

//初始化DS18B20的DQ 同時檢測DS18B20的存在
//傳回1:不存在
//傳回0:存在   	 
u8 DS18B20_Init(void)
{
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;		
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		  
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOC, &GPIO_InitStructure);

 	GPIO_SetBits(GPIOC,GPIO_Pin_10);    //拉高

	DS18B20_Rst();

	return DS18B20_Check();
}  

//從ds18b20得到溫度值
//精度0.1C
short DS18B20_Get_Temp(void)
{
    u8 temp;
    u8 TL,TH;
	short tem;
    DS18B20_Start ();  			// ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);	// skip rom
    DS18B20_Write_Byte(0xbe);	// convert	    
    TL=DS18B20_Read_Byte(); 	// LSB 
    TH=DS18B20_Read_Byte(); 	// MSB  
		USART_SendData(USART1, TL);
		delay_ms(10);
		USART_SendData(USART1, TH);
	   	  
    if(TH>7)
    {
        TH=~TH;
        TL=~TL; 
        temp=0;					//溫度為負
    }else temp=1;				//溫度為正  	  
    tem=TH; 					
    tem<<=8;    
    tem+=TL;					
    tem=(float)tem*0.625;		
	if(temp)return tem; 	
	else return -tem;    
}

           

然後這裡是51單片機的程式

這裡我用的是12M晶振,延時程式如下

/*us延時,參數為1時約延時7us
			  10時約延時50us
			 100時約延時205us
			 250時約延時480us	
*/
void delay(uchar us) {
	while(us--);
}
           

然後下面就是對DQ信号線操作的程式

//複位ds18b20
void Init_ds18b20(void) {
	DQ = 1; 
	delay(1); 
	DQ = 0; 
	delay(250); 
	DQ = 1; 
	delay(100);
}

//讀一個位元組
uchar ReadoneByte() {
	uchar i;
	uchar dat = 0;
	for(i=8; i>0; i--) {
		DQ = 0;
		_nop_();
		dat >>= 1;
		DQ = 1;
		delay(1);
		if(DQ) dat |= 0x80;
		delay(10);
	}
	return dat;
}

//寫一個位元組
void WriteoneByte(uchar dat) {
	uchar i;
	for(i=8; i>0; i--) {
		DQ = 0;
		_nop_();
		DQ = dat & 0x01;
		delay(10);
		DQ = 1;
		dat >>= 1;
		delay(1);
	}
}

//擷取溫度值
int GetTempe() {
	int temp;
	uchar teml, temh;
	Init_ds18b20();
	WriteoneByte(0xcc);
	WriteoneByte(0x44);
	Init_ds18b20();
	WriteoneByte(0xcc);
	WriteoneByte(0xbe);
	teml = ReadoneByte();//先讀低四位
	temh = ReadoneByte();//再讀高四位
	
	temp = teml/16+temh*16;//這裡隻保留了整數,去掉了小數
	//temp <<= 8;
	//temp += teml;
	//t = temp * 0.625;
	return temp;
}