Подсчет времени на автосоревнованиях

Adeni
Offline
Зарегистрирован: 26.01.2014

Разрабаотываю систему автоматичского подсчета времени для автомобильных соревнований, в частности для автослалома. Заезды парные, а занчит надо одновременно обрабатывать 2 результата. Примерную схему на макетке собрал, вроде работает как задумано. Время пока вывожу в Serial.print, т.к. 8 разрядные дисплеи еще не приехали.

Вместо светофора пока что диоды, в планах сделать их из таких вот штук: 

В качестве створа использую инфракрасный барьер BM083 от Мастеркит.

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

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

#define DATA_PIN    3 // пин данных (англ. data) 14 на микросхеме
#define LATCH_PIN   5 // пин такта (англ. clock) 11 на микросхеме
#define CLOCK_PIN   4 // пин строба (англ. latch) 12 на микросхеме
#define BUTTON_PIN  2  // пин сброса

#define DATA_PIN2    7 // пин данных (англ. data) 14 на микросхеме
#define LATCH_PIN2   9 // пин такта (англ. clock) 11 на микросхеме
#define CLOCK_PIN2   8 // пин строба (англ. latch) 12 на микросхеме
#define BUTTON_PIN2  6  // пин сброса

unsigned long time;
unsigned long time2;
unsigned long time22;
unsigned long time3;
unsigned long time4;
int buttonState =0;
//int buttonState2 =0;
int firstcarrun =0; //Если 1, переменные означают что машина проехала створ первый раз и находится на трассе
int secondcarrun =0;
int finish = 0;
int finish2 = 0;
int reset = 0; //Переменная для повторного заезда
int start = 0; //Если 0 процедура старта еще не прошла
int start2 = 0;
long previousMillis = 0;
long PM1 = 0; //
long PM2 = 0; // Переменные для хрянания предыдущего значения millis() при выполнении задержек
long PM3 = 0; //
long PM4 = 0; //
long interval = 1000; //Время задержки
int st = 0; ////
int st1 = 1;////// Переменные для процедуры старта (светофора)
int st2 = 1;////
int st3 = 1;//
int sensorPin = A0;            // устанавливаем входную ногу для створа
//unsigned int sensorValue = 0;  // цифровое значение фоторезистора
byte segments[7] = {
  254,250,234,213,191,127,255};//К,КК,ККК,ЗЗЗ,000К,000С,0000
byte segments2[6] = {
  254,252,248,239,247,255};//Y,YY,YYY,000G,000R,0000
int currentseg;
int currentseg2;
int fc1 = 0; //Переменная для определения первого пересечения створа
int fc2 = 0;
int lc1 = 0; //Переменная для определения второго и далее пересечения створа
int lc2 = 0;
int krug = 2; //Какое по счету пересечение створа считать финишем. 2 значит первый проход не считаем, т.к. его проехал соперник
int lp1 = 0; //Переменная для подсчета кол-ва кругов
int lp2 = 0;
long lt1 = 0;// Переменная для суммирования времени пройденных кругов
long lt2 = 0;


void setup(){
  Serial.begin(9600);
  pinMode(DATA_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);
  pinMode(DATA_PIN2, OUTPUT);
  pinMode(CLOCK_PIN2, OUTPUT);
  pinMode(LATCH_PIN2, OUTPUT);
  pinMode(BUTTON_PIN2, INPUT);


}
void loop(){
  //delay(5000);
  long currentMillis = millis();
  //-----------------ПРОЦЕДУРА СТАРТА----------------------------------------------------------
  if (start == 0){ 
    if (currentMillis - previousMillis > interval && st == 0) {
      currentseg=0;
      currentseg2=0;
      wrt();
      Serial.println("1");
      previousMillis = currentMillis;
      st=1;
      st1=0;
    }
    if (currentMillis - previousMillis > interval && st1 == 0){
      currentseg=1;
      currentseg2=1;
      wrt();
      previousMillis = currentMillis;
      Serial.println("2");
      st1=1;
      st2=0;
    }
    currentMillis = millis();
    if (currentMillis - previousMillis > interval && st2 == 0){
      currentseg=2;
      currentseg2=2;
      wrt();
      previousMillis = currentMillis;
      Serial.println("3");
      st2=1;
      st3=0;
    }
    currentMillis = millis();
    if (currentMillis - previousMillis > interval && st3 == 0){
      currentseg=3;
      currentseg2=3;
      wrt();
      start = 1;
      start2 = 1; 
      time2 = millis();
      time22 = millis();
      Serial.println("START");
      //Serial.println(analogRead(sensorPin));
      st3 = 1;
    }
    //---------------ДЛЯ ПЕРВЫХ ВОРОТ------------------------------    
    if (analogRead(sensorPin) < 100){//Если первые ворота пересекли раньше, то фальстарт
      falstart();
    }
    //---------------ДЛЯ ВТОРЫХ ВОРОТ------------------------------
    if (digitalRead(BUTTON_PIN2) == HIGH ){//Если вторые ворота пересекли раньше, то фальстарт
      falstart2();
    }

    //if (digitalRead(BUTTON_PIN2) == HIGH) falstart2();//Фальстарт 2 ворота -РАСКОММЕНТИРОВАТЬ
  }
  //------------КОНЕЦ ПРОЦЕДУРЫ СТАРТА-------------------------------------------------------------------- 

  //Если был старт на любых из ворот и нажали кнопку сброса, то начинаем сначала
  if (start == 2 && digitalRead(BUTTON_PIN ) == HIGH) rst();
  if (start2 == 2 && digitalRead(BUTTON_PIN ) == HIGH) rst();
  //----------------------------------------------------------------------------
  //if (start == 1 && firstcarrun == 1) {
  /*digitalWrite(12, HIGH);
   digitalWrite(10, HIGH);
   digitalWrite(8, HIGH);*/

  //}
  time = millis();
  //buttonState = analogRead(sensorPin);//digitalRead(2);
  reset = digitalRead(BUTTON_PIN);

  // Если проезд свободен (кнопка отжата)
  if (analogRead(sensorPin) > 600/*== LOW*/ && firstcarrun == 0) {
  }
  //Если машина перекрыла проезд первый раз (кнопка нажата, луч перекрыт)
  else if (/*buttonState == HIGH*/analogRead(sensorPin) < 600 && firstcarrun == 0 && start == 1 && fc1 == 0)
  {
    first();
  }
  //Если машина перекрыла проезд второй раз (кнопка нажата, луч перекрыт)
  else if (/*buttonState == HIGH*/analogRead(sensorPin) < 600 && firstcarrun == 1 && lc1 == 0 && finish == 0)
  {
    lap();
  }
  // Если машина на трассе (кнопка отжата, луч свободен)
  else if (analogRead(sensorPin) < 600 && firstcarrun == 1)
  {
  }
  if (digitalRead(BUTTON_PIN2) == HIGH && secondcarrun == 0 && start2 == 1 && fc2 == 0)
  {
    first2();
  }
  //Если машина перекрыла проезд второй раз (кнопка нажата, луч перекрыт)
  else if (digitalRead(BUTTON_PIN2) == HIGH && secondcarrun == 1 && lc2 == 0 && finish2 == 0)
  {
    lap2();
  } 
  if (reset == HIGH)//) && finish == 1)
  {
    rst();
  }
  if (PM1 >0) zaderzka(1, 5000, PM1);
  if (PM2 >0) zaderzka(2, 5000, PM2);
  if (PM3 >0) zaderzka(3, 2000, PM3);
  if (PM4 >0) zaderzka(4, 2000, PM4);

}

void first(void)
{
  Serial.println("Pervy raz peresekli 1 stvor");
  PM1 = millis();
  fc1 = 1;
}
void first2(void)
{
  Serial.println("Pervy raz peresekli 2 stvor");
  PM2 = millis();
  fc2 = 1;
}


void lap(void)
{
  currentseg=5;
  wrt();
  time3 = millis() - time2;
  lt1 = lt1 + time3; //Суммируем времена кругов
  lp1 = lp1 + 1; //Суммируем круги
  Serial.println("");
  if (lp1 == krug) {
    Serial.println("Peresekli stvor 1 - FINISH");
    laptime(lt1);
    finish = 1;
  }
  else {
    Serial.println("Peresekli stvor 1 - LAP");
    laptime(time3);
  }
  time2 = millis();
  lc1 = 1;
  PM3 = millis();
}

void lap2(void)
{
  currentseg2=0;
  wrt();
  time3 = millis() - time22;
  lt2 = lt2 + time3; //Суммируем времена кругов
  lp2 = lp2 + 1; //Суммируем круги
  Serial.println("");
  if (lp2 == krug) {
    Serial.println("Peresekli stvor 2 - FINISH");
    laptime(lt2);
    finish2 = 1; 
  }
  else {
    Serial.println("Peresekli stvor 2 - LAP");
    laptime(time3);
  }
  /*Serial.print("Krugov - ");
   Serial.println(lp2);*/
  time22 = millis();
  lc2 =1;
  PM4 = millis();
}

void falstart(void)
{
  Serial.println("FALSH START 1 VOROTA");
  start=2; //Фальстарт
  start2=2;
  currentseg=4;
  currentseg2=4;
  wrt();
}
void falstart2(void)
{
  Serial.println("FALSH START 2 VOROTA");
  start=2;
  start2=2; //Фальстарт
  currentseg=4;
  currentseg2=4;
  wrt();
}

void rst(void)
{
  firstcarrun = 0;
  secondcarrun = 0;
  finish = 0;
  finish2 = 0;
  time2 = 0;
  time22 = 0;
  start = 0;
  start2 = 0;
  previousMillis = millis();
  st=0;
  st1=1;
  st2=1;
  st3=1;
  fc1 = 0;
  fc2 = 0;
  lp1 = 0;
  lp2 = 0;
  lt1 = 0;
  lt2 = 0;
  Serial.println("Najali sbros");
  currentseg=6;
  currentseg2=5;
  wrt();
  delay(1000);

}

void wrt(void)
{
  // для записи в 74HC595 нужно притянуть пин строба к земле
  digitalWrite(LATCH_PIN, LOW);
  digitalWrite(LATCH_PIN2, LOW);
  // задвигаем (англ. shift out) байт-маску бит за битом, начиная со старшего бита
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, segments[currentseg]);
  shiftOut(DATA_PIN2, CLOCK_PIN2, MSBFIRST, segments2[currentseg2]);
  // чтобы переданный байт отразился на выходах Qx, нужно
  // подать на пин строба высокий сигнал
  digitalWrite(LATCH_PIN, HIGH);
  digitalWrite(LATCH_PIN2, HIGH);
}

void zaderzka(int p, int t, long z){//Параметр - Время задержки - Время с которым спавнивать
  if (millis() - z > t){// && (firstcarrun == 0 || secondcarrun == 0)) {
    if (p == 1) {
      currentseg = 6;
      firstcarrun = 1;
      start = 1;
      PM1=0;
      wrt();
    }
    if (p == 2) {
      currentseg2 = 5;
      secondcarrun = 1;
      start2 = 1;
      PM2=0;
      wrt();
    }
    if (p == 3) {
      currentseg=6;
      wrt();
      PM3=0;
      lc1=0; 
    }
    if (p == 4) {
      currentseg2=5;
      wrt();
      PM4=0;
      lc2=0; 
    }
  }
}

void laptime(long tm){//Выводим время круга
  //Вычисляем минуты
  int minut = tm/60000;//Вычисляем минуты
  char stringminut[2];
  itoa(minut,stringminut,10);//Преобразуем число в строку
  int lenminut = strlen(stringminut);//Определяем сколько символов в минутах
  //Вычисляем секунды
  int secund = (tm %60000)/1000;
  char stringsecund[2];
  itoa(secund,stringsecund,10);//Преобразуем число в строку
  int lensecund = strlen(stringsecund);//Определяем сколько символов в секундах
  //Вычисляем тысячные доли секунды
  int tyssec = (tm %60000)%1000;
  char stringtyssec[3];
  itoa(tyssec,stringtyssec,10);//Преобразуем число в строку
  int lentyssec = strlen(stringtyssec);//Оопределяем сколько символов в сотых секундах*/
  Serial.print("Lap time: ");
  if (lenminut == 1) {
    Serial.print("0");
    Serial.print(minut); 
  } 
  else Serial.print(minut);
  Serial.print(":");
  if (lensecund == 1) {
    Serial.print("0");
    Serial.print(secund);
  } 
  else Serial.print(secund);
  Serial.print(":");
  if (lentyssec == 1) {
    Serial.print("00");
    Serial.println(tyssec);
  }
  else if (lentyssec == 2) {
    Serial.print("0");
    Serial.println(tyssec);
  }
  else Serial.println(tyssec);
}

 

svk
Offline
Зарегистрирован: 12.02.2014

Интересный проект. Хотелось бы повторить, если не против. Можно более подробно описать подключение?

Adeni
Offline
Зарегистрирован: 26.01.2014

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

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

Чуть позже выложу переделнную программку и нарисую схему подключения ИК барьера и 7 сигментных дисплеев.

svk
Offline
Зарегистрирован: 12.02.2014

Хорошо, буду ждать!

hotjonny
Offline
Зарегистрирован: 25.11.2012

Adeni, а вы не используете часы реального времени?

 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

если машинки пришли на финиш с разницей по дистанции меньше корпуса машинки - как фотобарьер увидит отставшую машинку ? т.е. - её время прохождения трассы ?

Adeni
Offline
Зарегистрирован: 26.01.2014

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

1.Часы реального времени не использую, мне они пока ни к чему. Вот если развивать идею дальше, например для использования в Р3К или Р1К, тогда да, они нужны будут. 

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

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Adeni пишет:

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

1.Часы реального времени не использую, мне они пока ни к чему. Вот если развивать идею дальше, например для использования в Р3К или Р1К, тогда да, они нужны будут. 

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

по ширине полосы финиша - не знаю.... вариант - вертикальные фотобарьеры в двух полосах финиша, излучатели снизу - приёмники на растяжке сверху.... на каждую полосу можно поставить 2...3 датчика ( для расширения полосы захвата ) - зависит от ширины створа финиша....

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

что есть - "Р3К или Р1К" ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

> радиометки на каждую машину. Но насколько я знаю это не дешевое удовольствие. Дальнобойные RFID это моя мечта.

у RFID диаграмма направленности круговая.... невозможно по нему определить проезд ТРАВЕРЗА датчика финиша :( 

Adeni
Offline
Зарегистрирован: 26.01.2014

Р3К - это любительское ралли на стоковых автомобилях. Р1К - это профессиональное ралли на боевых, подготовленных автомобилях (как WRC).

Интересно на какой технологии построено отслеживание времени на круговых соревнованиях, типа Формула-1.

crwdc
Offline
Зарегистрирован: 24.08.2015

Автор отпиши на емейл плиз! есть несколько вопросов ! crwdc@mail.ru

alex_lisonok
Offline
Зарегистрирован: 06.12.2016

Здравствуйте Adeni! Получилось? Просто сейчас решаю похожую задачу (но у меня не про машины, а про собак :) ) хотел бы проконсультироваться. Реально? Заранее благодарю.