RTC DS3231 и LCD 2004A: вместе по I2C не работают

Rext
Offline
Зарегистрирован: 03.12.2016

Добрый день!

Дано: Arduino UNO, RTC DS3231, LCD экран 20х4 на I2C (чип PCF8574AT). Часы и экран подключены по I2C к Arduino. На SQW RTC установлена частота 1 Гц. На первое прерывание повешан выход SQW с RTC. Написан простейший скетч: по прерыванию надо мигать светодиодом и выводить на экран время.

Используемые дополнительные библиотеки: DS3231 (версия 1.01 от 25 Aug 2014), LiquidCrystal_I2C_V112 

Код скетча

#include <TimeLib.h>
#include <Time.h>         //http://www.arduino.cc/playground/Code/Time  
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DS3231.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4); 
DS3231  rtc(SDA, SCL);

volatile int state = LOW;

void setup()
{
  rtc.begin();
  rtc.setSQWRate(1);
  
  lcd.init(); 
  lcd.backlight();
  lcd.setCursor(0, 0); 
  lcd.print("Start");
  
  pinMode(LED_BUILTIN, OUTPUT);
   
  attachInterrupt(1, blink, FALLING);
}

void blink()
{
  state = !state;  
 digitalWrite(LED_BUILTIN, state); 
   
  //lcd.setCursor(0, 2); 
  //lcd.print("                    ");
  //lcd.print(String(hour(),1)+":"+String(minute(),1)+":"+String(second(),1)+" "+String(day(),1)+"."+String(month(),1)+"."+String(year(),1));  
 delay(200);
}

void loop(void)
{
    
}

 Преамбула: по отдельности часы и экран работают. Скетч, в том виде, что приведен, тоже работает: светодиод мигает.

Проблема: 

как только я раскомментирую любую из закомментируемых строк, все встает в ступор: светодиод не мигает, соответственно на экране ни чего не отображается.

Буду благодарен за любые идеи, бъюсь уже третий день, попробовал несколько библиотек rtc - все без изменения.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Вот пример, специально для Uni, что бывает, когда чайники используют прерывания.
Не то что ООП туда тащить, а вообще из фреймворка убрать attachIntrrrupt! Тогда вот таких вопросов не будет.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

А зачем, собственно, вся работа с экраном и даже delay() вынесены в прерывание?

Rext
Offline
Зарегистрирован: 03.12.2016

to wdrakula: А более расширенные комменты можно услышать? Что не так с приведенным примером?

Rext
Offline
Зарегистрирован: 03.12.2016

to andriano: delay остался от эксперимента. Работа с экраном вынесена в прерывание, т.к. в дальнейшем необходимо по прерыванию выводить время и состояние на экран.

bwn
Offline
Зарегистрирован: 25.08.2014

Rext пишет:

to andriano: delay остался от эксперимента. Работа с экраном вынесена в прерывание, т.к. в дальнейшем необходимо по прерыванию выводить время и состояние на экран.

Так и выводите, только не в прерывании, а после.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Rext пишет:

to andriano: delay остался от эксперимента. Работа с экраном вынесена в прерывание, т.к. в дальнейшем необходимо по прерыванию выводить время и состояние на экран.

Ну так и выводите по прерыванию, а не из прерывания: в прерывании выставляется флаг, который анализируется из loop() и уже оттуда осуществляется вывод.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Вот Ваш переделанный код

#include <TimeLib.h>
#include <Time.h>         //<a href="http://www.arduino.cc/playground/Code/Time" rel="nofollow">http://www.arduino.cc/playground/Code/Time</a>  
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DS3231.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); 
//экран у меня 16х2, это ничего в коде не меняет
DS3231  rtc(SDA, SCL);

//volatile int state = LOW;

boolean Flag = 0;
void myInt(void)
{
  Flag = true;
  return;
}


void setup()
{
  rtc.begin();
  rtc.setOutput(LOW);
// без этого режим прерываний включен по-умолчанию, а Вы выбрали SQW, я не стал корректировть Ваш выбор
  rtc.setSQWRate(SQW_RATE_1);
// то как у Вас было - это 1 КГц, один Герц это 0 или, что лучше, вот такая константа
  
  lcd.init(); 
  lcd.backlight();
  lcd.setCursor(0, 0); 
  lcd.print("Start");
  
  pinMode(LED_BUILTIN, OUTPUT);
   
  attachInterrupt(4, myInt, FALLING);
}


void loop(void)
{
static byte state = LOW;
if (Flag) 
  {
  Flag = false;
  state = !state;
  digitalWrite(LED_BUILTIN, state); 
  lcd.setCursor(0, 0); 
  lcd.print(rtc.getDateStr());
  lcd.setCursor(0, 1); 
  lcd.print(rtc.getTimeStr());  
  
  }

    
}

В таком виде, как НАДО было делать. Я старался почти ничего не менять.

Даже оставил все Ваши библиотеки. Хоть это и мусор какой-то.

Я убрал в выводе на экран извращения со стрингами. Простите уж.

вот фото комментарий:

Леонардо, часы, экран. Принес на кухню.

макет собран.

все работает, строки на экране по-своему разместил.

==========================

при редактировании:

есссно, что была некая адаптация под леонардо, например номер прерывания.

Если Нужно показать на Нанке или Меге - пожалуйста, если занят не буду.

Rext
Offline
Зарегистрирован: 03.12.2016

Всем огромное спасибо за пинок в нужном направлении!

Вопрос: а может ли кто рассказать, ПОЧЕМУ в приведенном мной коде все вставало в ступор? Почему вывод на lcd в прерывании не отработал?

Rext
Offline
Зарегистрирован: 03.12.2016

to wdrakula: спасибо за указание направления! А почему приведенные библиотеки - мусор?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Rext пишет:

to wdrakula: спасибо за указание направления! А почему приведенные библиотеки - мусор?

Преобразования в "time.h" проще делать руками. А обращение к hour(), min() и прочее, скрывает обращение к часам КАЖДЫЙ РАЗ.

Я с этими часами вообще без библиотек работаю, но Вам - совет: посмотрите что-то нибудь более приличное. Один раз запросить время в структуру, а потом из нее преобразовывать. Таких библиотек много.

Но еще лучше - преобразовывать руками, так как Вам нужно, не тратя память на ерунду.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Rext пишет:

Всем огромное спасибо за пинок в нужном направлении!

Вопрос: а может ли кто рассказать, ПОЧЕМУ в приведенном мной коде все вставало в ступор? Почему вывод на lcd в прерывании не отработал?

вы прерывание сделали 1000 раз в секунду, а не один! и за 1 мс оно не успевало выполниться. и накладывалось само-на-себя.

Вы б вообще поаккуратнее с прерываниями. Вот не нужны они новичкам. Есть millis() и micros() - вот и отмеряйте себе время.

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

 

nik182
Offline
Зарегистрирован: 04.05.2015

Наверно в прерывании все остальные прерывания запрещены и тайминги протокола общения с LCD не работали?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

nik182 пишет:

Наверно в прерывании все остальные прерывания запрещены и тайминги протокола общения с LCD не работали?

Это - в первую очередь. А если прерывания разрешить - то всанет вопрос нереентерабельности.

Не нужны прерывания новичкам. Не пользуйтесь delay() и никакие прерывания вам не будут нужны в коде.

Rext
Offline
Зарегистрирован: 03.12.2016

:) еще раз спасибо за пояснения