Зависают часы на DS1307 и индикаторе 4-чразрядном на TM1650 плюс Arduino UNO.

sadman41
Offline
Зарегистрирован: 19.10.2016

Может уже к snprintf_P перейдете?

Dimych70
Offline
Зарегистрирован: 03.02.2022

Чего-то ни одного нормального сайта не нахожу, где бы она была описана. Только отсылки на нее.

Но по тому, что я нашел, https://simple-devices.ru/attachments/article/12/AVR_11-2010.pdf например здесь, не пойму как в ней слить целые числа в строку.

sadman41
Offline
Зарегистрирован: 19.10.2016

Ищите printf. Отличие производной snprintf_P только в том, что она учитывает длину выделенного буфера и формат-строка расположена в PROGMEM.

http://arduino.ru/forum/programmirovanie/progmem-tricks#comment-439233

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Добавьте к этому скетчу описания переменных и setup c пустым loop'ом.

Убедитесь что не работает и выложите ПОЛНЫЙ (для особо непонятливых: П О Л Н Ы Й) скетч и напишите, что при это реально выводится.

Dimych70
Offline
Зарегистрирован: 03.02.2022

Вот скетч. Он из 3 файлов.

Вот основной файл:

#include "set.h"

void setup() {
  Serial.begin(115200);
  pinMode(OUTR, OUTPUT);
  digitalWrite(OUTR, HIGH);
  Wire.setClock(400000);
  Serial.begin(115200);
  watch.begin();
  //watch.settime(tm[0],tm[1],tm[2],tm[3],tm[4],tm[5]);
  d.init();
  d.displayOff();
  d.setBrightness(TM1650_MIN_BRIGHT);
  d.setBrightnessGradually(TM1650_MIN_BRIGHT); 
  d.displayOn();
  VAR_ON_MIN = eeprom_read_word(0);
  VAR_OFF_MIN = eeprom_read_word(2);
  VAR_ON_HOUR = eeprom_read_word(4);
  VAR_OFF_HOUR = eeprom_read_word(6);
}

void loop() {
  char* tm;
  if (Serial.available() > 0) {                                            // Если буфер серийного порта содержит несчитанные данные
    byte str = Serial.readString().toInt();                                      // Считываем строку
    if (str >=0 && str < 14) {display_mode = str;}
    if (str == 14) {
      watch.gettime();
      pressUP(watch.minutes, watch.Hours, watch.day, watch.month, watch.year);
    }
    if (str == 15) {
      watch.gettime();
      pressDOWN(watch.minutes, watch.Hours, watch.day, watch.month, watch.year);
    }
  }

  if (millis() - timer1 >= 1000){
    Serial.println(display_mode);
    timer1 = millis();
    Serial.println(watch.gettime("H:i:s"));
  // Вывод на дисплей
  switch (display_mode) {
      case 0:
        d.displayString(watch.gettime("Hi"));
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 1:
        d.displayString(watch.gettime("dm"));
        d.setDot(1, true);
        break;
      case 2:
        d.displayString(watch.gettime("Y"));
        d.setDot(1, false);
        break;
      case 3:
        char out_on[5] = "1234";
        char out_on0[2] = "";
        char out_on1[2] = "";
        char out_on2[2] = "";
        char out_on3[2] = "";
        itoa(VAR_ON_HOUR/10, out_on0, DEC);
        itoa(VAR_ON_HOUR%10, out_on1, DEC);
        itoa(VAR_ON_MIN/10, out_on2, DEC);
        itoa(VAR_ON_MIN%10, out_on3, DEC);
        out_on[0] = out_on0;
        out_on[1] = out_on1;
        out_on[2] = out_on2;
        out_on[3] = out_on3;
        d.displayString(out_on);
        Serial.println(out_on);
        d.setDot(1, true);
        break;
      case 4:
        //out_off[0] = VAR_OFF_HOUR/10;
        //out_off[1] = VAR_OFF_HOUR%10;
        //out_off[2] = VAR_OFF_MIN/10;
        //out_off[3] = VAR_OFF_MIN%10;
        //d.displayString(out_off);
        //d.setDot(1, true);
        break;
      case 5:
        tm = watch.gettime("Hi");
        if (dot_state) d.displayString(watch.gettime("Hi"));
        else {
          tm[2] = ' ';
          tm[3] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 6:
        tm = watch.gettime("Hi");
        if (dot_state) d.displayString(watch.gettime("Hi"));
        else {
          tm[0] = ' ';
          tm[1] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 7:
        tm = watch.gettime("dm");
        if (dot_state) d.displayString(watch.gettime("dm"));
        else {
          tm[0] = ' ';
          tm[1] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 8:
        tm = watch.gettime("dm");
        if (dot_state) d.displayString(watch.gettime("dm"));
        else {
          tm[2] = ' ';
          tm[3] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 9:
        tm = watch.gettime("Y");
        if (dot_state) d.displayString(watch.gettime("Y"));
        else {
          tm[2] = ' ';
          tm[3] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, false);         
        break;
     }
  }
}

Вот set.h:

#include <Wire.h>
#include <TM1650.h>
#include <iarduino_RTC.h>
#include <avr/eeprom.h>


//#define OUTR PB1 //Выход на реле Attiny
#define OUTR 7 //Выход на реле UNO

iarduino_RTC watch(RTC_DS1307);
TM1650 d;
//TM16xxButtons buttons(&d);       // TM16xx button
//TickerScheduler ts(1);

byte display_mode = 0;//Режимы вывода на дисплей
/*0-показ времени; 
1-день-месяц; 
2-год; 
3-включение утром; 
4-выключение вечером; 
5-установка минут в часах; 
6-установка часов в часах; 
7-установка числа в часах; 
8-установка месяца в часах; 
9-установка года в часах; 
10-установка часов включения утром; 
11-установка минут включения утром; 
12-установка часов выключения вечером.
13-установка минут выключения вечером.*/
//int chour, cmin;
char* out_on, out_off;
bool dot_state = false;
int8_t  VAR_ON_MIN     = 0;     // Задаем минуты включения света утром
int8_t  VAR_OFF_MIN     = 0;      // Задаем минуты выключения света вечером
int8_t  VAR_ON_HOUR    = 7;      // Задаем часы включения света утром
int8_t  VAR_OFF_HOUR    = 22;     // Задаем часы выключения света вечером

unsigned long timer1 = 0;

И вот файлик с дополнительными функциями. Пока в формате ino. Потом переделаю его в .h как советовали выше:

void pressUP(int cmin, int chour, int cday, int cmon, int cyear) {
  switch (display_mode) {
    case 5: watch.settime(-1, (cmin == 59?cmin = 0:cmin++));break;
    case 6: watch.settime(-1, -1, (chour == 23?chour = 0:chour++));break;
    case 8: watch.settime(-1, -1, -1, -1, (cmon == 12?cmon = 1:cmon++));break;
    case 9: watch.settime(-1, -1, -1, -1, -1, (cyear == 99?cyear = 99:cyear++));break;
    case 7: int dinmon = getdinmon(cmon, cyear);
            watch.settime(-1, -1, -1, (cday == dinmon?cday = 1:cday++));
    break;
  }
}

void pressDOWN(int cmin, int chour, int cday, int cmon, int cyear) {
  switch (display_mode) {
    case 5: watch.settime(-1, (cmin == 0?cmin = 59:cmin--));break;
    case 6: watch.settime(-1, -1, (chour == 0?chour = 23:chour--));break;
    case 8: watch.settime(-1, -1, -1, -1, (cmon == 1?cmon = 12:cmon--));break;
    case 9: watch.settime(-1, -1, -1, -1, -1, (cyear == 22?cyear = 22:cyear--));break;
    case 7: int dinmon = getdinmon(cmon, cyear);
            watch.settime(-1, -1, -1, (cday == 1?cday = dinmon:cday--));break;
  }
}

int getdinmon(int cmon, int cyear) {
  switch (cmon) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12: return 31;
    break;
    case 4:
    case 6:
    case 9:
    case 11: return 30;
    break;
    default: if (cyear % 4 == 0) return 29;
             else return 28;
    break;
  }
}

Пока отработку кнопок не сделал, делаю их нажатие через порт.

Вывод на экран имеет несколько режимов. В set.h они описаны. 2 режима (3 и 4) выводят настройки 2 будильников. По первому свет утром включается, по второму вечером выключается. Днем свет горит или нет - зависит от освещенности. Пока это еще не описывал в скетче.

Так вот вывод времени, даты, года в информацитонном режиме и в режиме установки значений уже сделал и там все работает. А вот вывод значений будильников на экран никак не получается. Со вчерашнего дня пытаюсь въехать в эти printf() и snprintf_P() никак не пойму как в этих вункциях собрать из времени 7 часов 0 минут вывод на экран строки '0700'. Для начала.

Итак вопрос в основном файле в режимах 3 и 4. Ну для начала 3. Остальные аналогично будут.

Dimych70
Offline
Зарегистрирован: 03.02.2022

Кажется я понял как sprintf() работает:

int time = 0;
int var = 55;
char buff[50];
void setup() {
    Serial.begin(115200);
}

void loop() {
    sprintf(buff, "the value is %d seconds %d", time++, var);
    Serial.println(buff);
}

Выводится будет "the value is <тут увеличенная на 1 time> seconds 55". Собственно сам примет с просторов инета, я только var добавил, что бы понять, что можно туда несколько переменных вставлять. Тогда возникает вопрос. Никак не найду где взять правила написания формата. инет вообще еле двигается, через google вааще ничего открываться не хочет. Можно ли там в формате задать, чтобы вместо 7 писалось 07 и вместо 0 соответственно 00.

Dimych70
Offline
Зарегистрирован: 03.02.2022

Все. Научился/разобрался. Возможно и не полностью, но для моего случая понял как делать.

      case 3:
        char out_on[5];
        sprintf(out_on, "%02d%02d", VAR_ON_HOUR, VAR_ON_MIN);
        d.displayString(out_on);
        Serial.println(out_on);
        d.setDot(1, true);
        break;

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

По запросу "спецификаторы printf" вываливает любой поисковик 100500 вариантов.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Dimych70 пишет:

Вот скетч. Он из 3 файлов.

У Вас был короткий скетч в #50. И Вы говорили, что он не работает. Вот Вы к нем присобачьте десяток строк чтобы он стал полным. Зачем нам три файла?

Dimych70
Offline
Зарегистрирован: 03.02.2022

Это был кусок скетча. Сейчас там получилось #57.

Описание переменных в set.h. Ну в loop там только switch. Это вариант 3.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Я бы вот это:

byte display_mode = 0;//Режимы вывода на дисплей
/*0-показ времени; 
1-день-месяц; 
2-год; 
3-включение утром; 
4-выключение вечером; 
5-установка минут в часах; 
6-установка часов в часах; 
7-установка числа в часах; 
8-установка месяца в часах; 
9-установка года в часах; 
10-установка часов включения утром; 
11-установка минут включения утром; 
12-установка часов выключения вечером.
13-установка минут выключения вечером.*/

заменил бы на такое:

enum display_mode : uint8_t {
  TIME,                       // показ времени
  DAY_MONTH,                  // день-месяц
  YAER,                       // год
  ...
  SET_MINUTES_OFF_EVENING     // установка минут выключения вечером
}

Тогда в case все становится человеко-понятным (чтобы к той "простынке" постоянно не листать):

case ON_MORNING:
  char out_on[5];
  sprintf(out_on, "%02d%02d", VAR_ON_HOUR, VAR_ON_MIN);
  d.displayString(out_on);
  Serial.println(out_on);
  d.setDot(1, true);
  break;

ЗЫ: ВЕРХНИЙ регистр не обязателен, это  у меня привычка такая ))

Dimych70
Offline
Зарегистрирован: 03.02.2022

Да я вчера про это тоже читал. Пока руки не дошли заменить. Сейчас все напишу, потом причесывать буду. А то как-то пока странно работает. То отрабатывает нажатие, а то нет. При чем ошибок никаких нет.

А вот еще я читал, что этот sprintf очень тяжелый для памяти. А у меня все это дело на Attiny работать будет. Может получиться, что не влезет?

Все. Индикацию написал. Теперь буду кнопки паять и обрабатывать и срабатывание реле. Ну срабатывание реле это уж мелочи.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Attiny какая? 
Да и все равно - сначала нужно все сделать, настроить - потом смотреть куда влезает.

Если штучно для себя - то вообще морочиться не нужно, я считаю. Выгоды никакой.

Dimych70
Offline
Зарегистрирован: 03.02.2022

Есть 25, 45 и 85. Но изначально планировал 25. Но у них контакты одинаковые, так что в какую влезет.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Dimych70 пишет:
А вот еще я читал, что этот sprintf очень тяжелый для памяти. А у меня все это дело на Attiny работать будет.

Теперь читай за itoa()

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Dimych70 пишет:
Есть 25, 45 и 85. Но изначально планировал 25. Но у них контакты одинаковые, так что в какую влезет.

Ну про 25-ую с sprintf можно забыть, сам sprintf - это чуть больше 2К.

По этой же причине и 45-ая (с sprintf, wire, RTC и DS1307) - не пройдет.

Поэтому 85-ая - как вариант. 

 

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

DetSimen пишет:
Dimych70 пишет:
А вот еще я читал, что этот sprintf очень тяжелый для памяти. А у меня все это дело на Attiny работать будет.
Теперь читай за itoa()

Полностью поддерживаю, даже предложил бы my_itoa(), исходники же itoa() - есть. Переписать под себя - не проблема.

char * my_itoa(int8_t val, char* buf, uint8_t dig)  // dig  кол-во цифр с выводимыми нулями слева. dig=0 - без нулей слева.

val - это byte, а не int16_t, signed, а может и unsigned - зависит от задачи,  без radix, и с количеством выводимых слева '0'.

И все это около сотни байт памяти программ.

UPD: не около сотни, проверил - получилось - 56 байт

Dimych70
Offline
Зарегистрирован: 03.02.2022

Народ, еще вопросик задам. Сейчас все закончил, причесываю.

Вот такой следующий код вызывает периодические зависания. Выявил это путем закомментирования этого куска и раскомментирования. Это собственно обработка нажатия кнопок. Нашел только одну библиотеку, где отрабатываются кнопки, но она какая-то навороченая и для 1650 там примеров нет. Может кто подскажет в чем я накосячил?

  //Отлавливаем кнопки
 Wire.requestFrom(0x24, 1); //делаем запрос 1 байта из
  //микросхемы с адресом 0x24. //Адресные A0,A1,A2 на землю.
  btn_num = Wire.read();
//Этот кусок я нашел в инете. Далее путем экспериментов нашел код каждой кновки.

bool ss = false, us = false, ds = false, sp = false, up = false, dp = false;
  if (btn_num == 68 && !ss) {b_timer = millis();ss = true;}
  if (btn_num == 4 && ss) {b_hold = millis() - b_timer;ss = false;sp = true;}
  if (btn_num == 84 && !us) {b_timer = millis();us = true;}
  if (btn_num == 20 && us) {b_hold = millis() - b_timer;us = false;up = true;}
  if (btn_num == 76 && !ds) {b_timer = millis();ds = true;}
  if (btn_num == 12 && ds) {b_hold = millis() - b_timer;ds = false;dp = true;}
  if (b_hold <= 500 && btn_num == 4 && sp) {
    if (display_mode < 5) display_mode == 4?display_mode = 0:display_mode++;
    else {
      switch (display_mode){
        case 5: display_mode = 6; break;
        case 6: display_mode = 5; break;
        case 7: display_mode = 8; break;
        case 8: display_mode = 7; break;
        case 10: display_mode = 11; break;
        case 11: display_mode = 10; break;
        case 12: display_mode = 13; break;
        case 13: display_mode = 12; break;
      }
    }
    sp = false;
  }
  else if (b_hold > 500 && btn_num == 4 && sp) {
    switch (display_mode){
      case 0: display_mode = 5; break;
      case 5:
      case 6: display_mode = 0; break;
      case 1: display_mode = 7; break;
      case 7: 
      case 8: display_mode = 1; break;
      case 2: display_mode = 9; break;
      case 9: display_mode = 2; break;
      case 3: display_mode = 10; break;
      case 10:
      case 11: display_mode = 3; break;
      case 4: display_mode = 12; break;
      case 12: 
      case 13: display_mode = 4; break;
    }
    sp = false;
  }
  watch.gettime();
  if (btn_num == 20 && up) {
    //watch.gettime();
    pressUP(watch.minutes, watch.Hours, watch.day, watch.month, watch.year);
    up = false;
  }
  if (btn_num == 12 && dp) {
    //watch.gettime();
    pressDOWN(watch.minutes, watch.Hours, watch.day, watch.month, watch.year);
    dp = false;
  }

Вроде все просто, но почему-то зависает устройство. Просто останавливает. Перестает менять изображение на экране и порт перестает выдавать данные.

Да, одна кнопка перебирает режимы, а две другие делают плюс-минус времени, будильникам при установке.

Зависает не сразу, минут через 20-30, может через час.

b707
Offline
Зарегистрирован: 26.05.2017

Dimych70, опять вы выкладываете какие-то куски кода без начала и конца? Кто в них будет копаться?

Если хотите, чтобы кто-то посмотрел ваш код - оформите проблемный кусок в виде отдельного скетча с сетап и луп, с декларацией всех переменных... Чтобы отвечающие могли запустить его у себя и протестировать проблему.

Dimych70
Offline
Зарегистрирован: 03.02.2022

Ну вырезать и оформлять в отдельный код может не совсем правильно. Вот весь код:

#include "set.h"

void setup() {
  Serial.begin(115200);
  pinMode(OUTR, OUTPUT);
  pinMode(OUTL, OUTPUT);
  pinMode(OSV, INPUT);
  digitalWrite(OUTR, LOW);
  digitalWrite(OUTL, HIGH);
  Wire.setClock(400000);
  Serial.begin(115200);
  watch.begin();
  //watch.settime(tm[0],tm[1],tm[2],tm[3],tm[4],tm[5]);
  d.init();
  d.displayOff();
  d.setBrightness(TM1650_MIN_BRIGHT);
  d.setBrightnessGradually(TM1650_MIN_BRIGHT); 
  d.displayOn();
}

void loop() {
  const int ur_osv = 200;
  char* tm;
  byte btn_num = 0;
  /*if (Serial.available() > 0) {                                            // Если буфер серийного порта содержит несчитанные данные
    byte str = Serial.readString().toInt();                                      // Считываем строку
    if (str >=0 && str < 14) {display_mode = str;}
    if (str == 14) {
      watch.gettime();
      pressUP(watch.minutes, watch.Hours, watch.day, watch.month, watch.year);
    }
    if (str == 15) {
      watch.gettime();
      pressDOWN(watch.minutes, watch.Hours, watch.day, watch.month, watch.year);
    }
  }*/
char * my_itoa(int8_t val, char* buf, uint8_t dig);
  //Отлавливаем кнопки
  Wire.requestFrom(0x24, 1); //делаем запрос 1 байта из
  //микросхемы с адресом 0x24. //Адресные A0,A1,A2 на землю.
  btn_num = Wire.read();
  //Serial.print("btn_num ");
  //Serial.println(btn_num);
  if (btn_num == 68 && !ss) {b_timer = millis();ss = true;}
  if (btn_num == 4 && ss) {b_hold = millis() - b_timer;ss = false;sp = true;}
  if (btn_num == 84 && !us) {b_timer = millis();us = true;}
  if (btn_num == 20 && us) {b_hold = millis() - b_timer;us = false;up = true;}
  if (btn_num == 76 && !ds) {b_timer = millis();ds = true;}
  if (btn_num == 12 && ds) {b_hold = millis() - b_timer;ds = false;dp = true;}
  if (b_hold <= 500 && btn_num == 4 && sp) {
    if (display_mode < 5) display_mode == 4?display_mode = 0:display_mode++;
    else {
      switch (display_mode){
        case 5: display_mode = 6; break;
        case 6: display_mode = 5; break;
        case 7: display_mode = 8; break;
        case 8: display_mode = 7; break;
        case 10: display_mode = 11; break;
        case 11: display_mode = 10; break;
        case 12: display_mode = 13; break;
        case 13: display_mode = 12; break;
      }
    }
    sp = false;
  }
  else if (b_hold > 500 && btn_num == 4 && sp) {
    switch (display_mode){
      case 0: display_mode = 5; break;
      case 5:
      case 6: display_mode = 0; break;
      case 1: display_mode = 7; break;
      case 7: 
      case 8: display_mode = 1; break;
      case 2: display_mode = 9; break;
      case 9: display_mode = 2; break;
      case 3: display_mode = 10; break;
      case 10:
      case 11: display_mode = 3; break;
      case 4: display_mode = 12; break;
      case 12: 
      case 13: display_mode = 4; break;
    }
    sp = false;
  }
  watch.gettime();
  if (btn_num == 20 && up) {
    //watch.gettime();
    pressUP(watch.minutes, watch.Hours, watch.day, watch.month, watch.year);
    up = false;
  }
  if (btn_num == 12 && dp) {
    //watch.gettime();
    pressDOWN(watch.minutes, watch.Hours, watch.day, watch.month, watch.year);
    dp = false;
  }
  if (millis() - timer1 >= 1000){
    //Serial.println(display_mode);
  Serial.println(analogRead(OSV));
  Serial.println(light);
    timer1 = millis();
    Serial.println(watch.gettime("H:i:s"));

  // Вывод на дисплей
  switch (display_mode) {
      case 0:
        d.displayString(watch.gettime("Hi"));
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 1:
        d.displayString(watch.gettime("dm"));
        d.setDot(1, true);
        break;
      case 2:
        d.displayString(watch.gettime("Y"));
        d.setDot(1, false);
        break;
      case 3:
        char out_on[5];
        VAR_ON_MIN = eeprom_read_word(0);
        VAR_ON_HOUR = eeprom_read_word(4);
        sprintf(out_on, "%02d%02d", VAR_ON_HOUR, VAR_ON_MIN);
        d.displayString(out_on);
        d.setDot(1, true);
        break;
      case 4:
        VAR_OFF_MIN = eeprom_read_word(2);
        VAR_OFF_HOUR = eeprom_read_word(6);
        char out_off[5];
        sprintf(out_off, "%02d%02d", VAR_OFF_HOUR, VAR_OFF_MIN);
        d.displayString(out_off);
        d.setDot(1, true);
        break;
      case 5:
        tm = watch.gettime("Hi");
        if (dot_state) d.displayString(watch.gettime("Hi"));
        else {
          tm[2] = ' ';
          tm[3] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 6:
        tm = watch.gettime("Hi");
        if (dot_state) d.displayString(watch.gettime("Hi"));
        else {
          tm[0] = ' ';
          tm[1] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 7:
        tm = watch.gettime("dm");
        if (dot_state) d.displayString(watch.gettime("dm"));
        else {
          tm[0] = ' ';
          tm[1] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 8:
        tm = watch.gettime("dm");
        if (dot_state) d.displayString(watch.gettime("dm"));
        else {
          tm[2] = ' ';
          tm[3] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, dot_state);
        break;
      case 9:
        tm = watch.gettime("Y");
        if (dot_state) d.displayString(watch.gettime("Y"));
        else {
          tm[2] = ' ';
          tm[3] = ' ';
          d.displayString(tm);
        }
        dot_state = !dot_state;
        d.setDot(1, false);         
        break;
      case 10:
        char out_on_cm1[5];
        char out_on_cm2[5];
        VAR_ON_MIN = eeprom_read_word(0);
        VAR_ON_HOUR = eeprom_read_word(4);
        sprintf(out_on_cm1, "%02d%02d", VAR_ON_HOUR, VAR_ON_MIN);
        sprintf(out_on_cm2, "%02d  ", VAR_ON_HOUR);
        dot_state = !dot_state;
        d.setDot(1, true);
        if (dot_state) d.displayString(out_on_cm1);
        else d.displayString(out_on_cm2);
        break;
      case 11:
        char out_on_ch1[5];
        char out_on_ch2[5];
        VAR_ON_MIN = eeprom_read_word(0);
        VAR_ON_HOUR = eeprom_read_word(4);
        sprintf(out_on_ch1, "%02d%02d", VAR_ON_HOUR, VAR_ON_MIN);
        sprintf(out_on_ch2, "  %02d", VAR_ON_MIN);
        dot_state = !dot_state;
        d.setDot(1, true);
        if (dot_state) d.displayString(out_on_ch1);
        else d.displayString(out_on_ch2);
        break;
      case 12:
        char out_off_cm1[5];
        char out_off_cm2[5];
        VAR_OFF_MIN = eeprom_read_word(2);
        VAR_OFF_HOUR = eeprom_read_word(6);
        sprintf(out_off_cm1, "%02d%02d", VAR_OFF_HOUR, VAR_OFF_MIN);
        sprintf(out_off_cm2, "%02d  ", VAR_OFF_HOUR);
        dot_state = !dot_state;
        d.setDot(1, true);
        if (dot_state) d.displayString(out_off_cm1);
        else d.displayString(out_off_cm2);
        break;
      case 13:
        char out_off_ch1[5];
        char out_off_ch2[5];
        VAR_OFF_MIN = eeprom_read_word(2);
        VAR_OFF_HOUR = eeprom_read_word(6);
        sprintf(out_off_ch1, "%02d%02d", VAR_OFF_HOUR, VAR_OFF_MIN);
        sprintf(out_off_ch2, "  %02d", VAR_OFF_MIN);
        dot_state = !dot_state;
        d.setDot(1, true);
        if (dot_state) d.displayString(out_off_ch1);
        else d.displayString(out_off_ch2);
        break;
     }

    //Работа будильников
    if (watch.Hours == VAR_ON_HOUR && watch.minutes == VAR_ON_MIN && !light){
      light = 1;
      digitalWrite(OUTR, HIGH);
      digitalWrite(OUTL, LOW);
    }
    if (watch.Hours == VAR_OFF_HOUR && watch.minutes == VAR_OFF_MIN && light){
      light = 0;
      digitalWrite(OUTR, LOW);
      digitalWrite(OUTL, HIGH);
    }
    if (watch.Hours > VAR_ON_HOUR && watch.minutes > VAR_ON_MIN && light && analogRead(OSV) > ur_osv){
      light = 0;
      digitalWrite(OUTR, LOW);
      digitalWrite(OUTL, HIGH);
    }
    if (watch.Hours > VAR_ON_HOUR && watch.minutes > VAR_ON_MIN && !light && analogRead(OSV) <= ur_osv){
      light = 1;
      digitalWrite(OUTR, HIGH);
      digitalWrite(OUTL, LOW);
    }
  }
}

Это основной файл.

void pressUP(int cmin, int chour, int cday, int cmon, int cyear) {
  switch (display_mode) {
    case 5: cmin == 59?cmin = 0:cmin++;watch.settime(-1, cmin);break;
    case 6: chour == 23?chour = 0:chour++;watch.settime(-1, -1, chour);break;
    case 8: cmon == 12?cmon = 1:cmon++;watch.settime(-1, -1, -1, -1, cmon);break;
    case 9: cyear == 99?cyear = 99:cyear++;watch.settime(-1, -1, -1, -1, -1, cyear);break;
    case 10: VAR_ON_MIN == 59?VAR_ON_MIN = 0:VAR_ON_MIN++;eeprom_update_word(0, VAR_ON_MIN);break;
    case 11: VAR_ON_HOUR == 23?VAR_ON_HOUR = 0:VAR_ON_HOUR++;eeprom_update_word(4, VAR_ON_HOUR);break;
    case 12: VAR_OFF_MIN == 59?VAR_OFF_MIN = 0:VAR_OFF_MIN++;eeprom_update_word(2, VAR_OFF_MIN);break;
    case 13: VAR_OFF_HOUR == 23?VAR_OFF_HOUR = 0:VAR_OFF_HOUR++;eeprom_update_word(6, VAR_OFF_HOUR);break;
    case 7: int dinmon = getdinmon(cmon, cyear);
            cday == dinmon?cday = 1:cday++;watch.settime(-1, -1, -1, cday);
    break;
  }
}

void pressDOWN(int cmin, int chour, int cday, int cmon, int cyear) {
  switch (display_mode) {
    case 5: cmin == 0?cmin = 59:cmin--;watch.settime(-1, cmin);break;
    case 6: chour == 0?chour = 23:chour--;watch.settime(-1, -1, chour);break;
    case 8: cmon == 1?cmon = 12:cmon--;watch.settime(-1, -1, -1, -1, cmon);break;
    case 9: cyear == 22?cyear = 22:cyear--;watch.settime(-1, -1, -1, -1, -1, cyear);break;
    case 10: VAR_ON_MIN == 0?VAR_ON_MIN = 59:VAR_ON_MIN--;eeprom_update_word(0, VAR_ON_MIN);break;
    case 11: VAR_ON_HOUR == 0?VAR_ON_HOUR = 23:VAR_ON_HOUR--;eeprom_update_word(4, VAR_ON_HOUR);break;
    case 12: VAR_OFF_MIN == 0?VAR_OFF_MIN = 59:VAR_OFF_MIN--;eeprom_update_word(2, VAR_OFF_MIN);break;
    case 13: VAR_OFF_HOUR == 0?VAR_OFF_HOUR = 23:VAR_OFF_HOUR--;eeprom_update_word(6, VAR_OFF_HOUR);break;
    case 7: int dinmon = getdinmon(cmon, cyear);
            cday == 1?cday = dinmon:cday--;watch.settime(-1, -1, -1, cday);break;
  }
}

int getdinmon(int cmon, int cyear) {
  switch (cmon) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12: return 31;
    break;
    case 4:
    case 6:
    case 9:
    case 11: return 30;
    break;
    default: if (cyear % 4 == 0) return 29;
             else return 28;
    break;
  }
}

Здесь функции.

И последний - set.h

#include <Wire.h>
#include <TM1650.h>
#include <iarduino_RTC.h>
#include <avr/eeprom.h>


//#define OUTR PB1 //Выход на реле Attiny
#define OUTR 7 //Выход на реле UNO
#define OUTL 4 //Выход на светодиод UNO
#define OSV A0 //Вход замера освещенности

iarduino_RTC watch(RTC_DS1307);
TM1650 d;
//TM16xxButtons buttons(&d);       // TM16xx button
//TickerScheduler ts(1);

byte display_mode = 0;//Режимы вывода на дисплей
/*0-показ времени; 
1-день-месяц; 
2-год; 
3-включение утром; 
4-выключение вечером; 
5-установка минут в часах; 
6-установка часов в часах; 
7-установка числа в часах; 
8-установка месяца в часах; 
9-установка года в часах; 
10-установка минут включения утром; 
11-установка часов включения утром; 
12-установка минут выключения вечером.
13-установка часов выключения вечером.*/
//int chour, cmin;
char* out_on, out_off;
bool dot_state = false;
int8_t  VAR_ON_MIN     = 0;     // Задаем минуты включения света утром
int8_t  VAR_OFF_MIN     = 0;      // Задаем минуты выключения света вечером
int8_t  VAR_ON_HOUR    = 7;      // Задаем часы включения света утром
int8_t  VAR_OFF_HOUR    = 22;     // Задаем часы выключения света вечером
unsigned long timer1 = 0, b_timer = 0, b_hold = 0;
bool ss = false, us = false, ds = false, sp = false, up = false, dp = false, light = false;  

 

Dimych70
Offline
Зарегистрирован: 03.02.2022

Код на отлов нажатия кнопок с 38 по 95 строки. Если их закомментировать, то все работает.

Я вообще почему кусок только выложил. Там идет обращение к wire. Я это обращение нашел раньше в инете. Там описывал товарищ как он сам отлавливал кнопки. Так вот может как-то что-то в этом wire закрыть надо или еще что сделать. Т.к. остальное то все обычные IF и элементарные математические действия.

Может надо не закрыть, а обозвать как-то отдельно это Wire. Я просто пока не очень въехал как работает wire. Там на более низком уровне я так понял работа идет.

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

А зачем для кнопок Wire? К чему они подключены?

Dimych70
Offline
Зарегистрирован: 03.02.2022

v258 пишет:

А зачем для кнопок Wire? К чему они подключены?

Они подключены к TM1650. Не к Ардуино.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

ИМХО код очень тяжело читается, сложно что то сказать по этому поводу.

Я посмотрел, при чтении клавиатуры вы обращаетесь к адресу 0x24. в даташите же указан адрес 0x49.

Протокол TM1650 несколько отличается от стандартного I2C,   Slave address в I2C - 7 bit +R/W bit

0x24 << 1 == 0x48; 0x48 + 1(read) == 0x49 это конечно понятно, но как то это неправильно, а он же у вас еще и с DS3107 на одной шине сидит?

Посмотрите TM16xx.h  там и индикатор и кнопочки есть. 

По кнопкам-  попробуйте анализировать только следующие значения получаемые от TM1650:  0x44, 0x4С, 0x54 - кнопки 1, 2, 3 соответственно. (это в десятичной 68, 76,84, как у вас), а остальные значения просто игнорировать. То есть не равно 0x44, 0x4С, 0x54 - обнуляем принятое значение. (некоторые значения возникают на переходах от нажатия к отпусканию и при включении питания, думаю они вам не нужны)

Просто если появилось значение 0x44 - нажали "кнопку 1",  0 - отпустили.

Появилось значение 0x4С- нажали "кнопку 2", 0 - отпустили кнопку. 

Будет как мне кажется проще и понятнее.

Посмотрел исходник iarduino_RTC.h, что не понравилось: при каждом вызове функции, возвращающей указатель на строку со временем, удаляется ранее выделенная динамическая память, и создается заново под необходимый размер буфера (через malloc()). То есть делается это на каждом вызове функции, и нигде не проверяется успешность выделения памяти. Просто прописываются данные по указателю. А вы потом еще и пробелы по этому указателю прописываете из loop().  И все это не быстро, и затратно, там и String используется, соответственно подтянется. Я бы отказался от этой библиотеки, как то только для демонстрации она и подходит,  да и с переполнением millis() там решение с "костылями".

Dimych70
Offline
Зарегистрирован: 03.02.2022

SergeiL пишет:

ИМХО код очень тяжело читается, сложно что то сказать по этому поводу.

Чужой код всегда тяжело читается. Это я заметил еще лет 20 назад когда на Delphi программировал. Но я вроде везде комментарии ставил что делается, да и собственно сам код достаточно короткий.

SergeiL пишет:

Я посмотрел, при чтении клавиатуры вы обращаетесь к адресу 0x24. в даташите же указан адрес 0x49.

В самом начале я сканировал i2c. Уже не вспомню, но там было 8 адресов. Вроде с 24 по 27 и с 34 по 37. 49 точно не было. Но попробую сейчас.

SergeiL пишет:

Посмотрите TM16xx.h  там и индикатор и кнопочки есть. 

Смотрел. Даже пытался в начале ее использовать. Но в примерах к сожалению 1650 нет. Пытался делать по аналогии с другими. Индикацию выдать получилось, но вот при подключении библиотеки с кнопками и попытках обработать их сразу начинался трэш. Все висло сразу намертво.

SergeiL пишет:

По кнопкам-  попробуйте анализировать только следующие значения получаемые от TM1650:  0x44, 0x4С, 0x54 - кнопки 1, 2, 3 соответственно. (это в десятичной 68, 76,84, как у вас), а остальные значения просто игнорировать. То есть не равно 0x44, 0x4С, 0x54 - обнуляем принятое значение. (некоторые значения возникают на переходах от нажатия к отпусканию и при включении питания, думаю они вам не нужны)

Просто если появилось значение 0x44 - нажали "кнопку 1",  0 - отпустили.

Появилось значение 0x4С- нажали "кнопку 2", 0 - отпустили кнопку. 

Будет как мне кажется проще и понятнее.

Будет проще. Но мне нужно еще отработать длинное нажатие кнопки установки режимов. А тут без отлова кода, который по отпускании кнопки появляется никак.

SergeiL пишет:

Посмотрел исходник iarduino_RTC.h, что не понравилось: при каждом вызове функции, возвращающей указатель на строку со временем, удаляется ранее выделенная динамическая память, и создается заново под необходимый размер буфера (через malloc()). То есть делается это на каждом вызове функции, и нигде не проверяется успешность выделения памяти. Просто прописываются данные по указателю. А вы потом еще и пробелы по этому указателю прописываете из loop().  И все это не быстро, и затратно, там и String используется, соответственно подтянется. Я бы отказался от этой библиотеки, как то только для демонстрации она и подходит,  да и с переполнением millis() там решение с "костылями".

С RTC вообще я бился еще год назад. iarduino_RTC.h работала лучше всех. Но все равно не всегда. Я даже как в начале этой темы сам надергал из библиотеки функции и год их использовал успешно. Но с 1650 наверное не захотела работать. Поэтому я и взял iarduino_RTC.h.

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

А к чему такие мучения? Тинька, тм-ка? На обычной ардуинке часы делаются на коленке за полчаса и работают без запинки. Или цель - побольше страданий? ))

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Dimych70 пишет:

SergeiL пишет:

По кнопкам-  попробуйте анализировать только следующие значения получаемые от TM1650:  0x44, 0x4С, 0x54 - кнопки 1, 2, 3 соответственно. (это в десятичной 68, 76,84, как у вас), а остальные значения просто игнорировать. То есть не равно 0x44, 0x4С, 0x54 - обнуляем принятое значение. (некоторые значения возникают на переходах от нажатия к отпусканию и при включении питания, думаю они вам не нужны)

Просто если появилось значение 0x44 - нажали "кнопку 1",  0 - отпустили.

Появилось значение 0x4С- нажали "кнопку 2", 0 - отпустили кнопку. 

Будет как мне кажется проще и понятнее.

Будет проще. Но мне нужно еще отработать длинное нажатие кнопки установки режимов. А тут без отлова кода, который по отпускании кнопки появляется никак.

Я TM1650 не тестировал, с описанием там полня хрень, видел только оч. короткое  и на китайском, перевел гуглом. По информации из интернет понял, что если нажали кнопку и держим, и если много раз считывать данные из ТМ, каждый раз  будет считываться код нажатой кнопки, пока ее не отпустят.

Не так?  

Dimych70
Offline
Зарегистрирован: 03.02.2022

Да так. Нажимаешь, код 68, отпускаешь, код (-64) 4, другая - 84-20 и третья 76-12. Можно конечно ловить просто смену скажем 68 на любой другой, согласен. И я пробовал, но так как я сделал мне показалось проще. (просто я думаю, что это сильно не изменит ситуацию).

А на счет адреса. Я конечно попробую. Но если бы я задал неправильный адрес считывания, разве что-нибудь считалось бы?

И еще я не совсем понял, почему когда я включал сканер, выдавалось 8 адресов i2c? У меня 1650, она рассчитана вроде на 4=сегментный индикатор. Откуда там 8 адресов? Там кнопки физически вешаются общей шиной на разряд.

Попробовал 49 адрес. Не реагирует. Все время 255 выдает.

Зато на 25 скажем тоже работает. Те же коды выдает.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Dimych70 пишет:

А на счет адреса. Я конечно попробую. Но если бы я задал неправильный адрес считывания, разве что-нибудь считалось бы?

И еще я не совсем понял, почему когда я включал сканер, выдавалось 8 адресов i2c? У меня 1650, она рассчитана вроде на 4=сегментный индикатор. Откуда там 8 адресов? Там кнопки физически вешаются общей шиной на разряд.

Наверное и не поможет. 

Тут вопрос в другом, TM1650 работает не по настоящему I2C, а по своему протоколу, похожему на I2C.

Поэтому адреса у  TM1650 и нет. В принципе нет адреса, по даташиту.

Есть команды. На них он отвечает, а сканер воспринимает их как адреса.

Главное чтобы TM1650 и DS1307 друг другу не мешали на одной шине.

Dimych70
Offline
Зарегистрирован: 03.02.2022

SergeiL пишет:

Главное чтобы TM1650 и DS1307 друг другу не мешали на одной шине.

Это понятно. У DS1307 вроде как 0х68 адрес. А сканер i2c находил для 1650 другие адреса.

Ну и без вот этих команд в скетче

  Wire.requestFrom(0x25, 1); //делаем запрос 1 байта из
  btn_num = Wire.read();

Все работает и не виснет

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Dimych70 пишет:

Это понятно. У DS1307 вроде как 0х68 адрес. А сканер i2c находил для 1650 другие адреса.

Ну и без вот этих команд в скетче

  Wire.requestFrom(0x25, 1); //делаем запрос 1 байта из
  btn_num = Wire.read();

Все работает и не виснет

Для wire c TM1650 адрес должн быть 0x24, не 0x25, если я не ошибаюсь:

  Wire.requestFrom(0x24, 1); 
  btn_num = Wire.read();

  Я бы попробовал для начала снизить скорость на I2C до стандартных 100 000 Hz

Dimych70
Offline
Зарегистрирован: 03.02.2022

SergeiL пишет:

Для wire c TM1650 адрес должн быть 0x24, не 0x25, если я не ошибаюсь:

  Wire.requestFrom(0x24, 1); 
  btn_num = Wire.read();

  Я бы попробовал для начала снизить скорость на I2C до стандартных 100 000 Hz

Я 25 поставил для теста, что бы посмотреть зависнет или нет. Пока не виснет вот уже пару часов. Но нажатие кнопок отрабатывается.

Скорость попробую снизить до стандартных 100000.

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Dimych70 пишет:

SergeiL пишет:

Для wire c TM1650 адрес должн быть 0x24, не 0x25, если я не ошибаюсь:

  Wire.requestFrom(0x24, 1); 
  btn_num = Wire.read();

  Я бы попробовал для начала снизить скорость на I2C до стандартных 100 000 Hz

Я 25 поставил для теста, что бы посмотреть зависнет или нет. Пока не виснет вот уже пару часов. Но нажатие кнопок отрабатывается.

Скорость попробую снизить до стандартных 100000.

Посмотрел,  по даташиту там два последних бита помечены как  "Х" - то есть не имеют значения.

Поэтому, что 0x24, что 0x25, что 0x26, что 0x27 - будет работать одинаково.

Красным выделена команда целиком (входят: 0x24, 0x25, 0x26, 0x27 - выделено зеленым, последние два бита - не принципиальны)

Так, с использованием wire передаются байты  адреса ((B6,B5,B4,B3,B2,B1,B0)<<1)  и 1 бит (write:0/read:1 - он должен быть 1, - чтение).

То есть зеленым, выделено то, что должно быть адресом на I2C (wire), синим - чтение. 

  

 

Dimych70
Offline
Зарегистрирован: 03.02.2022

Снизил скорость до стандартных 100000, прописал 24 порт. Все равно виснет. Не сразу, через 20-30 минут. Блин вот никогда раньше с таким не сталкивался. Не компилилось, но если скомпилилось и запустилось, пахало без проблем.

Сейчас пытаюсь еще с sprintf разобраться. my_itoa имеется ввиду не готовая уже стандартная функция, а самому какой-то обработчик написать или найти надо?

Блин, вот наверно я попоясдеревянный! Пытаюсь найти исходники itoa и нихрена! Ведь понимаю, что она в какой-то библиотеке по умолчанию. Не находится. В инете тоже куча примеров, но исходника не нахожу!

По поводу зависания. Как я раньше писал, всю ночь работа, при отключенной обработке кнопок. Вообще весь кусок удален был. Сейчас начал экспериментировать. Вставляем

Wire.requestFrom(0x24, 1);

и сразу виснет через стандартные 10-20-30 минут.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Dimych70 пишет:

Блин, вот наверно я попоясдеревянный! Пытаюсь найти исходники itoa и нихрена!

Зачем тебе исходники? Для чего?

Конвертирование целочисленных данных в строку через функции itoa, ltoa, ultoa.

Функции простые, позволяют конвертировать числа целых форматов в текстовую строку.

itoa (int data, char* string, int radix);     // преобразование int

ltoa (long data, char* string, int radix);  // преобразование long

ultoa (unsigned long data, char* string, int radix);  // преобразование unsigned long

    data – это конвертируемая переменная;
    char* string – указатель на строку (имя массива);
    radix – система исчисления результата в строке:
        10 для DEC;
        8 для OCT;
        16 для HEX;
        2 для BIN.

Например, конвертирование переменой x типа int в строку myStr1 можно сделать так.

itoa(x, myStr1, 10); // в десятичном виде
itoa(x, myStr1, 8); // в восьмеричном виде
itoa(x, myStr1, 16); // в шестнадцатеричном виде
itoa(x, myStr1, 2); // в двоичном виде

Что еще ты там увидеть хочешь?

http://mypractic.ru/urok-30-tekstovye-stroki-v-arduino-konvertirovanie-d...

Dimych70
Offline
Зарегистрирован: 03.02.2022

SergeiL предложил взять исходник и переделать его под себя, чтобы не использовать sprintf.

В принципе я уже накидал. Громоздко получается конечно, но без тяжелой sprintf.

  Serial.begin(115200);
  byte VAR_ON_MIN = eeprom_read_word(0);
  byte VAR_ON_HOUR = eeprom_read_word(2);
  Serial.println(VAR_ON_MIN);
  Serial.println(VAR_ON_HOUR);
  char x1[2], x2[2],y1[2],y2[2], out[5];
  itoa(VAR_ON_HOUR/10, x1, 10);
  itoa(VAR_ON_HOUR%10, x2, 10);
  itoa(VAR_ON_MIN/10, y1, 10);
  itoa(VAR_ON_MIN%10, y2, 10);
  strcat(out, x1);
  strcat(out, x2);
  strcat(out, y1);
  strcat(out, y2);
  Serial.println(out);

Ну и этот out на экран дисплея выводить.

sadman41
Offline
Зарегистрирован: 19.10.2016

Если нужно конвертировать только число 0..59 в два символа, то можно и без itoa и strcat обойтись, на нескольких ифах все реализовав.

Dimych70
Offline
Зарегистрирован: 03.02.2022

Я все-таки не разбираюсь в char переменных.

Вот написал функцию

char* convert_time_to_char(byte val1, byte val2, byte prop){
  char x1[2], x2[2],y1[2],y2[2], out[5];
  itoa(val1/10, x1, 10);
  itoa(val1%10, x2, 10);
  itoa(val2/10, y1, 10);
  itoa(val2%10, y2, 10);
  switch (prop){
    case 0: strcat(out, x1);
            strcat(out, x2);
            strcat(out, y1);
            strcat(out, y2);
            break;
    case 1: strcat(out, x1);
            strcat(out, x2);
            strcat(out, y1);
            strcat(out, y2);
            out[0] = ' ';
            out[1] = ' ';
            break;
    case 2: strcat(out, x1);
            strcat(out, x2);
            strcat(out, y1);
            strcat(out, y2);
            out[2] = ' ';
            out[3] = ' ';
            break;
  }
  Serial.println(out);
  return out;
}

Ну типа передаем 2 числа, третья переменная, это для мигания, вместо какого параметра выводить пробелы. В самой функции все прекрасно работает. Как положено выдает "0700".

Но вот когда запрашивается из тела программы результат функции, в него влезают какие-то символы.

"⸮0700" это выдается в теле программы, там еще в экране порта спереди два квадратика есть, которые через буфер не передаются. Вот здесь:

      case 3:
        char* out_on;
        VAR_ON_MIN = eeprom_read_word(0);
        VAR_ON_HOUR = eeprom_read_word(4);
        //sprintf(out_on, "%02d%02d", VAR_ON_HOUR, VAR_ON_MIN);
        out_on = convert_time_to_char(VAR_ON_HOUR, VAR_ON_MIN, 0);
        Serial.println(out_on);
        d.displayString(out_on);
        //d.displayString(convert_time_to_char(VAR_ON_HOUR, VAR_ON_MIN, 0));
        d.setDot(1, true);
        break;

И в итоге на табло вообще ничего не передается!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Что у Вас написано в строке №15 в #68?

Dimych70 пишет:

     if (display_mode < 5) display_mode == 4?display_mode = 0:display_mode++;
    else {
 ...

Можете пояснить?

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

ЕвгенийП пишет:

Что у Вас написано в строке №15 в #68?

Dimych70 пишет:

     if (display_mode < 5) display_mode == 4?display_mode = 0:display_mode++;
    else {
 ...

Можете пояснить?


Это у него аналог такого
if (++display_mode >= 5) display_mode =0;
))

b707
Offline
Зарегистрирован: 26.05.2017

Dimych70 пишет:

Я все-таки не разбираюсь в char переменных.

только в чар-переменных? - вы себе льстите...

Цитата:
В самой функции все прекрасно работает. Как положено выдает "0700".Но вот когда запрашивается из тела программы результат функции, в него влезают какие-то символы.

потому что вы пытаетесь передать наружу функции локальную переменную. Вы что-нибудь про "область видимости" почитайте...

Да и вообще какой-нить учебник по си было бы неплохо почитать на ночь недельки две, прежде чем продолжать. А то жалко на вас смотреть - буквально на каждой строке спотыкаетесь.

 

Dimych70
Offline
Зарегистрирован: 03.02.2022

Вот тут хотелось бы подробнее. Да наверное я и в других вещах не разбираюсь. Но я думал, что если я обращаюсь к функции и пытаюсь получить ее результат, я не должен объявлять еще и в теле программы переменную, которую использую в функции.

char convert_time_to_char(byte val1, byte val2, byte prop){
  char x1[2], x2[2],y1[2],y2[2], out[5];
  itoa(val1/10, x1, 10);
  itoa(val1%10, x2, 10);
  itoa(val2/10, y1, 10);
  itoa(val2%10, y2, 10);
  strcat(out, x1);
  strcat(out, x2);
  strcat(out, y1);
  strcat(out, y2);
  switch (prop){
    case 1: out[0] = ' ';
            out[1] = ' ';
            break;
    case 2: out[2] = ' ';
            out[3] = ' ';
            break;
  }
  Serial.println(out);
  return out;
}

Переменную out я задал в функции и через нее возвращаю результат работы функции. В теле программы функция передает свой результат другой переменной, которая у меня объявлена в теле программы. Да и если бы надо было объвлять эту переменную еще и в теле программы, была бы ошибка во время компиляции! Так всегда было. Если это не так, то я что-то совсем запутался!

Dimych70
Offline
Зарегистрирован: 03.02.2022

ЕвгенийП пишет:

Что у Вас написано в строке №15 в #68?

Dimych70 пишет:

     if (display_mode < 5) display_mode == 4?display_mode = 0:display_mode++;
    else {
 ...

Можете пояснить?

Уже давно такую конструкцию нашел. Работает, и существенно сокращает количество символов в скетче.

По хорошему надо было бы писать:

if (display_mode < 5) {
    if (display_mode == 4) display_mode = 0;
    else display_mode++;
}
    else {..........

А тут все значительно короче.

if (display_mode < 5) display_mode == 4?display_mode = 0:display_mode++;
    else {

 

b707
Offline
Зарегистрирован: 26.05.2017

во-первых, в коде #88 у вас возвращаемое значение функции было типа char*, а в последнем уже char. Надеюсь. вы понимаете что это огромная разница. Если нет - то сначала разберитесь.

Но в любом случае ни char*, ни char не соответвуют типу переменной out[5], поскольку это массив из 5 чаров...

 

b707
Offline
Зарегистрирован: 26.05.2017

Dimych70 пишет:

существенно сокращает количество символов в скетче

с вас за символы в скетче берут оплату посимвольно? - а если нет, к чему это? - если что, размер текста скетча к размеру бинарного кода имеет очень относительное отношение

Dimych70
Offline
Зарегистрирован: 03.02.2022

А что, если функция объявлена как char*, то переменную, которую она внутри использует и передает наружу надо объвлять еще и в теле основной программы?

А если функция char (без звездочки), то можно не объявлять?

Собственно я и говорю, что никак в char не въеду. Я знаю, что * это ссылка. Но вот что при этом внутреннюю переменную функции надо и вне функции объявлять - такого я не знал.

Dimych70
Offline
Зарегистрирован: 03.02.2022

b707 пишет:

Dimych70 пишет:

существенно сокращает количество символов в скетче

с вас за символы в скетче берут оплату посимвольно? - а если нет, к чему это? - если что, размер текста скетча к размеру бинарного кода имеет очень относительное отношение

По-моему так просто компактнее и читабельнее. Мне самому сначала было неудобно читать, но как привык очень удобно.

Но по сути ведь написано правильно. Давайте пусть так и останется, если это не влияет на работу.

b707
Offline
Зарегистрирован: 26.05.2017

Dimych70 пишет:

А что, если функция объявлена как char*, то переменную, которую она внутри использует и передает наружу надо объвлять еще и в теле основной программы?

char* - это не сам массив, а только его адрес. Наличие у вас в руках конверта с адресом не гарантирует. что по этому адресу существует дом. И тут так же.

После окончания работы функции она возвращает адрес массива, но самого массива по этому адресу уже нет, так он был локальным и при выходе из функции затерся новыми данными. Именно поэтому внутри функции ваша строчка out печатается, а снаружи уже нет.

Правильная стратегия - создавать массив снаружи и передавать его адрес внутрь функции. Ну или использовать глобальные переменные.

 

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Dimych70 пишет:

ЕвгенийП пишет:

Что у Вас написано в строке №15 в #68?

Dimych70 пишет:

     if (display_mode < 5) display_mode == 4?display_mode = 0:display_mode++;
    else {
 ...

Можете пояснить?

Уже давно такую конструкцию нашел. Работает, и существенно сокращает количество символов в скетче.

По хорошему надо было бы писать:

if (display_mode < 5) {
    if (display_mode == 4) display_mode = 0;
    else display_mode++;
}
    else {..........

А тут все значительно короче.

if (display_mode < 5) display_mode == 4?display_mode = 0:display_mode++;
    else {

 


По хорошему я привел в #90

Dimych70
Offline
Зарегистрирован: 03.02.2022

b707 пишет:

char* - это не сам массив, а только его адрес. Наличие у вас в руках конверта с адресом не гарантирует. что по этому адресу существует дом. И тут так же.

После окончания работы функции она возвращает адрес массива, но самого массива по этому адресу уже нет, так он был локальным и при выходе из функции затерся новыми данными. Именно поэтому внутри функции ваша строчка out печатается, а снаружи уже нет.

Правильная стратегия - создавать массив снаружи и передавать его адрес внутрь функции. Ну или использовать глобальные переменные.

Ага! Вот тут понятнее! Т.е. лучше сделать как в той же itoa, где результат работы внутри параметров, передаваемых в функцию! Ща попробую. Спасибо!