极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 149175|回复: 84

arduino学习笔记27 - DS1307 RTC时钟芯片与DS18B20数字温度传感器实验

  [复制链接]
发表于 2011-11-17 22:28:58 | 显示全部楼层 |阅读模式
本次实验我使用的是购买的一个DS1307 RTC模块,上面集成了一个DS18B20温度传感器,还集成了另外一个存储芯片~~
先上图






再看下硬件连接图,DS1307是I2C接口SCL接模拟5号口,SDA接模拟4号口。DS18B20是单总线模式,他的DS接口接数字2号口。





DS18B20:



DS18x20系列数字温度传感器主要有DS18S20和DS18B20(DS18S20只有9位一种工作模式,分辨率只到0.5摄氏度,DS18B20有9、10、11、12位四种工作可编程控制的模式,分辨率最高为0.0625摄氏度。),都是由美国Dallas半导体公司(现在改名叫Maxim)生产的。这个系列最大的特点就是采用了Maxim的专利技术1-Wire。顾名思义,1-Wire就是采用单一信号线,但可像I2C,SPI一样,同时传输时钟(clock)又传输数据(data),而且数据传输是双向的。1-Wire 使用较低的数据传输速率,通常是用来沟通小型device,如数位温度计。通过1-Wire技术可以在单一信号线的基础上构成传感器网络,Maxim起名”MicroLan”。

DS18x20的供电主要有两种模式:

Parasite power mode/寄生供电




所谓的寄生供电是指DS18x20只需要两根接线,一根数据线,一根接地线,数据线上还要接一个4.7k上拉电阻连电源,数据线同时也提供了电能。DS18x20内置了电容,高电平期时把电能储存在内部电容里,低电平期内消耗内部电容里的能量工作,直到下次高电平期内再次电容充电。虽然这样的模式简化了线路同时也带来了一些缺陷:

1. 电路的电流一般很小,只有当DS18x20进行温度转化或者写EEPROM时会高达1.5mA,当DS18x20进行上述操作时,数据线必须保持电平拉高状态直到操作结束,期间master端的Arduino不能做任何操作,DS18x20温度转化时这个时间间隔大概是750ms。

2.如果要求DS18x20有精确的转化,数据线在温度转化期间必须保证足够的能量,但当你使用多个DS18x20构成MicroLan进行多点测温时,单靠4.7k的上拉电阻无法提供足够的能量,会导致较大的测温误差。

Normal (external supply) mode/标准(外部供电)




标准外部供电模式,相比寄生供电模式,每个DS18x20需要多一条独立的电源线接独立电源。虽然多用些线,但由于外部供电,保证了每个设备的进精确度和稳定性。而且没有了上述温度转换期间Arduino不能做任何事的问题。

DS18B20的详细介绍就不多讲了,具体可以查看论坛的另一篇帖子http://www.geek-workshop.com/for ... =198&extra=page%3D1

直接进入实战,调用DS18B20,需要使用OneWire库。

把下面代码下载进入arduino控制板。
  1. #include <OneWire.h>

  2. // DS18S20 Temperature chip i/o
  3. OneWire ds(2);  // on pin 2

  4. void setup(void) {
  5.   // initialize inputs/outputs
  6.   // start serial port
  7.   Serial.begin(9600);
  8. }

  9. void loop(void) {
  10.   byte i;
  11.   byte present = 0;
  12.   byte data[12];
  13.   byte addr[8];

  14.   if ( !ds.search(addr)) {
  15.     Serial.print("No more addresses.\n");
  16.     ds.reset_search();
  17.     return;
  18.   }

  19.   Serial.print("R=");
  20.   for( i = 0; i < 8; i++) {
  21.     Serial.print(addr[i], HEX);
  22.     Serial.print(" ");
  23.   }

  24.   if ( OneWire::crc8( addr, 7) != addr[7]) {
  25.     Serial.print("CRC is not valid!\n");
  26.     return;
  27.   }

  28.   if ( addr[0] == 0x10) {
  29.     Serial.print("Device is a DS18S20 family device.\n");
  30.   }
  31.   else if ( addr[0] == 0x28) {
  32.     Serial.print("Device is a DS18B20 family device.\n");
  33.   }
  34.   else {
  35.     Serial.print("Device family is not recognized: 0x");
  36.     Serial.println(addr[0],HEX);
  37.     return;
  38.   }

  39.   ds.reset();
  40.   ds.select(addr);
  41.   ds.write(0x44,1);         // start conversion, with parasite power on at the end

  42.   delay(1000);     // maybe 750ms is enough, maybe not
  43.   // we might do a ds.depower() here, but the reset will take care of it.

  44.   present = ds.reset();
  45.   ds.select(addr);
  46.   ds.write(0xBE);         // Read Scratchpad

  47.   Serial.print("P=");
  48.   Serial.print(present,HEX);
  49.   Serial.print(" ");
  50.   for ( i = 0; i < 9; i++) {           // we need 9 bytes
  51.     data[i] = ds.read();
  52.     Serial.print(data[i], HEX);
  53.     Serial.print(" ");
  54.   }
  55.   Serial.print(" CRC=");
  56.   Serial.print( OneWire::crc8( data, 8), HEX);
  57.   Serial.println();
  58. }
复制代码
代码下载好以后打开串口编辑器,然后就会出现下面这样子的画面。



虽然我们读到了Scratchpad的数据,但是显示的是HEX16进制代码,我们还需要转化成我们能读的温度格式。这里推荐一个叫Dallas Temperature Control的Library,大大简化了这个过程。官方地址:http://www.milesburton.com/?titl ... ure_Control_Library
  1. #include <OneWire.h>
  2. #include <DallasTemperature.h>

  3. // Data wire is plugged into port 2 on the Arduino
  4. #define ONE_WIRE_BUS 2

  5. // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
  6. OneWire oneWire(ONE_WIRE_BUS);

  7. // Pass our oneWire reference to Dallas Temperature.
  8. DallasTemperature sensors(&oneWire);

  9. void setup(void)
  10. {
  11.   // start serial port
  12.   Serial.begin(9600);
  13.   Serial.println("Dallas Temperature IC Control Library Demo");

  14.   // Start up the library
  15.   sensors.begin();
  16. }

  17. void loop(void)
  18. {
  19.   // call sensors.requestTemperatures() to issue a global temperature
  20.   // request to all devices on the bus
  21.   Serial.print("Requesting temperatures...");
  22.   sensors.requestTemperatures(); // Send the command to get temperatures
  23.   Serial.println("DONE");
  24.   
  25.   Serial.print("Temperature for the device 1 (index 0) is: ");
  26.   Serial.println(sensors.getTempCByIndex(0));  
  27. }
复制代码
代码下载好以后,打开串口监视器,就可以看到当前室温了。



下面我们试用一下DS1307时钟芯片功能。
先把下面库自带测试代码下载进入arduino控制板
  1. #include <WProgram.h>
  2. #include <Wire.h>
  3. #include <DS1307.h>

  4. int rtc[7];
  5. int ledPin =  13;
  6. void setup()
  7. {
  8.   DDRC|=_BV(2) |_BV(3);  // POWER:Vcc Gnd
  9.   PORTC |=_BV(3);  // VCC PINC3
  10.   pinMode(ledPin, OUTPUT);  
  11.   Serial.begin(9600);

  12.   RTC.stop();
  13.   RTC.set(DS1307_SEC,1);
  14.   RTC.set(DS1307_MIN,57);
  15.   RTC.set(DS1307_HR,17);
  16.   RTC.set(DS1307_DOW,2);
  17.   RTC.set(DS1307_DATE,18);
  18.   RTC.set(DS1307_MTH,1);
  19.   RTC.set(DS1307_YR,10);
  20.   RTC.start();
  21. }

  22. void loop()
  23. {
  24.   RTC.get(rtc,true);

  25.   for(int i=0; i<7; i++)
  26.   {
  27.     Serial.print(rtc[i]);
  28.     Serial.print(" ");
  29.   }
  30.   Serial.println();
  31.         digitalWrite(ledPin, HIGH);
  32.         delay(500);
  33.         digitalWrite(ledPin, LOW);
  34.         delay(500);
  35. }
复制代码
然后打开串口监视器,就能看到类似下图的样子。


这个模块上还有一个T24C32A EEPROM存储器。。。下面上一个全面一点的代码,对各个期间进行测试。其中刚开始会对I2C器件进行扫描。。。代码不错,大家可以参考下。
  1. /**
  2. * I2CScanner.pde -- I2C bus scanner for Arduino
  3. *
  4. * 2009, Tod E. Kurt, [url]http://todbot.com/blog/[/url]
  5. *
  6. */
  7. #include <OneWire.h>
  8. #include "Wire.h"
  9. #include <WProgram.h>
  10. #include <DS1307.h>
  11. #include <avr/io.h>
  12. extern "C" {
  13. #include "utility/twi.h"  // from Wire library, so we can do bus scanning
  14. }


  15. byte start_address = 1;
  16. byte end_address = 127;
  17. OneWire  ds(2);  // on pin 2
  18. byte Tdata[12];
  19. int sensorValue = 0;        // value read from the pot
  20. int rtc[7];
  21. float TT=0.0;

  22. // Scan the I2C bus between addresses from_addr and to_addr.
  23. // On each address, call the callback function with the address and result.
  24. // If result==0, address was found, otherwise, address wasn't found
  25. // (can use result to potentially get other status on the I2C bus, see twi.c)
  26. // Assumes Wire.begin() has already been called
  27. void scanI2CBus(byte from_addr, byte to_addr,
  28.                 void(*callback)(byte address, byte result) )
  29. {
  30.   byte rc;
  31.   byte data = 0; // not used, just an address to feed to twi_writeTo()
  32.   for( byte addr = from_addr; addr <= to_addr; addr++ ) {
  33.     rc = twi_writeTo(addr, &data, 0, 1);
  34.     if(rc==0) callback( addr, rc );
  35.   }
  36. }

  37. // Called when address is found in scanI2CBus()
  38. // Feel free to change this as needed
  39. // (like adding I2C comm code to figure out what kind of I2C device is there)
  40. void scanFunc( byte addr, byte result ) {
  41.   Serial.print("addr: ");
  42.   Serial.print(addr,DEC);
  43.   addr = addr<<1;
  44.   Serial.print("\t HEX: 0x");
  45.   Serial.print(addr,HEX);
  46.   Serial.println( (result==0) ? "\t found!":"   ");
  47. //  Serial.print( (addr%4) ? "\t":"\n");
  48. }


  49.   void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
  50.     int rdata = data;
  51.     Wire.beginTransmission(deviceaddress);
  52.     Wire.send((int)(eeaddress >> 8)); // MSB
  53.     Wire.send((int)(eeaddress & 0xFF)); // LSB
  54.     Wire.send(rdata);
  55.     Wire.endTransmission();
  56.   }

  57.   // WARNING: address is a page address, 6-bit end will wrap around
  58.   // also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
  59.   void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
  60.     Wire.beginTransmission(deviceaddress);
  61.     Wire.send((int)(eeaddresspage >> 8)); // MSB
  62.     Wire.send((int)(eeaddresspage & 0xFF)); // LSB
  63.     byte c;
  64.     for ( c = 0; c < length; c++)
  65.       Wire.send(data[c]);
  66.     Wire.endTransmission();
  67.   }

  68.   byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
  69.     byte rdata = 0xFF;
  70.     Wire.beginTransmission(deviceaddress);
  71.     Wire.send((int)(eeaddress >> 8)); // MSB
  72.     Wire.send((int)(eeaddress & 0xFF)); // LSB
  73.     Wire.endTransmission();
  74.     Wire.requestFrom(deviceaddress,1);
  75.     if (Wire.available()) rdata = Wire.receive();
  76.     return rdata;
  77.   }

  78.   // maybe let's not read more than 30 or 32 bytes at a time!
  79.   void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
  80.     Wire.beginTransmission(deviceaddress);
  81.     Wire.send((int)(eeaddress >> 8)); // MSB
  82.     Wire.send((int)(eeaddress & 0xFF)); // LSB
  83.     Wire.endTransmission();
  84.     Wire.requestFrom(deviceaddress,length);
  85.     int c = 0;
  86.     for ( c = 0; c < length; c++ )
  87.       if (Wire.available()) buffer[c] = Wire.receive();
  88.   }
  89. void DS1302_SetOut(byte data ) {
  90.     Wire.beginTransmission(B1101000);
  91.     Wire.send(7); // LSB
  92.     Wire.send(data);
  93.     Wire.endTransmission();
  94. }
  95. byte DS1302_GetOut(void) {
  96.     byte rdata = 0xFF;
  97.     Wire.beginTransmission(B1101000);
  98.     Wire.send(7); // LSB
  99.     Wire.endTransmission();
  100.     Wire.requestFrom(B1101000,1);
  101.     if (Wire.available()) {
  102.       rdata = Wire.receive();
  103.       Serial.println(rdata,HEX);
  104.     }
  105.     return rdata;
  106. }
  107. void showtime(void){
  108.   byte i;
  109.   Serial.print("Time=");
  110.   DS1302_SetOut(0x00);
  111.   RTC.get(rtc,true);  
  112.   for(int i=0; i<7; i++)        {
  113.   Serial.print(rtc[i]);
  114.   Serial.print(" ");
  115.   }
  116. }

  117. void readBatVcc(void){
  118.     sensorValue = analogRead(A1);
  119.     TT = sensorValue*0.0047;
  120.     Serial.print("Battery: ");
  121.     Serial.print(TT);
  122.     Serial.print("V");
  123. }
  124.    
  125. // standard Arduino setup()
  126. void setup()
  127. {
  128.     DDRC|=_BV(2) |_BV(3);
  129.     PORTC |=_BV(3);
  130.     Wire.begin();

  131.     Serial.begin(19200);
  132.     Serial.println("--- I2C Bus Scanner Test---");
  133.     Serial.print("starting scanning of I2C bus from ");
  134.     Serial.print(start_address,DEC);
  135.     Serial.print(" to ");
  136.     Serial.print(end_address,DEC);
  137.     Serial.println("...");

  138.     // start the scan, will call "scanFunc()" on result from each address
  139.     scanI2CBus( start_address, end_address, scanFunc );

  140.     Serial.println("\n");
  141.     Serial.println("--- EEPROM Test---");
  142.     char somedata[] = "this is data from the eeprom"; // data to write
  143.     i2c_eeprom_write_page(0x50, 0, (byte *)somedata, sizeof(somedata)); // write to EEPROM
  144.     delay(100); //add a small delay
  145.     Serial.println("Written Done");   
  146.     delay(10);
  147.     Serial.print("Read EERPOM:");
  148.     byte b = i2c_eeprom_read_byte(0x50, 0); // access the first address from the memory
  149.     int addr=0; //first address
  150.     while (b!=0)
  151.     {
  152.       Serial.print((char)b); //print content to serial port
  153.       addr++; //increase address
  154.       b = i2c_eeprom_read_byte(0x50, addr); //access an address from the memory
  155.     }
  156.    Serial.println("\n");
  157.   Serial.println("");
  158.   Serial.println("--- DS11307 RTC Test---");  
  159.   showtime();
  160.   if(rtc[6]<2011){
  161.     RTC.stop();
  162.     RTC.set(DS1307_SEC,1);
  163.     RTC.set(DS1307_MIN,52);
  164.     RTC.set(DS1307_HR,16);
  165.     RTC.set(DS1307_DOW,2);
  166.     RTC.set(DS1307_DATE,25);
  167.     RTC.set(DS1307_MTH,1);
  168.     RTC.set(DS1307_YR,11);
  169.     RTC.start();
  170.     Serial.println("SetTime:");
  171.     showtime();   
  172.   }
  173.   
  174.   Serial.println("\n\n");
  175.   Serial.println("--- Reserve Power Test---");
  176.   Serial.println("  Close POWER!:");
  177.    PORTC &=~_BV(3);
  178.    byte time;
  179.    for(time=0;time<5;time++){
  180.      digitalWrite(13,HIGH);
  181.      delay(500);
  182.      digitalWrite(13,LOW);
  183.      delay(500);     
  184.      readBatVcc();
  185.      Serial.println("");
  186.    }
  187.     PORTC |=_BV(3);
  188.    Serial.println("\n  POWER On!");
  189.       delay(500);
  190.       showtime();
  191.       
  192.     Serial.println("\n");
  193.     Serial.println("===  Done   ===");
  194.     Serial.println("\n");
  195. }

  196. // standard Arduino loop()
  197. void loop()
  198. {
  199.     byte i;
  200.     byte present = 0;
  201.     unsigned int Temper=0;

  202.    
  203. readBatVcc();
  204.    
  205.     ds.reset();
  206.     ds.write(0xCC,1);
  207.     ds.write(0x44,1);         // start conversion, with parasite power on at the end
  208.     digitalWrite(13,HIGH);
  209.     delay(450);
  210.     digitalWrite(13,LOW);
  211.     delay(450);
  212.     present = ds.reset();
  213.     ds.write(0xCC,1);   
  214.     ds.write(0xBE);         // Read Scratchpad
  215.     for ( i = 0; i < 9; i++) {           // we need 9 bytes
  216.       Tdata[i] = ds.read();
  217.     }   
  218.     Temper = (Tdata[1]<<8 | Tdata[0]);
  219.     TT =Temper*0.0625;
  220.     if(TT>200){
  221.      Serial.println("\t DS18B20 Not installed!");
  222.     }else{
  223.       Serial.print("\t Temperature=");
  224.       Serial.println(TT);
  225.     }
  226.     Serial.println("");
  227. }
复制代码
然后打开串口监视器,波特率要调节为19200.


附件是这次需要用到的库(适用于0022与0023 IDE):





补充1.0.1下可用的DS180B20库

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2012-8-24 08:43:05 | 显示全部楼层
本例OneWire的库编译中有点问题,无法通过,需更新为V2.1版本

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 1 反对 0

使用道具 举报

发表于 2011-11-26 22:49:45 | 显示全部楼层
谢谢!标记学习!
回复 支持 反对

使用道具 举报

发表于 2011-11-30 14:06:47 | 显示全部楼层
呵呵,对这比较感兴趣,打算买个回来玩。
回复 支持 反对

使用道具 举报

发表于 2011-12-10 22:48:47 | 显示全部楼层
激动,今天收到了从淘宝买来的时钟模块了。打算做一个这个出来。嘎嘎。
回复 支持 反对

使用道具 举报

发表于 2012-1-14 17:51:14 | 显示全部楼层
请教一下,I2C接口SCL接模拟5号口,SDA接模拟4号口。I2C接口是不是指4、5 pin ?求教
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-1-14 18:22:20 | 显示全部楼层
milkgirl 发表于 2012-1-14 17:51
请教一下,I2C接口SCL接模拟5号口,SDA接模拟4号口。I2C接口是不是指4、5 pin ?求教

I2C口就是A4和A5
回复 支持 反对

使用道具 举报

发表于 2012-1-14 19:10:14 | 显示全部楼层
谢谢解答~谢谢
回复 支持 反对

使用道具 举报

发表于 2012-4-16 15:28:31 | 显示全部楼层
请教怎么设定N个温度到一定数值就输出N个信号呢?
回复 支持 反对

使用道具 举报

发表于 2012-5-2 14:50:09 | 显示全部楼层
在淘宝上看到这个模块了,淘宝上的商品介绍很简单。
1、不知道为什么要在时间模块里加测温模块?
2、所说里面还加了24C56存储模块,这又是为了什么?
总感觉把时间、温度、存储这三种做在同一个模块里看着别扭。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-5-2 14:52:58 | 显示全部楼层
MicroCao 发表于 2012-5-2 14:50
在淘宝上看到这个模块了,淘宝上的商品介绍很简单。
1、不知道为什么要在时间模块里加测温模块?
2、所说 ...

额。。。。设计者设计为3合1,其实可以分开的。。。
回复 支持 反对

使用道具 举报

发表于 2012-5-2 15:01:42 | 显示全部楼层
据卖家的商品介绍,此模块“解决DS1307带备用电池不能读写的问题”,是不是就是模块上加了锂电后,ARDUINO只需要通过A4、A5两条I2C线(不接VCC、GND)就可以读写模块的时间了?
真若这样倒是简化了模块的连接线。
回复 支持 反对

使用道具 举报

发表于 2012-7-13 20:45:19 | 显示全部楼层
学习一下了
回复 支持 反对

使用道具 举报

发表于 2012-7-13 23:22:44 | 显示全部楼层
本帖最后由 夏异 于 2012-7-13 23:34 编辑

我怎么已编译就这么多错误,好像这个库件有问题

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-7-13 23:29:48 | 显示全部楼层
夏异 发表于 2012-7-13 23:22
我怎么已编译就这么多错误,好像这个库件有问题

这个需要把附件的库全部放进去。当时环境是0022 IDE,1.0下估计会有报错问题。
回复 支持 反对

使用道具 举报

发表于 2012-7-13 23:32:49 | 显示全部楼层
弘毅 发表于 2012-7-13 23:29
这个需要把附件的库全部放进去。当时环境是0022 IDE,1.0下估计会有报错问题。

库我已经加进去了,可能是编译环境的缘故
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-20 05:58 , Processed in 0.054756 second(s), 31 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表