用18b20 測試溫度是非常常用的,不過18B20的調試不是這么容易的,有些內容網上很多的,不再重復說了,我先把波形說一下,再說程序部分:
整個都溫度數據的順序是:
1.700uS的低電平復位并測試18B20的低電平響應
2.主機發送0xCC,0x44兩個字節,表示跳過地址,只有一個18B20就不需要地址
3.再次復位
4.發送0xCC,0xBE,兩個字節讓它轉換溫度
5.讀取2個字節,這兩個字節就是溫度了。
6.這兩個字節乘0.625就是溫度了。
有一點說明一下,主機輸出用GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;用開漏不行。
代碼貼一下:
void b12_18b20_in()
{GPIO_InitStruct.Pin = GPIO_PIN_12;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void b12_18b20_out()
{GPIO_InitStruct.Pin = GPIO_PIN_12;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
管腳自己注意一下
#define DS18B20_DQ_OUT0 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET)
#define DS18B20_DQ_OUT1 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET)#define DS18B20_DQ_IN HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12)
void DS18B20_Reset(void)
{//設置DS18B20為輸出模式b12_18b20_out();//拉低總線480-960usDS18B20_DQ_OUT0;delay_us(660);//釋放總線15-60usDS18B20_DQ_OUT1;delay_us(15);
}//等待DS18B20的回應
//返回1:未檢測到DS18B20的存在 返回0:存在
uint8_t DS18B20_Check(void)
{uint8_t retry = 0;b12_18b20_in(); //設置為輸入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
//dat:要寫入的字節
void DS18B20_Write_Byte(uint8_t dat){uint8_t j;uint8_t testb;b12_18b20_out(); //設置為輸出for (j=1;j<=8;j++){testb=dat&0x01;dat=dat>>1;if (testb) //輸出高{DS18B20_DQ_OUT0; //輸出低電平delay_us(2); //延時2usDS18B20_DQ_OUT1; //輸出高電平delay_us(60); //延時60us}else //輸出低{DS18B20_DQ_OUT0; //輸出低電平delay_us(60); //延時60usDS18B20_DQ_OUT1; //輸出高電平delay_us(2); //延時2us}}
}//從DS18B20讀取一個位
//返回值:1/0
uint8_t DS18B20_Read_Bit(void) //讀一位
{uint8_t data;b12_18b20_out(); //設置為輸出DS18B20_DQ_OUT0; //輸出低電平delay_us(2);DS18B20_DQ_OUT1; //拉高b12_18b20_in(); //設置為輸入delay_us(12); //延時12usif(DS18B20_DQ_IN)data=1; //讀取總線數據else data=0;delay_us(50); //延時50usreturn data;
}//從DS18B20讀取一個字節
//返回值:讀到的數據
uint8_t DS18B20_Read_Byte(void) //讀一字節
{uint8_t i,j,dat;dat=0;for (i=1;i<=8;i++){j=DS18B20_Read_Bit();dat=(j<<7)|(dat>>1);}return dat;
}void DS18B20_start()
{DS18B20_Reset();DS18B20_Check();DS18B20_Write_Byte(0xCC);DS18B20_Write_Byte(0x44);
}short Get_temp(void){uint8_t temp;short tem;DS18B20_start();DS18B20_Reset();DS18B20_Check();DS18B20_Write_Byte(0xCC);DS18B20_Write_Byte(0xBE);uint8_t TL = DS18B20_Read_Byte();uint8_t TH = DS18B20_Read_Byte();if( TH > 7 ){temp = 0; //溫度為負TH = ~TH;TL = ~TL;}else{temp = 1; //溫度為正}tem = TH;tem <<= 8;tem += TL;//printf("=== %f\r\n", tem);tem = tem * 6.25;if(temp == 1){return tem;}else{return ~tem;}}
輸出
short temp = Get_temp();uint16_t t = temp ;printf("wendu = %02d.%02d\r\n" , t/100, t%100);
因為浮點數直接打印有點問題,現在這樣如果有負問題可能存在問題,自己注意一下。
使用了short。
us延時函數看我的前面一篇文章。