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.

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


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.
