Преотличнейшие часы на завалявшемся жк-индикаторе и супермикросхеме ATMega48. Но не получились.
То есть, часы, конечно, работают, но, увы, проработают они недолго.
Давным-давно в коробке в дальней тумбочке болталась у меня пара семисегментных жк-индикаторов. И так же давно мне хотелось взять их в оборот и соорудить на основе одного из них часы. Давным-давно: это, в буквальном смысле, семь лет. Именно тогда, в 2011 году возник у меня интерес к электронике. Не думая долго, заказал я тогда всякой всячины в одном хорошем интернет магазине (нет, не на Али; не уверен, что он тогда уже был). Но как-то у меня не заладилось творить вечное. После нескольких протравленных плат, забросил я это развлечение и забыл.
И вот, когда с Али пришла посылка, содержавшая макетки, пакетик 595-х в dip-корпусах, Tiny RTC на ds1307, и, что самое важное, USBasp, пришло время вернуться к старой задумке. Из старой заначки у меня был ATMega48, тот который о 28 ног, lm7805, всякая мелочевка в виде резисторов/конденсаторов/кнопок, и, собственно, индикатор на 40 ногах.
Вообще говоря, изначально планировалось использовать AtTiny13, которые у меня тоже валяются, но прикинув и так, и этак, я не придумал как обойтись его 5 ногами что бы и на индикатор выводить, и две кнопки читать, и с часами по i2c общаться. С 28 ногами меги, экономить и извращаться с объединением ног уже не приходится. Хотя, конечно, и в этом случае без 595-х не обойтись. Но если с тини я планировал выводить все 32 бита данных для индикатора последовательно, то с мегой можно выводить картинку сразу на все четыре микросхемы параллельно.
Все 595-е спрятаны под индикатором. На фото видны выводы корпуса микросхемы.
595 было использовано именно четыре штуки, потому что индикатор, хотя и имеет 40 ног, но на сегменты выведены только 32. Увы, но это только 3.5 индикатор, то есть у него 3 полноценных цифры, плюс единица. Есть символ секунд, но никакого обозначения для AM/PM. Но уж что есть. Заказывать более продвинутый индикатор, не собрав ни разу в жизни ничего на жк-индикаторах, мне бы не хотелось.
Рабочая документация на индикатор. Пришлось тестером выяснять какая ножка какому сегменту соответствует.
Ну а дальше дело техники. Схемы никогда не было, но там все очевидно. Надо было только выделить четыре ноги на вход буферов, общую ногу для индикатора, ногу для SCLK/RCLK, ногу на OE, две ноги для i2c, две ноги для кнопок. Все это было, конечно, неправильно. Почему я решил, что OE надо заводить на контроллер, а SCLK объединять с RCLK — уже и сам не вспомню. Надо было делать как раз наоборот. А общий провод индикатора на контроллере не нужен вообще, можно было обойтись одним из выводов первой 595-й (что я тоже, в итоге, сделал).
Провода. Много их. Вид изнутри.
Вид снаружи.
Самое интересное во всем этом прожекте: код вывода на индикатор. Тонкость в том, что на жк-индикатор нельзя просто так подать напряжение и забыть. Надо около ста раз в секунду менять полярность между сегментами и общим контактом, что бы все было красиво и приятно глазу. В качестве среды разработки, не мудрствуя лукаво, я использовал Arduino IDE, лишь чуть помучавшись в паре моментов. Во-первых, пришлось использовать пакет MiniCore ( https://github.com/MCUdude/MiniCore ), ведь писать пришлось не для большой готовой ардуины, а для слабого и голого ATMega48. Во-вторых, прямая попытка использовать встроенную библиотеку для i2c ни к чему не привела. По какой-то не вполне понятной причине, работать оно не пожелало, пришлось найти другую библиотеку, а потом и обрезать ее для своих нужд.
Как оказалось, 4 килобайта — это очень мало. Особенно, если писать на C. Возможно, если бы я решился перейти на ассемблер, это ограничение не давило бы так серьезно, но помня мои прошлые эксерсизы в писании на ассемблере для AVR, желания у меня такого не возникло. А на C писать — много места надо. Чуть скобку ненароком поставил — сотня байт в трубу.
#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?
Комментарии (215)
l_o_d
18.03.2018 18:39+1Ну для начала можно убрать 7805 и питать напрямую от батарейки на 3-3.6 вольт. Стабилизатор тоже немало кушает. Или хотя бы выбрать стабилизатор с малым собственным потреблением. А вывод на индикатор можно сделать через специализированный контроллер типа HT1621. Там мизерное собственное потребление.
dmiceman Автор
18.03.2018 18:45> HT1621
Вот спасибо, почитаю.dmiceman Автор
18.03.2018 19:23А нет, готовый дисплей — это неспортивно :-)
l_o_d
18.03.2018 19:33А это и не готовый дисплей:
LCD контроллер с организацией памяти 32х4 для работы с микроконтроллерами
Основные характеристики
Напряжение питания: 2.4…5.2В
Встроенный 256 kHz RC генератор
Работа с внешним 32.768 kHz кварцем или от источника частоты 256 kHz
Выбор напряжения смещения (bias) 1/2 или 1/3 и выбор продолжительности работы 1/2, 1/3 или 1/4 (duty)
Внутренний формирователь основной частоты
Две частоты работы драйвера звонка (2kHz/4kHz)
Режим пониженного энергопотребления
Внутренний генератор и WDT
Вывод основной частоты или вывод переполнения WDT
8 видов источников для получения основной частоты и для WDT
32x4 LCD драйвер
Встроенная оперативная память дисплея 32х4
Трехпроводный, последовательный интерфейс
Встроенное формирование частоты возбуждение LCD
Программное конфигурирование
Два режима работы: c данными и с командами
Операции обращения к памяти с автоинкрементом
Три режима доступа к данным
Вывод VLCD для настройки рабочего напряжения LCD
Стоит кстати вполне демократично, даже в чип и дипе рублей 60 всего. Правда там корпус не очень удобный. В китае наверное и DIP можно найти.
FGV
18.03.2018 18:437805 от кроны = кпд < 50%
ставьте импульсный dc/dc, в два раза меньше кушать будет (а то и в 5-6 раз).dmiceman Автор
18.03.2018 18:48Нет, нет, нет. Я, видимо, недостаточно раскрыл эту тему в статье. Потребление я смотрел до того как решился (для компактности) применить крону и 7805. Просто давал 5 вольт и смотрел в разрыве цешкой. И уже расстроившись решил, что как proof-of-concept и так сойдет.
FGV
18.03.2018 19:08Хм, тогда странно, вроде в активном режиме на 1МГц 48 кушает 1мА (по даташиту). Можно на полную схему взглянуть?
dmiceman Автор
18.03.2018 19:31Вот чего нет, того нет :-)
Вероятно в даташите имеется в виду ситуация, когда контроллер что-то внутри себя перемалывает. А мне же надо все время ногами дрыгать.
Четыре sn74hc595n дают 70 (max по даташиту) * 4 = 280 микроампер.
Подтяжки на всю схему ровно две, по 15 kOhm.
Tiny RTC должен давать совсем копейки.
А как оценить потребление собственно индикатора — даже не знаю. Но наверняка там какие-нибудь наноамперы :-)
l_o_d
18.03.2018 18:50Кстати слышал утверждение, что на малых токах импульсники не блещут высоким КПД. Самому замерять правда не приходилось…
olartamonov
18.03.2018 19:42Самому замерять
А даташиты читать в наше время, я так понимаю, не модно.l_o_d
18.03.2018 21:29Как то не было потребности в такой ситуации использовать импульсник. Да и в той промышленной аппаратуре с которой сталкивался обычно ставят литиевый элемент на 3.6 вольт и не парятся. Видимо в этом есть смысл.
olartamonov
18.03.2018 22:19А ведь вместо этого ля-ля можно было просто пойти на сайт TI, открыть табличку DC/DC понижаек, отсортировать по Iq и узнать много интересного.
l_o_d
18.03.2018 22:36Да я ведь не спорю что таких нет) Просто достать линейный стабилизатор с нужными характеристиками намного проще и дешевле. А в вашем примере еще и корпус довольно сложный в припайке. Ну и если делать не макет, а полноценное устройство то лучше сразу взять источник с подходящим напряжением. Будет меньше деталей, дольше время работы.
DarkTiger
18.03.2018 23:59А если пойти на алиэкспресс, там можно купить готовый слаботочный DC/DC за цену КРЕН-ки в рознице, и не ломать голову, если в конвертерах не специалист. Там, конечно, обвязка не совсем та, что в даташитах, что влияет на КПД, но потери все равно будут сильно, сильно меньше, чем у КРЕН-ки.
Хотя на самом деле это не критично, 6мА потребляет схема или 3 — при использовании CR2032 «всю систему надо менять» (с)olartamonov
19.03.2018 08:25И купите вы там с большой вероятностью что-то типа LM2596 с теми же 5-10 мА собственного потребления, что и у 7805.
Интересно, когда до любителей алиэкспресса дойдёт, что их судьба — наколенные поделки, нормально работающие через три раза на четвёртый, а у нормального разработчика минимум половина времени уходит не на махание паяльником, а именно что на чтение даташитов?..Mike_soft
19.03.2018 10:08потому, что электроника сильно «разрослась». уже доступна не пара десятков транзисторов, параметры которых можно было держать в голове, не полсотни цифровых микросхем, и т.п.
Т.е. чтобы заниматься этим профессионально — надо «очень быстро бежать»©.olartamonov
19.03.2018 10:14Надо уметь читать.
А чип с 360 нА собственного потребления, на который я ссылку давал, пять лет уже выпускается.Mike_soft
19.03.2018 10:26в контексте автора — «всего пять лет», ибо «интерес возник» в 2011 году.
Насчет «уметь читать» — согласен. ибо 99% всех возникающих вопросов решаются при изучении dataShit'ов :-) и TFM'ов.
DarkTiger
19.03.2018 11:59Э-э-э… Там фото более чем достаточного разрешения, чтобы увидеть маркировку чипа. Типичная LDO-шка китайская — это 1117, ее сразу видно и ни с чем не спутать :) Да и индуктивности, опять же :)
Еще раз — взять готовый будет быстрее и дешевле, если разработчик не спец в данном вопросе.
Вы про Point-of-Load в курсе? В телекоммуникационном оборудовании они используются сплошь и рядом, поскольку разработчики спецы в высокочастотных дизайнах, но питание — не их конек. Поэтому проще поставить что-нибудь приличное, от GE или Murata за полчаса, чем тратить неделю на курение даташитов. Там свои проблемы выползают, конечно, с охлаждением, например — тепло с PoL в плату почти не уходит, но в общем случае это быстрее и надежнее, чем ваять самому DC/DC конвертер с нуляolartamonov
19.03.2018 12:09Типичная LDO-шка китайская — это 1117, ее сразу видно и ни с чем не спутать :) Да и индуктивности, опять же :)
Что в названии LM2596 заставляет вас заподозрить, что я имел в виду LDO? Или вы не верите, что у DC/DC Iq может быть в десяток миллиампер? Ну, откройте даташит, что ли.
Еще раз — взять готовый будет быстрее и дешевле, если разработчик не спец в данном вопросе.
Большинство проблем имеет простое и очевидное неправильное решение.
Поэтому проще поставить что-нибудь приличное, от GE или Murata за полчаса, чем тратить неделю на курение даташитов
Я вам страшую вещь скажу: на все эти модули тоже есть даташиты. Которые тоже надо читать.
l_o_d
18.03.2018 19:35А из чего эти голубенькие стойки? Неужели бумага?
dmiceman Автор
18.03.2018 19:44Бумага :-) Как раз дочку привлек к процессу производства. Не оказалось в заначке подходящих шурупчиков, которые лезли бы в монтажные дырки этих макеток, поэтому стойки были сделаны из зубочисток, обернутых бумагой, покрытой цапонлаком. Крепление к макеткам — суперклей. На неделю конструкции хватит.
olartamonov
18.03.2018 19:42+1А один только вывод из сна занимает как минимум 65ms, требуемые на стабилизацию осциллятора
Выкидываем внешний кристалл, тактируемся от внутреннего RC, у которого минимальное время запуска — 6+14 KCK, т.е. 20000/8000000 = 2,5 мс.dmiceman Автор
18.03.2018 19:49Вот да, я про эти 65ms написал со слов на каком-то форуме. В даташите это как-то не очень ясно описано (ну или я не очень понял). Буду изучать это шаманство через неделю :-)
Другое дело, будет ли от этого толк вообще, если спать надо 10ms всего.olartamonov
18.03.2018 19:56
Я боюсь предположить, как можно ещё яснее-то это описать.
Не говоря уже про то, что у вас есть ещё и Standby Mode, в котором внешний осциллятор продолжает работать, энергопотребление в районе 100 мкА, а выход из сна — за единицы тактов.dmiceman Автор
18.03.2018 20:01Я вот это все время курю: ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2545-8-bit-AVR-Microcontroller-ATmega48-88-168_Datasheet.pdf
Там такой таблицы я не нашел. Это откуда?olartamonov
18.03.2018 20:07Там такой таблицы я не нашел
Попробуйте посмотреть ещё раз. Например, на странице 58.
Gudin
19.03.2018 19:27А почему 6+14, а не просто 14? Я так понял в случае выхода из сна (2 режима) будет только 6.
olartamonov
19.03.2018 20:46Да, вы правы, 6. И не KCK, а просто CK, т.е. ещё и микросекунды.
Много лет не работал с атмегами, а сейчас глянул по диагонали.
courser
18.03.2018 19:466ма однозначно говорят о криво написанной программе, извините.
Неоткуда взяться 6ти ма, если программа будет выходить из спячки по прерыванию RTC 25раз в секунду или около того(этого достаточно при 5в размахе) для быстрого инверса сегментов. Да даже и при 100герцах это очень много.
Используйте прерывания RTC, изучите внимательно типы сна.dmiceman Автор
18.03.2018 19:55> 25раз в секунду
Мало. Я пробовал разные режимы, и даже при 50 герцах заметно мерцание.
И тут другой момент — ds1307 умеет только 1Hz, 4kHz, 8kHz и 32kHz. Ничего подходящего.
> говорят о криво написанной программе, извините.
А это запросто :-) Это пока самая большая и сложная программа для контроллера, которую я написал в жизни. Знание специфики у меня очень умозрительное.courser
18.03.2018 20:28Используйте встроенный rtc меги, тактируйте проц от того же кварца 32768
для часов это более чем достаточно.
Постоянную времени вашего индикатора не знаю, но обычно мерцание заметно только под углом, и уж точно не на 50гц, это уже не увидит глаз. Скорее всего мерцание связано с другими причинами — цикл какой-нибудь вклинивается и тп.dmiceman Автор
19.03.2018 09:28Подозреваю, в моем случае мерцание на 50 Hz связано с неправильной разводкой. Ведь я (ошибочно) сделал так, что все продвижения битов по 595-м неизбежно отображаются на индикаторе. А может и нет. Тайминги у меня в этом месте немного с потолка взятые.
courser
19.03.2018 14:38Я б вообще рекомендовал для этого проекта мегу64L или А, она не так дорого стоит, и развести сегменты по портам напрямую. RTC использовать встроенный, питание взять от двух мизинцев 3в. Будет очень лаконично и экономично. Сотня-две микроампер максимум, думаю.
REPISOT
18.03.2018 20:00+1Как оказалось, 4 килобайта — это очень мало. Особенно, если писать на C.
Э, нет. Это не С. это Arduino IDE. Чистый C дает вполне себе компактный код.dmiceman Автор
18.03.2018 20:05Так какая разница какая IDE? Оно же все равно компилирует avr-gcc, с -Os. Если не допускать с++-ного оверхеда, никакой разницы быть не должно.
mksma
18.03.2018 20:15Оставил по этому поводу комментарий ниже. По моим наблюдениям Arduino IDE в исполняемый файл подсовывает какую-то свою библиотеку, отсюда и разница.
ProstoUser
19.03.2018 09:41Там еще стиль написания довольно странный. По крайней мере то, что я увидел в самом начале, можно заметно уменьшить, как по количеству занимаемого места, так и по количеству выполняемых команд.
Например, с самом начале, там где:
switch (num) { case 0: if (pos == 3) { buf = 0b11101110; } else { buf = 0b11100111; } break; ......
можно написать что-то вроде такого:
static const unsigned char DigitCode = {0b11100111, .....}; static const unsigned char DigitCodePos3 = {0b11101110, .....}; if (num<9) buf = (pos == 3) ? DigitCodePos3[num] : DigitCode[num] ;
Оно и короче, и по крайней мере не медленнее получится.
Подобных мест, где вместо простой таблички огромный копипаст, в вашем коде очень много. Так что, скорее, это стиль а не компилятор.
HiTechSpoon
20.03.2018 09:15Последнйи раз имел дело с Arduino лет 5 назад, и если я правильно помню, в Arduino IDE применялся язык Processing, у которого есть своя IDE — PDE (Processing Development Evironment). У этих IDE схожий вид и в Сети можно найти упоминания, что именно от Processing'а растут ноги у Arduino IDE. Также и слово «скетч» — название исходного кода программы в Arduino IDE, было позаимствовано из Processing.
Сейчас же на сайте википедии написано, что в Arduino IDE используется С++. Интересно, не ошибка ли это или действительно язык поменяли?
mksma
18.03.2018 20:11Как оказалось, 4 килобайта — это очень мало. Особенно, если писать на C.
Поправьте меня кто нибудь если я не прав. Но у меня сложилось впечатление, что Arduino IDE в исполняемый файл подсовывает еще какой-то свой код. Который берет довольно много места. Например, когда для работы с LCD дисплеем я использовал Arduino IDE + liquidcrystal_i2c библиотеку, сборка заняла примерно 2500 байт. Без Arduino IDE и со своей библиотекой для i2c и дисплея та же функциональность уместилась в 750 байт.dmiceman Автор
18.03.2018 20:22Загрузчик? Я-то использовал minicore, который для atmega48 загрузчика не использует.
mksma
18.03.2018 20:38Проверил что Arduino IDE добавляет в исполняемый файл. Среди прочего в линкер передавалось это:
arduino_cache_122843\core\core_arduino_avr_uno_27ad0de2390183402c74f07cbe44f9f8.a
На чистом C это можно убрать, но тогда нельзя использовать библиотеки созданные для Adruino IDE.
VTH
18.03.2018 21:12В таком приложении стоило бы тупую работу по обновлению жк-экрана возложить на какой-то аппаратный rc таймер/генератор. Вполне при этом получив микропотребеление. Тем более, внешние чипы помимо контроллера задействованы
andrrrrr
18.03.2018 22:34может вместо ЖК попробовать электронную бумагу? обновил цифру и в сон на минуту. оно не перестаёт отрисовывать изображение даже после отключения ото всего.
ссылка на али, цена $14, диагональ 2.9 дюймов
l_o_d
18.03.2018 22:39Еще бы подешевле стоил( Почему то никогда не видел что нибудь самодельное с таким типом дисплея. Видимо есть какие то сложности в реализации…
Alexashka
18.03.2018 23:32Waveshare сейчас выпускает со встроенным контроллером и SPI-интерфейсом. Цена только не совсем демократичная, около 500р за 2.13"
ploop
19.03.2018 08:46Видимо есть какие то сложности в реализации…
Дорого, да и появились они относительно недавно.
Mogwaika
19.03.2018 08:48Этот цветной перерисовывается очень долго, секунды. Надо брать мелкий ч/б, он отрисовывается за 0.3 с кажется…
Proektmnd
18.03.2018 22:43Можно взять 48 мегу с индексом V, или PA.У них нижний порог питания 1.8в. Для пущей экономии питания отключить ненужную периферию: компаратор(жрёт как конь), АЦП, УАРТ. RTC было бы лучше использовать, например, DS3231.У неё кварц уже на борту, питание 3.3в, потребление в активном режиме 200мкА. DS1307 тоже жрёт не мало, да ещё и кварц внешний(точности не добавляет).А что бы часы запустились, можно вписать в регистр секунд нолик и они пойдут без установки времени.
sfrolov
18.03.2018 22:49Если хотите использовать ЖКИ, то берите сразу микроконтроллер с драйвером ЖКИ. Это позволит разгрузить микроконтроллер и уменьшить токопотребление из-за того, что процессор не будет просыпаться 100 раз в секунду для обновления ЖКИ.
Правильное батареечное устройство с постоянной работой ЖКИ должно работать минимум полгода от одного комплекта батарей. Это единицы микроампер. Предложенный HT1621 плохо для этого годится, потому что только он потребляет в районе 20-30 мкА.l_o_d
18.03.2018 23:15Ну единиц микроампер в домашних условиях наверное сложно добиться. А при 100 — 200 мкА и комплекте хороших пальчиковых батареек думаю пол года проработать может.
olartamonov
19.03.2018 08:26Ну единиц микроампер в домашних условиях наверное сложно добиться
И что же в домашних условиях этому мешает?l_o_d
19.03.2018 10:49Большинство поделок лепится из того что под рукой) Иногда нет экономичного контроллера, иногда подходящих батареек или стабилизатора. Банально большинство самодельщиков скорее всего не имеют профильного образования или желания глубоко закапываться в даташиты. Одни могут написать экономичное ПО но у них проблемы с железом, у других обвязка почти ничего не жрет но не оптимальное ПО контроллера потребляет как паровоз.
ploop
19.03.2018 10:54Эх, если бы это была проблема самодельщиков… Сколько статей о том, как вмонтировать в мышку аккумулятор на 100500 мАч, чтобы проработала хоть месяц без зарядки, хотя у того же Logitech мыша работает год(!) на одной батарейке, соответственно два — на двух.
Meklon
19.03.2018 11:01Это смотря какие.
Logitech Performance MX — офигенная мышь. Но аккумулятора там хватает на 3-5 дней. Причем от рождения так было.
olartamonov
19.03.2018 12:10То есть в домашних условиях возникает какая-то непреодолимая сила, не позволяющая прочитать даташит на контроллер и написать прошивку нормально?
l_o_d
19.03.2018 13:19В домашних условиях делают устройства не только те кто могут осмыслить даташит. Часто просто дергают примеры из инета, поправляют по месту и вперед. Кому то может интереснее процесс пайки и непосредственно сборки, а к ПО отношение «лишь бы было». Это же просто хобби) Это как добиваться рекордных урожаев на домашней картофельной грядке: есть энтузиасты, а есть те кому «как то растет и ладно».
olartamonov
19.03.2018 14:10То есть оригинальную фразу «в домашних условиях сложно добиться единиц микроампер» надо читать как «лично мне в домашних условиях сложно добиться единиц микроампер, потому что лень этим заниматься, а хочется побыстрее сляпать на коленке»?
l_o_d
19.03.2018 14:42Можно и так. Хотя нет все немного сложнее. Например я могу хорошо развести плату, сделать или подобрать приличный корпус, все красиво спаять и собрать, но вот с ПО проблемы. Глядя на творения людей на проводах и скотче залитые из «соплемета» называть свои устройства сделанными «на коленке» я не хочу. Причем некоторые сопливые поделия реально жрут микроамперы, потому что создатели хорошо пишут ПО, чего я не могу. Каждому свое как говориться) Не отрицаю что есть те у кого все получается цивилизованно: и прошивка, и плата, и корпус.
Meklon
18.03.2018 23:03Как вы руками такие пучки проводов паяете? Чисто субъективно гораздо меньше вариантов ошибок при проектировании в чем-то вроде Eagle. Хотя, вероятно, тут моей недостаток опыта сказывается.
l_o_d
18.03.2018 23:18Тоже всегда удивлялся такому терпению) Мне проще сразу развести плату, попробовать собрать, потом в случае ошибок еще раз вытравить, чем напаивать проводок за проводком. Но обилие поклонников вот такого способа сборки говорит о том, что не все такие нетерпеливые.
dmiceman Автор
19.03.2018 09:49Как раз нетерпеливые :-)
На одну разводку я бы дня три убил. А так я всю схему в голове держал и паял, просто поглядывая на распиновку.ploop
19.03.2018 10:51На одну разводку я бы дня три убил
Это вы утрируете. Даже впервые попробовав это сделать в каком-нибудь спринте такая плата получится менее, чем за час. При том основная масса времени уйдёт на перфекционизм :)
Meklon
19.03.2018 11:02А потом внезапно помехи и наводки ловить на этот пучок проводов. А как делать дебаг такого я даже не представляю.
ploop
19.03.2018 00:21Хотя, вероятно, тут моей недостаток опыта сказывается.
Ваш недостаток опыта вполне дополняется достатком здравого смысла :)
Плату сделать действительно проще, быстрее, и с меньшим количеством ошибок. Просто под ЛУТ, дома.Meklon
19.03.2018 08:02+2Лут у меня получается, но не очень стабильно. Сейчас жду фабричные платы. Первый раз пробую. Хочу как белый человек нормальные использовать с шелкографией и маской.
ploop
19.03.2018 08:49ЛУТ для макета самое то. И то не всякого, если сложная двухслойная плата приходится и макеты заказывать на производстве.
А так да, впервые держать в руках заводскую плату собственной разводки нереально круто!Meklon
19.03.2018 10:01Лут я делал) только бумага из журнала медицинского оказалась неправильной. Тонер слишком тонким слоем перенёсся, хотя и отклеилась бумага сама без следов. В итоге вытравило сильно дорожки. Впрочем, для прототипа норм. Один чип я тупо сжёг перегрузкой) но это уже я проступил и ошибка была не в плате, а в коммутации гнезда наушников.
acin
19.03.2018 10:29Дорожки после травления хорошо бы залудить под паяльной кислотой и тщательно смыть (это если плата очень давно лежит и вся покрылась окислами, гидрокислами и прочей гадостью). Ну и попробовать сменить флюс и припой.
Sworfly
19.03.2018 11:06Зачем паяльной кислотой издеваться над жалом паяльника, дорожками, легкими и глазами? Пемолюкс на жесткую сторону губки, чуть воды и натереть плату этой кашей. Даже после сильного окисления медь становится как новой. Да и остатки тонера хорошо стираются.
Meklon
19.03.2018 11:47Я до травления и тонера поверхность платы обрабатывал алмазом на 2000 Grit. Вроде все снялось. Тут проблема в том, что после травления дорожка в мелкую сеточку. По факту даже участок обрыва был. Реально перетравлено сильно. Но на руках не было других материалов — работал с тем, что было. Флюс активный спирто-канифольный. Вроде смылся без остатков в изопропаноле. Дал полежать полчаса в нем, а потом хорошо потряс.
Если я наносил олово как положено пучком медных волосков, то нанесение было ровным. Но перетравленные дорожки не давали непрерывного гладкого рисунка. Поэтому нанес жалом паяльника с избытком и не очень красиво. С другой стороны, сопротивление низкое, все норм. А когда заводские придут — уже переделаю на них.
Meklon
19.03.2018 13:14
Вот такая грусть из-за плохого трансфера получилась. Причем там даже обрыв есть по питанию. В районе посадочной площадки конденсатора слева вверху. Что есть) Переделывать некогда было. Прототип, однако.
Mike_soft
19.03.2018 10:45ЛУТ требует навыка, «набивки руки» — именно в привязке к конкретному принтеру, утюгу и бумаге. Но при «набитой руке» крайне быстр. Фоторезист — более стабилен, хотя привычки тоже требует. Ну и чуть медленнее. ну а изготовление плат под заказ — медленно, но крайне качественно
ploop
19.03.2018 11:05Фоторезист требует ещё и некоторого оборудования — как минимум самого резиста, лампы, плёнки для шаблонов. А для ЛУТа утюг, принтер и журнал
с сиськами, то есть порог вхождения ниже, можно начать прям вот когда загорелось.Meklon
19.03.2018 11:07Я смотрел на фоторезист. Но там реально порог для единичных экземпляров уже такой, что проще на заводе заказать.
Karlson_rwa
20.03.2018 22:20Попробуйте ЛУТ на фольге.
Я когда активно сам платы делал, фольга очень выручила. Даже двухсторонние делал, правда, с особым подходом к проектированию таких изделий.
Mike_soft
19.03.2018 12:24абсолютно согласен. ЛУТ — это вотпрямщазз с нуля, фоторезист — следующий шаг, ибо надо заранее купить фоторезист (рублей 200), лампу (еще 200), пленку (еще 200). Зато когда это есть — оно по «старту» уже не отличается, но тут уже и качество выше, и повторяемость.
То же касается и паяльника — первый детекторный приемник можно и на скрутках, затем — дедовским стоваттником, потом хочется что-то нормально лежащего в руке и не перегреавющегося — ну а затем и станцию можно прикупить. То же касается и измерений. И отладки софта. Предела совершенству нет, но каждый останавливается на своем уровне.DASM
19.03.2018 13:23где Вы его за 200 видели? Давече покупал позитив 20 — 1000 р. Лампа — 2500 для ногтей, пленка может и 200, но лазерный принтер хорошо бы в смету добавить
Mike_soft
19.03.2018 13:37видел.
не рекламы радиsiriust.ru/oborudovanie/rashodnye-materialy/himiya-dlya-pechatnyh-plat/fotorezist-ordyl-350-305h1000mm-vodno-schelochnogo-proyavleniya-50mkm-ru
procontact74.ru/fotorezist-ordyl-alpha-340-shirina-305mm,-dlina-1mDASM
19.03.2018 13:54пленка тоже есть, но у меня с ней не заладилось, как-то грубо выходит, шаг 0.5 не протравливается. С позитивом лучше, там 0.5 не проблема. А черную лампу так и не нашел в продаже, пришлось купить косметическую лампу для полимеризации лака
Mike_soft
19.03.2018 14:16это уже нюансы. но главное то, что сейчас окромя древних методов а-ля стеклянный рейсфедер и цапон-лак (а то и резака из ножовочного полотна ) — вполне доступны и ЛУТ, и фоторезист (не из «белка куриного яйца и еще чего-то», как в рецептуре книги «радиолюбительские технологии», а вполне заводской ), причем фоторезисты еще можно выбирать.
плюс smd. Это ж по радиокружковым меркам — просто рай :-)DASM
19.03.2018 14:26о да, молодежь наверное о рейсфедерах не в курсе… особо было сложно степень разведения лака ацетоном подобрать чтобы нормально наносились дорожки. А еще вариант был в стержень шариковой ручки лак заливать, а из наконечника выдавить шарик. Эх время
Mike_soft
19.03.2018 14:33мы предпочитали «растягивать» стержень над спичкой и обрезать — поручившийся аналог рейсфедера ходил по фольге гораздо мягче, и не издавал скрипа…
l_o_d
19.03.2018 10:54Купите у китайцев бумагу для ЛУТ. Очень удобная вещь. Желтенькие такие листы:
www.ebay.com/itm/10PCS-A4-Sheets-Heat-Toner-Transfer-Paper-For-DIY-PCB-Electronic-Prototype-Mak-/400505239086?hash=item5d3ff8f62eMeklon
19.03.2018 10:57Я видел. Во всех комментариях стоят маты по поводу того, что китайцы не упаковывают в жесткий картон. В итоге все скомканное приходит.
l_o_d
19.03.2018 13:22Это да) Мне вообще в трубочку свернули пачку листов. Поставил под стопку книг чтоб выровнялись. Я потом режу лист на четыре и приклеиваю клейкими ценниками к обычной бумаге. Так экономичнее выходит и неровность не так сильно сказывается.
olartamonov
19.03.2018 08:41Чисто субъективно гораздо меньше вариантов ошибок при проектировании в чем-то вроде Eagle
Всё абсолютно правильно делаете. Время, потраченное на спагетти из проводов, ЛУТ и Sprint Layout — это время, потраченное впустую.akhkmed
19.03.2018 10:28Про Sprint Layout не пойму, чем он плох для любительских устройств низкой сложности?
l_o_d
19.03.2018 10:56Да ничем не плох на самом деле. Да и провода не плохи. Это же для себя, развлечение типо. Если говорить про потраченное впустую время, то и часы можно за 50 рублей купить в ларьке ближайшем)
olartamonov
19.03.2018 12:12Нет сквозного проектирования, соответственно, непригоден для сколь-нибудь сложного устройства.
Зачем тратить на него время, если тот же DipTrace бесплатен и осваивается за полчаса?Meklon
19.03.2018 12:22Eagle для двухслойных тоже бесплатен. Более чем достаточно.
ploop
19.03.2018 12:30Не бесплатен, у него ограничение на размеры. Вроде для большинства поделок и достаточные (100х100мм ЕМНИП, лень точно искать), но иногда можно упереться по одному габариту, т.е. например узенькую линеечку на 150 уже не сделаешь.
Meklon
19.03.2018 12:37Это согласен. На большинство хобби-проектов не влияет. Ну KiCad есть, в конце концов. Хотя я и к Eagle-то мучительно привыкал с нуля. До него цапонлаком рисовал кривулины на текстолите руками.
Mike_soft
19.03.2018 12:44запах цапонлака, хлорного железа и канифоли — прям картин «детство в радиокружке».
Meklon
19.03.2018 12:57Ага) Но оно было фантастически кривым. И еще все элементы выводные. Я сейчас прям не могу нарадоваться SMD. Сверлить не надо, места мало занимают.
Mike_soft
19.03.2018 13:10«и ведь всего-то — просто НЕ НАДО БЫЛО приделывать выводы к деталям»© :-0
l_o_d
19.03.2018 14:09Самое интересное ведь эти детали и раньше существовали. Помню в институте были древние советские гибридки с вполне себе современно выглядящими SMD конденсаторами. Почему их в обычных схемах не применяли непонятно… Видимо у нас эффект послезнания) Додуматься не приделывать ноги наверное было не так просто
dmiceman Автор
19.03.2018 09:47На самом деле, пайка пучка проводов на плате индикатора, вдумчиво и размеренно, заняла только около двух часов. Не то что бы это меня совсем не достало, но все же оказалось не так и страшно. В паре мест недопаял, в паре мест перепаял, но это легко удалось исправить. Где-то паяльником, а где-то кодом. Да, было бы здорово немного переделать, вывести линию RCLK на контроллер, но этим я вряд ли займусь :-)
А вот ЛУТ, с его множеством операций меня не привлекает. Плавали, знаем. Сначала развести, причем в один слой там не получится, придется пачку мостиков городить. Потом напечатать-прокатать утюгом. Где у меня валяется подходящая бумага, я даже не помню, и как ЛУТ отнесется к имеющемуся в наличии неродному тонеру — не знаю. Травить, мыть — вонюче и грязно. Сверлить. Не помню почему, но это операция почему-то вызывает особенное отвращение.
И при этом, в результате будет сложнее исправить неизбежные ошибки. Вон, пытался заодно реанимировать плату, красиво разведенную и распаянную семь лет назад под 0.3mm дорожки, TQFP и прочие smd. Думал когда-то красивый такой термометр соорудить. Оказалось — reset у AtMega8 забыл подтянуть. Поправить уже затруднительно.l_o_d
19.03.2018 10:59А вот ЛУТ, с его множеством операций меня не привлекает.
Это вы фоторезист не пробовали)
Травить, мыть — вонюче и грязно
Травите не хлорным железом, а перекисью и лимонной кислотой (ну еще соли щепотка) и будет все чисто.
Сверлить.
Переходить на поверхностный монтаж с минимумом дыр. В макете можно совсем без дырок обойтись.
YegorVin
18.03.2018 23:53А вы измеряли что именно жрет 6ма?
Сам микроконтроллер или может быть ЖК индикатор.
Если микроконтроллер то резать частоту. Зачем аж 1 МГц :)dmiceman Автор
19.03.2018 09:54> А вы измеряли что именно жрет 6ма?
На самом деле, нет. Методика получения этого результата хромает у меня на все ноги. Мерил я в одной точке, все целиком. И как бы даже с лишними деталями, имевшимися во время измерения в схеме.
Вот, будет чем через неделю заняться :-)
> Если микроконтроллер то резать частоту. Зачем аж 1 МГц :)
А тут уже есть варианты.
Вот хотелось бы всем участникам обсуждения спасибо сказать — здравых и интересных идей я увидел множество. Есть куда думать и что делать.
ploop
19.03.2018 00:31Как оказалось, 4 килобайта — это очень мало
А какой посоветуете контроллер под часы под ТЗ ниже?
Описание— 14 семисегментных индикаторов (светодиодных)
— 2 датчика температуры (DS18B20)
— Аналоговый датчик давления (выводить данные надо в мм.рт.ст с десятыми)
— Авторегулировка яркости по логарифмическому закону (датчик света + плавная регулировка)
— ИК пульт управления
— Режим обучения для пульта, чтобы можно было использовать пульт от любой ненужной техники
— Установка времени с пульта
— Цифровая коррекция хода (RTC не используются, только МК), с пульта
— Корректировка отображения давления (компенсация высоты) с пульта
— 10 режимов отображения информации (с секундами, без, дата, разные комбинации температуры/давления)
— Связь с ПК по UART (установка времени)dimaviolinist
19.03.2018 00:51Можно Atmega328 (1.7$) или STM32F103C8T6 (2.13$).
Проще, (и, уверен, дешевле) вместо 14 семисегментных индикаторов (светодиодных) использовать 0.96" I2C IIC Serial 128X64 за 2.91$.ploop
19.03.2018 01:00Ладно, я не зря процитировал автора — скорее ему на заметку.
Эти часы висят передо мной и работают 9й год, весь функционал как раз на ATMega48. И памяти ещё немного осталось :)
Светодиодные индикаторы выбраны из-за габаритов (6 шт под время 35мм высотой, два блока по 4 индикатора на 20мм) — их видно с любого места зала. Ну и читаемость отличная.
Авторегулировка позволяет не светить как ночник ночью, и нормально читаться при прямом солнечном свете. Индикаторы работают через те же 595е, т.к. никаких ног не хватит обслужить всё напрямую. Аналоговый датчик давления — за неимением лучшего.
По поводу точности: цифровая коррекция, при условии, что часы постоянно находятся при комнатной температуре, позволила их отстроить до нескольких секунд в год (около 15ти, ЕМНИП, дальше уже муторно), что более, чем достаточно.dimaviolinist
19.03.2018 01:12Вот. 595.
Плюс их, хоть и копеечная, но стоимость, плюс время на разработку и пайку…
работают 9й год
Сейчас всё очень сильно дешевле и удобнее.
Кстати, на больших светодиодных индикаторах у меня 595е неслабо даже грелись.ploop
19.03.2018 07:42Кстати, на больших светодиодных индикаторах у меня 595е неслабо даже грелись.
35-миллиметровые усиливал транзисторами. Под него как раз помещается 595й и 8 транзисторов :) 20-миллииетровые нормально тянут. Точнее, не просто «нормально», схема вся продумывалась и рассчитывалась по даташитам.
Сейчас всё очень сильно дешевле и удобнее.
И не так интересно :( Старею наверное…dimaviolinist
20.03.2018 22:19Меня учили, что «чем меньше элементов на плате, тем лучше» (если при этом задача правильно исполняется). Транзисторы на ULN2003 поменял бы.
И, кстати, интересно всё равно. Просто возможностей больше.ploop
21.03.2018 08:01ULN2003
Уж не помню, но по какой-то причине она меня не устроила. Может банально дороже выходила, может ещё что.
dmiceman Автор
19.03.2018 09:58Ну, поди, все-таки не на C прошивка? :-)
Нет, я знаю как и с моего кода примерно килобайт срезать оставаясь на C, но такого желания не испытываю. Переживания главного героя известного рассказа «Один байт» я повторять не хочу :-)ploop
19.03.2018 11:11Нет, не на Си, я тогда им ещё не владел на таком уровне. Но позже понял, что на Си это получилось бы ничуть не хуже.
Тут ещё дело в архитектуре — ассемблер AVR8 настолько прост и логичен, что после килобайта кода, на нём начинаешь разговаривать и посылаешь к чёрту все остальные средства разработки :) С каким-нибудь STM8 уже так не получится, а STM32 — это будет просто баловством, никак не связанным с реальностью.
legustarasov
19.03.2018 00:31На самом деле такие неудачи получаются, когда используешь микросхему широкого потребления для решения специфических задач.
Во-первых у серии ATmega есть контроллеры с буквой L — это как раз со сниженным потреблением питания (типа ATmega8L). Еще меньше потребляют STM8L… У некоторых микросхем STM32L есть внутренние часы реального времени, специализированная ножка Vbat с помощью которой они питаются и отдельный вход для часового кварца.
Во-вторых требуемый контроллеру ток пропорционален (кроме частоты работы, чего вы снижать не хотите из-за I2C) от напряжения питания. Снижайте напряжение питания до 1.8В.
В-третьих в данной ситуации постоянно загружать в SN54HC595 новые данные — расточительство. Надо грузить их туда раза 2 (на самом деле чуть чаще, чтобы обновление было без рывков) в секунду, а осцилляции напряжения на выходе из микросхемы, чтобы обновлялся экран с частотой 100 Гц с помощью отдельной микросхемы ключей, которые будут дергать ногами от генератора с чатотой 100 Гц… мультивибратора какого-нибудь.
В итоге микроконтроллер просыпается 2 раза в секунду, опрашивает часы, загружает информацию в буфер и засыпает.ploop
19.03.2018 00:33Еще меньше потребляют STM8L
… у которых есть серия с драйвером ЖК. Общее потребление уже в микроамперах идёт.Elmot
19.03.2018 02:57в серии stm32l до черта чипов с LCD контроллерами. Я нежно любил stm8(f правда, не l), но возьня с теперь имеет мало смысла.
ploop
19.03.2018 07:47У других производителей тоже есть.
Собственно, всё сводится у первому предложению выше: автор использовал "… микросхему широкого потребления для решения специфических задач", и он их решил отчасти, на сколько она позволяет.olartamonov
19.03.2018 08:40Да ничего он не решил.
У него в камне есть полдюжины режимов энергосбережения. Какой-нибудь Extended Standby Mode оставляет включённым внешний осциллятор, продолжает тактировать Timer/Counter2, имеет потребление 50 мкА на подходящем кристалле и выходит на полные обороты за 6 тактов.
Это, конечно, не 0,5-1,5 мкА чипов с нормальным RTC и низкопотребляющей периферией, но это в десятки раз лучше того, что получил автор.ploop
19.03.2018 08:53Решил в плане того, что устройство заработало. С потреблением конечно у него швах полный, можно было сократить намного, все варианты уже озвучили, но это всё равно не было бы решением задачи полностью (если она не звучит как «сделать кровь из носа на ATMega48»).
olartamonov
19.03.2018 09:34Я вот полистал даташит пятнадцать минут (а я в этом десятилетии, если мне память не изменяет, сделал один проект на AVR, да и тот был вспомогательной фигнёй на 8-ногой тиньке в одну страницу кода размером — это к вопросу о том, насколько хорошо я их знаю), и в принципе спокойно готов сделать на ATMega48 часы со средним потреблением не выше 10 мкА и без всякого внешнего обвеса.
1) вешаем внешний кварц 32,768 кГц на TOSC1/TOSC2
2) Timer/Counter2 включаем в асинхронный режим от этого кварца
3) чип заводим от встроенного RC на 8 МГц с делителем 8
4) уводим чип в Power-Save Mode, оставляя TC2 тикать асинхронно
5) каждые 1/128 с = 7,8125 мс просыпаемся по прерыванию от TC2, раскочегаривание внутреннего RC занимает 6 тактов, т.е. меньше микросекунды
6) перещёлкиваем полярность ЖК, добавляем 1/128 с в счётчик времени, засыпаем обратно
Даташит не раскрывает нам, сколько оно жрёт в PSM с часовым кварцем, но это не должно быть больше 2-3 мкА.
10 мкА среднего потребления — это почти три года работы на CR2032.BigBeaver
19.03.2018 09:49Вместе с потерями на сдвиговых регистрах и рассыпухе будет все равно под 0,5мА. По крайней мере, если оставить, как у автора.
olartamonov
19.03.2018 10:03Понятно, что 7805 придётся закопать, равно как и регистры на MC74VHC595 какой-нмбудь поменять.
Но в атмеге48 с 10 мкА среднего потребления в этой схеме совершенно ничего фантастического нет.BigBeaver
19.03.2018 10:07Не, с 7805 будет еще раз в 10-20 больше, но это так уж.
А вообще, я с вами полностью согласен, и для меня вообще было удивительно, что узким местом у автора какм-то образом оказался контроллер. Тем более, что они очень хорошие у Atmel, хоть и слабоваты по фаршу по нынешним меркам.olartamonov
19.03.2018 10:20А вообще, я с вами полностью согласен, и для меня вообще было удивительно, что узким местом у автора какм-то образом оказался контроллер
Для меня — нет, не удивительно. Нагромождение однотипных поверхностных руководств «для новичков» в интернете плюс привычка к тому, что думать не надо, надо на алиэкспрессе купить и готовую библиотечку скачать.
Причём последнее сейчас разными говорящими головами, которые попросту сами не умеют ничего более сложного, чем сунуть алиэкспрессу номер своей кредитки, воспитывается под лозунгами «стартап должен первым собрать MVP», «некогда тратить время на ненужные вещи» и т.п.
P.S. Параллельно этому треду наблюдаю, как в фейсбуке человеку в ответ на вопрос, как сделать в ардуине 10-секундный таймер, советуют в loop() воткнуть процедуру, которая на каждом витке будет смотреть аптайм и считать, не прошло ли десять секунд. Это при том, что даже в этом убожестве давно уже изобрели таймер с прерываниями, а для автора loop() вообще черти отдельную сковородку в аду греют.l_o_d
19.03.2018 11:03Тут кто то недавно автоматику лифта на ардуине делал) Скоро будут в производство пускать поделки сделанные на беспаечных макетках)
Mike_soft
19.03.2018 11:14залил провода, воткнутые в макетку, из пистолета-соплемёта (это еще один — судя по ютубу- любимый инструмент импортных DIYщиков), и «в продакшн»©
olartamonov
19.03.2018 12:14Так на GT были недавно чуваки, у которых китайский поставщик чип флэшки поменял на условно-совместимый — и всё встало, потому что скачанный из инета драйвер с новой флэшкой не работает, а как это отлаживать и править, они даже примерно не представляют.
У них там всё комьюнити за месяц (!) не смогло даже выяснить, что конкретно сломалось-то.l_o_d
19.03.2018 13:30Это все из за невероятно снизившегося порога вхождения. Сейчас любой может что то как то работающее сварганить посмотрев урок на ютубе и воткнув провода в ардуину. Это здорово повышает самооценку (и это очень даже хорошо). У многих повышает настолько, что они мнят себя гениальными конструкторами (что уже плохо) и начинают рожать «это». Раньше эти товарищи даже не сунулись бы в эту область или наняли бы профессионала.
olartamonov
19.03.2018 08:29У некоторых микросхем STM32L есть внутренние часы реального времени, специализированная ножка Vbat с помощью которой они питаются и отдельный вход для часового кварца.
RTC и часовой кварц есть у всех STM32L.
Ножки Vbat у STM32L нет, потому что она им не нужна.
Dark_Purple
19.03.2018 00:35Другая батарея, другой контроллер, лишние микросхемы выкинуть и всё будет ок.
CR2032 должно хватать на пару лет минимум.
dimaviolinist
19.03.2018 00:35Я делал (давно, правда) счётчик импульсов с некоторыми наворотами типа запоминания, установки и тоже на 3x7 segment индикаторе. Так импульсы ловил через прерывание. Всё работало идеально (правда, на PIC16F628A). Выполнял функции все и при этом спокойно считал до 10к Hz. (Код есть).
Сейчас как раз захотел попробовать на Atmega8 поуправлять пучком светодиодных лент в разных режимах, попробую и ваш код глянуть. Сразу удивляет отсутствиетакой структуры.const unsigned char seg[] = {
0b00000010, // 0
0b01001111, // 1
0b00010001, // 2
0b00000101, // 3
0b01001100, // 4
0b10000100, // 5
0b10000000, // 6
0b00001111, // 7
0b00000000, // 8
0b00000100, // 9
};dmiceman Автор
19.03.2018 10:19Все так. Код писался как удобнее, а не что бы выжать такты и байты. Места для оптимизации оставлено много.
NumLock
19.03.2018 03:54Штука в том, что все рекомендации встреченные мною на тему энергопотребления AVR-ок замечательно описываются фразой «спите глубже». Но контроллеру в часах нельзя спать! Ему денно и нощно, 100 раз в секунду необходимо обновлять экран.
Контроллер должен спать. Для обновления индикатора активируйте SQW/OUT на DS1307 и подайте его на ножку ОЕ 595-их. Для снижения потребляемой мощности от батарейки, можно также использовать солнечную панель, встроив её в корпус часов.
ittakir
19.03.2018 08:52Я бы так делал:
1. Микроконтроллер взял самый современный ATxxxPA.
2. Питание от 3 вольтовой литиевой батарейки напрямую.
3. Частота обновления LCD 50Гц или меньше.
4. ATmega почти все время в глубоком сне, запущен только Watchdog, который её и будит 50 раз в секунду. Потребление 4uA.
5. ATmega тактируется либо от внутреннего RC генератора, либо от внешнего клока, поданного напрямую от микросхемы часов.
6. Отключена вся остальная периферия.
7. Вывод цифр идет с помощью заранее расчитанных таблиц.
8. Никаких Arduino библиотек, пишем в нормальной среде с полным контролем кода на выходе (IAR) на С/С++.
mkc
19.03.2018 10:20А никто не подскажет где вообще описание на похожие жк дисплеи взять??? А то есть похожий, выбран из счетчика газа, только у него не 40 ног, а 8-мь. А как на него описание искать даже мыслей нет никаких(((
dmiceman Автор
19.03.2018 10:238 ног — это либо одна цифра, либо там есть свой контроллер.
Если это одна цифра, то соответствие сегментов ногам выясняется просто тестером и записывается на бумажке (как это делал я). А вот если там свой контроллер…
olartamonov
19.03.2018 10:25Это COG (Chip On Glass), у него внутри контроллер, с меньшей вероятностью — с I2C/SPI, с большей — просто сдвиговый регистр типа ML1001.
Смотреть у производителя данного экрана. Если он неизвестен — надо было смотреть, что там на ножках происходит, до того, как экран выдирать.
Alexashka
19.03.2018 10:36Сегментный ЖК-индикатор. Скорее всего 4bit-параллельный интерфейс. Смотрите по плате счетчика, где питание, а где данные.
Bobovor
19.03.2018 10:21- Снизить рабочее напряжение контроллера. 2.7V
- Снизить до минимума рабочее напряжение дисплея.
- Снизить временные периоды сигналов дисплея.
- Нафиг линейник и крону. 2032 и диод ваш друг.
borisxm
19.03.2018 11:04Все уже придумано. 20 мкА при питании от 3-х вольт: danyk.cz/avr_lcd_hod_en.html
moviq
19.03.2018 11:48Всякие DC/DC здесь, конечно, ни к чему. Мой вариант также на ATMega48 (хотел на Atmega8 сначала сделать) — собственно этот контроллер с работой от внутреннего генератора 1МГц (8МГц, деленное на 8), ЖК индикатор от мультиметра DT890. Управляется четырьмя регистрами 595. Сами часы на DS1302. Они и модуль с ЖК индикатором работают через аппаратный SPI. Он настроен на максимальную частоту. К контроллеру подключен часовой кварц для работы в асинхронном режиме. Настроено прерывание по совпадению. В прерывании в SPI выводятся 4 байта, которые записываются в регистры. Каждый раз в прерывании данные выводятся инвертированными по сравнению с значениями ранее. Прерывание происходит приблизительно 50 раз секунду. Все остальное время спим. Итого от 4 с небольшим вольт потребление около 160мкА. Точнее это то, что усредненно показывает мультиметр. Работает это от б/у мизинчиковых батареек от тонометра. Т.к. там они уже не тянут, хотя и напряжение на них 1.35В. А в таких часах вполне год могут отработать. Планирую заменить их на аккумуляторы с подзарядкой от солнечной батареи. Правда теряется некоторая мобильность в таком случае. А так же хочу добавить к часам датчик температуры DS1820 и выбросить его за окно (программно это уже реализовано), а также подсветку на светодиодах от светодиодной ленты.
Часыl_o_d
19.03.2018 13:33Класс)
Планирую заменить их на аккумуляторы с подзарядкой от солнечной батареи.
Поставьте лучше вместо аккумулятора ионистор. Проблем с деградацией не будет (хотя ионистор тоже не вечен). Энергии как раз должно хватить.moviq
19.03.2018 15:10Надо будет подрасчитать — если его ставить и ставить подсветку, которая дает +300...400мка дополнительного потребления, хватит ли на темное время. Часто в комнате свет почти не включается и зимой темное время еще больше получится.
OLEGator_by
19.03.2018 11:48Любой проект нужно начинать с исходного задания и выбора материалов.
Если исходное задание уже выбрано – часы, то далее нужно подойти к выбору материалов.
1 Конечно есть специализированные контроллеры в которых уже всё реализовано (сами часы включительно), однако это не интересно и не принесёт вам пользы – всё продумано за вас.
Можно взять контроллер распространённый – но это чревато не оптимальностью схемы и сложностью схемы. Я бы конечно взял какой STM с встроенным RTC. По итогу получается компактнее и надёжнее. Но даже выбор ARDUINO не проблема – да, микросхема должна почти всё время спасть.
2 Писать конечно нужно не на С а на ассемблере, так вы контролируете процесс поле полно.
3 Батарея не нужна на 9в, возьмите литиевую. При меньшем размере вы получите большую ёмкость. И конечно никаких 7805.
4 контроллер LCD – использовать в схеме прорисовки(обновления) контроллер — непозволительная роскошь. Для таких схем используются готовые контроллеры или как в вашем случае можно взять например К176ИЕ4(вместо 595 как я понял из описания вашей схемы). Там есть вход 6, на который подаётся сигнал модуляции для экрана. Частоту на эту ногу подавать с ds1307. В принципе должны быть аналоги данной микросхемы(если для вас советское не кошерно), нужно просто поискать.
В таком случае контроллер будет спасть у вас 99,9% времени, а просыпаться только в момент изменения секунд. В этом случае ток потребления будет минимальный.
SadAngel
19.03.2018 11:48В PSoC 4 есть контроллер LCD дисплея:
http://www.cypress.com/documentation/component-datasheets/psoc-4-segment-lcd-seglcd
gerasimenkoao
19.03.2018 11:487805 — в топку, как и любой другой стабилизатор — они в любом случае единицы миллиампер потребляют.
olartamonov практически прав, но я не люблю режимы сна.
лучше взять атмег-у с индексом V, есть одна хитрость с питанием — как ни парадоксально, на одной и той-же частоте при снижении напряжения питания с 5 до 3.3, ток потребления падает на порядок. У меня на двух солевых батарейках АА безо всяких стабилизаторов напряжения месяц молотит без сна(1 мегагерц).
olartamonov
19.03.2018 12:16но я не люблю режимы сна
месяц молотит без сна(1 мегагерц)
Вот мы и дожили до счастливого момента, когда месяц работы электронных часов на батарейке — уже достижение, потому что автор «не любит режимы сна».
Автор, не любящий режимы сна! У меня водосчётчик с ЖК-экраном и радио на одной батарейке молотит 8 лет (и часы в нём тоже есть).Mike_soft
19.03.2018 12:31а можно схему? а то поставить-то счетчики «с контактом» — поставил, а до съема данных руки не доходят… :-(
olartamonov
19.03.2018 12:44Берёте провод от контакта, протягиваете к ножке микроконтроллера.
С точки зрения схемотехники этого достаточно, далее начинается софт.Mike_soft
19.03.2018 12:50радиоканал хочется. BLE, например.
ну нет, так нет. дойдут руки — наваяю. главное, чтоб не в конце межповерочного интервала :-)Meklon
19.03.2018 12:58А я все хочу во время глобального ремонта туда два Cat5e кабеля кинуть. И PoE и данные. Или один кабель, а в ванной Raspberry Pi, который уже ведет логи кидает куда надо.
ploop
19.03.2018 14:50Во, аналогично. При чём у меня уже мысль в каждую розетку по кабелю. Если не надо — закроется, а так и управление чем угодно можно замутить, да и просто розетку под LAN поставить.
Meklon
19.03.2018 15:07Сложно найти деньги на одномоментный ремонт всего. Приходится планировать кучу промежуточных стадий. Поэтому иногда сложновато в каждую розетку протащить. Я уже думаю о коммутационном шкафе в коридор.
ploop
19.03.2018 15:23Мне если делать, то всё. Квартира требует капитального ремонта — от пола до потолка.
olartamonov
20.03.2018 12:34Радиоканал тут LoRa, и разработка в общем и целом коммерческая.
Mike_soft
20.03.2018 13:28+1ну и нужно было начинать с того, что «разработка коммерческая» :-)
но и за то спасибо, хот пинок получил — может, и правда на выходных займусь…olartamonov
20.03.2018 14:53С точки зрения энергопотребления контроллеру всё равно, платили за это деньги или нет. С точки зрения выкладывания исходников на хабре — нет.
Yurich
21.03.2018 11:24А не нужна Вам схема (потому, мнээээ..., что она не поможет). А не поможет она потому, что Вы никогда не сможете гарантировать, что все импульсы прочитаны (села батарейка, например, или в розетке электричество кончилось и так далее).
Совсем панковский вариант, который я встречал — OCR того, что у счетчика на морде. Это, кстати, 99% гарантия правильности сбора данных в колхозно-домашних условиях, 1% заложим на то, что софт глюканет и в первом разряде вместо 0 распознает 9, что приведет к довольно большому счету на воду (решается логикой софта, конечно же).
А Олег, насколько я знаю, не пользуется готовыми счетчиками, которые генерят импульсы, он строит счетчики с нуля.olartamonov
21.03.2018 15:31А Олег, насколько я знаю, не пользуется готовыми счетчиками, которые генерят импульсы, он строит счетчики с нуля.
Да могу и готовыми пользоваться.
А за батарейкой следить надо, конечно.
l_o_d
19.03.2018 13:35Однако ведь есть уже наручные часы которые каждый день заряжать надо) Так что месяц для настольных это прям лонг лайф)
BigBeaver
19.03.2018 14:11они в любом случае единицы миллиампер потребляют.
Нет. Есть полно Low Quiescent Current LDO с собственным током на уровне 1-2µA. В том числе доступных.Bismuth208
20.03.2018 11:54Именно! Я вот ставлю MCP1700, где это возможно.
olartamonov
20.03.2018 12:31Да их сейчас как грязи, с собственными токами в единицы-десятки микроампер.
Даже у 1117 есть низкопотребляющая версия — TLV1117LV (и у неё же заодно нет требований по минимальной нагрузке).Bismuth208
20.03.2018 14:02Да, вот только ток утечки без нагрузки в даташите указан от 50 до 100 мкА!
Но с другой стороны, максимальный ток на нагрузку около ампера! В то время как MCP1700 2мкА утеки без нагрузки и не больше 250 мА на нагрузку.olartamonov
20.03.2018 14:54Это замена LM1117, у которого 5 мА потребление и ещё 5 мА минимальная нагрузка.
dmsav
19.03.2018 13:16Ну. я не стал бы называть это неудачей, скорее это опыт. И очень полезный.
Идея интересная, я бы все же поставил DC-DC преобразователь и две обычные батарейки или аккумуляторы типа АА.
И еще один момент, ЖКИ без подсветки? Если да, то можно поставить вместо него сегментный LED индикатор. Есть модели как раз под часы.
И их бы еще в корпус и классно было бы)
А еще, бумажные стойки это оригинальное решение)
madf
19.03.2018 14:28- Нельзя использовать обычный линейный стаб, КПД у него никакущее. Обычно узают DC-DC, причем есть специализированные, с сверх малым потреблением и режимом спячки.
- Почитайте документацию на на МК, там есть разные уровни засыпания, возможно схему надо было собрать так, чтобы можно было использовать(скажем) один таймер и ещё почитать по принцип управления ЖКИ (там же аля емкости, не всегда нужно аж на 180 градусов менять полярность): http://www.russianelectronics.ru/leader-r/review/2195/doc/57771/
ZaitsXL
19.03.2018 14:35Я бы посоветовал заменить скучный ЖК индикатор на что то более гиковское, газоразрядные лампы там, или светодиоды какие нить, и работать от сети т.к. даже в нынешнем виде часы явно не наручные. В противном случае не совсем ясно ради чего это все
GarryC
19.03.2018 18:24Лет 20 назад я делал устройство с батарейным питанием для анализа АОН сигналов, применил дешевый калькулятор (чип+индикатор) и управлял воспроизведением на нем из Atmel контроллера путем имитации нажатий на клавиши.
izobr
19.03.2018 19:29А кто подскажет RTC, которая просто имеет двоичный счётчик без всяких там календарей в бинарно-десятичном формате как у DS1307?
Наверное это лет 20 назад было оправданно, когда подобная логика была в железе зашита. Сейчас контроллер любую конвертацию сделает сам. И наоборот, надо какие-то странные вычисления проводить, если, например, две таймзоны хочется отобразить. Почему все эти микросхемы с годами, месяцами, днями, минутами и секундами всё-ещё так популярны, а тупой счётчик миллисекунд не найти?ploop
19.03.2018 22:40Конвертацию чего он сделает, если обесточен? В том и смысл RTC — работать независимо ни от чего.
Если нужен тупой счётчик — ставьте тупой счётчик. Их, кстати, и в МК можно использовать независимо от ядра (когда то спит), минимизируя потребление.izobr
19.03.2018 23:20Конвертацию сделает, когда проснётся, чтобы прочитать время из RTC, работающей независимо и питающейся от CR2032 и обновит индикатор. Из DS1307 он прочитает год, месяц, день, час (в 12 или 24 часовом формате, как настроено), минуты и секунды. При этом это всё по одной цифре в двоично-десятичном формате. И большинство RTC имеют такой API. А я хочу прочитать тупо 64 бит счётчика миллисекунд и сам сконвертить в дату.
avf1906
20.03.2018 15:151. сама 7805 жрет минимум 5-6мА. вывод — заменить на менее жручее.
2. емкость кроны 200мАч. Заменить на более емкое.
Простой вариант — 7805 убрать, запитать от 3 последовательных алкалиновых элемента АА емкость 2000мАч, время работы — два-три месяца.
Хороший вариант — взять stm32L053, L152 и т.п. со встроенными часами и контроллером LCD и запитать напрямую от CR2032 потребление будет не больше 30мкА, проработает минимум год. Потренироваться взять такую штуку ru.aliexpress.com/item/Free-Shipping-1pc-ST-STM32L-Discovery-STM32L152-Cortex-M3-development-board/1238095354.html
dan939
20.03.2018 23:07решение есть. 176ИЕ18, 176ИЕ13, 176ИД3. от «Кроны» будет работать несколько месяцев.)))
а вообще у автора в корне неверный подход к проектированию устройств с малым потреблением. жечь половину энергии батареи на 7805-жесть конечно.Mike_soft
21.03.2018 07:48автор ничего не проектировал. он нашел одно, другое, третье — слепил в кучу (просто потому, что это «уже было») и удивляется, что работа полученного устройства не соотвествует некоторым ожиданиям…
gbg
Следует заметить, что крона — одна из наименее емких батарей и что при таком включении, 7805 рассеет примерно половину батарейкиной энергии в атмосферу.
Далее, стоит рассмотреть применение специализированных RTC в отдельном чипе, которые работают годами от одной CR2032. Тогда основной контроллер может дрыхнуть сколько угодно, лишь изредка просыпаясь для смены картинки. Ну и взять менее жирный и древний контроллер, например, STM8.
l_o_d
RTC у автора как раз есть, проблема в том что контроллер не может спать из-за необходимости постоянно менять полярность напряжения на сегментах ЖК индикатора.
DmitriyDev
Это относительно.
Для человека, менять полярность раз в секунду — это достаточно быстро, а для микроконтроллкра милионы тактов в холостую.
safari2012
По фотке не понятно, были ли там секунды вообще…
safari2012
Хотя, в тексте про секунды есть, что-то я затупил. В любом случае, можно просыпаться раз в секунду по прерыванию от RTC?
moviq
Раз в секунду от RTC маловато для ЖК индикатора. Надо хотя бы 50 раз в секунду. А читать раз в секунду из RTC в прицепе можно
dmiceman Автор
> 7805 рассеет примерно половину батарейкиной энергии в атмосферу.
Конечно. Но если бы вся схема потребляла микроамперы, это было бы даже и не важно.
> RTC в отдельном чипе, которые работают годами от одной CR2032
Как раз у меня стоит очень специализированная ds1307 :-)
> Тогда основной контроллер может дрыхнуть сколько угодно, лишь изредка просыпаясь для смены картинки
А вот это нельзя по условиям задачи. ЖК-индикатор надо обновлять сто раз в секунду всегда.
> STM8
Вот это-то и интересно, как он себя чувствует в режиме постоянной работы?
olartamonov
Собственное потребление 7805/78L05 — 3-5 мА, кроме того, её параметры не гарантируются при нагрузке менее 1 мА. В микропотребляющих схемах применяют LDO совершенно другого класса.
ProstoUser
В даташите написано, что STM8L просыпается (выходит из состояния HALT с потреблением порядка 1 мкА) за 5 микросекунд.
Этого достаточно?
HogsOfWar
По поводу STM8 можете в сторону stm8l051 посмотреть, там есть режим работы Low-power run, где МК работает на частоте 32КГц но ест всего 5 микроАмпер (не считая периферии), к тому же в этом МК и часы встроенные есть, и цена копеечная.
Если 100 раз в секунду ножкой подрыгать то такой режим хорошо подойдет
Alexashka
А у STM8L152 есть встроенный контроллер LCD, даже ножками дрыгать не надо, он сам умеет.
Mike_soft
а часы вообще купить можно :-)
не, я не против DIY, но просто нужно понять, что же хочет автор: достичь микропотребления у атмеги, или сделать часы с ЖКИ собственными руками, или ему просто «нужны часы»?
каждая из этих проблем решается своим способом.