发上来的程序是主要基于stm32f1的驱动程序,如果你需要清楚了解ds18b20的工作时序,寄存器配置,那么在论坛上找找看看数据手册,如果你想直接用,那么把头文件和c文件直接添加到你的工程中就可以了。 本程序在实质上和51驱动的没有区别,都是模拟I2C。两者区别在于大部分51对于IO口的输入输出配置没有硬性规定,既可以当输入又可以当输出,而stm32的输入输出必须明确模式配置。而ds18b20是一线通信,所以需要输入输出模式来回配置。
本程序我通过硬件明确测试过,可以准确读出数据,如果数据无法读出,可能是以下几点问题:
1、引脚配置未修改。可在h文件中修改宏定义即可
2、请注意该函数void DS18B20_DQ_DDR(uint8_t ddr),他是用于修改IO输入输出模式的,本程序使用的标准库函数进行操作,用到的时间可能会有一点长,影响到了I2C的模拟时序,建议可以直接对寄存器进行操作,库函数的实质也是修改寄存器,只是由于为了程序兼容性,牺牲了时间。
3、由于是模拟的I2C时序,请务必注意中断对于通信时序的影响。
单片机源程序如下:
- #include "ds18b20.h"//主要包含了一些引脚宏定义,移植时必须包含
- #include "delay.h"//主要是声明了延时函数,由于是模拟I2C,延时必须精准
- #include "math.h"//使用了库函数pow()函数,该函数为幂次函数,如pow(10,2),相当于10^2,移植时必须包含
- /*******************************************************************************
- 函数名:DS18B20_DQ_DDR
- 功能:配置IO输入/输出状态
- 输入:0/1 输入0配置为输入,输入1配置为输出
- 输出:
- 返回值:
- *******************************************************************************/
- void DS18B20_DQ_DDR(uint8_t ddr)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- //使能GPIO时钟
- RCC_APB2PeriphClockCmd(DS18B20_GPIO_CLK, ENABLE);
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
- //配置为输出
- if(ddr == 1)
- {
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN;
- GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
-
- }
- //配置为输入
- else
- {
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN;
- GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure);
- }
- }
- /*******************************************************************************
- 函数名:DS18B20_Init
- 功能:初始化DS18B20
- 输入:
- 输出:
- 返回值:初始化成功为0,不成功为1
- 备注:
- *******************************************************************************/
- u8 DS18B20_Init(void)
- {
- u8 x = 0;
- //改变DQ引脚为输出
- DS18B20_DQ_DDR(1);
- //先置高
- DS18B20_DQ_H;
- //延时700us,使总线稳定
- delay_us(700);
- //复位脉冲,低电位
- DS18B20_DQ_L;
- //保持至少480us,这里500us
- delay_us(500);
- //改变DQ引脚为输入
- DS18B20_DQ_DDR(0);
- //拉高数据线,释放总线
- DS18B20_DQ_H;
- //等待15-60us,这里40us
- delay_us(40);
- //等待35us
- delay_us(35);
- //聆听,判断有没有初始化成功(DS18B20有没有发送应答脉冲)
- x = DS18B20_DQ_ReadPin;
- //至少480us后进入接收状态,这里500us
- delay_us(500);
- return x;
- }
- /*******************************************************************************
- 函数名:DS18B20_Wbyte
- 功能:写一个字节
- 输入:uint8_t xbyte
- 输出:
- 返回值:
- 备注:
- *******************************************************************************/
- void DS18B20_Wbyte(uint8_t xbyte)
- {
- //i:循环控制变量,x:取位运算变量
- int8_t i ,x = 0;
- //改变DQ引脚为输出
- DS18B20_DQ_DDR(1);
- //8次循环实现逐位写入
- for(i = 1; i <= 8; i++)
- {
- //先取低位
- x = xbyte & 0x01;
- //写1
- if(x)
- {
- DS18B20_DQ_H;
- //拉低总线
- DS18B20_DQ_L;
- //延时15us
- delay_us(15);
- //总线写1
- DS18B20_DQ_H;
- //延时15us
- delay_us(15);
- //保持高电平
- DS18B20_DQ_H;
- delay_us(4);
- }
- //写0
- else
- {
- DS18B20_DQ_H;
- //总线拉低
- DS18B20_DQ_L;
- //延时15us
- delay_us(15);
- //总线写0
- DS18B20_DQ_L;
- //延时15us
- delay_us(15);
- //保持高电平
- DS18B20_DQ_H;
- delay_us(4);
- }
- //xbyte右移一位
- xbyte = xbyte >> 1;
- }
- }
- /*******************************************************************************
- 函数名:DS18B20_Rbit
- 功能:从DS18B20读一个位
- 输入:
- 输出:
- 返回值:读取到的位
- 备注:
- *******************************************************************************/
- uint8_t DS18B20_Rbit(void)
- {
- //rbit是最终位数据,x是取状态变量
- uint8_t rbit = 0x00,x = 0;
- //改变DQ为输出模式
- DS18B20_DQ_DDR(1);
- DS18B20_DQ_H;
- //总线写0
- DS18B20_DQ_L;
- //延时15us以内
- delay_us(5);
- //释放总线
- DS18B20_DQ_H;
- //改变DQ为输入模式
- DS18B20_DQ_DDR(0);
- //延时大约3us
- delay_us(3);
- //获取总线电平状态
- x = DS18B20_DQ_ReadPin;
- //如果是1,则返回0x80,否则返回0x00
- if(x)
- rbit = 0x80;
- //延时大约60us
- delay_us(60);
- return rbit;
- }
- /*******************************************************************************
- 函数名:DS18B20_Rbyte
- 功能:从DS18B20读一个字节
- 输入:
- 输出:
- 返回值:读取到的字节
- 备注:
- *******************************************************************************/
- uint8_t DS18B20_Rbyte(void)
- {
- //rbyte:最终得到的字节
- //tempbit:中间运算变量
- uint8_t rbyte = 0,i = 0, tempbit =0;
- for (i = 1; i <= 8; i++)
- {
- //读取位
- tempbit = DS18B20_Rbit();
- //右移实现高低位排序
- rbyte = rbyte >> 1;
- //或运算移入数据
- rbyte = rbyte|tempbit;
- }
- return rbyte;
- }
- int ReadTemperature(void)
- {
- //fg:符号位
- //data:温度的整数部分
- int fg;
- int data;
- //DS18B20初始化
- DS18B20_Init();
- //跳过读序列号
- DS18B20_Wbyte(0xcc);
- //启动温度转换
- DS18B20_Wbyte(0x44);
- //等待温度转换
- delay_ms(1);
- DS18B20_Init();
- DS18B20_Wbyte(0xcc);
- //读温度寄存器
- DS18B20_Wbyte(0xbe);
- uint8_t TempL = DS18B20_Rbyte();//读取低8位
- uint8_t TempH = DS18B20_Rbyte();//读取高8位
- //符号位为负
- if(TempH > 0x70)
- {
- TempL = ~TempL;
- TempH = ~TempH;
- fg = 0;
- }
- else fg = 1;
-
- //将数据高低位合并
- data = TempH;//数据高八位
- data <<= 8;//左移8位
- data += TempL;//加上低八位
- //data的"1"相当于0.0625℃
- //换句话说,想要多少精度可以这样写:data=(float)data*0.0625*pow(10,n)
- //其中n为保留的小数精度位数,可以从目前对ds18b20配置情况下看出最高保留小数的精度位数为4位
- //这样只需要对返回值进行处理就可以用于显示了
- //特别注意的是,int类型的数据长度为16位,最大值为65535,因此需要注意使用范围
- data=(float)data*0.0625*pow(10,1);//这样写等同于下面一句
- //data = (float)data*0.625;//这样相当于精度为0.1℃
- if(fg)
- return data;
- else
- return -data;
- }
复制代码
所有资料51hei提供下载:
DS18B20.rar
(2.56 KB, 下载次数: 101)
|