Помогите новичку понять логику выполнения параллельных процессов

kinder
Offline
Зарегистрирован: 29.03.2015

Всем привет. Я новичок, поэтому прошу не сильно пинать.
Решил сделать часы на 6 газоразрядных индикаторах и ардуино. Микросхема часов DS1307. При написании кода столкнулся со следующей проблемой. Если ардуина работает только с часами, то часы выдают нужную информацию без проблем. Цифры выводятся динамически, с помощью таймера MsTimer2.h тоже  без проблем. Но  одновременно и опрос часов раз в 1 секунду и вывод цифр не работает корректно. Проявляется проблема в том, что часть сигналов от часов  приходят корректно, а часть нет. Пробовал различные варианты: в Loop делал опрос часов. Данные не всегда приходили корректные. Как я понимаю в момент общения с часами срабатывало прерывание по таймеру и данные не обрабатывались, пока выполнялось прерывание. Потом сделал опрос часов в самом прерывании, данные тоже не всегда приходят корректные. 
Подскажите пожалуйста ответ на следующие вопросы:
1) Как правильно должна быть реализована логика работы микроконтроллера, который опрашивает различные датчики по различным шинам данных (SPI,I2C.1-Wire и т.д.) и при этом делает динамический вывод данных на дисплей с частотой например 100Гц каждого сегмента. То есть как обеспечить качественный опрос датчиков и одновременный вывод данных на индикаторы по прерыванию? Меня интересует именно последовательность выполнения кусков кода и в каких частях программы (Loop, прерывание) они должны быть реализованы. Скетч не прикладываю, потому-что пока необходимо понять саму логику и последовательность опроса датчиков.

2) Как понять сколько времени необходимо на опрос какого либо датчика по какой либо шине. То есть как называется параметр в даташите на датчик, который указывает величину времени  необходимого на опрос датчика.

3) Как определить величину времени, необходимого на вывод информации в СОМ порт. То есть например есть строка  Serial.println(unitsecond);  СОМ порт работает на скорости 9600. Сколько времени потратит микроконтроллер на вывод int-ой переменной unitsecond? Как определить это время?

Очень буду рад ссылкам на соответствующие темы. 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

нечем дуино делать параллельные процессы - у контроллера одно ядро.

поэтому принцип работы программы следующий - бегаешь по кругу вечного цикла loop и что-то делаешь. пока делаешь что-то одно - остальное мирно ждёт своей очереди.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

1. если критично точное исполнение, то народ привязывается к прерываниям на аппаратных таймерах, если нет - то лепишь программный таймер на миллис.

2. если сложно найти все слова time в документации на датчик, то зачем понимать - спросил датчик, датчик ответил, сохранил значение в переменную.

3. стоять с секундомером.

ты точно хоть один скетч написал сам?

9400
Offline
Зарегистрирован: 15.07.2017

kinder пишет:
1) Как правильно должна быть реализована логика работы микроконтроллера, который
При считывании значений переменных, используемых в прерываниях, начало и конец нужно защищать  конструкцией

noInterrupts(); 
// Ваш код
interrupts();

а сами переменные модифицировать при помощи  volatile

kinder
Offline
Зарегистрирован: 29.03.2015

Пробовал 

1 noInterrupts();
2 // Ваш код
3 interrupts();

и переменные которые используются в прерывании у меня  volatile  не помогает. 

 

 

kinder
Offline
Зарегистрирован: 29.03.2015

Согласен, что ардуина может выполнять только один процесс в один момент времени. Но под параллельными процессами я имел в виду, что например ардуина делает какие-то вычисления, потом происходит прерывание, она откладывает этот процесс и выполняет код в прерывании, потом возвращается и продолжает вычисления. То есть микроконтроллер не выполняет последовательно одну задачу пока ее не выполнит и переходит к следующей, а прыгает между задачами "как-бы" параллельно выполняя их. Согласен, что в терминологии я не очень подкован.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

kinder пишет:

 не помогает. 

публикуй код с комментариями, в каком месте кода у тебя не помогает.

*Вставка программного кода в тему/комментарий

kinder
Offline
Зарегистрирован: 29.03.2015

Клапауций 112 пишет:

1. если критично точное исполнение, то народ привязывается к прерываниям на аппаратных таймерах, если нет - то лепишь программный таймер на миллис.

3. стоять с секундомером.

ты точно хоть один скетч написал сам?

1. Я и пытаюсь привязаться к таймеру 2, чтобы стабильно выводить цифры. Но что-то делаю неправильно. Поэтому и пытаюсь уточнить у специалистов, какая же последовательность кусков кода позволит корректно опрашивать датчиков.

3. Очень дельный совет :-)

скетчи писал, но очень простые. Проблема появилась именно с динамическим выводом с помощью прерываний

qwone
qwone аватар
Онлайн
Зарегистрирован: 03.07.2016

ну есть один вариант. http://arduino.ru/forum/programmirovanie/klassy-arduino-po-qwone-dlya-chainikov разберетесь, будет вам и решение. А нет, то не будет.

SLKH
Offline
Зарегистрирован: 17.08.2015

kinder пишет:

Клапауций 112 пишет:

1. если критично точное исполнение, то народ привязывается к прерываниям на аппаратных таймерах, если нет - то лепишь программный таймер на миллис.

3. стоять с секундомером.

ты точно хоть один скетч написал сам?

1. Я и пытаюсь привязаться к таймеру 2, чтобы стабильно выводить цифры. Но что-то делаю неправильно. Поэтому и пытаюсь уточнить у специалистов, какая же последовательность кусков кода позволит корректно опрашивать датчиков.

3. Очень дельный совет :-)

скетчи писал, но очень простые. Проблема появилась именно с динамическим выводом с помощью прерываний

 

1. Например:

loop() {

MsTimer2::stop()  
/* 
здесь в спокойной обстановке считываем в переменную время из DS1307
*/
 
MsTimer2::start()
/*
здесь выводим информацию на индикатор.
*/
 
}
 
 
3. Желательно самому найти информацию и 1 раз разобраться со скоростями, битами и пр. (см. UART).
А при твоих условиях переменная будет передаваться приблизительно 2 миллисекунды.
kinder
Offline
Зарегистрирован: 29.03.2015

SLKH пишет:

1. Например:

loop() {

MsTimer2::stop()  
/* 
здесь в спокойной обстановке считываем в переменную время из DS1307
*/
 
MsTimer2::start()
/*
здесь выводим информацию на индикатор.
*/
 
}
 
 
 
Хорошая идея останавливать таймер. Я просто не знал как это сделать. Спасибо зза подсказку. Попробовал этот вариант. Часы стали стабильнее опрашиваться. Но все равно проскакивает битый пакет данных.
 
Прилагаю свой код 
Подскажите пожалуйста что в нем не так?
#include <iarduino_RTC.h>
#include <MsTimer2.h>
iarduino_RTC time(RTC_DS1307);

#define clock 13
#define data 11
#define latch 8
#define DIG1 2   //анод А1
#define DIG2 3   //анод А2
#define DIG3 7   //анод А3
#define DIG4 6   //анод А4
#define DIG5 5   //анод А5
#define DIG6 4   //анод А6

byte hour = 0;
byte dechour = 0;
byte unithour = 0;
byte minut = 0;
byte decminut = 0;
byte unitminut = 0;
byte second = 0;
byte decsecond = 0;
byte unitsecond = 0;

volatile short counterTime = 0;
volatile byte cifra1 = 0; //значение выводимое на 1-й индикатор
volatile byte cifra2 = 0; //значение выводимое на 2-й индикатор
volatile byte cifra3 = 0; //значение выводимое на 3-й индикатор
volatile byte cifra4 = 0; //значение выводимое на 4-й индикатор
volatile byte cifra5 = 0; //значение выводимое на 5-й индикатор
volatile byte cifra6 = 0; //значение выводимое на 6-й индикатор

byte flagdig = 3;  // флаг определяющий, какая цифра зажигается в данный момент
byte flagtime = 1;  // флаг определяющий,  что на индикаторы выводится время
byte flagtemp = 0;  // флаг определяющий,  что на индикаторы выводится температура
byte flaghumidity = 0;  // флаг определяющий,  что на индикаторы выводится влажность

byte g_digits[] = {0b01000000, 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b00000001, 0b10000000, 0b00100000 };
//                      0           1           2           3           4            5          6            7         8             9          DP


void setup() {
  pinMode(clock, OUTPUT);
  pinMode(data, OUTPUT);
  pinMode(latch, OUTPUT);
  pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT);
  pinMode(DIG3, OUTPUT);
  pinMode(DIG4, OUTPUT);
  pinMode(DIG5, OUTPUT);
  pinMode(DIG6, OUTPUT);
  digitalWrite(latch, HIGH);
  digitalWrite(DIG1, LOW);
  digitalWrite(DIG2, LOW);
  digitalWrite(DIG3, LOW);
  digitalWrite(DIG4, LOW);
  digitalWrite(DIG5, LOW);
  digitalWrite(DIG6, LOW);

  Serial.begin(9600); // открываем последовательный порт, задаем скорость передачи данных 9600 бод
  time.begin();
  shiftOut(data, clock, LSBFIRST, 0b00000000);
  shiftOut(data, clock, LSBFIRST, 0b00000000);
  shiftOut(data, clock, LSBFIRST, 0b00000000);
  shiftOut(data, clock, LSBFIRST, 0b00000000);
  digitalWrite(latch, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах

  MsTimer2::set(5, SistemTimer); // 1000ms period
  MsTimer2::start();
  Serial.println(time.gettime("d-m-Y, H:i:s, D")); // выводим время
  
}


void loop() {

  if (millis() % 1000 == 0) { // если прошла 1 секунда
    //      Serial.println(time.gettime("d-m-Y, H:i:s, D")); // выводим время
    MsTimer2::stop(); 
    time.gettime();
    
    hour = time.Hours;
    Serial.print(hour); // выводим время
    minut = time.minutes;
    Serial.print(minut); // выводим время
    second = time.seconds;
    Serial.println(second); // выводим время
    
        dechour = hour / 10;
    Serial.print(dechour); // выводим десятки часов
    unithour = hour % 10;
    Serial.print(unithour); // выводим единицы часов

    decminut = minut / 10;
    Serial.print(decminut); // выводим десятки минут
    unitminut = minut % 10;
    Serial.print(unitminut); // выводим единицы минут

    decsecond = second / 10;
    Serial.print(decsecond); // выводим десятки секунд
    unitsecond = second % 10;
    Serial.println(unitsecond); // выводим единицы секунд
   Serial.println(g_digits[0]); // выводим единицы секунд
   MsTimer2::start();

}
}


void SistemTimer (void){
  
   if (flagtime == 1){
    cifra1 = dechour;
    cifra2 = unithour;
    cifra3 = decminut;
    cifra4 = unitminut;
    cifra5 = decsecond;
    cifra6 = unitsecond;
  }

  if (flagdig == 3){  //вывод по 2 цифры одновременно
    digitalWrite(DIG1, LOW);// выключаем анод  DIG1
    digitalWrite(DIG2, LOW);// выключаем анод  DIG2
    digitalWrite(DIG3, HIGH);// включаем анод  DIG3
    digitalWrite(DIG4, LOW);// выключаем анод  DIG4
    digitalWrite(DIG5, LOW);// выключаем анод  DIG5
    digitalWrite(DIG6, HIGH);// включаем анод  DIG6
    digitalWrite(latch, LOW); // устанавливаем синхронизацию "защелки" на LOW

 if ((cifra6 == 0)|| (cifra6 == 9)) { 
    shiftOut(data, clock, LSBFIRST, g_digits[cifra6]);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
    shiftOut(data, clock, LSBFIRST, 0b00000000);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
  }
 if ((cifra6 > 0)& (cifra6 < 9)) { 
    shiftOut(data, clock, LSBFIRST, 0b00000000);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
    shiftOut(data, clock, LSBFIRST, g_digits[cifra6]);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
  }
    shiftOut(data, clock, LSBFIRST, 0b00000000);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
    shiftOut(data, clock, LSBFIRST, 0b00000000);  // Записываем информацию в регистр
    digitalWrite(latch, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах

   }
}

 

 
 
 
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

если закомментировать вывод в сериал должно заработать стабильней

kinder
Offline
Зарегистрирован: 29.03.2015

ua6em пишет:

если закомментировать вывод в сериал должно заработать стабильней

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

kinder
Offline
Зарегистрирован: 29.03.2015

Если я пойму что происходит, то я смогу попробовать решить эту проблему. А пока я не понимаю, что это за глюк то и устранить его не смогу.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

kinder пишет:

ua6em пишет:

если закомментировать вывод в сериал должно заработать стабильней

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

мне так и не удалось заставить Timer2 работать стабильно, разбираться пока не стал, обошёлся другими методами, но где пробегало, при вызове кода таймера надо запретить прерывания

kinder
Offline
Зарегистрирован: 29.03.2015

 

ua6em пишет:

мне так и не удалось заставить Timer2 работать стабильно, разбираться пока не стал, обошёлся другими методами, но где пробегало, при вызове кода таймера надо запретить прерывания

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

kinder
Offline
Зарегистрирован: 29.03.2015

SLKH пишет:

1. Например:

loop() {

MsTimer2::stop()  
/* 
здесь в спокойной обстановке считываем в переменную время из DS1307
*/
 
MsTimer2::start()
/*
здесь выводим информацию на индикатор.
*/
 
}
 

kalapanga
Offline
Зарегистрирован: 23.10.2016

Я бы по другому действия распределил.

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

И Ваше определение того, что "прошла секунда" (77 строка), мне кажется несколько некорректным.

SLKH
Offline
Зарегистрирован: 17.08.2015

1. если отключить всю индикацию, оставить только вывод в сериал - часы работают/читаются правильно?

2. я бы выкинул из SistemTimer() всё, кроме установки какого-то флага - мол, очередной тик пришел.

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

kinder
Offline
Зарегистрирован: 29.03.2015

kalapanga пишет:

Я бы по другому действия распределил.

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

И Ваше определение того, что "прошла секунда" (77 строка), мне кажется несколько некорректным.

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

 

По поводу 77 строки - это стандартный скетч и комментарий из него же. Понятно что с millis() точно измерить секунду в обычном цикле не получится.

kinder
Offline
Зарегистрирован: 29.03.2015

SLKH пишет:

1. если отключить всю индикацию, оставить только вывод в сериал - часы работают/читаются правильно?

2. я бы выкинул из SistemTimer() всё, кроме установки какого-то флага - мол, очередной тик пришел.

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

1. Да часы работают как часы (без проблем). Извините за тавтологию.

2. Идея интересная. Буду пробовать. Но по логике ничего не будет мешать таймеру срабатывать во время опроса часов, что повлечет за собой битые данные. Также в Loop невозможно будет обеспечить стабильную частоту вывода на индикаторы. 

kalapanga
Offline
Зарегистрирован: 23.10.2016

kinder пишет:

Также в Loop невозможно будет обеспечить стабильную частоту вывода на индикаторы. 

А зачем она Вам нужна? В прерывании должны выполняться действительно критичные действия. Отображение информации к этому совсем не относится. Ну неужели можно заметить, если один раз информация обновится не через 5, а через 8 миллисекунд? Я именно из таких же соображений предложил не размещать индикацию в прерывании.

SLKH
Offline
Зарегистрирован: 17.08.2015

kalapanga пишет:

Я бы по другому действия распределил.

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

И Ваше определение того, что "прошла секунда" (77 строка), мне кажется несколько некорректным.

скорее, изрядно некорректное.

стандартное millis()-prevmillis > 1000 было бы ладнее. 

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

kinder
Offline
Зарегистрирован: 29.03.2015

kalapanga пишет:

А зачем она Вам нужна? В прерывании должны выполняться действительно критичные действия. Отображение информации к этому совсем не относится. Ну неужели можно заметить, если один раз информация обновится не через 5, а через 8 миллисекунд? Я именно из таких же соображений предложил не размещать индикацию в прерывании.

Код в Loop будет очень разрастаться. И не известно сколько вемени понадобится на один проход Loop.  Если взять например 8 мс, то частота вывода каждого символа будет 1000/(8*3) = 42 Гц. А с учетом времени задержки на запись в сдвиговых регистрах и того меньше. Это уже возможно кто-то сможет заметить.  Таймер же позволял не беспокоиться о такой проблеме.

Pyotr
Offline
Зарегистрирован: 12.03.2014

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

const word interval = 10;// 1 сек = 100 х 10
void setup(){
  
}
void loop(){
  //нам не нужно измерять интервалы > 1 мин.
  //поэтому достаточно word вместо unsigned long
  static word carrMillis = 0, prevMillis = 0;
  static byte counter = 0;
  carrMillis = word(millis());
  if(carrMillis - prevMillis >= interval){ 
    prevMillis += interval;
    
    printDispl();//каждые 10 мс
    
    switch (counter){
       case 0: 
         readRTC();//читаем RTC раз в сек
       break;
       case 1: 
         //что-то делаем раз в сек
       break;
       case 2: 
         //что-то делаем раз в сек
       break;
       // и так далее до 19
    }
  counter ++;
  if(counter >= 100)  counter = 0;  
  }
}//END loop()      
//=========================
void printDispl(){
  //обновляем инфу на одном индикаторе (по очереди)
}
//========================
void readRTC(){
  
}

И отключать-включать прерывания правильней так

byte oldSREG = SREG;   
noInterrupts();
  //что-то сделали
SREG = oldSREG; 

 

kinder
Offline
Зарегистрирован: 29.03.2015

Попробовал вариант предложенный Pyotr. К сожалению стало хуже. И опять таже проблема. согласно этого кода я и близко не вижу что может влиять на опрос часов. Снова проверил часы. Работают четко. 

Pyotr
Offline
Зарегистрирован: 12.03.2014

Код покажите и что значит хуже?

kinder
Offline
Зарегистрирован: 29.03.2015
#include <iarduino_RTC.h>
#include <MsTimer2.h>
iarduino_RTC time(RTC_DS1307);

#define clock 13
#define data 11
#define latch 8
#define DIG1 2   //анод А1
#define DIG2 3   //анод А2
#define DIG3 7   //анод А3
#define DIG4 6   //анод А4
#define DIG5 5   //анод А5
#define DIG6 4   //анод А6

byte hour = 0;
byte dechour = 0;
byte unithour = 0;
byte minut = 0;
byte decminut = 0;
byte unitminut = 0;
byte second = 0;
byte decsecond = 0;
byte unitsecond = 0;

volatile short counterTime = 0;
volatile byte cifra1 = 0; //значение выводимое на 1-й индикатор
volatile byte cifra2 = 0; //значение выводимое на 2-й индикатор
volatile byte cifra3 = 0; //значение выводимое на 3-й индикатор
volatile byte cifra4 = 0; //значение выводимое на 4-й индикатор
volatile byte cifra5 = 0; //значение выводимое на 5-й индикатор
volatile byte cifra6 = 0; //значение выводимое на 6-й индикатор

byte flagdig = 3;  // флаг определяющий, какая цифра зажигается в данный момент
byte flagtime = 1;  // флаг определяющий,  что на индикаторы выводится время
byte flagtemp = 0;  // флаг определяющий,  что на индикаторы выводится температура
byte flaghumidity = 0;  // флаг определяющий,  что на индикаторы выводится влажность

byte g_digits[] = {0b01000000, 0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000, 0b00000100, 0b00000010, 0b00000001, 0b10000000, 0b00100000 };
//                      0           1           2           3           4            5          6            7         8             9          DP

const word interval = 10;// 1 сек = 100 х 10


void setup() {
  pinMode(clock, OUTPUT);
  pinMode(data, OUTPUT);
  pinMode(latch, OUTPUT);
  pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT);
  pinMode(DIG3, OUTPUT);
  pinMode(DIG4, OUTPUT);
  pinMode(DIG5, OUTPUT);
  pinMode(DIG6, OUTPUT);
  digitalWrite(latch, HIGH);
  digitalWrite(DIG1, LOW);
  digitalWrite(DIG2, LOW);
  digitalWrite(DIG3, LOW);
  digitalWrite(DIG4, LOW);
  digitalWrite(DIG5, LOW);
  digitalWrite(DIG6, LOW);

  Serial.begin(9600); // открываем последовательный порт, задаем скорость передачи данных 9600 бод
  time.begin();
  shiftOut(data, clock, LSBFIRST, 0b00000000);
  shiftOut(data, clock, LSBFIRST, 0b00000000);
  shiftOut(data, clock, LSBFIRST, 0b00000000);
  shiftOut(data, clock, LSBFIRST, 0b00000000);
  digitalWrite(latch, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах

//  MsTimer2::set(5, SistemTimer); // 1000ms period
//  MsTimer2::start();
  Serial.println(time.gettime("d-m-Y, H:i:s, D")); // выводим время
  
}


void loop() {
  //нам не нужно измерять интервалы > 1 мин.
  //поэтому достаточно word вместо unsigned long
  static word carrMillis = 0, prevMillis = 0;
  static byte counter = 0;
  carrMillis = word(millis());
  if(carrMillis - prevMillis >= interval){ 
    prevMillis += interval;
    
    printDispl();//каждые 10 мс
    
    switch (counter){
       case 0: 
         readRTC();//читаем RTC раз в сек
       break;
       case 1: 
         //что-то делаем раз в сек
       break;
       case 2: 
         //что-то делаем раз в сек
       break;
       // и так далее до 19
    }
  counter ++;
  if(counter >= 100)  counter = 0;  
  }
}//END loop()      

//=========================
void printDispl(){   //обновляем инфу на одном индикаторе (по очереди)
    if (flagtime == 1){
    cifra1 = dechour;
    cifra2 = unithour;
    cifra3 = decminut;
    cifra4 = unitminut;
    cifra5 = decsecond;
    cifra6 = unitsecond;
  }

  if (flagdig == 3){  //вывод по 2 цифры одновременно
    digitalWrite(DIG1, LOW);// выключаем анод  DIG1
    digitalWrite(DIG2, LOW);// выключаем анод  DIG2
    digitalWrite(DIG3, HIGH);// включаем анод  DIG3
    digitalWrite(DIG4, LOW);// выключаем анод  DIG4
    digitalWrite(DIG5, LOW);// выключаем анод  DIG5
    digitalWrite(DIG6, HIGH);// включаем анод  DIG6
    digitalWrite(latch, LOW); // устанавливаем синхронизацию "защелки" на LOW

 if ((cifra6 == 0)|| (cifra6 == 9)) { 
    shiftOut(data, clock, LSBFIRST, g_digits[cifra6]);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
    shiftOut(data, clock, LSBFIRST, 0b00000000);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
  }
 if ((cifra6 > 0)& (cifra6 < 9)) { 
    shiftOut(data, clock, LSBFIRST, 0b00000000);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
    shiftOut(data, clock, LSBFIRST, g_digits[cifra6]);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
  }
    shiftOut(data, clock, LSBFIRST, 0b00000000);  // Записываем информацию в регистр (сдвигаем данные на один регистр)
    shiftOut(data, clock, LSBFIRST, 0b00000000);  // Записываем информацию в регистр
    digitalWrite(latch, HIGH); //"защелкиваем" регистр, тем самым устанавливая значения на выходах

   }


}

 
  //========================
void readRTC(){
  
    time.gettime();
    
    hour = time.Hours;
    Serial.print(hour); // выводим время
    minut = time.minutes;
    Serial.print(minut); // выводим время
    second = time.seconds;
    Serial.println(second); // выводим время
    
    dechour = hour / 10;
    Serial.print(dechour); // выводим десятки часов
    unithour = hour % 10;
    Serial.print(unithour); // выводим единицы часов

    decminut = minut / 10;
    Serial.print(decminut); // выводим десятки минут
    unitminut = minut % 10;
    Serial.print(unitminut); // выводим единицы минут

    decsecond = second / 10;
    Serial.print(decsecond); // выводим десятки секунд
    unitsecond = second % 10;
    Serial.println(unitsecond); // выводим единицы секунд
   Serial.println(g_digits[0]); // выводим единицы секунд
   
}

 

kinder
Offline
Зарегистрирован: 29.03.2015

kinder
Offline
Зарегистрирован: 29.03.2015

красными прямоугольниками выделено не корректное время. И они чаще,  чем при использовании таймера2.

Pyotr
Offline
Зарегистрирован: 12.03.2014

Строки 15-23 не нужны. 
hour = time.Hours; ?? - есть time.Hours зачем ещё hour 

25-31 уберите volatile

Со стандартной библиотекой RTC пробовали?

kinder
Offline
Зарегистрирован: 29.03.2015

Pyotr пишет:

Строки 15-23 не нужны. 
hour = time.Hours; ?? - есть time.Hours зачем ещё hour 

25-31 уберите volatile

Со стандартной библиотекой RTC пробовали?

Строки 15-23  нужны. Потому что  в этих переменных храню значение цифры, которую вывожу на индикатор. Для того чтобы зажечь например цифру 5  отправляется определенная комбинация битов в сдвиговый регистр и включается соответствующий катод индикатора. При этом цифре пять соответствует комбинация битов, которые находятся в таблице g_digits[] под номером пять. Таким образом, чтобы вывести определенную цифру мне необходимо определить эту цифру из данных полученных от часов. Для чего и служат переменные в строках 15-23. 

hour - это переменная, которая хранит количество целых часов полученное от DS1307
  dechour =  - это переменная, которая хранит количество десятков часов
 

unithour = - это переменная, которая хранит количество единиц часов

и т.д.

volatile осталось от работы с таймером2. Не уверен, что это может влиять на работу часов. 

Для работы с часами использовал только библиотеку iarduino_RTC.h.  Подскажите пожалуйста название стандартной, а еще  лучше проверенной библиотекой. С которой не было проблем.

SLKH
Offline
Зарегистрирован: 17.08.2015

 "Снова проверил часы. Работают четко. " - меня терзают смутные сомненья...

Предлагаю:

loop() {

readRTC();

Serial.println("==================");

Serial.println();

delay(200);

}

void readRTC(){

//  из #27

}

kinder
Offline
Зарегистрирован: 29.03.2015
Для проверки часов использую следующий код

#include <iarduino_RTC.h>
iarduino_RTC time(RTC_DS1307);
void setup() {
    delay(300);
    Serial.begin(9600);
    time.begin();
}
void loop(){
    if(millis()%1000==0){ // если прошла 1 секунда
      Serial.println(time.gettime("d-m-Y, H:i:s, D")); // выводим время
      delay(1); // 
}

 

kinder
Offline
Зарегистрирован: 29.03.2015

kinder
Offline
Зарегистрирован: 29.03.2015

результат меня устраивает. Нет ни пропущенных секунд, ни испорченных данных.

SLKH
Offline
Зарегистрирован: 17.08.2015

kinder пишет:

результат меня устраивает. Нет ни пропущенных секунд, ни испорченных данных.

при этом испорченные данные откуда-то появляются при разборе полученной от часов информации?

вот я и предлагаю проверить, без прерываний, индикации и т.п.

не нравится вариант из #32 - можно к скетчу из #33 после строки 13 добавить, например,  строки 80 - 102 из #10.

 

и при нормальной нагрузке в цикле и пропущенные секунды появятся.

Logik
Offline
Зарегистрирован: 05.08.2014

SLKH пишет:

 я бы выкинул из SistemTimer() всё, кроме установки какого-то флага - мол, очередной тик пришел.

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

А цветом Вы выделили специально, чтоб все видели - это вредный совет? Наверно так.

Почему вредный? Смотрим и сравниваем 2 варианта реализации.

1. Как у Вас, прерывание установка флага в лупе - вся остальная работа.

2. Просто в лупе проверяем аппаратный флаг переполнения соответствующего таймера (или просто, на миллисе отмеряем ) и выполняем всю работу если он установлен.

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

Чем они различаются - в первом варианте время выполнения лупа еще и увеличилось на время обработки прерывания. Ну и код сложней разумеется в первом. А преимуществ перед 2 нет вобще.

ПС. Не помню кто на форуме продвигал эту дурь несусветную с установкой флажка в прерывании и обработкой в лупе, но практически всегда это просто глупость. За исключением случая, когда событие вызвавшее прерывание очень быстротечно, тогда флажок просто продлевает его, на время пока луп сможет активизироватся. Правильный стиль - обработчик прерывания выполняет работу быстро и завершается, если же ему нужно формировать временные интервалы, то он настраивает и запускает таймер и тоже завершается. А у таймера будет свой обработчик и он продолжит в том же стиле. Но это если луп неуспевает. В примере он все успевает, прерывания трогать не надо вобще.

 

 

kinder
Offline
Зарегистрирован: 29.03.2015

SLKH пишет:

kinder пишет:

результат меня устраивает. Нет ни пропущенных секунд, ни испорченных данных.

при этом испорченные данные откуда-то появляются при разборе полученной от часов информации?

вот я и предлагаю проверить, без прерываний, индикации и т.п.

не нравится вариант из #32 - можно к скетчу из #33 после строки 13 добавить, например,  строки 80 - 102 из #10.

и при нормальной нагрузке в цикле и пропущенные секунды появятся.

Пробовал и такой вариант 

прилагаю код

#include <iarduino_RTC.h>
iarduino_RTC time(RTC_DS1307);

byte hour = 0;
byte dechour = 0;
byte unithour = 0;
byte minut = 0;
byte decminut = 0;
byte unitminut = 0;
byte second = 0;
byte decsecond = 0;
byte unitsecond = 0;

void setup() {
    delay(300);
    Serial.begin(9600);
    time.begin();
}
void loop(){
    if(millis()%1000==0){ // если прошла 1 секунда
      Serial.println(time.gettime("d-m-Y, H:i:s, D")); // выводим время
       time.gettime();
    
    hour = time.Hours;
    Serial.print(hour); // выводим время
    minut = time.minutes;
    Serial.print(minut); // выводим время
    second = time.seconds;
    Serial.println(second); // выводим время
    
    
    dechour = hour / 10;
    Serial.print(dechour); // выводим десятки часов
    unithour = hour % 10;
    Serial.print(unithour); // выводим единицы часов

    decminut = minut / 10;
    Serial.print(decminut); // выводим десятки минут
    unitminut = minut % 10;
    Serial.print(unitminut); // выводим единицы минут

    decsecond = second / 10;
    Serial.print(decsecond); // выводим десятки секунд
    unitsecond = second % 10;
    Serial.println(unitsecond); // выводим единицы секунд
    delay(1); //
    }
}

 

kinder
Offline
Зарегистрирован: 29.03.2015

Данные получаются корректные.

Pyotr
Offline
Зарегистрирован: 12.03.2014
//Ваши 4 строки 
hour = time.Hours;
dechour = hour / 10;
cifra1 = dechour;
g_digits[cifra1]

//можно заменить двумя
cifra1 = time.Hours / 10;
g_digits[cifra1]

//или одной
g_digits[time.Hours / 10]
//это не решение проблемы, а совет

Я пользуюсь библиотекой DS1307new. Проблем не было.  В IDE конечно не включена библа для RTC.

Можно ещё попробовать вывод через аппаратный SPI.