#1 2017-07-16 22:03:36

navernjaka
Участник
Зарегистрирован: 2017-07-16
Сообщений: 1

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

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

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

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

#2 2017-07-29 08:04:15

Green
Участник
Зарегистрирован: 2015-11-08
Сообщений: 279

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

Вариантов всегда несколько. Один из.
Формируете системный тик. Не менее частоты динамической индикации.
По тику формируете временные интервалы для работы с датчиками.
Важно (для индикации!) что бы главный цикл не превышал время системного тика.

Редактировался Green (2017-07-29 08:05:21)

#3 2017-07-29 08:23:47

vvr
Участник
Зарегистрирован: 2015-04-12
Сообщений: 351

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

а зачем MsTimer2 для опроса часов ?
и без него всё прекрасно работает

#4 2017-07-29 09:33:36

Вячеслав Азаров
Участник
Из Запорожье
Зарегистрирован: 2017-05-25
Сообщений: 406

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

navernjaka пишет:

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

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

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

Приехали. smile  Вы здесь первый кто задает такие вопросы. Что касается параллельных процессов то на одно-процессорных компьютерах могут быть только квази-параллельные. Т.е. имитация параллелизма многозадачным монитором. По сути же, все вычисления выполняются последовательно. Относительно ваших часиков, сначала убедитесь в исправности DS1307 и его драйвера (класса), а так же в качестве электрических сигналов соединений в привилегированном режиме, без других вычислений. Для того что-бы определить время выполнения фрагментов программ существуют специальные программы - профайлеры, но в Ардуино их нет. Для простых фрагментов Можно сделать вывод ассемблерного листинга и посчитать время выполнения инструкций процессора вручную. В любом случае, для плоской модели прерываний (для всех Мег), задержка обслуживания прерываний может составлять время выполнения самого "длинного" обработчика прерывания. Время необходимое на передачу данных по интерфейсам можно определить зная скорость передачи и протокол обмена. В Ардуино можно использовать функцию millis() для определения времени выполнения с точностью до 1 мс, разностным методом.

Редактировался Вячеслав Азаров (2017-07-29 10:00:54)

#5 2017-07-29 18:22:44

qwone
Участник
Зарегистрирован: 2016-07-25
Сообщений: 104

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

Что бы мне не писать долго, то прочтите это.http://rsdn.org/article/baseserv/RUThreadingMethodology.xml

#6 2017-07-29 18:33:59

lkj
Участник
Зарегистрирован: 2016-02-03
Сообщений: 84

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

Микропроцессор - не мощный процессор для которых написана та статья.

#7 2017-07-29 19:11:22

qwone
Участник
Зарегистрирован: 2016-07-25
Сообщений: 104

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

lkj пишет:

Микропроцессор - не мощный процессор для которых написана та статья.

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

#8 2017-07-29 19:26:26

lkj
Участник
Зарегистрирован: 2016-02-03
Сообщений: 84

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

qwone пишет:
lkj пишет:

Микропроцессор - не мощный процессор для которых написана та статья.

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

Автоматическое распараллеливание (функция предварительного анализа)
Компилятор Intel C++ 7.1 включает функцию автоматического распараллеливания циклов. Эта функция производит поиск циклов, которые можно безопасно выполнять параллельно, и автоматически генерирует для них многопоточный код. Автоматическое распараллеливание освобождает разработчика от необходимости вникать в детали разбиения циклов, совместного использования данных, планирования потоков и синхронизации.

Хотя бы полистайте документацию на Atmega328

#9 2017-07-29 19:32:43

Вячеслав Азаров
Участник
Из Запорожье
Зарегистрирован: 2017-05-25
Сообщений: 406

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

Статья касается многопроцессорных систем.  Основная цель этой задачи - уменьшение времени вычислений за счет реального параллелизма. Это не для микроконтроллеров а для многоядерных процессоров и кластерных суперкомпьютеров. Хотя уже есть и такие микроконтроллеры.

Редактировался Вячеслав Азаров (2017-07-29 19:37:46)

#10 2017-07-29 20:46:28

Green
Участник
Зарегистрирован: 2015-11-08
Сообщений: 279

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

Бедный navernjaka. Называется, задал первый вопрос.)) Молчит, даже слова сказать не может... Хотя да, есть такой метод обучения плаванию - сразу на глубину. А там, если выплывет - молодец, не выплывет - значит не пловец...

Редактировался Green (2017-07-29 20:50:51)

#11 2017-08-28 21:25:35

rf68
Гость

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

//Подключаем библиотеки для работы часов реального времени

#include <DS3231.h>
#include <Wire.h>

// выводы для дешифратора
  int out1 = A3;
  int out2 = A1;
  int out4 = A0;
  int out8 = A2;
// выводы для транзисторных ключей
  int key1= 4;
  int key2 = 6;
  int key3 = 7;
  int key4 = 8;

  int led1=11;// вывод светодиода
  int keyb=A6;// пин для клавиатуры


  int keynum=0; //номер нажатой кнопки
  int mode =0; //0 - отображение текущего времени 1- установка времени
  int currentdigit = 0; //0 - установка часов 1- установка минут
  bool blinkflag = 0; // флаг для мигания цифр при установке времени
  bool timeout=false; // таймаут после нажатия кнопки (для устраниния дребезга)
  unsigned long startTime; //для мигания светодиода
  unsigned long startTime2; // для опроса нажатых кнопок
  int sec; //переменная увеличивается каждые 500мс на единицу. Нужна для мигания секундных светодиодов, бывает в двух значениях 0 - светодиоды не горят, 1 - горят, если больше 1, то сбрысывается в 0
    //переменные для счетчиков
    int v = 0, p = 7, k = 0, lock = 0;
  // переменные, необходимые для работы ds3231
  DS3231 Clock;
  bool Century=false;
  bool h12;
  bool PM;
  byte ADay, AHour, AMinute, ASecond, ABits;
  bool ADy, A12h, Apm;

  //определяем глобальные переменные для различных параметров часов
  int second,minute,hour,date,month,year,temperature;


void setup() {
  // put your setup code here, to run once:
  // задаем частоту ШИМ на 9 выводе 30кГц
  TCCR1B=TCCR1B&0b11111000|0x01;
  analogWrite(9,130);

    // Start the I2C interface
  Wire.begin();
  // Start the serial interface
  Serial.begin(9600);
 
  //задаем режим работы выходов микроконтроллера
  pinMode(out1,OUTPUT);
  pinMode(out2,OUTPUT);
  pinMode(out4,OUTPUT);
  pinMode(out8,OUTPUT);

  pinMode(key1,OUTPUT);
  pinMode(key2,OUTPUT);
  pinMode(key3,OUTPUT);
  pinMode(key4,OUTPUT);

  pinMode(led1,OUTPUT);

  startTime = millis();
  startTime2=startTime;
  sec = 0;
  // считываем текущее вермя
  ReadDS3231();
}

void ReadDS3231()   //функция считывает в глобальные переменные minute и hour текущие значения
{
  minute=Clock.getMinute();
  hour=Clock.getHour(h12, PM);
}


void loop() {
  // put your main code here, to run repeatedly:
   
  k++;//счетчик для мигания цифрами
  v++;//счетчик для пебора всех цифр

  if (v >= 32760) {//делам прогон всех цифр во избежание "Отравление" катодов ламп
    scroll(25);
    v = 0;
  }
  int digits[3]; // массив для текущего значения времени на четыре цифры
  int keyval= analogRead(keyb); // считываем значение с клавиатуры
 
  unsigned long currentTime = millis(); //текущее время с момента запуска рограммы
   if (currentTime>=(startTime2+200)) // если прошло 200мс посмотрим какая кнопка была нажата
   {
      timeout=false;
     //проверим нажатие кнопок
      if (keynum==3) // кнопка переключения между режимами "время" и "настройка"
      {
        timeout=true; // запрещаем считывать нажатия кнопок
        if (mode==0) mode=1; // если отображалось время, переходим в режим настроек
        else
          if (mode==1) mode=0; //если был режим настроек, переключаемся на текущее время
      }
      if (keynum==2) // кнопка переключения между часами и минутами
      {
        timeout=true; // запрещаем считывать нажатия кнопок
        // currentdigit либо 0 - настройка часов, либо 1 - настройка минут
        currentdigit++;
        if (currentdigit==2) currentdigit=0;
      }
      if (keynum==1) // кнопка увеличения количества часов или минут(при настройке)
      {
        blinkflag=true; // прекращаем мигать цифрами
        startTime=millis();
        timeout=true;  // запрещаем считывать нажатия кнопок
        if (currentdigit==0) // если меняем часы
        {
          if (hour<=22) hour++;
          else
            hour=0;
          Clock.setHour(hour);
        }
        if (currentdigit==1) // если меняем минуты
        {
          if (minute<=58) minute++;
          else
            minute=0;
         Clock.setMinute(minute);//Set the minute
         Clock.setSecond(0);
        }
      }
      keynum=0; //сбрасываем нажатую кнопку
      startTime2=millis();
   }

  if (currentTime>=(startTime+500)) // если прошло 500мс
  {
    blinkflag=!blinkflag; // инвертируем флаг мигающей цифры
     
    if(sec<1) // светодиоды не горят
    {
      // зажечь светодиоды
      digitalWrite(led1,HIGH);
      Serial.println(blinkflag);
     
    }
    if(sec>=1) // светодиоды горят
    {
      // потушить светодиоды
      digitalWrite(led1,LOW);
    }
    startTime = currentTime;
    ReadDS3231();
    sec = (sec+1);
    if(sec>=2) sec=0;

  }
    digits[0] = hour/10;
    digits[1] = hour%10;
    digits[2] = minute/10;
    digits[3] = minute%10;

    show(digits); // вывести цифры на дисплей

  //проверяем нажатые кнопки
  if(!timeout) //если разрешено, считываем нажатую кнопку
  {
    /*keyval - значение функции analogread
     * если нажата первая кнопка, то принимает значение около 200
     * если нажата вторая кнопка то значение около 700
     * если третяя кнопка, то значение будет около 1000
     * эти значения зависят от выбранных резисторов в клавиатуре
    */
    if (keyval>150 && keyval<400) keynum=1;
    if (keyval>700 && keyval<900) keynum=2;
    if (keyval>960) keynum=3;
  }

}
//пебора всех цифр
void scroll(int pause) {
  for (int i = 0; i < 9; i++) {
    int a[] = {i, i, i, i, i, i};
    show(a);
    delay(pause);
  }}
void show(int a[])
{
    //выведем цифру a[0] на первый индикатор
  setNumber(a[0]);
  if (!(mode==1&&currentdigit==0&&blinkflag==false)) //если мы в режиме настройки и происходит настройка часов, то в первая цифра будет мигать
  {
    digitalWrite(key1,HIGH);
    delay(2);
    //потушим первый индикатор
    digitalWrite(key1,LOW);
    delay(1);
  }
 
  //цифра a[1] на второй индикатор
  setNumber(a[1]);
  if (!(mode==1&&currentdigit==0&&blinkflag==false))
  {
  digitalWrite(key2,HIGH);
  delay(2);
  //потушим второй индикатор
  digitalWrite(key2,LOW);
  delay(1);
  }

  //цифра a[2] на третий индикатор
  setNumber(a[2]);
  if (!(mode==1&&currentdigit==1&&blinkflag==false))
  {
  digitalWrite(key3,HIGH);
  delay(2);
  //потушим третий индикатор
  digitalWrite(key3,LOW);
  delay(1);
  }

  //выведем цифру a[3] на четвертый индикатор
  setNumber(a[3]);
  if (!(mode==1&&currentdigit==1&&blinkflag==false))
  {
  digitalWrite(key4,HIGH);
  delay(2);
  //потушим четвертый индикатор
  digitalWrite(key4,LOW);
  delay(1);
  }
}
// передача цифры на дешифратор
void setNumber(int num)
{
  switch (num)
  {
    case 0:
    digitalWrite (out1,LOW);
    digitalWrite (out2,LOW);
    digitalWrite (out4,LOW);
    digitalWrite (out8,LOW);
    break;
    case 1:
    digitalWrite (out1,HIGH);
    digitalWrite (out2,LOW);
    digitalWrite (out4,LOW);
    digitalWrite (out8,LOW);
    break;
    case 2:
    digitalWrite (out1,LOW);
    digitalWrite (out2,HIGH);
    digitalWrite (out4,LOW);
    digitalWrite (out8,LOW);
    break;
    case 3:
    digitalWrite (out1,HIGH);
    digitalWrite (out2,HIGH);
    digitalWrite (out4,LOW);
    digitalWrite (out8,LOW);
    break;
    case 4:
    digitalWrite (out1,LOW);
    digitalWrite (out2,LOW);
    digitalWrite (out4,HIGH);
    digitalWrite (out8,LOW);
    break;
    case 5:
    digitalWrite (out1,HIGH);
    digitalWrite (out2,LOW);
    digitalWrite (out4,HIGH);
    digitalWrite (out8,LOW);
    break;
    case 6:
    digitalWrite (out1,LOW);
    digitalWrite (out2,HIGH);
    digitalWrite (out4,HIGH);
    digitalWrite (out8,LOW);
    break;
    case 7:
    digitalWrite (out1,HIGH);
    digitalWrite (out2,HIGH);
    digitalWrite (out4,HIGH);
    digitalWrite (out8,LOW);
    break;
    case 8:
    digitalWrite (out1,LOW);
    digitalWrite (out2,LOW);
    digitalWrite (out4,LOW);
    digitalWrite (out8,HIGH);
    break;
    case 9:
    digitalWrite (out1,HIGH);
    digitalWrite (out2,LOW);
    digitalWrite (out4,LOW);
    digitalWrite (out8,HIGH);
    break;
  }
}
https://youtu.be/CXWt-Is_Eo8
схема надо?

Быстрое сообщение

Введите сообщение и нажмите Отправить

Подвал раздела