Operácie

Zbernica i2c: hodiny reálneho času s DS1388

Zo stránky SensorWiki

Záverečný projekt predmetu MIPS / LS2025 - Filip Boco


Zadanie

Zadaním tohto projektu bolo navrhnúť a realizovať hodiny reálneho času s RTC modulu DS1388 komunikujúcim cez zbernicu I2C. Systém s mikroprocesorom ATmega328P, ktorý zobrazuje aktuálny čas pomocou UART (PuTTY) alebo LCD displeja.

RTC I2C modul DS138833 a jeho pinout.

Literatúra:


Analýza a opis riešenia

Modul s obvodom RTC typu DS1388 je veľmi podobný ako PCF8583P, má rovnaký pinout a totožné funkcionality. Bolo pre mňa jednoduchšie použiť DS138833 pretože PCF8583P som nemal a musel by som si ho kúpiť alebo požičať. Oba tieto moduly komunikujú cez zbernicu I2C, majú základné pripojenie pomocou liniek SDA (data) a SCL (clock), napájanie VCC a GND. PCF8583P je starší a jednoduchší obvod vyrábaný firmou NXP. Poskytuje základnú funkciu RTC – uchovávanie hodín, minút, sekúnd, ako aj dátumu. Interný register je rozdelený do 8-bitových buniek, ktoré sú prístupné cez I²C protokol. Jeho výhodou je, že je často dostupný v podobe modulu s vývodmi prispôsobenými pre breadboard. Okrem základného napájania potrebuje tento modul zvyčajne externú záložnú batériu aby si zachoval čas aj pri strate hlavného napájania. DS1388, vyrábaný firmou Maxim Integrated, je modernejší RTC obvod. Poskytuje presnejšie počítanie času, integrované záložné napájanie (cez pin Vbackup), EEPROM pamäť na ukladanie dát a alarmového výstupu. DS138833 je SMD súčiastka, ktorú mám osadenú aj spolu s pull-up odpormi na PCB.


Použité komponenty

  • Arduino UNO v3
  • DS138833
  • 2ks 4.7 kΩ pull-up rezistory na I2C SDA a SCL
  • MS621FE batéria
  • káblové vodiče
Typická schéma zapojenia z datasheetu.


PCB s RTC modulom DS138833.

Algoritmus a program

Algoritmus programu obsahuje hlavičkovú časť programu s použitými knižnicami, definíciu pomocných funkcií a hlavnú funkčnú časť.

Použité knižnice

  • uart - knižnica na komunikáciu cez UART
  • i2cmaster - knižnica pre I2C komunikáciu

Vlastné funkcie

  • bcd2hex(uint8_t val) - prevod BCD (Binary-Coded Decimal) na HEX, využívaná pri čítaní aktuálneho času z RTC modulu
  • hex2bcd(uint8_t val) - prevod HEX na BCD, využívaná pri zápise aktuálneho času do RTC modulu
  • i2c_scanner(void) - funkcia vypíše do sériovej linky I2C adresu pripojeného zariadenia
  • set_time_date(...) - nastaví aktuálny čas a dátum do RTC modulu DS1388
  • read_time_date(...) - číta aktuálny čas a dátum z RTC modulu DS1388

Hlavný program

Main začína inicializáciou uart a i2c. Ďalej mám dve pomocné testovanie funkcie. Prvá uart_puts(...) testuje správnu funkcionalitu sériovej linky. Druhá i2c_scenner() overuje adresu RTC DS1388 modulu. Pokračuje definícia premenných a ich typu. Nakoniec samotný zápis času a čítanie s výpisom času vo while cykle. Knižnice i2cmaster.h a i2cmaster.c som nevkladal, pretože som na nich neurobil žiadne zmeny.

/*
uPrijekt MIPS 
Filip Boco
Téma: Zbernica i2c: hodiny reálneho času
Poznámka: Namiesto čipu PCF8583P som použil čip DS1388 I2C RTC. 
*/

#define F_CPU 16000000UL
#define BAUD 9600

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "i2cmaster.h"
#include "uart.h"

#define DS1388_ADDR 0x68

/*--------------------/ Funkcie na prevod BCD na HEX a HEX na BCD /--------------------*/

static uint8_t bcd2hex(uint8_t val) { 
	return ((val>>4)*10)+(val&0x0F); 
}

static uint8_t hex2bcd(uint8_t val) {
    return ((val/10)<<4)|(val % 10);
}

/*--------------------/ I2C scenner na zistenie I2C adresy /--------------------*/

void i2c_scanner(void) {
    uart_puts("I2C scanner start...\r\n");

    for (uint8_t address = 1; address < 127; address++) {
        i2c_start(address << 1); // Shift adresa na zápis (write)
        if (i2c_write(0) == 0) {
            uart_puts("Device found at 0x");
            uart_put_hex(address);
            uart_puts("\r\n");
        }
        i2c_stop();
        _delay_ms(10);
    }
}

/*--------------------/ Funkcie pre zápis a čítanie času na RTC module /--------------------*/

void set_time_date(uint8_t h, uint8_t m, uint8_t s, uint8_t day, uint8_t date, uint8_t month, uint8_t year) {
    i2c_start_wait(DS1388_ADDR<<1 | I2C_WRITE);
    i2c_write(0x01); // 0x01 register sekúnd, 0x00 sú desatiny sekundy

    i2c_write(hex2bcd(s));
    i2c_write(hex2bcd(m));
    i2c_write(hex2bcd(h));
    i2c_write(hex2bcd(day));
    i2c_write(hex2bcd(date));
    i2c_write(hex2bcd(month));
    i2c_write(hex2bcd(year));

    i2c_stop();
}

void read_time_date(uint8_t *h, uint8_t *m, uint8_t *s, uint8_t *day, uint8_t *date, uint8_t *month, uint8_t *year) {
	
	i2c_start_wait(DS1388_ADDR<<1 | I2C_WRITE);
	i2c_write(0x01); // 0x01 register sekúnd
	i2c_rep_start(DS1388_ADDR<<1 | I2C_READ);
	
	uint8_t sec = i2c_readAck();
	uint8_t min = i2c_readAck();
	uint8_t hour = i2c_readAck();    
	uint8_t d = i2c_readAck();     // d - day
	uint8_t dt = i2c_readAck();    // dt - date
	uint8_t mo = i2c_readAck();    // mo - month
	uint8_t yr = i2c_readNak();    // yr - year
	i2c_stop();
	
	*s = bcd2hex(sec & 0x7F);
	*m = bcd2hex(min);
	*h = bcd2hex(hour & 0x3F);
	*day = bcd2hex(d);
	*date = bcd2hex(dt);
	*month = bcd2hex(mo & 0x1F);
	*year = bcd2hex(yr);
}

/*--------------------/ Hlavný program /--------------------*/


int main(void) {
	
	i2c_init();
    uart_init();
	
	/*uart_puts("DS1388 RTC Test\r\n");*/
	
	/*i2c_scanner();*/
	
	char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
	
	uint8_t h,m,s,day,date,month,year;
	char buf[48];
	
// Nastavenie času a dátumu 
	/*set_time_date(6, 39, 0, 5, 13, 6, 25);*/ // 1 = Monday, ...
	
	while (1) {
		read_time_date(&h, &m, &s, &day, &date, &month, &year);
		sprintf(buf, "%s %02u.%02u.20%02u %02u:%02u:%02u\r", days[day-1], date, month, year, h, m, s); 
		uart_puts(buf);
		_delay_ms(1000);
	}
}
/* FileName: uart.c */

#include "uart.h"

#include <avr/io.h>
#include <util/setbaud.h>

#define F_CPU		16000000UL
#define BAUDRATE       9600
//#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)  // vzorček z datasheetu

void uart_init( void ) 
{
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;
	
	//UBRR0 = (unsigned char)BAUD_PRESCALE;                 // Set baud rate: Load the UBRR register

    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);                     // Set format: 8data, 1stop bit 

    UCSR0B = (1 << RXEN0) | (1 << TXEN0);                 // Enable receiver and transmitter

#if USE_2X
    UCSR0A |= _BV(U2X0);
#else
    UCSR0A &= ~(_BV(U2X0));
#endif

    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);   /* Enable RX and TX */
}


void uart_putc(char c) 
{
   if (c == '\n') 
    {
       uart_putc('\r');
    }
   loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
   UDR0 = c;
}

void uart_puts(const char *s)
{ 
  while(*s!='\0'){
	  uart_putc(*s);
	  s++;
  }
}

char uart_getc(void) 
{
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}

void uart_put_hex(uint8_t num) {
    const char hex[] = "0123456789ABCDEF";
    uart_putc(hex[(num >> 4) & 0x0F]);  // vyššia štvorica bitov
    uart_putc(hex[num & 0x0F]);         // nižšia štvorica bitov
}
/* FileName: uart.h */

#ifndef UART_H_
#define UART_H_
#define F_CPU		16000000UL
#define BAUD       9600
#define BAUD_PRESCALE  (((F_CPU / (BAUD * 16UL))) - 1)  // vzor?ek z datasheetu

void uart_init( void );
     
void uart_putc( char c );
void uart_puts( const char *s );

char uart_getc( void );

#endif /* UART_H_ */

Zdrojový kód: Boco_Projekt_i2c_RTC.zip

Overenie

Funkčnosť som overil porovnaním reálneho času a času vypísaného do PuTTY sériovej linky.

Finálny obvod s RTC modulom DS1388.