Excelentes relojes en una pantalla LCD iluminada y supermicrocircuito ATMega48. Pero no funcionaron.

UPD : Crohn murió, cortó dos cables, suspendió, 0.3-1.6mA
Es decir, los relojes, por supuesto, funcionan, pero, por desgracia, no funcionarán por mucho tiempo.
Érase una vez, en una caja en la mesita de noche lejana colgué un par de indicadores LCD de siete segmentos. Y hace mucho tiempo, quería ponerlos en circulación y construir un reloj basado en uno de ellos. Érase una vez: son, literalmente, siete años. Fue entonces, en 2011, cuando me interesé en la electrónica. Sin pensarlo durante mucho tiempo, ordené todo tipo de cosas en una buena tienda en línea (no, no en Ali; no estoy seguro de que ya estuviera allí). Pero de alguna manera no funcionó para mí crear lo eterno. Después de varias tablas grabadas, abandoné este entretenimiento y lo olvidé.
Y así, cuando Ali recibió un paquete que contenía maquetas, un paquete de 595 en estuches, Tiny RTC en ds1307 y, lo más importante, USBasp , era hora de volver a la vieja idea. Desde el antiguo escondite tenía un ATMega48 , el que tenía 28 patas, lm7805 , todas las cosas pequeñas en forma de resistencias / condensadores / botones y, de hecho, un indicador en 40 patas.
En términos generales, originalmente se planeó usar AtTiny13, que también utilizo, pero después de estimarlo de una manera y otra, no descubrí cómo moverse con sus 5 patas para mostrar el indicador, leer dos botones y comunicarme con el reloj i2c. Con 28 mega patas, ya no es necesario guardar y pervertir con la unión de las patas. Aunque, por supuesto, en este caso, no puedes prescindir de los 595. Pero si planeaba generar los 32 bits de datos para el indicador de un adolescente en serie, entonces con mega puede mostrar una imagen en los cuatro microcircuitos a la vez.

Todos los 595 están ocultos debajo del indicador. La foto muestra las conclusiones de la carcasa del chip.
Se usaron 595 exactamente cuatro piezas, porque el indicador, aunque tiene 40 patas, muestra solo 32 en segmentos. Por desgracia, es solo un indicador 3.5, es decir, tiene 3 dígitos completos, más uno. Hay un símbolo por segundos, pero no hay designación para AM / PM. Pero realmente lo hay. No quisiera pedir un indicador más avanzado sin haber recogido nada en los indicadores LCD en mi vida.

Documentación de trabajo para el indicador. El probador tuvo que averiguar qué pierna corresponde a qué segmento.
Bueno, entonces una cuestión de tecnología. Nunca hubo un esquema, pero todo es obvio allí. Solo era necesario seleccionar cuatro patas para la entrada de buffers, una pata común para el indicador, una pata para SCLK / RCLK, una pata para OE, dos patas para i2c, dos patas para botones. Todo esto estaba, por supuesto, mal. Por qué decidí que OE debería instalarse en el controlador y SCLK combinado con RCLK, no lo recuerdo. Era necesario hacer todo lo contrario. Y el cable indicador común en el controlador no es necesario en absoluto, una de las conclusiones de la primera 595a podría prescindirse (lo que también hice, al final).

Alambres Muchos de ellos. Vista interior

La vista desde el exterior.
Lo más interesante de todo este proyecto: el código de salida para el indicador. La sutileza es que no puede simplemente aplicar voltaje al indicador LCD y olvidarlo. Es necesario cambiar la polaridad entre los segmentos y el contacto común unas cien veces por segundo, para que todo sea hermoso y agradable a la vista. Como entorno de desarrollo, sin más preámbulos, utilicé el IDE de Arduino, solo un pequeño tormento en un par de puntos. En primer lugar, tuve que usar el paquete MiniCore ( https://github.com/MCUdude/MiniCore ), porque tuve que escribir no para un gran arduino listo para usar, sino para un ATMega48 débil y desnudo. En segundo lugar, un intento directo de usar la biblioteca integrada para i2c falló. Por alguna razón, no quería trabajar, tuve que buscar otra biblioteca y luego recortarla para mis necesidades.
Al final resultó que, 4 kilobytes es muy pequeño. Especialmente si escribe en C. Tal vez si decidiera cambiar al ensamblador, esta restricción no hubiera presionado tan en serio, pero recordando mis extractos anteriores por escrito en ensamblador para AVR, no tenía ese deseo. Y para escribir en C, se necesita mucho espacio. Puse un pequeño soporte inadvertidamente: cien bytes en la tubería.
Código realmente comentado#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-. - :-)