Эхолот

76region
Offline
Зарегистрирован: 08.07.2011

Здравствуйте!

Есть у меня плата приемопередатчика от буржуйского старого эхолота, я ее восстановил и хочу поэкспереметировать. А вот в програмировании я начинающий по сему прошу помочь. плата имеет два выхода , импульс посылки (посылки плата генерирует сама) и импульс отраженный.В теории надо измерять время между этими импульсами и из этого получать расстояние. Также несложно сделать посылку импульса вручную ( то есть ардуиной) . Ну и собственно вопрос кто как видит программу которая это сможет сделать измерение времени между сигналами приходящими на 2 разных пина,или установка пина в "1" на допустим 10 мкс и отсчет времени до прихода высокого уровня на пин IN. Будем считать что приходящий сигнал имеет стандартный ттл уровень.

76region
Offline
Зарегистрирован: 08.07.2011

Интуиция мне подсказывает что нужно использовать таймер запускаемый импульсом посылки и считать время до получения ответного сигнала но как это отразить програмно я незнаю :)

 

leshak
Offline
Зарегистрирован: 29.09.2011

 

 >измерение времени между сигналами приходящими на 2 разных пина

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

Из второго времени вычесть первое.

>установка пина в "1" на допустим 10 мкс и отсчет времени до прихода высокого уровня на пин IN

Установить пин в "1", запомнить текущие время (время 1). Прибавить к нему 10мкс и сохранить как "время 3" (время когда пин нужно будет выключить). Ждать прихода высокого уровня на пин IN, запомнить текущие время (время2). От второго, отнять первое - искомая длительность.

Во время "Ждать прихода высокого уровня на пин IN" все время проверять "текущие время", если оно стало больше чем "время 3" (то есть от момента включения уже прошло 10мкс) - погасить первый пин.

Что-бы понять "как это все закодить", нужно почитать http://arduino.ru/Reference/Millis,arduino.ru/Reference/Micros,http://arduino.ru/Reference/AttachInterrupt

 

 

MAFia
Offline
Зарегистрирован: 26.10.2011
long Time1 = 0; //время подачи импульса
long Time2 = 0; //Время окончания импулса
long dTime =0;  //Время прохождения импулса
Void setup(){
pinMode (3,OUTPUT); //Подача импульса
attachInterrupt(4, Stop, RISING); /*Прерывание. Когда на входе 4 сигнал изменится с LOW на HIGH вызовется процедура Stop*/
Serial.begin //Инициализируем посл. соединение с компом
} 

void loop(){
digitalWrite(3,HIGH); //Посылаем сигнал
Time1 = micros();/*Засекаем время посылки импулса
delay(3);//Пауза, во время которой подается сигнал. Нужна, //чтобы схема эхолота сработала. Подбирается экспериментально*/
digitalWrite(3,LOW); //Прекращаем подачу импулса
}
//Вызывается, когда сигнал изменится с LOW на HIGH
void Stop(){
Time2 = micros() //Измеряем новое время.
dTime = Time2-Time1;
Serial.println(dTime);/*Отправляем время в комп. Можно так:
Serial.println(dTime/1000*330); Это расстояние в метрах. Только 330 м/с - скорость звука в воздухе, в воде не помню */
delay (100); /*Задержка. Чтобы не сильно тролить комп и избавится от всяких глюков.*/
}

 

leshak
Offline
Зарегистрирован: 29.09.2011

В фунциях-обработчиках прерываний (функция stop()), лучше не держать "ничего лишнего" (. Serial.print, все делаи и проч. лучше выносить в главный loop. В обработчике только самый необходимый минимум - захватили время, установили какой-нибудь флаг (что-бы loop знал что "пора что-то делать").

Так же глобальные  переменные которые используются в обработчике прерывания лучше объявлять с модификатором volatile

http://arduino.ru/Reference/Volatile

  •  

 

76region
Offline
Зарегистрирован: 08.07.2011

спасибо, поробую,отпишу что получилось

установили какой-нибудь флаг (что-бы loop знал что "пора что-то делать")  а можно на примере ?

leshak
Offline
Зарегистрирован: 29.09.2011

 Ну так в ссылке на документацию,которую я дал, есть же пример. Уставливают переменную state в обработчике, а используют ее в loop.

В вашем случае можно либо завести отдельную переменную (так код будет наглядней), например так:

long Time1 = 0; //время подачи импульса
volatile long Time2 = 0; //Время окончания импулса
long dTime =0;  //Время прохождения импулс

volatile  boolean stopRised=0;

Void setup(){
pinMode (3,OUTPUT); //Подача импульса
attachInterrupt(4, Stop, RISING); /*Прерывание. Когда на входе 4 сигнал изменится с LOW на HIGH вызовется процедура Stop*/
Serial.begin //Инициализируем посл. соединение с компом
} 

void loop(){

Time1 = micros();/*Засекаем время посылки импулса */
digitalWrite(3,HIGH); //Посылаем сигнал
delay(3);//Пауза, во время которой подается сигнал. Нужна, чтобы схема эхолота сработала. Подбирается экспериментально
digitalWrite(3,LOW); //Прекращаем подачу импулса

if(stopRised){ // прерывание "что-то словило", пока мы слали импульс, нужно это обработать

   dTime = Time2-Time1;
   .... репортим компу, включаем самоликвидатор и т.п.

   stopRised=0;// сбрасываем "флаг" в первоначальное состояние
}



}
//Вызывается, когда сигнал изменится с LOW на HIGH
void Stop(){
Time2 = micros() //Запомнили новое время
stopRised=1; //установили флаг что произошло прерывание и быстренько из него вышли

}

 При желании можно и без переменной stopRised обойтись. В качестве "признака" использовать Time2==0; 

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

Если за время "посылаем импульс" пришло несколько "ответок", то в Time2 попадет время последней ответки. Если нужно что-бы "первый", то в Stop() нужно проверять: если stopRised уже 1, то новое время запоминать не нужно. 

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

Если нужно что-бы "обработка импульса" не дожидалась окончания "посылаем" импульс, то нужно пользоватся не delay, а "включили излучатель", запомнили время когда его "нужно выключить", и дальше крутимся в loop. Все время проверяя: если настало время "пора выключить" - выключили, если stopRised==1 - обработали. Тогда они будут меньше "друг другу мешать", да еще на что-то другое у проца время останется.

76region
Offline
Зарегистрирован: 08.07.2011

большое спасибо буду пробовать

 

MAFia
Offline
Зарегистрирован: 26.10.2011

Кстате, в моем примере есть еще один косяк - delay(100). Delay нельзя использовать в прерываниях. 

76region
Offline
Зарегистрирован: 08.07.2011

вот поправил маленько, теперь вроде правильно считает, пока в теории без подключения к железу

long Time1 = 0; //время подачи импульса
volatile long Time2 = 0; //Время окончания импулса
long dTime =0;  //Время прохождения импулс

volatile  boolean stopRised=false;

void setup(){
pinMode (4,OUTPUT); //Подача импульса пин 4
attachInterrupt(1, Stop, RISING); /*Прерывание. Когда на входе 3 сигнал изменится с LOW на HIGH вызовется процедура Stop*/
Serial.begin(9600) ; //Инициализируем посл. соединение с компом
} 

void loop(){

Time1 = micros();/*Засекаем время посылки импулса */
digitalWrite(4,HIGH); //Посылаем сигнал
delay(3);//Пауза, во время которой подается сигнал. Нужна, чтобы схема эхолота сработала. Подбирается экспериментально
digitalWrite(4,LOW); //Прекращаем подачу импулса

if(stopRised== true){ // прерывание "что-то словило", пока мы слали импульс, нужно это обработать

   dTime = Time2-Time1;
  
Serial.println(dTime);// .... репортим компу, включаем самоликвидатор и т.п.
   stopRised=false;// сбрасываем "флаг" в первоначальное состояние
}



}
//Вызывается, когда сигнал изменится с LOW на HIGH
void Stop(){
Time2 = micros(); //Запомнили новое время
stopRised=true; //установили флаг что произошло прерывание и быстренько из него вышли

}

 

Warn
Offline
Зарегистрирован: 13.01.2012

на железе проверил я, только у меня ультразвуковой эхолот.

прога ловит прерывания от себя: в момент активации элолота, приёмник эхолота ловит передатчик, после на какое-то время эфир чист, потом приходит отражение.

в итоге она мерить то мериет, но делает это неправильно.

так как идёт засветка приёмника в момент передачи.

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

76region
Offline
Зарегистрирован: 08.07.2011

а так

long Time1 = 0; //время подачи импульса
volatile long Time2 = 0; //Время окончания импулса
long dTime =0;  //Время прохождения импулс

volatile  boolean stopRised=false;

void setup(){
pinMode (4,OUTPUT); //Подача импульса пин 4
attachInterrupt(1, Stop, RISING); /*Прерывание. Когда на входе 3 сигнал изменится с LOW на HIGH вызовется процедура Stop*/
Serial.begin(9600) ; //Инициализируем посл. соединение с компом
} 

void loop(){

Time1 = micros();/*Засекаем время посылки импулса */
digitalWrite(4,HIGH); //Посылаем сигнал
delay(3);//Пауза, во время которой подается сигнал. Нужна, чтобы схема эхолота сработала. Подбирается экспериментально
digitalWrite(4,LOW); //Прекращаем подачу импулса

if(stopRised== true){ // прерывание "что-то словило", пока мы слали импульс, нужно это обработать

   dTime = Time2-Time1;
   if (dTime>100) { // если полученное время меньше 100мкс то игнорируем результат      
  
Serial.println(dTime); // .... репортим компу, включаем самоликвидатор и т.п.
   }
   stopRised=false;// сбрасываем "флаг" в первоначальное состояние
}



}
//Вызывается, когда сигнал изменится с LOW на HIGH
void Stop(){
Time2 = micros(); //Запомнили новое время
stopRised=true; //установили флаг что произошло прерывание и быстренько из него вышли

}

 

Warn
Offline
Зарегистрирован: 13.01.2012

завтра проверю, и отпишу результат. Я пытался использовать команду detachInterrupt, но в голову почему-то не пришло то, что можно просто делать проверку на результат. Завтра напишу конкретные цифры которые она шлёт в сериал.

484 2284 2288 2996 2992 3000 3020 384 2996 2996 2996 3024 2996 3004 3024 3012 3028 464 2992 128 3012 356 3004 3008 188 2992 3008 3024 3020 2616 2996 3008 2996 3036 548 3012 3008 3016 3008 108 2896 164 3000 3024 3016 3000 2968 1244
 

 1.

Я тоже начинающий программист, но думаю что могут быть ещё и следующие ошибки. Программа крутится в цикле нереально быстро, там 16мгц.

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

надо где-то использовать delay на максимальное расстояние, но delay это очень плохо, так как в этот момент у меня "танк" едет вперёд. А delay делает тупое зависание всего контроллера, кроме прерывания. В общем надо думать.

2.

Как каждый раз в начале цикла в loop сбрасывать значение micros в ноль.

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

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

leshak
Offline
Зарегистрирован: 29.09.2011

 >Я тоже начинающий программист, но думаю что могут быть ещё и следующие ошибки

Хоть вы и "начинающий", но интуиция вас не подвела :)  Они есть в любой программе больше 10-ти строчек ;) Более того, вы их еще и увидеть правильно смогли. Так что дай бо что-бы все "начинающие" были такими.

>но delay это очень плохо, так как в этот момент у меня "танк" едет вперёд

Плохо, но по другим причинам. За то время пока сигнал мотнется "туда-сюда" танк далеко уехать не успеет. Все-таки скорости у них довольно разные ;) Так что за это можно не переживать.

>надо где-то использовать delay

Вы правы. Нужно. После "digitalWrite(4,LOW); //Прекращаем подачу импулса", но до ""if(stopRised== true){"

Тут не "танк", а сам контроллер "уедет дальше" не успев дождаться отражения импульса. Между ними "нужно немного подождать" и,  вы опять правы, лучше это делать не через delay(), а как-то так

while(stopRised==false){} //крутим бесконечный пустой цикл, до тех пор пока не произойдет прерывание

Получается это тот же "delay", но до "ожидания сработки импульса". Возможно в него нужно будет добавить какой-то счетчик-ограничение. Если импульс уйдет "в белый свет" и не отразится вообще, что-бы он не зависал на этом. Что-то типа "если 300 милисекунд ответа не дождались, то все сбрасывать и начинать все сначало" ( не зря вы про ""delay на максимальное расстояние" думали )

76region
Offline
Зарегистрирован: 08.07.2011

Warn на каком железе проверяете? Чтото самодельное ?

Warn
Offline
Зарегистрирован: 13.01.2012
long Time1 = 0; //время подачи импульса
volatile long Time2 = 0; //Время окончания импульса
long dTime =0;  //Время прохождения импульса

volatile  boolean stopRised=false;

void setup(){
pinMode (4,OUTPUT); //Подача импульса пин 4
attachInterrupt(1, Stop, RISING); /*Прерывание. Когда на входе 3 сигнал изменится с LOW на HIGH вызовется процедура Stop*/
Serial.begin(9600) ; //Инициализируем посл. соединение с компом
} 

void loop(){


Time1 = micros();/*Засекаем время посылки импулса */
digitalWrite(4,HIGH); //Посылаем сигнал
delayMicroseconds(450);//Пауза, во время которой подается сигнал. Нужна, чтобы схема эхолота сработала. Подбирается экспериментально
digitalWrite(4,LOW); //Прекращаем подачу импулса
if (stopRised== true) {
   dTime = Time2-Time1;
   if (dTime>100) { // если полученное время меньше 100мкс то игнорируем результат      
      Serial.println(dTime); // .... репортим компу, включаем самоликвидатор и т.п.
      Serial.println('work');
      }
  } 
  else {delay(10);
}
   } 
void Stop(){
Time2 = micros(); //Запомнили новое время
stopRised=true; //установили флаг что произошло прерывание и быстренько из него вышли
}

 

Проверяю на ультразвуковом самодельном дальномере. Передатчик на ne555, приёмник на операционнике.

Переписал чуть чуть, но всё-равно как-то не так работает, но уже лучше. И от delay пока не избавился.