Официальный сайт компании Arduino по адресу arduino.cc
HC-SR04 безбожно врёт
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Помогите решить проблему. Требуется создать GPS трекер для грузовых контейнеров, который помимо координат должен передавать наполненность контейнера, вскрытие и пожар. Основное требование - устройство должно работать без зарядки до 6 месяцев. В качестве датчика наполнения я выбрал ультразвуковой сонар HC-SR04. Скетч, написанный мной в начале лета всех устраивал, но сейчас, то ли из за холода, то ли просто время пришло, короче начали массово садиться аккумуляторы. Было решено переделать девайсы. В старом использовались 12 V аккумуляторы + КРЕН 5 (КР142ЕН5) который, как выяснилось сам потребляет энергию, в новом же я решил использовать Li-Pol аккумулятор на 3,7v. Соответственно Ардуину я взял Arduino pro mini на 3,3v HC-SR04 запитал через DC/DC преобразователь, так как эти модули отказываются работать от 3,3 v. Всё прекрасно работало, пока я не решил загонять МК в сон. Скачал на этом форуме пример, поправил его, и тут выяснилась приниприятная вещь. По отдельности скетчи работают нормально (один для сонара, другой для сна), а вот вместе, ну ни как не хотят. Сонар ужасно врёт (показывает расстояние от 6 см до реального, но каждый раз разное), а тот что отвечает за сон, виснет, при чём в тот момент, когда он всё узнал и должен отправить данные на сервер. Хотя на данный момент он ни чего не отправляет, а вместо отправки на сервер, отправляет соответствующее сообщение в консоль.
Вот злосчастный скетч.
#include <avr/sleep.h> #include <avr/wdt.h> #include <SoftwareSerial.h> int wakePin = 2; // Пин используемый для просыпания (прерывания) int sleepStatus = 0; // Переменная для хранения статуса (спим, проснулись) int LedPin=13; // Светодиод, включение обвязки int count; // Счётчик пробуждений const int slp = 3; // Количество пробуждений до включения сонара bool wdog, alarm; // Сработал таймер, тревога #include <Ultrasonic.h> Ultrasonic ultrasonic(10,11); //trig, echo int ds = 0; //Здесь хранится расстояние для сравнения bool snr = false; #include <TinyGPS.h> TinyGPS gps; SoftwareSerial ss(4, 3); //RX, TX String lat, lon; //Здесь хранятся широта и долгота для сравнения bool gpson; ISR (WDT_vect) { wdog = true; wakeUpNow(); // пробуждение по таймеру } void wakeUpNow() // Прерывание сработает после пробуждения { if (sleepStatus) // Если мы спали, { sleep_disable(); // то первое, что нужно сделать после просыпания - выключить спящий режим wdt_disable(); // загоняем собаку в конуру sleepStatus = 0; // В переменную заносим статус бодрствования if(wdog == false){ // если не по таймеру, значит тревога alarm = true; } } } void setup() { //сон - пробуждение count = 0; pinMode(LedPin, OUTPUT); pinMode(wakePin, INPUT); digitalWrite(wakePin, HIGH); // Подтягивем ногу к 5. digitalWrite(LedPin, LOW); delay(5000); // на всякий случай, если войдет в бесконечный цикл, можно будет перепрошить //инициализация портов Serial.begin(115200); // удалить после настройки //предварительные установки gpson = false; wdog = false; alarm = false; Serial.println("INIT"); } void sleepNow() // Функция увода ардуины в спячку. { delay(5000); // подготовка WatchDog wdog = false; MCUSR = 0; // clear various "reset" flags WDTCSR = bit (WDCE) | bit (WDE); // allow changes, disable reset // set interrupt mode and an interval WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // set WDIE, and 8 seconds delay //WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1); // set WDIE, and 1 second delay wdt_reset(); // pat the dog // конец подготовки WatchDog set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Здесь устанавливается режим сна sleep_enable(); // Включаем sleep-бит в регистре mcucr. Теперь возможен слип attachInterrupt(0, wakeUpNow, FALLING); // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow (прерывание вызывается только при смене значения на порту с HIGH на LOW - подтянуть ногу 2 на 5в.) sleepStatus = 1; // В переменную заносим статус сна sleep_mode(); // Здесь устройство перейдет в режим сна!!! sleep_disable(); // Первое, что нужно сделать после просыпания - выключить спящий режим detachInterrupt(0); // Выключаем прерывание - при нормальном режиме wakeUpNow() не будет вызываться } void transmit(int d, String l){ if(d == 1){ Serial.println("TRANSMIT "+l); } digitalWrite(LedPin, HIGH); // Выключаем светодиод delay(500); snr = false; Serial.println("SLEEP"); sleepNow(); // Вызов функции sleep() для засыпания } String sonar(){ // функция определения расстояния int us = 0; delay(5000); for (int i = 0; i < 10; i++){ us = us + ultrasonic.Ranging(CM); Serial.println(ultrasonic.Ranging(CM)); delay(1000); Serial.println("OK"); } us = us/10; if(ds != us){ Serial.println("TR"); transmit(1,String(us)); ds = us; } else { Serial.println("ITOGO "+String(us)); Serial.println("SLEEP"); snr = false; sleepNow(); } } void get_gps(){ // получаем координаты ss.begin(9600); bool newData = false; unsigned long chars; unsigned short sentences, failed; String locla, loclo; // For one second we parse GPS data and report some key values for (unsigned long start = millis(); millis() - start < 1000;) { while (ss.available()) { char c = ss.read(); // Serial.write(c); // uncomment this line if you want to see the GPS data flowing if (gps.encode(c)) // Did a new valid sentence come in? newData = true; } } if (newData) { float flat, flon; unsigned long age; gps.f_get_position(&flat, &flon, &age); locla = String(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6); loclo = String(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6); Serial.println("LAT= "+locla+" LON= "+loclo); // удалить после настройки if(gpson == false){ gpson = true; transmit(0,"917"); // инициализация выполнена } else { if((lat != locla)or(lon != loclo)){ transmit(0,"902"); // тревога lat = locla; lon = loclo; } } } } void loop() { if(alarm == true){ Serial.println("ALARM"); digitalWrite(LedPin, LOW); delay(5000); get_gps(); alarm = false; } if(gpson == false){ delay(5000); get_gps(); } else { if(snr == false){ if(count < slp){ count++; sleepNow(); } else { snr = true; count = 0; Serial.println("WAKE"); digitalWrite(LedPin, LOW); sonar(); //включаем сонар } } } }
А вот схема
С зависанием вроде разобрался, у меня в функции sonar вместо void стояло String. Наверно осталось от старой, где она возвращала расстояние. А вот глюк с расстояниями так и остался...
А вот что выводится в консоль
есть такое дело, сам наступил на эти грабли, после подачи питания на HC-SR04 нужно выждать около 1 секунды, сделать замер, игнорировать его, выждать 100мс и произвести новый замер, он будет валидный.
Спасибо за информацию, так оно и есть. Даже 10 замеров с вычислением среднего арифметического делать не нужно. Только интервалы колеблются для каждого из сонаров. Для одного 100мс нормально, а для другого 400 ставить пришлось.
кстати про враньё, у меня он лежит на полке и смотрит в крышу, слева дистанция в сантиметрах http://savepic.net/8531887.htm