Operácie

Zbernica i2c: hodiny reálneho času s PCF8583P

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 PCF8583P komunikujúcim cez zbernicu I2C. Systém s mikroprocesorom ATmega328P, ktorý zobrazuje aktuálny čas pomocou UART (PuTTY) alebo LCD displeja.

Súbor:DS138833.jpg RTC čip DS1388.

Literatúra:


Analýza a opis riešenia

V zadaní špecifikovaný RTC modul PCF8583P som pri vypracovaní nepoužil. Opíšte sem čo a ako ste spravili, ak treba, doplňte obrázkami... Podrobne opíšte použité komponenty (okrem základnej dosky s ATmega328P procesorom), pridajte linky na datasheety alebo opis obvodu.

Celkový pohľad na zariadenie.

Nezabudnite doplniť schému zapojenia! V texte by ste mali opísať základné veci zo zapojenia, samotná schéma nie je dostačujúci opis.

Schéma zapojenia.


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
}

</syntaxhighlight ></tab> <tab name="uart.h"><syntaxhighlight lang="c++" style="background: LightYellow;"> /* FileName: uart.h */

  1. ifndef UART_H_
  2. define UART_H_
  3. define F_CPU 16000000UL
  4. define BAUD 9600
  5. 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 );

  1. endif /* UART_H_ */

Zdrojový kód: zdrojaky.zip

Overenie

Ako ste overili funkciu, napríklad... Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia. Na konci uvádzame fotku hotového zariadenia.

Aplikácia.

Video:



Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.