原创 ATmega16单片机的温控程序(二)

2012-7-3 17:48 2195 18 18 分类: MCU/ 嵌入式
关于DS18B20温度传感器的控制,在网络上也有很多的参考代码,但自己在查找的时候发现都不尽相同,甚至很多都无法通用。于是想自己整理一份可供大家参考的设计。

DS18B20概述:

如下图,是几种DS18B20的封装。传感器一共三个管脚,VDD、DQ、GND。

00.jpg

供电模式:共有两种供电模式——寄生电源模式和外部供电模式。寄生电源模式由DQ管脚供电,GND和VDD都接地;外部供电模式由VDD和GND供电,注意电源使用直流电+3-+5V。

配置电路:如下图DS18B20结构图,通信时需在DQ总线上接一个4.7k的上拉电阻用来释放总线。需注意的是,有时候采用的控制器,如单片机内部是带有上拉电阻的,此时不宜再在外部接上拉电阻。因为如果多接了上拉电阻后,相当于在原有上拉电阻并联了一个电阻,使得新的“上拉电阻”的阻值呈指数递减,会引起总线传输低电平时,电流增大,相应的低电平增大。

03.jpg
时序控制:单片机控制DQ单总线访问DS18B20时每个工作周期协议分三步。
1、初始化;
2、ROM操作(如果不操作,发送0xCC指令跳过ROM操作);
3、功能指令+返回参数;
 
初始化及读写字节时序如下图:
05.jpg
06.jpg

初始化时序:

首先我们必须对DS18B20芯片进行复位,复位就是由控制器(单片机)给DS18B20单总线至少480uS的低电平信号。当18B20接到此复位信号后则会在15~60uS后回发一个芯片的存在脉冲。存在脉冲:在复位电平结束之后,控制器应该将数据单总线拉高,以便于在15~60uS后接收存在脉冲,存在脉冲为一个60~240uS的低电平信号。至此,通信双方已经达成了基本的协议,接下来将会是控制器与18B20间的数据通信。如果复位低电平的时间不足或是单总线的电路断路都不会接到存在脉冲,在设计时要注意意外情况的处理。

读写时序:

写时间隙:

写时间隙分为写“0”和写“1”,时序如图。在写数据时间隙的前15uS总线需要是被控制器拉置低电平,而后则将是芯片对总线数据的采样时间,采样时间在15~60uS,采样时间内如果控制器将总线拉高则表示写“1”,如果控制器将总线拉低则表示写“0”。每一位的发送都应该有一个至少15uS的低电平起始位,随后的数据“0”或“1”应该在45uS内完成。整个位的发送时间应该保持在60~120uS,否则不能保证通信的正常。

读时间隙:

读时间隙时控制时的采样时间应该更加的精确才行,读时间隙时也是必须先由主机产生至少1uS的低电平,表示读时间的起始。随后在总线被释放后的15uS中DS18B20会发送内部数据位,这时控制如果发现总线为高电平表示读出“1”,如果总线为低电平则表示读出数据“0”。每一位的读取之前都由控制器加一个起始信号。注意:必须在读间隙开始的15uS内读取数据位才可以保证通信的正确。

在通信时是以8位“0”或“1”为一个字节,字节的读或写是从高位开始的,即A7到A0.字节的读写顺序也是自上而下的。
 
本程序设计只对DS18B20做两个操作:转换温度和读取温度,则两个工作周期如下:复位、跳过ROM指令[CCH]、执行温度转换存储器操作指令[44H]、等待750ms温度转换时间;紧接着执行第二个周期:复位、跳过ROM指令[CCH]、执行读RAM的存储器操作指令[BEH]、读数据(最多为9个字节,中途可停止,只读简单温度值则读前2个字节即可)。代码如下:

以下是代码片段:
//ATmega16晶振为8Mhz
#include
#include
#define uchar unsigned char
#define uint unsigned int
#define F_CPU  8000000      
#define BAUD   250000
//下面定义了新加的部分参数和函数
//DQ接在了PB2管脚上
#define DQ PB2
//风扇开启温度设置
#define TEMPERATURE 28
//风扇接开关接在了PA3管脚上
#define FAN PA3
//将风扇管脚置为输出
#define FAN_INI() DDRA|=BIT(FAN)
//开风扇,即PA3输出高电平
//原理就是让RFD123的栅极和源级有个2到4V的开启电压
//这样漏极和源极就导通了,风扇就开了
#define FAN_ON() PORTA |= BIT(FAN)
//关风扇,即PA3输出低电平
//栅极和源极电压小于2V,漏极和源极就断开
#define FAN_OFF() PORTA &= ~BIT(FAN)
//下面是DQ总线的操作
//总线拉高
#define SET_DQ() PORTB |= BIT(DQ)
//总线清零
#define CLR_DQ() PORTB &= ~BIT(DQ)
//总线为输出
#define DQ_OUT() DDRB |= BIT(DQ)
//总线为输入
#define DQ_IN() DDRB &= ~BIT(DQ)
/*--------------------DS18B20处理程序------------------*/
//延时1us
void DELAY_1US()
{
NOP();  
}
//延时delay个us
void DELAY_US(uint delay)
{
do
{
  delay--;
}
while(delay>1);  
}
//延时delay个ms
//这里中间插入了很多pwmbo1()这个函数
//因为在操作温度传感器的时候,
//需要先进行温度转换,会有长时间的等待,
//而这段时间里面,pwm波形需要正常运转,
//所以每隔100us插入一个pwm控制,来保证灯的控制
void DELAY_MS(uint delay)
{
while(delay!=0)
{
  DELAY_US(1000);
  delay--;

}
//DS18B20复位功能函数
void DS_RESET()
{
SET_DQ();
NOP();
NOP();
CLR_DQ();
DELAY_US(600);
SET_DQ();
DQ_IN();
DELAY_US(30);
if(PINB&BIT(DQ))
{
  DQ_RESET = 0;
}
else
{
  DQ_RESET = 1;
}
DELAY_US(300);
DQ_OUT();
SET_DQ();
}
//DS18B20写字节函数
void DS_WRITE(uchar DATA)
{
uchar i;
for(i=0;i<8;i++)
{
  DQ_OUT();
  SET_DQ();
  NOP();
  NOP();
  CLR_DQ();
  DELAY_US(15);
  if(DATA & 0X01)
   SET_DQ();
  DELAY_US(60);
  SET_DQ();
  DATA>>=1;     
}
}
//DS18B20读字节函数
uchar DS_READ()
{
uchar i,data_read;
data_read = 0;
DQ_OUT();
for(i=0;i<8;i++)
{
  CLR_DQ();
  DELAY_US(1);
  SET_DQ();
  NOP();
  DQ_IN();
  NOP();
  DELAY_US(5);
  if(PINB&BIT(DQ))
   data_read |= BIT(i);
  else
   data_read &= ~BIT(i);
  DELAY_US(70);
  DQ_OUT();
  NOP();
  SET_DQ();   
}
return data_read;
}
//读温度函数,返回截取之后的温度值
uchar READ_TEMPERATURE()
{
//设置几个变量来保存读取的值和温度值
uchar TEMP1,TEMP2,TEMP;
TEMP1 = 0;
TEMP2 = 0;
TEMP = 0;
//第一个工作周期
//先复位
DS_RESET();
//写CCH,跳过ROM操作
DS_WRITE(0XCC);
//写44H,温度转换命令
DS_WRITE(0X44);
//下面是等待DS18B20转换温度
//先插入一个PWM控制
pwmbo1();
//等待750ms,其中也要插入PWM控制
DELAY_MS(750);
//第二个工作周期
//先复位
DS_RESET();
//写CCH,跳过ROM操作
DS_WRITE(0XCC);
//写BEH,进行读取寄存器
DS_WRITE(0XBE);
//读寄存器第一个值,温度表示的低字节
TEMP1 = DS_READ();
//读寄存器第二个值,温度表示的高字节
TEMP2 = DS_READ();
//温度转换,取低字节的高4位做温度低4位
//取高字节的低4位做温度的高4位
TEMP = ((TEMP2&0X0F)<<4)|((TEMP1&0XF0)>>4);
//返回温度值
return TEMP;
 
}
void main(void)

int ad,value;
//PORTA输出为低
//PA3为风扇开关,风扇初始关闭
PORTA=0X00;
DDRA=0XFF;
//PORTB设置输出,并输出高,PB2为温度传感器的通信口
//设置为高,总线闲置
PORTB=0XFF;
DDRB = 0XFF;
while(1)
{
//下面是读取温度函数
  TEMPE = READ_TEMPERATURE();
//如果读取的温度大于某个值,开启风扇,
//小于了某个值关闭风扇
//这两个值可以实际测测,现在是28℃
//个人建议可以把关闭的值设定的比开启的值更低,
//这样风扇不会开关得那么快
//TEMPERATURE的设置在预编译里面定义了,最上面
  if(TEMPE > TEMPERATURE)
   FAN_ON();
  else if(TEMPE < (TEMPERATURE-3))
   FAN_OFF();
}
}
用示波器读取到温度00110001 10000000019BH=25.75℃,如下图:
000.jpg
 
 
 

文章评论0条评论)

登录后参与讨论
我要评论
0
18
关闭 站长推荐上一条 /2 下一条