Vamos mostrar como utilizar dois módulos I2C no mesmo barramento, juntando o display LCD 16×2 com módulo I2C (que mostrei no artigo Como utilizar o módulo I2C com display LCD), ao módulo relógio de tempo real (RTC) DS1307. Juntando o módulo I2C e o módulo RTC DS1307, temos o resultado abaixo:
Apesar de não ter falado ainda sobre o módulo RTC DS1307 aqui no blog, eu já mostrei como utilizar o CI DS1307, que segue o mesmo esquema de ligação. A diferença é que no módulo temos também alguns pinos de saída que podem ser utilizados para ligar os dispositivos em cascata.
Circuito módulo I2C e RTC DS1307 com Arduino
O módulo I2C pode ser soldado diretamente no display, ou montado em uma protoboard, como no circuito abaixo. Apesar da utilização de vários componentes, perceba que temos as demais portas do Arduino totalmente livres para utilização com motores, sensores ou outros dispositivos.
Para comunicação entre o Arduino Uno e os módulos, vamos usar os dois pinos da interface I2C: A4 – SDA e A5 – SCL (se for um Arduino Mega, pinos 20 e 21).
Usando o esquema acima, podemos ligar vários sensores e módulos I2C no mesmo barramento, mas eles não podem ter o mesmo endereço. Os dispositivos geralmente já vem com um endereço pré-definido, e em alguns casos você pode alterar esse endereço para evitar conflitos, como é o caso do módulo I2C, que permite selecionar um endereço diferente alterando a configuração dos pinos A0, A1 e A2:
Se você não souber qual o endereço do módulo, ou se deseja apenas confirmar se o dispositivo I2C está respondendo, pode utilizar no Arduino um programa chamado I2C Scanner:
// -------------------------------------- // i2c_scanner // // Version 1 // This program (or code that looks like it) // can be found in many places. // For example on the Arduino.cc forum. // The original author is not know. // Version 2, Juni 2012, Using Arduino 1.0.1 // Adapted to be as simple as possible by Arduino.cc user Krodal // Version 3, Feb 26 2013 // V3 by louarnold // Version 4, March 3, 2013, Using Arduino 1.0.3 // by Arduino.cc user Krodal. // Changes by louarnold removed. // Scanning addresses changed from 0...127 to 1...119, // according to the i2c scanner by Nick Gammon // http://www.gammon.com.au/forum/?id=10896 // Version 5, March 28, 2013 // As version 4, but address scans now to 127. // A sensor seems to use address 120. // // // This sketch tests the standard 7-bit addresses // Devices with higher bit address might not be seen properly. #include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); Serial.println("\nI2C Scanner"); } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); nDevices = 0; for(address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address<16) Serial.print("0"); Serial.print(address,HEX); Serial.println(" !"); nDevices++; } else if (error==4) { Serial.print("Unknow error at address 0x"); if (address<16) Serial.print("0"); Serial.println(address,HEX); } } if (nDevices == 0) Serial.println("No I2C devices found\n"); else Serial.println("done\n"); delay(5000); // wait 5 seconds for next scan }
Esse programa varre o barramento I2C e mostra no serial monitor o endereço dos dispositivos conectados:
No caso, foram encontrados 3 dispositivos: o módulo I2C do display no endereço 0x27, o CI DS1307 no endereço 0x68 e a EEPROM do módulo RTC (CI 24C32), no endereço 0x50.
Mostrando data e hora no display
Juntando tudo isso, temos o programa que lê os dados do módulo DS1307 (data e hora), e envia essas informações para um display LCD 16×2.
Retire as barras duplas da linha SelecionaDataeHora() (linha 22) para executar a rotina que vai ajustar a data e hora do seu módulo. Nas variáveis das linhas 86 à 92 você define os novos valores.
// Programa : Modulo I2C Display e Modulo DS1307 // Autor : Arduino e Cia #include "Wire.h" #include <LiquidCrystal_I2C.h> // Modulo RTC no endereco 0x68 #define DS1307_ADDRESS 0x68 // Modulo I2C display no endereco 0x27 LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3, POSITIVE); byte zero = 0x00; void setup() { Wire.begin(); Serial.begin(9600); lcd.begin (16,2); //A linha abaixo pode ser retirada apos setar a data e hora //SelecionaDataeHora(); } void loop() { // Le os valores (data e hora) do modulo DS1307 Wire.beginTransmission(DS1307_ADDRESS); Wire.write(zero); Wire.endTransmission(); Wire.requestFrom(DS1307_ADDRESS, 7); int segundos = ConverteparaDecimal(Wire.read()); int minutos = ConverteparaDecimal(Wire.read()); int horas = ConverteparaDecimal(Wire.read() & 0b111111); int diadasemana = ConverteparaDecimal(Wire.read()); int diadomes = ConverteparaDecimal(Wire.read()); int mes = ConverteparaDecimal(Wire.read()); int ano = ConverteparaDecimal(Wire.read()); // Mostra os dados no display lcd.setCursor(0,0); lcd.print(" "); // Acrescenta o 0 (zero) se a hora for menor do que 10 if (horas <10) lcd.print("0"); lcd.print(horas); lcd.print(":"); // Acrescenta o 0 (zero) se minutos for menor do que 10 if (minutos < 10) lcd.print("0"); lcd.print(minutos); lcd.setCursor(2,1); // Mostra o dia da semana switch(diadasemana) { case 0:lcd.print("Dom"); break; case 1:lcd.print("Seg"); break; case 2:lcd.print("Ter"); break; case 3:lcd.print("Quar"); break; case 4:lcd.print("Qui"); break; case 5:lcd.print("Sex"); break; case 6:lcd.print("Sab"); } lcd.setCursor(6,1); // Acrescenta o 0 (zero) se dia do mes for menor do que 10 if (diadomes < 10) lcd.print("0"); lcd.print(diadomes); lcd.print("/"); // Acrescenta o 0 (zero) se mes for menor do que 10 if (mes < 10) lcd.print("0"); lcd.print(mes); lcd.print("/"); lcd.print(ano); } void SelecionaDataeHora() //Seta a data e a hora do DS1307 { byte segundos = 20; //Valores de 0 a 59 byte minutos = 16; //Valores de 0 a 59 byte horas = 15; //Valores de 0 a 23 byte diadasemana = 4; //Valores de 0 a 6 - 0=Domingo, 1 = Segunda, etc. byte diadomes = 9; //Valores de 1 a 31 byte mes = 4; //Valores de 1 a 12 byte ano = 15; //Valores de 0 a 99 Wire.beginTransmission(DS1307_ADDRESS); Wire.write(zero); //Stop no CI para que o mesmo possa receber os dados //As linhas abaixo escrevem no CI os valores de //data e hora que foram colocados nas variaveis acima Wire.write(ConverteParaBCD(segundos)); Wire.write(ConverteParaBCD(minutos)); Wire.write(ConverteParaBCD(horas)); Wire.write(ConverteParaBCD(diadasemana)); Wire.write(ConverteParaBCD(diadomes)); Wire.write(ConverteParaBCD(mes)); Wire.write(ConverteParaBCD(ano)); Wire.write(zero); Wire.endTransmission(); } byte ConverteParaBCD(byte val) { //Converte o número de decimal para BCD return ( (val/10*16) + (val%10) ); } byte ConverteparaDecimal(byte val) { //Converte de BCD para decimal return ( (val/16*10) + (val%16) ); }
Gostou deste post com módulo I2C e RTC DS1307? Veja também o post onde mostro como ligar um display LCD 16×2 I2C na Raspberry Pi!