DS18B20是一款单总线驱动的温度传感器,占用口线少,驱动简单,只要按照协议发出符合时序要求的信号,就可以得到温度数据。
典型应用电路:
我这里使用的第一种应用电路,使用PB4连接DQ端。为了方便驳接,我选择的是现成的模块:
是用杜邦线连接到开发板上。
简单的读取温度值的步骤如下:
1、跳过ROM操作。
2、发送温度转换命令。
3、跳过ROM操作。
4、发送读取温度命令。
5、读取温度值。
DS18B20温度传感器的初始化
主器件首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有DS18B20温度传感器已做出应答。若无低电平出现一直都是高电平说明总线上无DS18B20温度传感器应答。 做为从器件的DS18B20温度传感器在一上电后就一直在检测总线上是否有480-960微秒的低电平出现,如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,告诉主机本器件已做好准备。若没有检测到就一直在检测等待。
DS18B20温度传感器的写操作
写周期最少为60微秒,最长不超过120微秒。写周期一开始主器件先把总线拉低1微秒表示写周期开始。随后若主器件想写0,则将总线置为低电平,若主器件想写1,则将总线置为高电平,持续时间最少60微秒直至写周期结束,然后释放总线为高电平至少1微秒给总线恢复 。而DS18B20温度传感器则在检测到总线被拉底后等待15微秒然后从15us到45us开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0。
工程使用80MHZ的主频,DS18B20的驱动程序如下:
- #include "ds18b20.h"
- // 初始化18B20用到的GPIO口:PB4,输出模式
- static void gpio_config_DS18B20_Out(void) {
- gpio_init_type gpio_initstructure;
-
- crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
-
- gpio_default_para_init(&gpio_initstructure);
- /* DATA引脚:PB5 */
- gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
- gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
- gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
- gpio_initstructure.gpio_pins = DS18B20_DATA_PIN;
- gpio_initstructure.gpio_pull = GPIO_PULL_UP;
- gpio_init(GPIOB, &gpio_initstructure);
- }
- // 初始化18B20用到的GPIO口:PB4,输入模式
- static void gpio_config_DS18B20_In(void) {
- gpio_init_type gpio_initstructure;
-
- gpio_default_para_init(&gpio_initstructure);
- /* DATA引脚:PB5 */
- gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
- gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
- gpio_initstructure.gpio_mode = GPIO_MODE_INPUT;
- gpio_initstructure.gpio_pins = DS18B20_DATA_PIN;
- gpio_initstructure.gpio_pull = GPIO_PULL_UP;
- gpio_init(GPIOB, &gpio_initstructure);
- }
- void Ds18b20Rst(void) {
- gpio_config_DS18B20_Out();
-
- gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
- delay_us(750); //主机发送复位脉冲480us-960us
- gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
-
- delay_us(25);//18b20等待15-60us
- }
-
- /*等待18b20响应
- * 返回1:未检测到18b20
- * 返回0:存在
- */
- uint8_t Ds18b20Check(void) {
- uint8_t retry=0;
-
- // 输入模式
- gpio_config_DS18B20_In();
- while(gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN) && retry < 200) {
- retry++;
- delay_us(1);
- }
-
- if(retry>=200)return 1;
- else retry=0;
-
- while(!gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN) && retry < 240) {
- retry++;
- delay_us(1);
- }
- if(retry>240)return 1;
- return 0;
- }
- /*从18b20读取一个位
- * 返回值1/0
- */
- uint8_t Ds18b20ReadBit(void) {
- uint8_t data;
- gpio_config_DS18B20_Out();
- gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
-
- delay_us(2);
-
- gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
-
- // 输入模式
- gpio_config_DS18B20_In();
- delay_us(12);
-
- if(gpio_input_data_bit_read(DS18B20_PORT, DS18B20_DATA_PIN)) data=1;
- else data=0;
-
- delay_us(50);
- return data;
- }
- /*从18b20读取一个字节
- * 返回值:读到的数据
- */
- uint8_t Ds18b20ReadByte(void) {
- uint8_t i,j,dat;
- dat=0;
- for(i=1;i<=8;i++) {
- j=Ds18b20ReadBit();
- dat=(j<<7)|(dat>>1);//低位在前
- }
- return dat;
- }
- /*写一个字节到Ds18b20
- * dat:要写入的字节
- */
- void Ds18b20WriteByte(uint8_t dat) {
- uint8_t i;
- uint8_t temp;
- gpio_config_DS18B20_Out();
- for(i=1;i<=8;i++) {
- temp=dat&0x01;
- dat=dat>>1;
- if (temp) {
- // 输出1
- gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
- delay_us(2);
- gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
- delay_us(60);
- } else {
- // 输出0
- gpio_bits_reset(DS18B20_PORT, DS18B20_DATA_PIN);
- delay_us(60);
- gpio_bits_set(DS18B20_PORT, DS18B20_DATA_PIN);
- delay_us(2);
- }
- }
- }
-
- /*从Ds18b20得到温度值
- * 返回值:温度值
- */
- float Ds18b20GetTemp() {
- uint8_t temp;
- uint8_t TH=0,TL=0;
- short tem;
- float t;
- Ds18b20Rst();
- Ds18b20Check();
- // 跳过ROM操作
- Ds18b20WriteByte(0XCC);
- // 发出转换指令
- Ds18b20WriteByte(0X44);
- Ds18b20Rst();
- Ds18b20Check();
- // 跳过ROM操作
- Ds18b20WriteByte(0XCC);
- // 读数据,低位在前
- Ds18b20WriteByte(0XBE);
- TL=Ds18b20ReadByte();//LSB
- TH=Ds18b20ReadByte();//MSB
-
- if(TH>7) {
- // 如果数据是负的
- TH=~TH;
- TL=~TL;
- // 负温度标志
- temp=0;
- } else {
- // 正温度
- temp=1;
- }
- tem=TH;//高八位
- tem<<=8;
- tem+=TL;//低八位
- // 计算温度值
- t=((float)tem*0.0625);
- if(temp) return t;
- else return -t;
- }
在主程序中每间隔300ms读一次温度,得到的结果输出到SPI显示屏上。
只要时序没问题,很容易调通的。如果通讯失败,建议用逻辑分析仪截取通讯过程信号分析,通常是脉冲的时间不匹配造成的。
|