Žiūrėkite DS1307 nuo idėjos iki įgyvendinimo. DS1307 prijungimas prie AVR mikrovaldiklių Ds1307 jungtis

DS1307 taip pat vadinamas RTC (Real Time Clock). Šis lustas yra realaus laiko laikrodis ir kalendorius. Ryšys su mikroschema vyksta per I 2 C sąsają Jo pranašumas yra tas, kad jis veikia (skaičiuoja laiką), kai pagrindinis maitinimas yra išjungtas iš atsarginio 3 voltų maitinimo šaltinio (pavyzdžiui, iš CR3022 baterijos). Tačiau DS1307 turi vieną trūkumą: netikrina, ar įvesti duomenys teisingi. Norėdami dirbti su mikroschema, jums reikės minimalaus rinkinio: 32768 Hz kvarco, 3 voltų akumuliatoriaus ir dviejų 4,7 kOhm rezistorių. Sujungimo schema DS1307:

Darbas su DS1307 BASCOM-AVR

Norėdami pradėti dirbti su mikroschema, turite sukonfigūruoti prievadus, prie kurių prijungta mikroschema, naudokite komandą konfig:
Sda konfigūracija =(Mikrovaldiklio prievadas, prie kurio prijungta DS1307 lusto SDA kojelė)
Config Scl =(Mikrovaldiklio prievadas, prie kurio prijungta DS1307 lusto SCL kojelė)
Pavyzdžiui:
Sda konfigūracija = Portb.1
Config Scl = Portb.0

Sukonfigūravę prievadus, galite pradėti dirbti su lustu: skaityti ir rašyti duomenis. DS1307 lusto laiką ir datą galima perskaityti taip:

I2cstart I2cwbyte &HD0 I2cwbyte &H00 I2cstart I2cwbyte &HD1 I2crbyte (kintamasis, kuriame rašome sekundes), Ack I2crbyte (kintamasis, kuriame rašome minutes), Ack I2crbyte (kintamasis, kuriame rašome valandas), Ack I2crbyte (kintamasis kuriame we parašykite savaitės dienos skaičių), Ack I2crbyte (kintamasis, kuriame rašome datą), Ack I2crbyte (kintamasis, kuriame rašome mėnesio numerį), Ack I2crbyte (kintamasis, kuriame rašome metus), Nack I2cstop

Perskaitę duomenis, turite juos konvertuoti į dešimtainį formatą, pavyzdžiui:
(sekundės kintamasis) = Makedec((sekundės kintamasis) )
(minutės kintamas) = Makedec((minutės kintamas) )
(laikrodžio kintamasis) = Makedec((laikrodžio kintamasis) )
(savaitės dienos kintamasis) = Makedec((savaitės dienos kintamasis) )
(datos kintamasis) = Makedec((datos kintamasis) )
(mėnesio kintamasis) = Makedec((mėnesio kintamasis) )
(metų kintamasis) = Makedec((metų kintamasis) )

Štai pavyzdys, kaip nuskaityti laiką ir datą ir konvertuoti juos į dešimtainį formatą:

I2cstart I2cwbyte &HD0 I2cwbyte &H00 I2cstart I2cwbyte &HD1 I2crbyte Seco , Ack I2crbyte Mine , Ack I2crbyte Hour , Ack I2crbyte Day , Ack I2crbyte Dat , Ack I2crbyte I2cwbyte co M) ine = Makedec (mano) Valanda = Makedec(valanda) Diena = Makedec(diena) Dat = Makedec(dat) Mėnuo = Makedec(mėnuo) Metai = Makedec(metai)

Išmokome skaityti duomenis, o dabar pabandykime įrašyti duomenis į DS1307. Kaip šitas:
(Kintamasis, kurį užsirašysime) = Makebcd((Kintamasis, kurį užsirašysime) )
I2cstart
I2cwbyte&HD0
I2cwbyte(Ląstelė, kurioje rašysime duomenis)
I2cwbyte(Kintamasis, kurį užsirašysime)
I2cstop

Atkreipkite dėmesį, kad komanda Makebcd konvertuoja kintamąjį į dvejetainį dešimtainį formatą. Ląstelių numeriai ir pavadinimai:

Štai sekundžių kintamojo rašymo pavyzdys:
Seco = Makebcd (seco)
I2cstart
I2cwbyte&HD0
I2cwbyte 0
I2cwbyte Seco
I2cstop
Beje, reikia pažymėti, kad pirmą kartą paleidus DS1307 (pavyzdžiui, prijungus atsarginę bateriją), mikroschema per sekundes grąžins 80 reikšmę, o tai reiškia, kad laikrodis sustabdomas. Norėdami juos paleisti, užrašykite 1 reikšmę sekundėmis. Jei skaitydamas bet kokius duomenis DS1307 grąžina 255 arba 168, tai reiškia, kad lustas netinkamai prijungtas arba nėra atsarginės baterijos.

Praktinis darbas su DS1307 lustu

Dabar pabandykime dirbti su DS1307 mikroschema praktiškai: surinkime paprastą laikrodį su laiko nustatymu mygtukais. Norėdami tai padaryti, paimkime patį DS1307 lustą, Attiny2313 mikrovaldiklį, HD44780 valdiklio LCD indikatorių ir keletą atskirų komponentų. Sudarykime paprastą diagramą:

Ir parašykime paprastą programą naudodami įgytas žinias:

$regfile = "attiny2313.dat" $crystal = 4000000 Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.3 , Rs = Portb .2 Config Lcd = 16 * 2 Config Pind.5 = Input Config Pind.4 = Input Config Sda = Portb.1 Config Scl = Portb.0 Dim Seco As Byte Dim Mine As Byte Dim Valanda As Byte Initlcd Cls žymeklis išjungtas Do I2cs Start I2cwbyte &HD0 I2cwbyte &H00 I2cstart I2cwbyte &HD1 I2crbyte Seco , Ack I2crbyte Mine , Ack I2crbyte Hour , Nack I2cstop Seco = Makedec(seco) Mine = Makedec(mine) Hour = Makedec(mano) valanda = Makedec(mano) valanda = Lodec(hour) ":" ; Mano; ":" ; seco ; " " If Pind.5 = 0 Tada Inr Mine Mine = Makebcd(mine) I2cstart I2cwbyte &HD0 I2cwbyte 1 I2cwbyte Mine I2cstop Laukimas 100 Pabaiga, jei Pind.4 = 0 Tada Inr Hour Hour = Makebcd(valanda) I2byctew2HD I2byte2byte Valanda I2cstop laukia 100 pabaigos, jei ciklo pabaiga

DS1307- Realaus laiko laikrodžio lustas su sąsaja I2C (TWI). Laikrodis / kalendorius saugo šią informaciją: sekundes, minutes, valandas, dieną, datą, mėnesį ir metus. Mėnesio pabaiga automatiškai koreguojama mėnesiams, kurių trukmė yra mažesnė nei 31 diena, įskaitant koregavimą keliamieji metai. Laikrodis veikia 24 valandų arba 12 valandų formatu su AM/PM indikatoriumi. DS1307 turi įmontuotą galios stebėjimo grandinę, kuri aptinka energijos praradimą ir automatiškai perjungia grandinę į baterijos maitinimą.

Vbat- Baterijos įvestis bet kokiam standartiniam 3 voltų ličio elementui ar kitam maitinimo šaltiniui. Normaliam veikimui akumuliatoriaus įtampa turi būti palaikoma nuo 2,5 iki 3,5 V. Lygis, kuriam esant draudžiama prieiga prie realaus laiko laikrodžio ir vartotojo RAM, viduje nustatytas į 1,25 x Vbat. 35 mAh ar didesnės talpos ličio baterijos pakanka, kad DS1307 maitintų daugiau nei 10 metų, kai nėra energijos.
SCL(Serial Clock Input) – SCL naudojamas duomenų perdavimui per nuosekliąją sąsają sinchronizuoti.
S.D.A.(Serial Data Input/Output) – SDA – duomenų įvestis/išvestis 2 laidų nuosekliajai sąsajai. Tai atvira nutekėjimo išvestis, kuriai reikalingas išorinis traukimo rezistorius.
SQW/OUT(Kvadratinis kvadratas / išvesties tvarkyklė) – kai SQWE bitas nustatytas į 1, SQW/OUT išvestis generuoja kvadratinės bangos impulsus vienu iš keturių dažnių: 1 Hz, 4 kHz, 8 kHz, 32 kHz. SQW/OUT kaištis yra atviras, todėl jam reikalingas išorinis traukimo rezistorius.
X1, X2- 32,768 kHz standartinio kvarco kristalo prijungimo laidai. Osciliatoriaus vidinė grandinė skirta veikti su kristalu, kurio vardinė talpa (CL) yra 12,5 pF.
GND- Žemė.
VCC- maitinimo šaltinis 5 voltai.

DS1307 veikia kaip pagalbinis įrenginys nuosekliojoje magistralėje. Norėdami jį pasiekti, turite nustatyti būseną PRADĖTI ir perduoda įrenginio identifikavimo kodą, po kurio nurodomas registro adresas. Tolesni registrai gali būti pasiekiami nuosekliai, kol bus nustatyta būsena SUSTABDYTI. Kada VCC nukrenta žemiau 1,25 x Vbat, įrenginys nustoja bendrauti ir iš naujo nustato adresų skaitiklį. Per šį laiką jis nereaguos į įvesties signalus, kad būtų išvengta klaidingos informacijos įrašymo. Kada VCC nukrenta žemiau Vbat, įrenginys persijungia į mažos galios saugojimo režimą. Kai įjungiate maitinimą, įrenginys perjungia maitinimą iš akumuliatoriaus į VCC kai maitinimo įtampa viršija Vbat + 0,2V, ir reaguoja į įvesties signalus, kai VCC taps daugiau nei 1,25 x Vbat. Kai galia yra normaliose ribose, įrenginys yra visiškai prieinamas ir duomenis galima rašyti bei skaityti. Kai prie įrenginio prijungtas trijų voltų akumuliatorius ir VCC yra mažesnis nei 1,25 x Vbat, skaityti ir rašyti draudžiama. Tačiau laiko skaičiavimas vis dar veikia. Kada VCC nukrenta žemiau Vbat, RAM ir laiko matavimo maitinimas perjungiamas į išorinę 3 V bateriją.

Informacija apie laiką ir datą gaunama skaitant atitinkamus registrus. Laikrodžių registrai pateikti toliau esančioje lentelėje. Laikas ir kalendorius nustatomi arba inicijuojami įrašant baitus į atitinkamus registrus. Laiko ir kalendoriaus registrų turinys saugomas BCD (BCD) formatu, todėl prieš pateikiant informaciją LCD ekrane arba septynių segmentų indikatoriuje, būtina konvertuoti BCD kodą į dvejetainį arba ANSII kodą.

0 registro 7 bitas yra laikrodžio sustabdymo bitas. Kai šis bitas nustatomas į 1, generatorius sustabdomas. Nustačius nulį, generatorius veikia ir laikrodis skaičiuoja laiką.

DS1307 gali veikti 12 valandų arba 24 valandų režimu. Laikrodžio registro 6 bitas nurodo vieną iš šių režimų. Kai jis lygus 1, nustatomas 12 valandų režimas. 12 valandų režimu aukštas lygis 5 bitas rodo popietės laiką. 24 valandų režimu 5 bitas yra antrasis bitas 10 valandų (20–23 valandos).

DS1307 valdymo registras skirtas valdyti išvesties veikimą SQW/OUT. Bit OUT- išėjimo valdymas. Šis bitas valdo kaiščio išvesties lygį SQW/OUT, kai išjungta meandro generacija. Jei SQWE = 0, kaiščio loginis lygis SQW/OUT lygus 1 jei OUT= 1, o 0 - jei OUT = 0. SQWE- Medžio raiška. Kai šis bitas nustatytas į 1, įjungiama kvadratinių bangų generavimas. Kvadratinės bangos dažnis priklauso nuo RS0 ir RS1 bitų reikšmių. Šie bitai valdo kvadratinės bangos dažnį, kai įjungtas jos generavimas. Žemiau esančioje lentelėje rodomi dažniai, kuriuos galima nurodyti RS bitais.

DS1307 palaiko dvikryptę 2 laidų magistralę ir duomenų perdavimo protokolą. Įrenginys, siunčiantis duomenis į magistralę, vadinamas siųstuvu, o įrenginys, kuris priima duomenis, vadinamas imtuvu. Įrenginys, valdantis transmisiją, vadinamas pagrindiniu. Įrenginiai, kuriuos valdo pagrindinis valdiklis, yra vergai. Magistralę turi valdyti pagrindinis įrenginys, kuris generuoja serijinius laikrodžius (SCL), kontroliuoja prieigą prie magistralės ir generuoja START ir STOP būsenas. DS1307 veikia kaip pavaldinys 2 laidų magistralėje.

Norint dirbti su DS1307, būtina organizuoti skaitymo iš lusto ir rašymo funkciją.

1. Įrašymo režimas DS1307. Serijiniai duomenys ir laikrodžiai gaunami per SDA ir SCL. Perdavus kiekvieną baitą, perduodamas patvirtinimo bitas. KLAUSTI. valstybėse PRADĖTI Ir SUSTABDYTI yra pripažįstami kaip serijinio perdavimo pradžia ir pabaiga. Adreso atpažinimas atliekamas aparatinėje įrangoje gavus pavaldinį adresą ir krypties bitą. Adreso baite yra DS1307 septynių bitų adresas 1101000, po kurio seka krypties bitas (R/W), kuris rašant yra 0 Kai adreso baitas yra gautas ir iškoduotas, DS1307 išduoda patvirtinimą KLAUSTI SDA linijoje. Kai DS1307 patvirtina pavaldų adresą ir rašymo bitą, pagrindinis įrenginys perduoda registro adresą DS1307. Tai nustatys registro žymeklį DS1307. Tada pagrindinis įrenginys pradės siųsti duomenų baitus į DS1307, kuris patvirtins kiekvieną gautą baitą. Įrašo pabaigoje vedėjas sukurs būseną SUSTABDYTI.

2. Skaitymo režimas iš DS1307. Pirmasis baitas gaunamas ir apdorojamas kaip vergo imtuvo režimu. Tačiau šiuo režimu krypties bitas parodys, kad perdavimo kryptis buvo pakeista. Serijos duomenys perduodami per SDA iš DS1307, o serijiniai laikrodžiai per SCL perduodami į DS1307. valstybėse PRADĖTI Ir SUSTABDYTI atpažįstami kaip serijinio perdavimo pradžia ir pabaiga. Adreso baitas yra pirmasis baitas, gautas po to, kai pagrindinis kompiuteris sugeneravo būseną. PRADĖTI. Adreso baite yra DS1307 septynių bitų adresas 1101000, po kurio seka krypties bitas (R/W), kuris nuskaitant yra 1 Kai adreso baitas yra gautas ir iškoduotas, DS1307 išduoda patvirtinimą KLAUSTI SDA linijoje. Tada DS1307 pradeda siųsti duomenis nuo registro adreso, kurį nurodė registro žymeklis. Jei registro rodyklė neparašyta prieš pradedant skaitymo režimą, pirmasis nuskaitomas adresas yra paskutinis adresas, likęs registro žymeklyje. DS1307 turėtų būti nepripažintas NOASKAS baigti skaityti.

Pažvelkime į darbo su DS1307 ypatybes naudodami paprasto laikrodžio, rodančio valandas, minutes ir sekundes, pavyzdį. Duomenys bus rodomi 16x2 LCD ekrane. Du mygtukai „Valandos+“ ir „Minutės+“ leis nustatyti norimą laiką. Atmega 8 mikrovaldiklis veikia iš vidinio osciliatoriaus, kurio dažnis yra 1 MHz, todėl nepamirškite pakeisti saugiklių. Žemiau yra prijungimo schema.

Valdymo programoje yra funkcijų rinkiniai, skirti darbui su TWI magistrale, DS1307 laikrodžiu ir LCD ekranu.

I2CInit - magistralės inicijavimas;
I2CStart - START sąlygos perdavimas;
I2CStop - STOP sąlygos perdavimas;
I2CWriteByte - įrašyti duomenis;
I2CReadByte – duomenų skaitymas;
DS1307Read – funkcija nuskaityti duomenis iš DS1307;
DS1307Write – Funkcija įrašyti duomenis į DS1307;
lcd_com - komandų perdavimas į LCD;
lcd_data - duomenų perdavimas į LCD;
lcd_string – funkcija, rodanti eilutę LCD ekrane;
lcd_num_to_str - funkcija int tipo simboliui išvesti;
lcd_init – LCD inicijavimas.

Žemiau yra programos kodas:

#įtraukti #įtraukti // TWI magistralės inicijavimo funkcija void I2CInit(void) ( TWBR = 2; // Magistralės dažnio nustatymas TWSR = (1<< TWPS1)|(1 << TWPS0); // Предделитель на 64 TWCR |= (1 << TWEN); // Включение модуля TWI } // Функция СТАРТ void I2CStart(void) { TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWSTA); // Передача условия СТАРТ while(!(TWCR & (1 << TWINT))); // Ожидание установки флага TWINT } // Функция СТОП void I2CStop(void) { TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWSTO); // Передача условия СТОП while(TWCR & (1 << TWSTO)); // Ожидание завершения передачи условия СТОП } // Функция записи данных по шине uint8_t I2CWriteByte(uint8_t data) { TWDR = data; // Загрузка данных в TWDR TWCR = (1 << TWEN)|(1 << TWINT); // Сброс флага TWINT для начала передачи данных while(!(TWCR & (1 << TWINT))); // Ожидание установки флага TWINT // Проверка статуса // Если адрес DS1307+R и принято "подтверждение"(0x18) // или адрес DS1307+W и принято "подтверждение"(0x40) // или передается байт данных и принято "подтверждение"(0x28) if((TWSR & 0xF8) == 0x18 || (TWSR & 0xF8) == 0x40 || (TWSR & 0xF8) == 0x28) return 1; // OK else return 0; // ОШИБКА } // Функция чтения данных по шине uint8_t I2CReadByte(uint8_t *data,uint8_t ack) { // Возвращаем "подтверждение" после приема if(ack) TWCR |= (1 << TWEA); // Возвращаем "неподтверждение" после приема // Ведомое устройство не получает больше данных // обычно используется для распознования последнего байта else TWCR &= ~(1 << TWEA); // Разрешение приема данных после сброса TWINT TWCR |= (1 << TWINT); while(!(TWCR & (1 << TWINT))); // Ожидание установки флага TWINT // Проверка статуса // Если принят байт данных и возвращается "подтверждение"(0x50) // или принят байт данных и возвращается "ненеподтверждение"(0x58) if((TWSR & 0xF8) == 0x50 || (TWSR & 0xF8) == 0x58) { *data = TWDR; // Читаем данные из TWDR return 1; // OK } else return 0; // ОШИБКА } // Функция чтения данных из DS1307 uint8_t DS1307Read(uint8_t address,uint8_t *data) { uint8_t res; I2CStart(); // СТАРТ res = I2CWriteByte(0b11010000); // адрес DS1307+W if(!res) return 0; // ОШИБКА // Передача адреса необходимого регистра res = I2CWriteByte(address); if(!res) return 0; // ОШИБКА I2CStart(); // Повторный СТАРТ res = I2CWriteByte(0b11010001); // адрес DS1307+R if(!res) return 0; // ОШИБКА // Чтение данных с "неподтверждением" res = I2CReadByte(data,0); if(!res) return 0; // ОШИБКА I2CStop(); // СТОП return 1; // OK } // Функция записи данных в DS1307 uint8_t DS1307Write(uint8_t address,uint8_t data) { uint8_t res; I2CStart(); // СТАРТ res = I2CWriteByte(0b11010000); // адрес DS1307+W if(!res) return 0; // ОШИБКА // Передача адреса необходимого регистра res = I2CWriteByte(address); if(!res) return 0; // ОШИБКА res = I2CWriteByte(data); // Запись данных if(!res) return 0; // ОШИБКА I2CStop(); // СТОП return 1; // OK } // Функции работы с LCD #define RS PD0 #define EN PD2 // Функция передачи команды void lcd_com(unsigned char p) { PORTD &= ~(1 << RS); // RS = 0 (запись команд) PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл _delay_us(100); PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл _delay_us(100); PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); } // Функция передачи данных void lcd_data(unsigned char p) { PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл _delay_us(100); PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл _delay_us(100); PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); } // Функция вывода строки на LCD void lcd_string(unsigned char command, char *string) { lcd_com(0x0C); lcd_com(command); while(*string != "\0") { lcd_data(*string); string++; } } // Функция вывода переменной void lcd_num_to_str(unsigned int value, unsigned char nDigit) { switch(nDigit) { case 4: lcd_data((value/1000)+"0"); case 3: lcd_data(((value/100)%10)+"0"); case 2: lcd_data(((value/10)%10)+"0"); case 1: lcd_data((value%10)+"0"); } } // Функция инициализации LCD void lcd_init(void) { PORTD = 0x00; DDRD = 0xFF; _delay_ms(50); // Ожидание готовности ЖК-модуля // Конфигурирование четырехразрядного режима PORTD |= (1 << PD5); PORTD &= ~(1 << PD4); // Активизация четырехразрядного режима PORTD |= (1 << EN); PORTD &= ~(1 << EN); _delay_ms(5); lcd_com(0x28); // шина 4 бит, LCD - 2 строки lcd_com(0x08); // полное выключение дисплея lcd_com(0x01); // очистка дисплея _delay_us(100); lcd_com(0x06); // сдвиг курсора вправо lcd_com(0x0C); // включение дисплея, курсор не видим } int main(void) { _delay_ms(100); DDRC = 0x00; PORTC = 0xFF; lcd_init(); // Инициализация LCD I2CInit(); // Инициализация шины I2C lcd_string(0x81, "«acГ Ѕa DS1307"); // Часы на DS1307 lcd_string(0xC4, " : : "); // Запускаем ход часов uint8_t temp; DS1307Read(0x00,&temp); temp &= ~(1 << 7); // обнуляем 7 бит DS1307Write(0x00,temp); while(1) { unsigned char hour, minute, second, temp; // Читаем данные и преобразуем из BCD в двоичную систему DS1307Read(0x00,&temp); // Чтение регистра секунд second = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F); DS1307Read(0x01,&temp); // Skaityti minučių registrą minutė = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F); DS1307Read(0x02,&temp); // Skaityti laikrodžio registrą valanda = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F); lcd_com(0xC4); lcd_num_to_str(valanda, 2); // Rodyti laikrodį lcd_com(0xC7); lcd_num_to_str(minute, 2); // Rodyti minutes lcd_com(0xCA); lcd_num_to_str(sekunda, 2); // Rodyti sekundes if((PINC & (1<< PC0)) == 0) // Если нажата кнопка { while((PINC & (1 << PC0)) == 0){} // Ждем отпускания кнопки hour++; // Увеличиваем часы на 1 if(hour >23) valanda = 0; // Konvertuoti iš dvejetainio į BCD ir įrašyti į DS1307 uint8_t temp; temp = ((val./10)<< 4)|(hour%10); DS1307Write(0x02, temp); _delay_ms(100); } if((PINC & (1 << PC1)) == 0) // Если нажата кнопка { while((PINC & (1 << PC1)) == 0){} // Ждем отпускания кнопки minute++; // Увеличиваем минуты на 1 if(minute >59) minutė = 0; // Konvertuoti iš dvejetainio į BCD ir įrašyti į DS1307 uint8_t temp; temp = ((min./10)<< 4)|(minute%10); DS1307Write(0x01, temp); _delay_ms(100); } } }

DS1307 lusto laikrodžio tema yra gana aktuali – tai paprastas, bet kartu ir įdomus įrenginys. Be to, tai tikrai gali praversti. Tačiau nėra prasmės aprašinėti mikroschemos atskirai, todėl nusprendžiau surinkti panašų įrenginį sau ir tuo pačiu pakalbėti apie problemas, su kuriomis susidūriau šiame procese. Aprašysiu patį kūrimo ir surinkimo procesą, kai pereisime per kai kuriuos įrenginio paruošimo etapus.

Atnaujinimas 2015-10-17
Iš pradžių tai buvo straipsnių ciklas, kurio tikslas buvo kalbėti apie įrenginio sukūrimą nuo nulio iki paruošto būsenos, bet staiga pasidariau alergiškas viskam, kas vadinama „laikrodiu“, todėl viską sujungiau į vieną straipsnį. Prietaisas 99,9% sukomplektuotas (lieka tik priveržti varžtus), bet tai padaryti nėra paprasta :) Kai tik alergija praeis, pasirodys galutinė nuotrauka.

Pradėkime nuo to, kad iki šiol nieko nežinome apie ds1307, išskyrus tai, kad su juo gaminami laikrodžiai. Todėl atsisiųskite šios mikroschemos dokumentaciją ir perskaitykite jame esančių „gėrybių“ sąrašą. Taigi iš pirmos pastraipos apskritai aišku, kad jis turi mažai energijos, informacija perduodama per I2C, galima sužinoti datą ir laiką, 12 ir 24 valandų formatą, automatinį datos reguliavimą. Bet įdomiausia yra grandinė (TIPINĖ VEIKIMO GRANDAS).

Rūkome duomenų lapą ir bandome išsiaiškinti, kas yra kas. Einame iš kairės į dešinę, CPU - mikrovaldiklis (tai yra mūsų atmega), du rezistoriai, rašo pull up - tai reiškia patraukti (galite paimti po 10k), kvarcas 32768 Hz, pati mikroschema ir baterija. SQW/OUT išvestis gali šokinėti 1Hz, 4kHz, 8kHz, 32kHz dažniu, kol mūsų tai nedomina. Galbūt kol kas šios informacijos užtenka, norėčiau ką nors užkoduoti :)

Sukuriame projektą CodeVision, I2C skiltyje surandame ds1307 ir įtraukiame į projektą. Būtų gerai, kad informacija būtų rodoma kur nors, pavyzdžiui, LCD ekrane, ir pora mygtukų nepakenktų.

Viskas, ko jums reikia, yra sukonfigūruoti skystųjų kristalų ekraną D prievadui ir tris ištraukiamus įvesties mygtukus. Tada turime parodyti laiką LCD ekrane, pažiūrėkime į CodeVision vadovą ir paimkime iš ten pavyzdį. Pasirodo, viskas paprasta - yra funkcija, kuri nustato laiką:
rtc_set_time(3,0,0); //nustatyti 03:00:00

tie. iškvietus šią funkciją, kintamuosiuose h, m, s bus valandos (h), minutės (m) ir sekundės (s). Belieka juos parodyti ekrane. Tai mes žinome, kaip tai padaryti)
Galutinis kodas atrodys taip:

#įtraukti #įtraukti #įtraukti #įtraukti // Raidinis ir skaitmeninis LCD modulio funkcijos#asm .equ __lcd_port= 0x12 ; PORTD #endasm #įtraukti char lcd_buf[33] ; void main(void ) ( char valanda, min., sek; PORTC= 0x07 ; DDRC= 0x00 ; // I2C magistralės inicijavimas i2c_init() ; rtc_init(0 , 0 , 0 ) ; // LCD modulio inicijavimas lcd_init(16 )set; (3 , 0 , 0 ) ; while (1 ) ( rtc_get_time(& valanda,& min,& sek) ; lcd_clear() ; lcd_gotoxy(0 , 0 ) ; sprintf (lcd_buf, "%2d:%02d:%02d" \n", valanda, min., sek) ; lcd_puts(lcd_buf) ; delay_ms(500 ) ; ) ; )

#įtraukti #įtraukti #įtraukti // Raidinio ir skaitmeninio LCD modulio funkcijos #asm .equ __lcd_port=0x12 ;PORTD #endasm #include char lcd_buf; void main(void) ( char valanda,min,sek; PORTC=0x07; DDRC=0x00; // I2C magistralės inicijavimas i2c_init(); // DS1307 Realaus laiko laikrodžio inicijavimas rtc_init(0,0,0); // LCD modulis inicijavimas lcd_init(16); :%02d\n",valanda,min.sek.);lcd_puts(lcd_buf); delay_ms(500); ); )

Surenkame ir testuojame Proteus:

Grandinė ir programinė įranga

Mes ir toliau atnaujinsime savo programinę-aparatinę įrangą. Pradėkime nuo šios idėjos: DS1307 turi SQW/OUT išvestį, kuri gali generuoti kelis dažnius. Jei nustatysite šį išėjimą į 1Hz ir pritaikysite šį signalą išoriniam pertraukimo įėjimui, paaiškės, kad kartą per sekundę 1307 ištrauks mūsų atmega8 „uodegą“. Mega tai bus signalas, kad laikas atnaujinti laiką. Tai leis neapkrauti mikrovaldiklio su nuolatiniu laiko atnaujinimu, informacija apie esamą laiką bus atnaujinama tiksliai kartą per sekundę.

Pridėkime prie projekto išorinį žemo lygio pertraukimą ant Int1 kaiščio ir įjunkime ištraukimą. Nustatykime DS1307 išvestį 1 Hz dažniu. Beje, naudinga perskaityti vadovus, radau įdomią savybę - SCL ir SDA kojų traukimo rezistoriai turėtų būti 3,3–4,7 tūkst. Atsižvelgkime į tai.

Gautas kodas atrodys taip:

pertraukimas [ EXT_INT1] void ext_int1_isr(void ) ( time_flag= 1 ; )

nutraukti void ext_int1_isr(void) (time_flag=1; )

Pertraukime nustatome vėliavėlę, kuri leidžia išvesti laiką pagrindiniame cikle, jei vėliavėlė nustatyta, tada rodome laiką, jei ji nenustatyta, nieko nedarome;

if (time_flag== 1 ) ( rtc_get_time(& valanda,& min,& sek) ; lcd_gotoxy(0 , 0 ) ; sprintf (lcd_buf, "%02d:%02d:%02d \n", valanda, min., sek) ; lcd_puts(lcd_buf) ; )

if(time_flag==1) ( rtc_get_time(&valanda,&min,&sek); lcd_gotoxy(0,0); sprintf(lcd_buf,"%02d:%02d:%02d\n",valanda,min.sek); lcd_puts( lcd_buf)

Dabar pereikime prie kito klausimo: kiek efektyvu naudoti sprintf? Kad neprasidėtų tušti pokalbiai, duosiu 2 kodo dalis, kurios daro tą patį – rodo laiko informaciją ekrane.

Pirmas mums jau žinomas variantas:

sprintf (lcd_buf, "%02d:%02d:%02d \n", valanda, min., sek) ; lcd_puts(lcd_buf) ;

sprintf(lcd_buf,"%02d:%02d:%02d\n",valanda,min.sek); lcd_puts(lcd_buf);

Sutikite, jį lengva naudoti ir aišku. Dabar variantas numeris 2:

lcd_putchar(valanda/ 10 + 0x30 ); lcd_putchar(valanda% 10 + 0x30 ) ; lcd_putchar(":" ) ; lcd_putchar(min/ 10 + 0x30 ) ; lcd_putchar(min% 10 + 0x30 ) ; lcd_putchar(":" ) ; lcd_putchar(sek/ 10 + 0x30 ) ; lcd_putchar(sek% 10 + 0x30 ) ;

lcd_putchar(valanda/10+0x30); lcd_putchar(valanda%10+0x30); lcd_putchar(":"); lcd_putchar(min/10+0x30); lcd_putchar(min%10+0x30); lcd_putchar(":"); lcd_putchar(sek/10+0x30); lcd_putchar(sek%10+0x30);

Tai nėra labai aišku, bet jūs galite tai išsiaiškinti. Kaip mes juos palyginsime? Tai daroma labai paprastai – paleiskite AVR STUDIO derintuvą ir pažiūrėkite, kiek laikrodžio ciklų sugaišta jų vykdymui. Taigi, būgno sukimas, rezultatai... Pirmoji kodo dalis veikė 16 466 laikrodžio ciklus, o tai atitinka 2 058,25 μs, o antrosios kodo dalies veikimo dažnis buvo 8 MHz, šis skaičius buvo 12 278 laikrodžio ciklai arba 1 534,75 μs. Sutikite, sutrumpinti vykdymo laiką ir dėl to atleisti mikrovaldiklį ~25% yra pakankamai gera priežastis nenaudoti sprintf. Iš savo projekto išmetame sprintf, po to stdio.h ir lcd_buf.

Negražu, kai pagrindinėje kilpoje yra sumaišytas kodas, todėl informacijos išvestis gali būti įtraukta į funkciją. Pagrindinėje kilpoje jis išliks

while (1) ( if (time_flag== 1) ( show_time() ; //rodyti informaciją apie dabartinį laiką } } ;

while (1) ( if(time_flag==1) ( show_time(); //rodyti informaciją apie esamą laiką) );

Pati funkcijos deklaracija atrodys taip:

void show_time() ( rtc_get_time(& valanda,& min,& sek) ; lcd_gotoxy(0 , 0 ) ; lcd_putchar(valanda/ 10 + 0x30 ) ; lcd_putchar(valandos% 10 + 0x30 ) ) charput ; ("dl" (min/ 10 + 0x30 ) ; lcd_putchar(":" ) ;

void show_time() ( rtc_get_time(&hour,&min,&sek); lcd_gotoxy(0,0); lcd_putchar(valanda/10+0x30); lcd_putchar(valanda%10+0x30); lcd_putchar(":"); lcd_putchar(min/ 10+0x30);

Dabar prie programinės įrangos turime pridėti datos išvestį. Datos nustatymas atliekamas naudojant šią funkciją:

rtc_set_date(6,13,10,13); //6 - savaitės diena, 13 - diena, 10 - mėnuo, 13 - metai

rtc_get_date(&savaitės_diena,&diena,&mėnuo,&metai); //savaitės diena, diena, mėnuo, metai

Datos išvestį galima organizuoti, kol kas pagrindinėje kilpoje, šalia laiko, visas šaltinio kodas pasirodė taip:

#įtraukti // I2C magistralės funkcijos #asm .equ __i2c_port= 0x18 ; PORTB .equ __sda_bit= 0 .equ __scl_bit= 1 #endasm #include // DS1307 Realiojo laiko laikrodžio funkcijos#įtraukti // Raidinių ir skaitmeninių LCD funkcijų #įtraukti char valanda= 0, min= 0, sek= 0, diena= 0, mėnuo= 0, metai= 0, savaitės_diena= 0; bito laikas_vėliava= 0 ; char meniu= 0 ; // Išorinio pertraukimo 1 tarnybos rutina nutraukti [ EXT_INT1] void ext_int1_isr(void ) ( time_flag= 1 ; ) void show_time() ( rtc_get_time(& valanda,& min,& sek) ; rtc_get_date(& savaitės_diena,& diena, mėnuo, metai) ; lcd_gotoxy , 0 ) ; lcd_putchar(hour/ 0x30 ) ; lcd_putchar(min% 10 + 0x30 ) ; 0) lcd_gotoxy(0 , 1 ); lcd_putchar(day% 10 + 0x30 ) lcd_putchar(" /" ; 0 + 0x30) ; = 0x00 // I2C magistralės inicijavimas i2c_init() ; // DS1307 Realaus laiko laikrodžio inicijavimas // Kvadratinės bangos išvestis ant kaiščio SQW/OUT: Įjungta// Kvadratinės bangos dažnis: 1Hz rtc_init(0, 1, 0) ; // Išorinio pertraukimo (-ų) inicijavimas// INT0: Išjungta // INT1: Įjungta // INT1 Režimas: Žemas lygis GICR|= 0x80 ; MCUCR= 0x00; GIFR= 0x80; // LCD modulio inicijavimas lcd_init(16) ; rtc_set_time(12, 0, 0); rtc_set_date(6, 13, 10, 13); #asm("sei") while (1 ) ( if (time_flag== 1 ) ( show_time() ; ) ); )

#įtraukti // I2C magistralės funkcijos #asm .equ __i2c_port=0x18 ;PORTB .equ __sda_bit=0 .equ __scl_bit=1 #endasm #include // DS1307 Realiojo laiko laikrodžio funkcijos #įskaitant // Raidinių ir skaitmeninių LCD funkcijų #įtraukti char valanda=0,min=0,sek=0,diena=0,mėnuo=0,metai=0,savaitė_diena=0; bito laikas_vėliava=0; char meniu=0; // 1 išorinis pertraukimas paslaugos rutinos pertraukimas void ext_int1_isr(void) ( time_flag=1; ) void show_time() ( rtc_get_time(&hour,&min,&sek); rtc_get_date(&week_day,&day,&month,&year); lcd_got lcd_putchar(hour/10+0x30) lcd_putchar(min%10+0x30) lcd_putchar("/"); lcd_putchar(year%10+0x30 main(void) ( PORTC=0x0F; PORTD=0x08; DDRD=0x00; // I2C magistralės inicijavimas i2c_init(); DS1307 Realaus laiko laikrodžio inicijavimas // Kvadratinės bangos išvestis ant kaiščio SQW/OUT: Įjungta / / Kvadratinės bangos dažnis: 1Hz rtc_init(0,1,0) // Išorinio pertraukimo (-ų) inicijavimas // INT0: Išjungtas // INT1: Įjungta // INT1 režimas: žemo lygio GICR|=0x80; // LCD modulio inicijavimas lcd_init(16); rtc_set_time(12,0,0); rtc_set_date(6,13,10,13); #asm("sei") while (1) ( if(time_flag==1) ( show_time(); ) ); )

Rezultatas:

Grandinė ir programinė įranga:

Pereikime prie meniu organizavimo. Svarbiausias klausimas buvo kaip visa tai turi atrodyti, t.y. reikėjo suformuluoti technines specifikacijas (t.z.).
Norėjau, kad tai būtų atskiri ekranai:
-Pagrindinis ekranas;
-laiko nustatymo ekranas;
-datos nustatymo ekranas;
-žadintuvo nustatymų ekranas.

Tokiu atveju galite naudoti keturis mygtukus – aukštyn, žemyn, kairėn, dešinėn. Perjungimas tarp ekranų turėtų būti atliekamas naudojant aukštyn ir žemyn mygtukus. Nustatymai atliekami atitinkamame ekrane. Naudojamas mikrovaldiklis yra atmega8. Tai toks primityvus techninis terminas.

Nuo pat pradžių buvo aišku, kad kodo dydis bus gana didelis. Kartu reikėjo suskaidyti į logiškai susijusias dalis. Su dalimis viskas aišku – vieno ekrano apdorojimas yra viena kodo dalis. Todėl pradėjau nuo pagrindinės kilpos padalijimo į keturias dalis, tarp kurių perjungimas atliekamas jungiklio teiginiu. Į vidų dedu funkcijas – manekenus. C prievado mygtukai 0 (aukštyn) ir 3 (žemyn) leidžia keisti meniu kintamąjį. Taigi mes šokinėjame tarp meniu. Tačiau iki šiol tokia programinė įranga negalėjo veikti, nes funkcijos dar nebuvo apibrėžtos.

while (1) ( jungiklis (meniu) ( case 0 : show_time(); break ; case 1 : set_time() ; break ; case 2 : set_date() ; break ; case 3 : set_alarm() ; break ; ) );

while (1) ( jungiklis(meniu) ( 0 atvejis: rodyti_laikas(); pertrauka; 1 atvejis: set_time(); pertrauka; 2 atvejis: set_date(); pertrauka; 3 atvejis: set_alarm(); pertrauka; ) );

Kitas žingsnis yra šių funkcijų apibrėžimas iš pradžių nubrėžiau statinius pavadinimus, pvz., lcd_puts("Nustatyti laiką"); Funkcijos pasirodė taip.

void set_alarm() ( ////////peržiūrėti signalo nustatymus lcd_gotoxy(0,0); lcd_puts("Nustatyti signalą"); ) void set_time() ( ////////peržiūrėti laiko nustatymus lcd_gotoxy( 0,0); lcd_puts("Nustatyti laiką");

Dabar jau veikė programinė įranga, kurioje galėjai perjungti meniu ir žiūrėti į statines etiketes. Atėjo laikas atgaivinti šiuos ženklus. Nebuvo jokių problemų su pagrindiniu ekranu, laiko / datos rodymas yra panašus į ankstesnę pamoką.

Iškilo kitas klausimas: kaip organizuoti patį sąrankos procesą? Pamąsčius man pasirodė įdomi tokia mintis: mygtukais aukštyn/žemyn einame į dominantį meniu, spaudžiame į dešinę, pasirodo žymeklis, pranešantis, kad vyksta sąrankos procesas. Mygtukais aukštyn/žemyn keičiame reikšmę, kairėn/dešinėn perkeliame žymeklį tarp reguliuojamų parametrų. Kai žymeklis yra po paskutiniu parametru, dar kartą paspaudus dešinįjį mygtuką, nustatymas išjungiamas. Žymeklis dingsta, o tai rodo, kad palikome nustatymus ir vėl galime perjungti meniu.

Tačiau yra nedidelių problemų, pavyzdžiui, mygtukas aukštyn turėtų pakeisti parametrus ir tuo pačiu perjungti kitą ekraną. Tie. turėjo būti atskirta viename ekrane esančių mygtukų logika. Dėl šios priežasties kodas labai išaugo. Pavyzdžiui, žadintuvo ekrane įvedame nustatymo paprogramę (sub_alarm), atitinkamai paprogramės viduje esantys mygtukai apdorojami vienaip, o išorėje – kitaip.

void set_alarm() //Aliarmo apdorojimo funkcija ( //signalizacijos nustatymų meniu rodymo režimas if(sub_alarm==0) ( if(PINC.0==0) //mygtukas aukštyn - pakeisti meniu ekraną ( menu=0; ... .. ) ) //signalizacijos nustatymų submeniu if(sub_alarm==1) ( if(PINC.0==0) //mygtukas aukštyn - padidinti reikšmę ( a_valanda++; .... ) )

Taip pat yra momentas, kai einate į nustatymų submeniu ir tuo pačiu mygtuku (pavyzdžiu vėl paimkime mygtuką aukštyn) galima pakeisti valandas, o gal minutes. Todėl buvo pristatyta kita kintamoji subPrograma.
Pavyzdžiui:

if(PINC.0==0) //mygtukas aukštyn ( if(subProgram==1) //subProgram=1 - pakeisti laikrodį ( a_valanda++; ... ) if(subProgram==2) //subProgram=2 - pakeisti minutes ( a_min++; ... ) if(subProgram==3) //subProgram=3 pakeisti aliarmo vėliavėlę (... ) )

Vienintelis dalykas, kurį verta paminėti, yra specialus simbolis, kuris rodomas pagrindiniame ekrane, kai įjungiamas žadintuvas.

Pavyzdys paimtas iš pavyzdžių, esančių CodeVision\examples\lcd char aplanke.

typedef unsigned char baitas; //iš naujo apibrėžti tipą flash baitas char_table[8] = ( //nupieškite savo simbolį 0b10000000, 0b10000100, 0b10001110, 0b10001110, 0b10001110, 0b10011111, 0b10100100, 0b11000000); // funkcija, naudojama vartotojo simboliams apibrėžti void define_char(byte flash * pc, byte char_code) ( i baitas, adresas; adresas= (char_code)<< 3 ) | 0x40 ; for (i= 0 ; i< 8 ; i++ ) lcd_write_byte(address++,* pc++ ) ; } void main(void ) { byte i, address; lcd_init(16 ) ; define_char(char_table, 0 ) ; //Įkelkite simbolį į LSD while (1) ( lcd_putchar(0) ; //parodyti simbolį }

typedef unsigned char baitas; //iš naujo apibrėžkite „flash“ tipo baitą char_table=( //nupieškite savo simbolį 0b10000000, 0b10000100, 0b10001110, 0b10001110, 0b10001110, 0b10011101, 00101,010); // funkcija, naudojama vartotojo simboliams apibrėžti void define_char(byte flash *pc,byte char_code) ( baitas i,adresas; adresas=(char_code)<<3)|0x40; for (i=0; i<8; i++) lcd_write_byte(address++,*pc++); } void main(void) { byte i,address; lcd_init(16); define_char(char_table,0); //Грузим символ в лсд while(1) { lcd_putchar(0); //выводим символ на дисплей }

Galite nupiešti 5x7 simbolį, vienetas reiškia, kad pikselis užpildytas, nulis reiškia, kad jis neužpildytas. Rezultatas yra varpo simbolis.

Firmware

Kitas žingsnis yra apgalvoti įrenginio išvaizdą. Mano nuomone, tai bus LCD ekranas ir keturi mygtukai priekyje, viduje bus spausdintinė plokštė, ant kurios bus išdėstyti visi kiti elementai. Maitinimas bus iš maitinimo šaltinio, panašus į pagamintą iš kiniško įkroviklio.

Pradėkime nuo spausdintinės plokštės. Yra daug panašių programų: P-cad, Altium, Sprint layout... Man Altium patinka tik todėl, kad jame yra daug paruoštų bibliotekų su elementais, nes, mano nuomone, skirti laiko savo elementų bibliotekos kūrimui nėra esmė. Bendra visų tokių programų prasmė ta pati – pirmiausia nubraižoma elektros grandinė.

Traceryje dėl elektros grandinės visi elementai jau žino, kuriuos prie kurių reikia prijungti.

Belieka patogiai išdėstyti elementus ir sujungti juos laidininkais.

Atsiliepimai apie šį laikrodį internete yra patys prieštaringiausi. Vieni sako, kad laikrodis yra nuostabus, o kiti vadina jį prastu Dalaso kūriniu. Taigi, norėdamas išsklaidyti visus klaidingus gandus, ištraukiau mikrukhą iš saugyklos ir pradėjau eksperimentuoti.

Ypatumai:

  • Labai mažas energijos suvartojimas. Gamintojas žada 10 metų laikrodžio veikimo iš vienos standartinės baterijos. CR2032
  • 56 baitai vartotojo duomenims saugoti. Manau, kad tai nėra itin reikalingas pasirinkimas, bet gal kam nors pravers.
  • Programuojama išvestis išorinių įrenginių laikrodžiui. Gali išvesti 1 Hz, 4,096 kHz, 8,192 kHz ir 32,768 kHz dažnius.
  • 24 valandų ir 12 valandų režimas

Pinout

Laikrodžio kaiščiai išdėstyti taip:

X1, X2— Kaiščiai kvarciniam rezonatoriui prijungti 32,768 kHz dažniu
VBAT— Išėjimas 3 voltų atsarginiam akumuliatoriui prijungti
GND- Žemė
S.D.A.- i2c magistralės duomenų linija
SCL- i2c magistralės laikrodžio linija
SQW/OUT– išvesties signalas išoriniams įrenginiams fiksuoti
VCC- 5 voltų maitinimo šaltinis

Prijungimas prie valdiklio
Įrišimas minimalus. Jums reikės 32,768 kHz kvarco, poros rezistorių, kad galėtumėte valdyti i2c magistralę, ir trijų voltų akumuliatoriaus.

Teisingas lentos išdėstymas
Laikrodžio tikslumas ir apskritai laikrodžio veikimas priklauso nuo spausdintinės plokštės išdėstymo. Dalasas savo duomenų lape rekomenduoja iki minimumo sumažinti laidininkų ilgį nuo mikroschemos iki kvarcinio rezonatoriaus ir apjuosti šiuos laidus stačiakampiu, prijungtu prie žemės. Be to, dėl patikimumo prilitavau laidus, einančius į žemę prie kvarcinio korpuso ir lygiagrečiai su maitinimo šaltiniu įdėjau 0,1 uF kondensatorių.

Beje, jis gali veikti ir be kvarco. Norėdami tai padaryti, į koją X1 tiekiamas išorinis laikrodžio signalas, kurio dažnis yra 32,768 kHz, o X2 lieka pakabintas ore.

Laikrodžio atminties organizavimas
Šiame miniatiūriniame įrenginyje yra 64 baitų atmintis. Pirmieji aštuoni baitai veikia. Jie saugo laiką, datą, savaitės dieną. Likusi dalis yra skirta vartotojo poreikiams. Pavyzdžiui, juose galite išsaugoti kai kuriuos nustatymus ar dar ką nors. Natūralu, kad praradus atsarginę galią, visa šioje atmintyje esanti informacija sunaikinama. Visas darbas su laikrodžiu (skaitymas ir laiko/datos nustatymas) priklauso nuo reikalingų atminties langelių skaitymo ir rašymo.

Visi atmintyje esantys skaičiai išsaugomi dvejetainiu dešimtainiu formatu. Tai reiškia, kad viename baite gali būti saugomi du skaitmenys. Pavyzdžiui, skaičiuje 0x23 yra skaičius 2 ir skaičius 3. Kiekvienam skaičiui skiriami 4 bitai. Kodėl tai daroma? Patogumui ir atminties taupymui. Be laiko ir datos, atmintyje saugomi keli nustatymų bitai:

  • Laikrodžio sustabdymas- valdo laikrodį. Nustačius bitą, laikrodis sustoja. Norėdami paleisti laikrodį, į šį bitą turite įrašyti 0 Prijungus atsarginę bateriją, šis bitas yra nustatytas ir laikrodis neskaičiuoja laiko! Jūs turite tai atsiminti.
  • 24/12 - šis bitas skirtas laikrodžio režimui pasirinkti. Kai šis bitas lygus vienetui, naudojamas 12 valandų režimas. Kitu atveju 24 val. Jei naudojamas 12 valandų režimas, penktasis bitas rodo AM arba PM dabar. Jei bitas yra 1, tai reiškia PM. 24 valandų režimu šis bitas naudojamas dešimtims valandų saugoti kartu su 4 bitu.
  • Išvestis— valdo SQW/OUT kojos būseną. Antgalis nustatytas – ant kojos 1. Atstatyti – ant kojos 0. Norėdami tokiu būdu valdyti, antgalis SQWE turi būti nustatytas iš naujo.
  • SQWE- kai antgalis yra nustatytas, ant SQW/OUT kojos atsiranda stačiakampiai impulsai.
  • RS1, RS0— šie bitai nustato impulsų dažnį. Dažnio priklausomybė nuo bitų derinio yra žemiau esančioje lentelėje:

Programinė įranga

Norint dirbti su DS1307 laikrodžiu, buvo parašyta paprasta biblioteka, kurioje yra šios pagrindinės funkcijos:

DS_start– paleidžia laikrodį. Taip pat galite paleisti laikrodį nustatydami laiką.
DS_stop- sustabdo laikrodį
DS_set_time – Laiko nustatymas. Prieš iškviečiant procedūrą, į tmp1 reikia įrašyti sekundes, į tmp2 – minutes ir į tmp3 – valandas. Laikrodis 24 valandų formatu.
DS_get_time: — skaitymo laikas iš laikrodžio. sekundės bus įrašytos tmp1, minutės tmp2, valandos tmp3
DS_get_date:- datos skaitymas iš laikrodžio. Diena bus įrašyta tmp1, mėnuo tmp2, metai tmp3
DS_set_date: — nustatant datą. Prieš iškviesdami procedūrą, turite įrašyti dieną į tmp1, mėnesį į tmp2 ir metus į tmp3 (paskutiniai 2 skaitmenys)

Laiko ir datos nustatymo / skaitymo tvarka gali priimti / grąžinti įvesties duomenis BCD ir dešimtainiu formatu. Norint pasirinkti norimą formatą, kiekvienoje procedūroje reikia pakomentuoti arba atšaukti tris eilutes (kode yra pastabos apie tai).

Testavimo programa leidžia valdyti laikrodį per UART (greitis 9600, valdiklis veikia 8 MHz). Paleidus, iš karto rodomas laikas, data ir raginimas įvesti komandas nuo 1 iki 3. Kai pasirenkate 1 parinktį, laikas / data nuskaitomi dar kartą. 2 parinktis leidžia nustatyti laiką, o 3 parinktis – datą. Jei norite pabandyti žaisti su laikrodžiu, į šaltinio archyvą įtraukiamas modeliavimo failas.

Tikslumas
Čia daug kas priklauso nuo naudojamo kvarco ir lentos išdėstymo. Duomenų lape teigiama, kad kvarco talpa turėtų būti 12,5 pF. Jie sako, kad geriausia naudoti kristalus iš pagrindinių plokščių. Norėdami ištaisyti eigą, prie rezonatoriaus galite prilituoti apipjaustymo kondensatorių ir juo keisti dažnį nedidelėmis ribomis. Asmeniškai man šis laikrodis dirba dvi dienas ir atsilieka 3 sekundėmis. Kažkas man sako, kad problema yra kvarco talpoje, aš išbandysiu kitą ir pranešiu.

Išvada
Neblogas laikrodis. Idealiai tinka mėgėjiškam naudojimui. Nors kai kas rašo apie nesklandumus, aš su jais dar nesusidūriau.

DS1307 yra mažas modulis, skirtas laiko skaičiavimui. Surinkta DS1307ZN lusto pagrindu ir maitinama ličio baterija (LIR2032), kuri leidžia ilgą laiką dirbti autonomiškai. Taip pat modulyje yra 32 KB nepastovi EEPROM atmintis (AT24C32). AT24C32 mikroschema ir DS1307ZN yra sujungtos bendra magistrale naudojant I2C sąsają.

Techninės specifikacijos

Maitinimo įtampa: 5V
Darbinė temperatūra: – 40 ℃ … + 85 ℃
Atmintis: 56 baitai (nekintama)
Baterija : LIR2032 (automatinis maitinimo šaltinio aptikimas)
Sąsaja: I2C
Matmenys: 28mm x 25mm x 8mm

Bendra informacija

Modulio DS1307 naudojimas dažnai yra labai pagrįstas, pavyzdžiui, kai duomenys nuskaitomi retai, daugiau nei savaitės intervalais, yra neprotinga arba neįmanoma naudoti valdiklio nuosavų išteklių. Nepertraukiamo maitinimo tiekimas, pavyzdžiui, Arduino plokštėms ilgą laiką yra brangus, net ir naudojant bateriją.
Dėl savo atminties ir autonomijos galima registruoti įvykius (su autonominiu maitinimo šaltiniu), tokius kaip temperatūros pokyčiai ir pan., duomenys saugomi atmintyje ir gali būti nuskaitomi iš modulio atminties. Taigi DS1307 modulis dažnai naudojamas, kai Arduino valdikliai turi žinoti tikslų laiką, suaktyvinti kokį nors įvykį ir pan.

Duomenų mainai su kitais įrenginiais vyksta per I2C sąsają iš SCL ir SDA kaiščių. Kondensatoriai C1 ir C2 yra būtini norint sumažinti triukšmą elektros linijoje. Norint užtikrinti tinkamą SCL ir SDA signalų lygį, yra sumontuoti rezistoriai R2 ir R3 (traukiami iki maitinimo šaltinio). Norint patikrinti modulio funkcionalumą, į DS1307Z lusto 7 kaištį tiekiamas stačiakampio formos SQ signalas, kurio dažnis yra 1 Hz. Elementai R4, R5, R6, VD1 būtini norint įkrauti ličio bateriją. Taip pat plokštėje yra sėdynė (U1) DS18B20 temperatūros jutiklio montavimui (jei reikia, galite įlituoti), rodmenis galite nuskaityti iš DS kaiščio, kuris yra prijungtas prie maitinimo šaltinio, per rezistorių R1 su atsparumas 3,3 kOhm. Kontaktų schemą ir paskirtį galite pamatyti toliau pateiktuose paveikslėliuose.

Plokštėje yra dvi kontaktų grupės, kurių žingsnis 2,54 mm, patogiam prijungimui prie duonos lentos naudosiu pin jungtis, jas reikia lituoti.

Pirmoji kontaktų grupė:
DS: DS18B20 išvestis (1 laidas)


VCC: „+“ modulio maitinimo šaltinis
GND: „-“ modulio maitinimo šaltinis

Antroji kontaktų grupė:
SQ: 1 MHz įvestis
DS: DS18B20 išvestis (1 laidas)
SCL: serijinis laikrodis
SDA: duomenų linija (Serial Dфta)
VCC: „+“ modulio maitinimo šaltinis
GND: "-" modulio maitinimo šaltinis
ŠIKŠNOSPARNIS:

Akumuliatoriaus įkrovimas
Kaip aprašyta, jūsų modulis gali įkrauti bateriją, tai įgyvendinama naudojant komponentus R4, R5, R6 ir diodą D1. Tačiau ši grandinė turi trūkumą: per rezistorius R4 ir R6 akumuliatorius išsikrauna (kaip pastebėjo vartotojas ALEXEY, visai nedaug). Kadangi modulis sunaudoja mažai srovės, galite nuimti maitinimo grandinę, nuimti R4, R5, R6 ir VD1, pakeisti R6 trumpikliu (išėmę komponentus galite naudoti įprastą CR2032 bateriją);

DS1307 prijungimas prie Arduino

Reikalingos dalys:
Arduino UNO R3 x 1 vnt.
DuPont viela, 2,54 mm, 20 cm x 1 vnt.
USB 2.0 A-B laidas x 1 vnt.
Realaus laiko laikrodis RTC DS1307 x 1 vnt.

Ryšys:
Norint prijungti DS1307 realaus laiko laikrodį, reikia įlituoti kaiščių jungtis į pirmąją kaiščių grupę. Toliau jungiame laidus SCL (DS1307) prie 4 kontakto (Arduino UNO) ir SDA (DS1307) prie 5 kontakto (Arduino UNO), belieka prijungti VCC prie +5V, o GND – prie GND. Beje, skirtingose ​​Arduino plokštėse I2C sąsajos išėjimai skiriasi, kiekvienos paskirtį galima pamatyti žemiau.

DS1307 laiko nustatymas
Pirmiausia turite atsisiųsti ir įdiegti „DS1307RTC“ ir „TimeLib“ biblioteką į „Arduino IDE“ kūrimo aplinką, tada turite nustatyti laiką, atidaryti pavyzdį iš DS1307RTC bibliotekos „Failas“ -> „Pavyzdžiai“ - > „DS1307RTC“ -> „SetTime“ arba nukopijuokite toliau esantį kodą.

// Prijunkite DS1307RTC biblioteką const char *monthName = ( "Sausio", "Vas.", "Kov", "Apr", "gegužė", "birželis", "liepa", "rugpjūčio", "rugsėjo", "spalio mėn. " , "Lap", "Gruodis" ); tmElements_t tm; void setup() ( bool parse=false; bool config=false; // gauti datą ir laiką, kai kompiliatorius buvo paleistas if (getDate(__DATE__) && getTime(__TIME__)) ( parse = true; // ir sukonfigūruokite RTC su ši informacija if (RTC.write(tm)) ( config = true; ) ) Serial.begin (9600), while (!Serial) ; Time="); Serial.print(__TIME__); Serial.print(", Date="); Serial.println(__DATE__); else (analizuoti) ( Serial.println ("DS1307 ryšio klaida:-("); serija .println("Patikrinkite schemą") else ( Serial.print("Nepavyko išanalizuoti informacijos iš kompiliatoriaus, laikas=\""); Serial.print(__TIME__); Serial.print("\", data) =\""); Serial.print(__DATE__); ) ) void loop() ( ) bool getTime(const char *str) ( int Hour, Min, Sec; if (sscanf) (str, "%d:%d:%d", &Hour, &Min, &Sec) != 3) return false Second = Sec ) bool getDate(const char *str) ( char Mėnuo; int Diena, Metai; uint8_t monthIndex; if (sscanf(str, "%s %d %d", mėnuo, &diena, &metai) != 3) return false; for (monthIndex = 0; monthIndex< 12; monthIndex++) { if (strcmp(Month, monthName) == 0) break; } if (monthIndex >= 12) return false; tm.Diena = diena; tm.Mėnuo = mėnuoIndeksas + 1; tm.Year = CalendarYrToTm(Year); grįžti tiesa; )

Atsisiųsti eskizą

Įkeliame šį eskizą į „Arduino“ valdiklį (laikas paimamas iš OS), atidarome „Port Monitoring“

Programa
Bibliotekoje yra dar vienas pavyzdys, galite jį atidaryti DS1307RTC „Failas“ -> „Pavyzdžiai“ -> „DS1307RTC“ -> „ReadTest“

/* Testavimas atliktas naudojant Arduino IDE 1.6.12 Bandymo data 2016-11-23. */ #įtraukti // Įtraukti Wire biblioteką #include // Įtraukite TimeLib biblioteką #include // Prijunkite DS1307RTC biblioteką void setup() ( Serial.begin(9600); // Nustatykite duomenų perdavimo spartą, kol (!Serial) ; // Palaukite, kol prisijungs nuoseklusis prievadas. Reikalingas tik Leonardo delsai (200); // Palaukite 200 µs Serial.println("DS1307RTC skaitymo testas" // Išvesti duomenis į nuoseklųjį prievadą Serial.println("-------------------"); ); ; print2digits (tm.Minute); Mėnuo); Serial.print(tmYearToCalendar(tm.Year)); else (if (RTC) .chipPresent()) ( Serial.println ("DS1307 yra sustabdytas. Paleiskite SetTime"); Serial.println ("example" Norėdami inicijuoti laiką ir pradėti paleisti."); Serial.println(); ) else ( Serial .println ("DS1307 skaitymo klaida! Patikrinkite grandinę."); Serial.println(); ) delay (9000); ) delay (1000); ) void print2digits (int number) (jei (skaičius >= 0 && numeris)< 10) { Serial.write("0"); } Serial.print(number); }

Atsisiųsti eskizą

Įkeliame šį kodą į „Arduino“ valdiklį, atidarome „Port Monitoring“