Arloji yang luar biasa pada layar LCD yang menyala dan supermicrocircuit ATMega48. Tetapi mereka tidak berhasil.

UPD : Crohn meninggal, memotong dua kabel, diterapkan tidur, 0,3-1,6mA
Yaitu, arloji, tentu saja, bekerja, tetapi, sayangnya, mereka tidak akan bekerja lama.
Sekali waktu, di sebuah kotak di meja jauh saya menggantung beberapa indikator LCD tujuh segmen. Dan seperti dulu, saya ingin membawa mereka ke sirkulasi dan membuat arloji berdasarkan salah satunya. Sekali waktu: secara harfiah, tujuh tahun. Saat itulah, pada 2011, saya menjadi tertarik pada elektronik. Tanpa berpikir lama, saya kemudian memesan segala macam barang di satu toko online yang bagus (tidak, bukan pada Ali; saya tidak yakin dia sudah ada di sana). Tetapi entah bagaimana itu tidak berhasil bagi saya untuk menciptakan yang abadi. Setelah beberapa papan tergores, saya meninggalkan hiburan ini dan lupa.
Jadi, ketika Ali menerima paket berisi mock-up, paket 595-an dalam kasus-dip, Tiny RTC pada ds1307 , dan, yang paling penting, USBasp , sudah waktunya untuk kembali ke ide lama. Dari simpanan lama saya memiliki ATMega48 , yang dengan 28 kaki, lm7805 , semua hal-hal kecil dalam bentuk resistor / kapasitor / tombol, dan, pada kenyataannya, indikator pada 40 kaki.
Secara umum, pada awalnya direncanakan untuk menggunakan AtTiny13, yang juga saya putar, tetapi setelah memperkirakan ini dan itu, saya tidak mencari cara untuk berkeliling dengan 5 kaki untuk menampilkan indikator, membaca dua tombol, dan berkomunikasi dengan jam i2c. Dengan 28 kaki mega, menabung dan memutarbalikkan dengan penyatuan kaki tidak lagi diperlukan. Meskipun, tentu saja, dalam hal ini, Anda tidak dapat melakukannya tanpa 595-an. Tetapi jika saya berencana untuk mengeluarkan semua 32 bit data untuk indikator dari remaja secara seri, maka dengan mega Anda dapat menampilkan gambar pada keempat sirkuit mikro sekaligus.

Semua 595 disembunyikan di bawah indikator. Foto tersebut menunjukkan kesimpulan perumahan dari sirkuit mikro.
595 tepat empat potong digunakan, karena indikator, meskipun memiliki 40 kaki, hanya menampilkan 32 pada segmen. Sayangnya, itu hanya indikator 3,5, yaitu, ia memiliki 3 digit penuh, ditambah satu. Ada simbol untuk detik, tetapi tidak ada sebutan untuk AM / PM. Tapi memang ada. Saya tidak ingin memesan indikator yang lebih maju tanpa mengumpulkan apa pun dalam indikator LCD dalam hidup saya.

Dokumentasi yang berfungsi untuk indikator. Penguji harus mencari tahu kaki mana yang sesuai dengan segmen mana.
Nah, kalau begitu soal teknologi. Tidak pernah ada skema, tetapi semuanya jelas di sana. Itu hanya perlu untuk memilih empat kaki untuk input buffer, kaki umum untuk indikator, kaki untuk SCLK / RCLK, kaki untuk OE, dua kaki untuk i2c, dua kaki untuk tombol. Semua ini, tentu saja, salah. Mengapa saya memutuskan bahwa OE harus diinstal pada controller, dan SCLK dikombinasikan dengan RCLK - Saya tidak mengingatnya sendiri. Itu perlu untuk melakukan yang sebaliknya. Dan kawat indikator umum pada controller tidak diperlukan sama sekali, salah satu kesimpulan dari 595 pertama dapat ditiadakan (yang saya juga lakukan, pada akhirnya).

Kabel. Banyak dari mereka. Tampak dalam.

Pemandangan dari luar.
Hal yang paling menarik dalam semua proyek ini: kode output untuk indikator. Kehalusannya adalah Anda tidak bisa menerapkan voltase ke indikator LCD dan melupakannya. Perlu untuk mengubah polaritas antara segmen dan kontak umum sekitar seratus kali per detik, sehingga semuanya indah dan menyenangkan mata. Sebagai lingkungan pengembangan, tanpa basa-basi lagi, saya menggunakan Arduino IDE, hanya sedikit siksaan dalam beberapa poin. Pertama, saya harus menggunakan paket MiniCore ( https://github.com/MCUdude/MiniCore ), karena saya harus menulis bukan untuk arduino siap pakai yang besar, tetapi untuk ATMega48 yang lemah dan telanjang. Kedua, upaya langsung untuk menggunakan pustaka bawaan untuk i2c gagal. Untuk beberapa alasan, itu tidak mau bekerja, saya harus menemukan perpustakaan lain, dan kemudian memotongnya untuk kebutuhan saya.
Ternyata, 4 kilobyte sangat kecil. Terutama jika Anda menulis dalam bahasa C. Mungkin jika saya memutuskan untuk beralih ke assembler, pembatasan ini tidak akan mendesak begitu serius, tetapi mengingat kutipan masa lalu saya secara tertulis dalam assembler untuk AVR, saya tidak memiliki keinginan seperti itu. Dan untuk menulis dalam C - banyak ruang dibutuhkan. Saya menempatkan braket kecil secara tidak sengaja - seratus byte ke dalam pipa.
Kode sebenarnya berkomentar#include <avr/io.h>
#include <util/delay.h>
#include <avr/power.h>
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// ds1307,
#define DS3231_I2C_ADDRESS 0x68
#define LCD_PORT PORTD
#define LCD_DDR DDRD
#define LCD_DATA1 PD0
#define LCD_DATA2 PD1
#define LCD_DATA3 PD2
#define LCD_DATA4 PD3
#define LCD_SCLK PD4
#define LCD_OE PD5
#define LCD_COM PD6
#define KEY1_PORT PORTB
#define KEY1_DDR DDRB
#define KEY1_PIN PINB
#define KEY1 PB0
#define KEY2_PORT PORTD
#define KEY2_DDR DDRD
#define KEY2_PIN PIND
#define KEY2 PD7
#define DS1307SQ PB1
#define DS1307SQ_INT PCIE0
#define DS1307SQ_PORT PORTB
#define DS1307SQ_DDR DDRB
#define DS1307SQ_PIN PINB
#define DS1307SQ_VEC PCINT0_vect
#define DS1307SQ_MSK PCMSK0
// . , -, , -
#define LM335_PORT PORTC
#define LM335_DDR DDRC
#define LM335 PC3
//
unsigned char lcd_buf[4];
#define MODE_MAIN 0
#define MODE_CALENDAR 1
#define MODE_YEAR 2
#define MODE_TERMOMETER 3 //
#define MODE_VOLTMETER 4 //
#define MODE_SET_MINUTE 5
#define MODE_SET_HOUR 6
#define MODE_SET_DAY 7
#define MODE_SET_MONTH 8
#define MODE_SET_YEAR 9
#define MODE_SECOND 10
#define MODE_DEBUG 11 //
// 10ms ()
#define MODE_TIMEOUT 20 // 2
#define MODE_TIMEOUT_SET 100 // 10
#define KEY_TIMEOUT 10 // 1
byte mode = MODE_MAIN;
byte mode_timeout = 0;
byte key1_press = 0;
byte key1_time = 0;
byte key2_press = 0;
byte key2_time = 0;
byte cycle_count_10 = 0; //
byte even_10 = 0; // 1/10
// ds1307
byte second;
byte minute;
byte hour;
byte dayOfWeek;
byte dayOfMonth;
byte month;
byte year;
volatile byte need_render_int = 1;
uint8_t porthistory = 0xFF;
volatile uint8_t debug_value = 0;
byte twi_problems = 0;
// ds1307 SQ
// ,
ISR(DS1307SQ_VEC) {
uint8_t changedbits = DS1307SQ_PIN ^ porthistory;
porthistory = DS1307SQ_PIN;
if (changedbits & _BV(DS1307SQ) && porthistory & _BV(DS1307SQ)) {
need_render_int = 1;
}
}
//
void lcd_num(char pos, char num) {
unsigned char buf = 0b01110110;
if (pos < 1 || pos > 3) {
return;
}
switch (num) {
case 0:
// 3- , ?
// , ,
// :-(
if (pos == 3) {
buf = 0b11101110;
} else {
buf = 0b11100111;
}
break;
case 1:
if (pos == 3) {
buf = 0b10001000;
} else {
buf = 0b10000001;
}
break;
case 2:
buf = 0b11010110;
break;
case 3:
if (pos == 3) {
buf = 0b11011100;
} else {
buf = 0b11010011;
}
break;
case 4:
if (pos == 3) {
buf = 0b10111000;
} else {
buf = 0b10110001;
}
break;
case 5:
if (pos == 3) {
buf = 0b01111100;
} else {
buf = 0b01110011;
}
break;
case 6:
if (pos == 3) {
buf = 0b01111110;
} else {
buf = 0b01110111;
}
break;
case 7:
if (pos == 3) {
buf = 0b11001000;
} else {
buf = 0b11000001;
}
break;
case 8:
if (pos == 3) {
buf = 0b11111110;
} else {
buf = 0b11110111;
}
break;
case 9:
if (pos == 3) {
buf = 0b11111100;
} else {
buf = 0b11110011;
}
break;
}
lcd_buf[pos] = buf;
}
//
void lcd_one(bool e) {
if (e) {
lcd_buf[0] |= (1 << 0);
} else {
lcd_buf[0] &= ~(1 << 0);
}
}
void lcd_sec(bool e) {
if (e) {
lcd_buf[0] |= (1 << 7);
} else {
lcd_buf[0] &= ~(1 << 7);
}
}
void lcd_minus(bool e) {
if (e) {
lcd_buf[0] |= (1 << 1);
} else {
lcd_buf[0] &= ~(1 << 1);
}
}
void lcd_plus(bool e) {
if (e) {
lcd_buf[0] |= (1 << 6);
} else {
lcd_buf[0] &= ~(1 << 6);
}
}
void lcd_lo(bool e) {
if (e) {
lcd_buf[0] |= (1 << 5);
} else {
lcd_buf[0] &= ~(1 << 5);
}
}
void lcd_over(bool e) {
if (e) {
lcd_buf[0] |= (1 << 4);
} else {
lcd_buf[0] &= ~(1 << 4);
}
}
void lcd_dot(int pos, bool e) {
int pos_buf;
if (pos == 1) {
pos_buf = 3;
} else if (pos == 2) {
pos_buf = 2;
} else if (pos == 3) {
pos_buf = 1;
} else {
return;
}
if (pos_buf == 3) {
if (e) {
lcd_buf[pos_buf] |= (1 << 0);
} else {
lcd_buf[pos_buf] &= ~(1 << 0);
}
} else {
if (e) {
lcd_buf[pos_buf] |= (1 << 3);
} else {
lcd_buf[pos_buf] &= ~(1 << 3);
}
}
}
// 100
// 595-,
void lcd_refresh() {
unsigned char data1 = lcd_buf[0];
unsigned char data2 = lcd_buf[1];
unsigned char data3 = lcd_buf[2];
unsigned char data4 = lcd_buf[3];
byte reverse = data1 & (1 << 3); //
if (reverse) { // ,
data1 = ~data1;
data2 = ~data2;
data3 = ~data3;
data4 = ~data4;
}
for (int i = 0; i < 8; i++) {
//
if (data1 & (1 << i)) {
LCD_PORT |= _BV(LCD_DATA1);
} else {
LCD_PORT &= ~_BV(LCD_DATA1);
}
if (data2 & (1 << i)) {
LCD_PORT |= _BV(LCD_DATA2);
} else {
LCD_PORT &= ~_BV(LCD_DATA2);
}
if (data3 & (1 << i)) {
LCD_PORT |= _BV(LCD_DATA3);
} else {
LCD_PORT &= ~_BV(LCD_DATA3);
}
if (data4 & (1 << i)) {
LCD_PORT |= _BV(LCD_DATA4);
} else {
LCD_PORT &= ~_BV(LCD_DATA4);
}
// SCLK 595-
sbi(LCD_PORT, LCD_SCLK);
// SCLK 595-
cbi(LCD_PORT, LCD_SCLK);
}
// SCLK
// SCLK RCLK ,
// .
// , -, .
// SCLK RCLK, OE (. 74HC595)
// .
sbi(LCD_PORT, LCD_SCLK);
cbi(LCD_PORT, LCD_SCLK);
// -
// - - , 1 40
// (- ; )
// 4 595-,
// ,
if (reverse) {
sbi(LCD_PORT, LCD_COM);
} else {
cbi(LCD_PORT, LCD_COM);
}
//
lcd_buf[0] ^= (1 << 3);
}
// ,
void do_render() {
lcd_buf[0] = 0;
lcd_buf[1] = 0;
lcd_buf[2] = 0;
lcd_buf[3] = 0;
if (twi_problems) {
lcd_lo(1);
}
if (mode == MODE_MAIN) {
lcd_num(3, minute % 10);
lcd_num(2, minute / 10);
byte hour1 = (hour <= 12) ? hour : (hour % 12);
lcd_num(1, hour1 % 10);
if (hour1 >= 10) {
lcd_one(1);
}
// , . .
// SQ ,
// ,
//
if (second % 2) {
lcd_sec(1);
}
} else if (mode == MODE_CALENDAR) {
lcd_num(3, dayOfMonth % 10);
lcd_num(2, dayOfMonth / 10);
lcd_num(1, month % 10);
if (month >= 10) {
lcd_one(1);
} else {
lcd_one(0);
}
lcd_dot(2, 1);
} else if (mode == MODE_YEAR) {
lcd_num(3, year % 10);
lcd_num(2, year / 10);
lcd_buf[1] = 0b10110011; // y.
} else if (mode == MODE_TERMOMETER) {
} else if (mode == MODE_VOLTMETER) {
} else if (mode == MODE_SET_MINUTE) {
if (even_10) {
lcd_num(3, minute % 10);
lcd_num(2, minute / 10);
}
byte hour1 = (hour <= 12) ? hour : (hour % 12);
lcd_num(1, hour1 % 10);
if (hour1 >= 10) {
lcd_one(1);
} else {
lcd_one(0);
}
lcd_sec(1);
} else if (mode == MODE_SET_HOUR) {
lcd_num(3, minute % 10);
lcd_num(2, minute / 10);
if (even_10) {
byte hour1 = (hour <= 12) ? hour : (hour % 12);
lcd_num(1, hour1 % 10);
if (hour1 >= 10) {
lcd_one(1);
} else {
lcd_one(0);
}
if (hour > 12) {
lcd_over(1);
} else {
lcd_over(0);
}
}
lcd_sec(1);
} else if (mode == MODE_SET_DAY) {
if (even_10) {
lcd_num(3, dayOfMonth % 10);
lcd_num(2, dayOfMonth / 10);
}
lcd_num(1, month % 10);
if (month >= 10) {
lcd_one(1);
} else {
lcd_one(0);
}
lcd_dot(2, 1);
} else if (mode == MODE_SET_MONTH) {
lcd_num(3, dayOfMonth % 10);
lcd_num(2, dayOfMonth / 10);
if (even_10) {
lcd_num(1, month % 10);
if (month >= 10) {
lcd_one(1);
} else {
lcd_one(0);
}
}
lcd_dot(2, 1);
} else if (mode == MODE_SET_YEAR) {
if (even_10) {
lcd_num(3, year % 10);
lcd_num(2, year / 10);
}
lcd_buf[1] = 0b10110011;
} else if (mode == MODE_SECOND) {
lcd_sec(1);
lcd_num(3, second % 10);
lcd_num(2, second / 10);
} else if (mode == MODE_DEBUG) {
byte d = debug_value;
lcd_num(3, d % 10);
d /= 10;
lcd_num(2, d % 10);
lcd_num(2, d / 10);
}
}
int main(void)
{
// - .
// , , .
// ACSR = (1<<ACD);
ADCSRA = (0<<ADEN);
PRR = (1<<PRTIM0) | (1<<PRTIM1) | (1<<PRTIM2) | (1<<PRSPI) | (1<<PRADC) | (1<<PRUSART0);
//
DDRB = 0x00;
PORTB = 0xff;
DDRC = 0x00;
PORTC = 0xff;
DDRD = 0x00;
PORTD = 0xff;
lcd_buf[0] = 0x0;
lcd_buf[1] = 0x0;
lcd_buf[2] = 0x0;
lcd_buf[3] = 0x0;
twi_begin();
// . usbasp,
// , ,
// DDRB |= _BV(PB7);
// PORTB |= _BV(PB7); // off
// -
LCD_DDR |= (_BV(LCD_DATA1) | _BV(LCD_DATA2) | _BV(LCD_DATA3) | _BV(LCD_DATA4) | _BV(LCD_SCLK) | _BV(LCD_OE) | _BV(LCD_COM));
cbi(LCD_PORT, LCD_SCLK);
cbi(LCD_PORT, LCD_OE);
//
KEY1_DDR &= ~(_BV(KEY1));
KEY1_PORT |= _BV(KEY1);
KEY2_DDR &= ~(_BV(KEY2));
KEY2_PORT |= _BV(KEY2);
// ds1307
DS1307SQ_DDR &= ~_BV(DS1307SQ);
DS1307SQ_PORT |= _BV(DS1307SQ);
PCICR |= _BV(DS1307SQ_INT);
DS1307SQ_MSK |= _BV(DS1307SQ);
sei();
// ds1307 , ,
// , -
// setDS3231time(30,40,21,6,11,3,18);
while(1)
{
byte need_render = 0;
byte need_date_set = 0;
// ds1307,
//
if (need_render_int) {
byte rc;
if (mode == MODE_MAIN) {
rc = readDS3231time_hms(&second, &minute, &hour);
} else {
rc = readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
}
if ( ! rc && twi_problems) {
twi_problems -= 1;
} else {
twi_problems += rc;
}
need_render = 1;
need_render_int = 0;
}
// 1/10
if ( ! cycle_count_10) {
even_10 = ! even_10;
// ,
if (mode_timeout > 0) {
mode_timeout -= 1;
}
// ,
if (mode != MODE_MAIN && ! mode_timeout) {
mode = MODE_MAIN;
need_render = 1;
}
// , 10
if (mode == MODE_SET_MINUTE || mode == MODE_SET_HOUR || mode == MODE_SET_DAY || mode == MODE_SET_MONTH || mode == MODE_SET_YEAR) {
need_render = 1;
}
//
byte key1_down = (KEY1_PIN & _BV(KEY1)) ? 0 : 1;
byte key2_down = (KEY2_PIN & _BV(KEY2)) ? 0 : 1;
if (key1_down || key2_down || key1_press || key2_press) {
need_render = 1;
}
if (key1_down && key1_press) {
key1_time += 1;
}
if (key2_down && key2_press) {
key2_time += 1;
}
//
if (key1_down && ! key1_press) {
if (mode == MODE_SET_MINUTE) {
mode = MODE_SET_HOUR;
mode_timeout = MODE_TIMEOUT_SET;
} else if (mode == MODE_SET_HOUR) {
mode = MODE_SET_DAY;
mode_timeout = MODE_TIMEOUT_SET;
} else if (mode == MODE_SET_DAY) {
mode = MODE_SET_MONTH;
mode_timeout = MODE_TIMEOUT_SET;
} else if (mode == MODE_SET_MONTH) {
mode = MODE_SET_YEAR;
mode_timeout = MODE_TIMEOUT_SET;
} else if (mode == MODE_SET_YEAR) {
mode = MODE_MAIN;
} else if (mode == MODE_MAIN) {
mode = MODE_SECOND;
mode_timeout = MODE_TIMEOUT_SET;
} else if (mode == MODE_SECOND) {
mode = MODE_MAIN;
mode_timeout = 0;
}
} else if ( ! key1_down && key1_press) {
if (key1_time >= KEY_TIMEOUT) {
} else {
}
} else if (key1_down && key1_press) {
if (key1_time >= KEY_TIMEOUT) {
if (mode == MODE_MAIN || mode == MODE_SECOND) {
mode = MODE_SET_MINUTE;
mode_timeout = MODE_TIMEOUT_SET;
}
} else {
}
}
if (key2_down && ! key2_press) {
if (mode == MODE_MAIN) {
mode = MODE_CALENDAR;
mode_timeout = MODE_TIMEOUT;
} else if (mode == MODE_CALENDAR) {
mode = MODE_YEAR;
mode_timeout = MODE_TIMEOUT;
} else if (mode == MODE_YEAR) {
mode = MODE_MAIN;
mode_timeout = 0;
} else if (mode == MODE_SET_MINUTE) {
minute += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SET_HOUR) {
hour += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SET_DAY) {
dayOfMonth += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SET_MONTH) {
month += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SET_YEAR) {
year += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SECOND) {
second = 0;
need_date_set = 1;
mode_timeout = MODE_TIMEOUT_SET;
}
} else if ( ! key2_down && key2_press) {
if (key2_time >= KEY_TIMEOUT) {
} else {
}
} else if (key2_down && key2_press) {
if (key2_time >= KEY_TIMEOUT) {
if (mode == MODE_SET_MINUTE) {
minute += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SET_HOUR) {
hour += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SET_DAY) {
dayOfMonth += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SET_MONTH) {
month += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
} else if (mode == MODE_SET_YEAR) {
year += 1;
mode_timeout = MODE_TIMEOUT_SET;
need_date_set = 1;
}
} else {
}
}
key1_press = key1_down;
if ( ! key1_press) {
key1_time = 0;
}
key2_press = key2_down;
if ( ! key2_press) {
key2_time = 0;
}
}
if (need_date_set) {
//
// ds1307 ,
// , ,
if (minute > 59) {
minute = 0;
}
if (hour > 23) {
hour = 0;
}
if (dayOfMonth > 31) {
dayOfMonth = 1;
}
if (month > 12) {
month = 1;
}
if (year > 99) {
year = 0;
}
// ds1307
setDS3231time(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
}
// ,
if (need_render) {
do_render();
}
//
cli();
lcd_refresh();
sei();
_delay_ms(10);
cycle_count_10 += 1;
if (cycle_count_10 >= 10) {
cycle_count_10 = 0;
}
}
return 0;
}
// -
byte decToBcd(byte val)
{
return( (val/10*16) + (val%10) );
}
byte bcdToDec(byte val)
{
return( (val/16*10) + (val%16) );
}
// ds1307
void setDS3231time(byte second,
byte minute,
byte hour,
byte dayOfWeek,
byte dayOfMonth,
byte month,
byte year)
{
twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 0, (uint8_t) decToBcd(second));
twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 1, (uint8_t) decToBcd(minute));
twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 2, (uint8_t) decToBcd(hour));
twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 3, (uint8_t) decToBcd(dayOfWeek));
twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 4, (uint8_t) decToBcd(dayOfMonth));
twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 5, (uint8_t) decToBcd(month));
twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 6, (uint8_t) decToBcd(year));
// SQ 1Hz
// , ds1307
// 8kHz
twi_write((uint8_t) DS3231_I2C_ADDRESS, (uint8_t) 7, (uint8_t) 0b00010000);
}
// ds1307
byte readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
byte rc = twi_read(DS3231_I2C_ADDRESS, 0, 7);
if (rc) return 1;
*second = bcdToDec(twi_receive() & 0x7f);
*minute = bcdToDec(twi_receive());
*hour = bcdToDec(twi_receive() & 0x3f);
*dayOfWeek = bcdToDec(twi_receive());
*dayOfMonth = bcdToDec(twi_receive());
*month = bcdToDec(twi_receive());
*year = bcdToDec(twi_receive());
}
// , , ,
byte readDS3231time_hms(byte *second, byte *minute, byte *hour) {
byte rc = twi_read(DS3231_I2C_ADDRESS, 0, 3);
if (rc) return 1;
*second = bcdToDec(twi_receive() & 0x7f);
*minute = bcdToDec(twi_receive());
*hour = bcdToDec(twi_receive() & 0x3f);
}
/*
* , , : http://dsscircuits.com/articles/arduino-i2c-master-library
* , 4k .
*/
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define START 0x08
#define REPEATED_START 0x10
#define MT_SLA_ACK 0x18
#define MT_SLA_NACK 0x20
#define MT_DATA_ACK 0x28
#define MT_DATA_NACK 0x30
#define MR_SLA_ACK 0x40
#define MR_SLA_NACK 0x48
#define MR_DATA_ACK 0x50
#define MR_DATA_NACK 0x58
#define LOST_ARBTRTN 0x38
#define TWI_STATUS (TWSR & 0xF8)
#define SLA_W(address) (address << 1)
#define SLA_R(address) ((address << 1) + 0x01)
#define MAX_BUFFER_SIZE 32
uint8_t twi_bytesAvailable = 0;
uint8_t twi_bufferIndex = 0;
uint8_t twi_totalBytes = 0;
uint16_t twi_timeOutDelay = 0;
uint8_t twi_returnStatus;
uint8_t twi_nack;
uint8_t twi_data[MAX_BUFFER_SIZE];
void twi_begin()
{
sbi(PORTC, 4);
sbi(PORTC, 5);
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
TWBR = ((F_CPU / 100000) - 16) / 2;
TWCR = _BV(TWEN) | _BV(TWEA);
}
uint8_t twi_read(uint8_t address, uint8_t registerAddress, uint8_t numberBytes)
{
twi_bytesAvailable = 0;
twi_bufferIndex = 0;
if(numberBytes == 0){numberBytes++;}
twi_nack = numberBytes - 1;
twi_returnStatus = 0;
twi_returnStatus = twi_start();
if(twi_returnStatus){return(twi_returnStatus);}
twi_returnStatus = twi_sendAddress(SLA_W(address));
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(2);}
return(twi_returnStatus);
}
twi_returnStatus = twi_sendByte(registerAddress);
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(3);}
return(twi_returnStatus);
}
twi_returnStatus = twi_start();
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(4);}
return(twi_returnStatus);
}
twi_returnStatus = twi_sendAddress(SLA_R(address));
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(5);}
return(twi_returnStatus);
}
for(uint8_t i = 0; i < numberBytes; i++)
{
if( i == twi_nack )
{
twi_returnStatus = twi_receiveByte(0);
if(twi_returnStatus == 1){return(6);}
if(twi_returnStatus != MR_DATA_NACK){return(twi_returnStatus);}
}
else
{
twi_returnStatus = twi_receiveByte(1);
if(twi_returnStatus == 1){return(6);}
if(twi_returnStatus != MR_DATA_ACK){return(twi_returnStatus);}
}
twi_data[i] = TWDR;
twi_bytesAvailable = i+1;
twi_totalBytes = i+1;
}
twi_returnStatus = twi_stop();
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(7);}
return(twi_returnStatus);
}
return(twi_returnStatus);
}
uint8_t twi_write(uint8_t address, uint8_t registerAddress, uint8_t data)
{
twi_returnStatus = 0;
twi_returnStatus = twi_start();
if(twi_returnStatus){return(twi_returnStatus);}
twi_returnStatus = twi_sendAddress(SLA_W(address));
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(2);}
return(twi_returnStatus);
}
twi_returnStatus = twi_sendByte(registerAddress);
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(3);}
return(twi_returnStatus);
}
twi_returnStatus = twi_sendByte(data);
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(3);}
return(twi_returnStatus);
}
twi_returnStatus = twi_stop();
if(twi_returnStatus)
{
if(twi_returnStatus == 1){return(7);}
return(twi_returnStatus);
}
return(twi_returnStatus);
}
uint8_t twi_receive()
{
twi_bufferIndex = twi_totalBytes - twi_bytesAvailable;
if(!twi_bytesAvailable)
{
twi_bufferIndex = 0;
return(0);
}
twi_bytesAvailable--;
return(twi_data[twi_bufferIndex]);
}
uint8_t twi_start()
{
unsigned long startingTime = millis();
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)))
{
if(!twi_timeOutDelay){continue;}
if((millis() - startingTime) >= twi_timeOutDelay)
{
twi_lockUp();
return(1);
}
}
if ((TWI_STATUS == START) || (TWI_STATUS == REPEATED_START))
{
return(0);
}
if (TWI_STATUS == LOST_ARBTRTN)
{
uint8_t bufferedStatus = TWI_STATUS;
twi_lockUp();
return(bufferedStatus);
}
return(TWI_STATUS);
}
uint8_t twi_sendAddress(uint8_t i2cAddress)
{
TWDR = i2cAddress;
unsigned long startingTime = millis();
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)))
{
if(!twi_timeOutDelay){continue;}
if((millis() - startingTime) >= twi_timeOutDelay)
{
twi_lockUp();
return(1);
}
}
if ((TWI_STATUS == MT_SLA_ACK) || (TWI_STATUS == MR_SLA_ACK))
{
return(0);
}
uint8_t bufferedStatus = TWI_STATUS;
if ((TWI_STATUS == MT_SLA_NACK) || (TWI_STATUS == MR_SLA_NACK))
{
twi_stop();
return(bufferedStatus);
}
else
{
twi_lockUp();
return(bufferedStatus);
}
}
uint8_t twi_sendByte(uint8_t i2cData)
{
TWDR = i2cData;
unsigned long startingTime = millis();
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)))
{
if(!twi_timeOutDelay){continue;}
if((millis() - startingTime) >= twi_timeOutDelay)
{
twi_lockUp();
return(1);
}
}
if (TWI_STATUS == MT_DATA_ACK)
{
return(0);
}
uint8_t bufferedStatus = TWI_STATUS;
if (TWI_STATUS == MT_DATA_NACK)
{
twi_stop();
return(bufferedStatus);
}
else
{
twi_lockUp();
return(bufferedStatus);
}
}
uint8_t twi_receiveByte(uint8_t ack)
{
unsigned long startingTime = millis();
if(ack)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
}
else
{
TWCR = (1<<TWINT) | (1<<TWEN);
}
while (!(TWCR & (1<<TWINT)))
{
if(!twi_timeOutDelay){continue;}
if((millis() - startingTime) >= twi_timeOutDelay)
{
twi_lockUp();
return(1);
}
}
if (TWI_STATUS == LOST_ARBTRTN)
{
uint8_t bufferedStatus = TWI_STATUS;
twi_lockUp();
return(bufferedStatus);
}
return(TWI_STATUS);
}
uint8_t twi_stop()
{
unsigned long startingTime = millis();
TWCR = (1<<TWINT)|(1<<TWEN)| (1<<TWSTO);
while ((TWCR & (1<<TWSTO)))
{
if(!twi_timeOutDelay){continue;}
if((millis() - startingTime) >= twi_timeOutDelay)
{
twi_lockUp();
return(1);
}
}
return(0);
}
void twi_lockUp()
{
TWCR = 0;
TWCR = _BV(TWEN) | _BV(TWEA);
}
. , , — . , 1MHz, , 6mA. . , , : USBasp- .
, AVR- " ". ! , 100 . 65ms, , .
, - , , , 7805 , - .
! . , - , , , ? , . STM8/32? MSP430? , -, AVR?

UPD
, , . . , i2c ds1307. , VCC 1.2*VBAT. , i2c. : , +5v - 2.5v, i2c , . VBAT Tiny RTC 3v. .
. , . — , , 595, . , RCLK, , , , . , , . , .
, . - , , , , AVR 65 . , , . , AVR , , , . olartamonov .
, , 6mA , lm7805, (Vout ; Vin ). — 4mA.
, 0.3 1.6 mA. , — , , .
— ! , , 595- 555 , - , 32 595-. - :-)