Operácie

Hodinový modul DS1302

Zo stránky SensorWiki

Záverečný projekt predmetu MIPS / LS2024 - Meno Priezvisko


Zadanie

Hodinový modul DS1302 - napíšte rutiny na nastavenie a prečítanie aktuálneho času a dátumu.
Vývojová doska Arduino Uno.

Literatúra:


Analýza a opis riešenia

Hodinový modul DS1302 je real-time clock (RTC) modul, ktorý poskytuje presný čas a dátum pre systémy s mikrokontrolérmi. Umožňuje sledovať sekundy, minúty, hodiny, deň v týždni, deň v mesiaci, mesiac a rok s automatickou korekciou pre mesiac a počet dní v mesiaci, vrátane priestupných rokov. DS1302 komunikuje s mikrokontrolérom pomocou sériového rozhrania. Do zapojenia som nepridal batériu CR2032, lebo bola v tomto prípade zbytočná batéria tu slúži len na udržanie zadaného času a dátumu na hodinovom module, pre naše ukážky nebola potrebná.

Zapojenie do arduino dosky.

schéma zapojenia RTC hodinového modulu DS1302

Schéma zapojenia modulu DS1302.


Algoritmus a program

Algoritmus programu je....


#define F_CPU 16000000UL  // Definícia frekvencie mikrokontroléra
#define BAUDRATE 9600  // Rýchlosť komunikácie cez UART
#define BAUD_PRESCALE ((F_CPU / (BAUDRATE * 16UL)) - 1)  // Výpočet hodnôt pre nastavenie UART

#define RTC_SCLK_PIN PD6  // Definícia pinov pre komunikáciu s DS1302
#define RTC_IO_PIN PD7
#define RTC_CE_PIN PD8

ds1302RTC myRTC(RTC_SCLK_PIN, RTC_IO_PIN, RTC_CE_PIN);  // Inicializácia objektu pre prácu s DS1302

void ds1302RTC_init() {
    DDRB |= (1 << DS1302_SCLK_PIN) | (1 << DS1302_IO_PIN) | (1 << DS1302_CE_PIN);
}

int main() {
    uart_init(BAUD_PRESCALE);  // Inicializácia UART s vypočítanými hodnotami
    myRTC.initRTC(RTC_SCLK_PIN, RTC_IO_PIN, RTC_CE_PIN);  // Inicializácia RTC modulu

    // NASTAVENIE ČASU: formát > sekundy, minúty, hodiny, deň v týždni, deň v mesiaci, mesiac, rok
    // myRTC.setDS1302Time(20, 04, 11, 2, 4, 6, 2024); 

    while (1) {  // Nekonečná slučka
        myRTC.updateTime();  // Aktualizácia času z RTC modulu

        // Vytvorenie reťazca s aktuálnym dátumom a časom
        char timeString[30];
        sprintf(timeString, "Aktuálny dátum a čas: %d.%d.%d  %02d:%02d:%02d\r\n",
                myRTC.dayofmonth, myRTC.month, myRTC.year, myRTC.hours, myRTC.minutes, myRTC.seconds);

        uart_puts(timeString);  // Poslanie reťazca cez UART
        _delay_ms(1000);  // Oneskorenie 1 sekundu
    }

    return 0; 
}
#ifndef ds1302_H
#define ds1302_H

#include <avr/io.h>
#include <util/delay.h>
#include <string.h>

#define DS1302_ENABLE            0x8E
#define DS1302_TRICKLE           0x90

class ds1302RTC {
public:
    ds1302RTC(uint8_t inSCLK, uint8_t inIO, uint8_t inC_E);

    void initRTC(uint8_t CLK, uint8_t IO, uint8_t ENABLE);
    void DS1302_clock_burst_read(uint8_t *p);
    void DS1302_clock_burst_write(uint8_t *p);
    uint8_t DS1302_read(int address);
    void DS1302_write(int address, uint8_t data);
    void _DS1302_start();
    void _DS1302_stop();
    uint8_t _DS1302_toggleread();
    void _DS1302_togglewrite(uint8_t data, uint8_t release);
    void setDS1302Time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t dayofweek, uint8_t dayofmonth, uint8_t month, int year);
    void updateTime();

private:
    uint8_t SCLK;
    uint8_t IO;
    uint8_t C_E;
    uint8_t seconds;
    uint8_t minutes;
    uint8_t hours;
    uint8_t dayofweek;
    uint8_t dayofmonth;
    uint8_t month;
    int year;
};

#endif
#include <avr/io.h>
#include <util/delay.h>
#include "ds1302.h"

#define DS1302_SCLK_PIN  PD6
#define DS1302_IO_PIN    PD7
#define DS1302_CE_PIN    PD8

void ds1302RTC_init() {
    // Initialize pins as output
    DDRB |= (1 << DS1302_SCLK_PIN) | (1 << DS1302_IO_PIN) | (1 << DS1302_CE_PIN);
}

void DS1302_clock_burst_read(uint8_t *p) {
    int i;
    _DS1302_start();
    _DS1302_togglewrite(DS1302_CLOCK_BURST_READ, true);
    for(i = 0; i < 8; i++) {
        *p++ = _DS1302_toggleread();
    }
    _DS1302_stop();
}

void DS1302_clock_burst_write(uint8_t *p) {
    int i;
    _DS1302_start();
    _DS1302_togglewrite(DS1302_CLOCK_BURST_WRITE, false);
    for(i = 0; i < 8; i++) {
        _DS1302_togglewrite(*p++, false);
    }
    _DS1302_stop();
}

uint8_t DS1302_read(int address) {
    uint8_t data;
    bitSet(address, DS1302_READBIT);
    _DS1302_start();
    _DS1302_togglewrite(address, true);
    data = _DS1302_toggleread();
    _DS1302_stop();
    return data;
}

void DS1302_write(int address, uint8_t data) {
    bitClear(address, DS1302_READBIT);
    _DS1302_start();
    _DS1302_togglewrite(address, false);
    _DS1302_togglewrite(data, false);
    _DS1302_stop();
}

void _DS1302_start(void) {
    digitalWrite(DS1302_CE_PIN, LOW);
    pinMode(DS1302_CE_PIN, OUTPUT);
    digitalWrite(DS1302_SCLK_PIN, LOW);
    pinMode(DS1302_SCLK_PIN, OUTPUT);
    pinMode(DS1302_IO_PIN, OUTPUT);
    digitalWrite(DS1302_CE_PIN, HIGH);
    _delay_us(4);
}

void _DS1302_stop(void) {
    digitalWrite(DS1302_CE_PIN, LOW);
    _delay_us(4);
}

uint8_t _DS1302_toggleread(void) {
    uint8_t i, data = 0;
    for(i = 0; i <= 7; i++) {
        digitalWrite(DS1302_SCLK_PIN, HIGH);
        _delay_us(1);
        digitalWrite(DS1302_SCLK_PIN, LOW);
        _delay_us(1);
        bitWrite(data, i, digitalRead(DS1302_IO_PIN));
    }
    return data;
}

void _DS1302_togglewrite(uint8_t data, uint8_t release) {
    int i;
    for(i = 0; i <= 7; i++) {
        digitalWrite(DS1302_IO_PIN, bitRead(data, i));
        _delay_us(1);
        digitalWrite(DS1302_SCLK_PIN, HIGH);
        _delay_us(1);
        if(release && i == 7) {
            pinMode(DS1302_IO_PIN, INPUT);
        } else {
            digitalWrite(DS1302_SCLK_PIN, LOW);
            _delay_us(1);
        }
    }
}

void ds1302RTC_setDS1302Time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t dayofweek, uint8_t dayofmonth, uint8_t month, int year) {
    struct ds1302_struct rtc;
    seconds = seconds;
    minutes = minutes;
    hours = hours;
    dayofweek = dayofweek;
    dayofmonth = dayofmonth;
    month = month;
    year = year;

    memset((char *)&rtc, 0, sizeof(rtc));

    rtc.Seconds = bin2bcd_l(seconds);
    rtc.Seconds10 = bin2bcd_h(seconds);
    rtc.CH = 0;
    rtc.Minutes = bin2bcd_l(minutes);
    rtc.Minutes10 = bin2bcd_h(minutes);
    rtc.h24.Hour = bin2bcd_l(hours);
    rtc.h24.Hour10 = bin2bcd_h(hours);
    rtc.h24.hour_12_24 = 0;
    rtc.Date = bin2bcd_l(dayofmonth);
    rtc.Date10 = bin2bcd_h(dayofmonth);
    rtc.Month = bin2bcd_l(month);
    rtc.Month10 = bin2bcd_h(month);
    rtc.Day = dayofweek;
    rtc.Year = bin2bcd_l(year - 2000);
    rtc.Year10 = bin2bcd_h(year - 2000);
    rtc.WP = 0;

    DS1302_clock_burst_write((uint8_t *)&rtc);
}

void ds1302RTC_updateTime() {
    struct ds1302_struct rtc;
    DS1302_clock_burst_read((uint8_t *)&rtc);

    seconds = (rtc.Seconds10 * 10) + rtc.Seconds;
    minutes = (rtc.Minutes10 * 10) + rtc.Minutes;
    hours = (rtc.h24.Hour10 * 10) + rtc.h24.Hour;
    dayofweek = rtc.Day;
    dayofmonth = (rtc.Date10 * 10) + rtc.Date;
    month = (rtc.Month10 * 10) + rtc.Month;
    year = (rtc.Year10 * 10) + rtc.Year + 2000;
}
/* ************************************************************************* */
/* FileName:             uart.h                                              */
/* ************************************************************************* */

#define LED PB5  // internal on-board LED 

 /* na testovanie su uz zadefinovane */
 // bit_is_set(PINB, SW1)
 // bit_is_clear(PINB, SW1)

 /* na cakanie su preddefinovane slucky */
 // loop_until_bit_is_set(PINB, SW1);    // cakanie na uvolnenie tlacitka
 // loop_until_bit_is_clear(PINB, SW1);  // cakanie na stlacenie tlacitka


#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))

#ifndef UART_H_
#define UART_H_

#include <stdio.h>

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

void hw_init( void );
void uart_init( void );
     
/* Following definition is compatible with STDIO.H, for more
 * information see https://www.appelsiini.net/2011/simple-usart-with-avr-libc/
 */
	 
int uart_putc( char c, FILE *stream );
void uart_puts( const char *s );

char uart_getc( void );

void delay(int delay); 

#endif /* UART_H_ */

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

  1. include <avr/io.h>
  2. include <util/delay.h>
  3. include "uart.h"

void hw_init( void ) {

 DDRB |= (1<<LED);    // PORTB.5 kde je LED ma byt OUTPUT
 /* sem si mozete dopisat svoje vlastne inicializacne prikazy */ 	

}

void uart_init( void ) { // for different BAUD rate change the project settings, or uncomment // following two lines: // #undef BAUD // avoid compiler warning // #define BAUD 115200

  #include <util/setbaud.h>  // requires defined BAUD
  
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  #if USE_2X                 // defined in setbaud.h 
   UCSR0A |= (1 << U2X0);
  #else
   UCSR0A &= ~(1 << U2X0);
  #endif


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

}


int uart_putc( char c, FILE *stream ) {

  if (c == '\n') 
     uart_putc('\r',stream);
  
  loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
  UDR0 = c;
  return 0;

}


void uart_puts(const char *s) {

 /* toto je vasa uloha */

}

char uart_getc(void) {

   loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
   return UDR0;

}

void delay(int delay) // vlastna funkcia pre dlhsie casy {

 for (int i=1; i<=delay; i++)
 _delay_ms(1);

}

Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x zdrojaky.zip:

Zdrojový kód: zdrojaky.zip


Overenie

Overenie sa spraví cez serial(putty) na ktorom vidíme ako sa každú sekundu vypíše náš aktuálny čas a dátum.

Aplikácia.

Video:

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