小插曲
在网上翻阅了STM32代码,移植到到TMS320F28335上一直读取到的温度值一直显示固定值,查阅半天资料翻阅DSB18B20产品手册都没有解决,偶尔看到论坛中说TMS320F28335中的延迟函数DELAY_US在RAM调试时是准确的,但下载到FLASH中并不准确,会出现比设定值多延迟几微秒的结果,看到这个之后就不断调延迟,但是之后想了一下,多这几微秒在DS18B20允许时序内,按理说应该能够获取到温度。
解决方案
注意DS18B20数据端要外接一个上拉电阻,仅仅单片机配置IO口上拉不够,我的接线图如下所示
代码
ds18b20.c & ds18b20.h
#ifndef __DS18B20_H
#define __DS18B20_H
#include "DSP2833x_Device.h" // DSP2833x Headerfile
#include "DSP2833x_Examples.h" // DSP2833x Examples
typedef unsigned char u8;
//IO方向
#define DS18B20_IO_IN() {EALLOW;GpioCtrlRegs.GPCDIR.bit.GPIO77 = 0;EDIS;}
#define DS18B20_IO_OUT() {EALLOW;GpioCtrlRegs.GPCDIR.bit.GPIO77 = 1;EDIS;}
//IO操作
#define DS18B20_DQ_OUT_1 (GpioDataRegs.GPCSET.bit.GPIO77 = 1) //数据端口GPIO77
#define DS18B20_DQ_OUT_0 (GpioDataRegs.GPCCLEAR.bit.GPIO77 = 1) //数据端口GPIO77
//读取IO
#define DS18B20_DQ_IN (GpioDataRegs.GPCDAT.bit.GPIO77) //数据端口GPIO77
u8 DS18B20_Init(void); //初始化
float DS18B20_Get_Temp(void); //获取温度
void DS18B20_Start(void); //开始温度转换
void DS18B20_Write_Byte(u8 dat);
u8 DS18B20_Read_Byte(void);
u8 DS18B20_Read_Bit(void);
u8 DS18B20_Check(void);
void DS18B20_Rst(void);
#endif
#include "ds18b20.h"
//复位DS18B20
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //GPIO77 OUTPUT
DS18B20_DQ_OUT_0; //拉低DQ
DELAY_US(750); //拉低总线480~960 us ,对 DS18B20 芯片进行复位
DS18B20_DQ_OUT_1; //DQ=1
DELAY_US(15); //释放总线15~60 us
}
/*
* 等待DS18B20的回应
* 返回1:未检测到DS18B20的存在
* 返回0:存在
*
* */
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN(); //GPIO77 INPUT
while (DS18B20_DQ_IN && retry<240) //等待DS18B20 拉低总线 (60~240 us 响应复位信号)
{
retry++;
DELAY_US(1);
};
if(retry>=240)return 1;
else retry=0;
while (!DS18B20_DQ_IN && retry<240) //判断DS18B20是否释放总线(60~240 us 响应复位信号之后会释放总线)
{
retry++;
DELAY_US(1);
};
if(retry>=240)return 1;
return 0;
}
//从DS18B20读取一个位
u8 DS18B20_Read_Bit(void)
{
u8 data;
DS18B20_IO_OUT();
DS18B20_DQ_OUT_0;
DELAY_US(8);
DS18B20_DQ_OUT_1;
DS18B20_IO_IN();
DELAY_US(12);
if(DS18B20_DQ_IN)data=1;
else data=0;
DELAY_US(50); //延时确保DS18B20采样周期已经过去(非常重要)
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
//dat:写入的字节
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();
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);
DS18B20_Write_Byte(0x44);
}
//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
EALLOW; //关闭写保护
//开启GPIO时钟
SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1;
//GPIO配置
GpioCtrlRegs.GPCMUX1.bit.GPIO77 = 0; //选择通用GPIO功能
GpioCtrlRegs.GPCDIR.bit.GPIO77 = 1; //设置为输出
GpioCtrlRegs.GPCPUD.bit.GPIO77 = 1; //上拉电阻
GpioDataRegs.GPCSET.bit.GPIO77 = 1; //起始设置输出为高
EDIS; //打开写保护
DS18B20_Rst();
return DS18B20_Check();
}
//从ds18b20得到温度值
//精度:0.1C
float DS18B20_Get_Temp(void)
{
u8 TL,TH;
short s_tem;
float f_tem;
DS18B20_Start();
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0XCC); /* 跳过 ROM */
DS18B20_Write_Byte(0XBE); /* 读温度值 */
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
s_tem = TH<<8;
s_tem = s_tem | TL;
if( s_tem < 0 ) /* 负温度 */
f_tem = (~s_tem+1) * 0.0625;
else
f_tem = (s_tem * 0.0625);
return f_tem;
}
主函数里只需要在前面初始化DS18B20_Init();然后就可以在while循环里用DS18B20_Get_Temp()函数读取传感器的温度。
最后结果
前面两个为整数部分,后面两位为小数部分。为什么不加小数点,因为懒。