Сильно тормозит скетч
- Войдите на сайт для отправки комментариев
Доброе время суток
С ардуино работаю совсем недавно, писал как правило простые программы управления всякой ерундой, но тут появилась необходимость в GPS спидометре, ну и начитавшись форума решил собрать себе нормальный спидометр, с температурой, временем, и одометром.
Платформа UNO на Atmega328, по началу всё было отлично, программа летала, но в один день, начались тормоза, экран просто прорисовывается построчно, дико неудобно, и ни как не могу понять в чём проблема.
Большая просьба посмотреть программу и по возможности ткнуть меня носом в косяк.
Вот что мы имеем:
Ардуино как чип отдельно Atmega328P-PU(плату сделал сам, но проблема остаётся и на заводской платформе и на плате)
Сам чип работает на внутреннем генераторе на 8 МГц.
Экран LCD12864
Датчик температуры (модель не помню)
Модуль GPS ATGM336H (Выбран из-за Глонас)
скетч ниже
[code] #include <OneWire.h> #include <iarduino_GPS_NMEA.h> #include <SoftwareSerial.h> #include <U8glib.h> #include "sav_button.h" #include <EEPROM.h> SButton button(6,50,1000,4000,200); U8GLIB_ST7920_128X64_1X u8g(10); // Часы const uint8_t rook_bitmap[] U8G_PROGMEM = { // массив, хранящий изображение. 0 – пиксель не горит, 1 – пиксель горит 0x3c, // 00000000 – 2-ичная кодировка 16-ричного числа 0x4a, // 01010101 0x89, // 01111111 0x89, // 00111110 0xb1, // 00111110 0x81, // 00111110 0x42, // 00111110 0x3c // 01111111 }; // Антенна const uint8_t satell[] U8G_PROGMEM = { // массив, хранящий изображение. 0 – пиксель не горит, 1 – пиксель горит 0x00, // 00000000 – 2-ичная кодировка 16-ричного числа 0x02, // 01010101 0x02, // 01111111 0x0a, // 00111110 0x0a, // 00111110 0x2a, // 00111110 0x2a, // 00111110 0x00 // 01111111 }; double lastlat,lastlng; // Для вычисления пройденного растояния OneWire ds(8); // Создаем объект OneWire для шины 1-Wire, с помощью которого будет осуществляться работа с датчиком static int led = 9; // Пин управления яркости экрана static int brightness =174; // Первоначальная яркость экрана static int but=0; // Не используется static int fadeAmount = 80; // Минимальная яркость экрана static int temp = 0; // Первоначальная температура static int km=0; // Первоначальная скорость static int has=0; // Часы static int mi=0; // Минуты static int xs=68; // Положение курсора для КМ/Ч static int alti=0; // Выоста static long odog=372000; // Предыдущий пробег static long odox=0; // Общий пробег static long odos=0; // Суточый пробег static long odot=0; // Пробег с начала работы static long odo=0; // на всякий случай static long odo1=0; static long lat1=1; static long lat2=1; static long distance=0; static long lastUpdateTime = 0; // Переменная для хранения времени последнего считывания с датчика const int TEMP_UPDATE_TIME = 5000; // Определяем периодичность проверок float input_volt = 0.0; float volt=0.0; float r1=24000.0; //сопротивление резистора r1 float r2=10000.0; // сопротивление резистора r2 unsigned long next_time; // время очередной прорисовки int timeout = 500; // период прорисовки static const int RXPin = 2, TXPin = 3; static const uint32_t GPSBaud = 9600; iarduino_GPS_NMEA gps; //iarduino_GPS_ATGM336 SettingsGPS; SoftwareSerial ss(RXPin, TXPin); char* wd[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; // Определяем массив строк содержащих по две первых буквы из названий дня недели. void setup() { Serial.begin(9600); gps.timeZone(5); ss.begin(GPSBaud); gps.begin(ss);// Считываем данные из памяти EEPROM.get(0, odot); EEPROM.get(4, odos); pinMode(led, OUTPUT); // Определение пина для яркости button.begin(); pinMode(5, INPUT); // Вход питания pinMode(4, OUTPUT); // Упревление реле digitalWrite(4, HIGH); // Включение реле analogWrite(led, brightness); // Включение подсветки экрана // Страница приветсвия u8g.firstPage(); do{ u8g.setRot180(); u8g.setFont(u8g_font_8x13B); u8g.setPrintPos( 40, 35); u8g.print("HELLO!"); } while(u8g.nextPage()); delay (2000); next_time = millis() + timeout; // вычисляем время следующей прорисовки odox = odog + odot/1000; } void loop() { detecthas(); //определине часов lcdscreen(); //прорисовка экрана detectTemperature(); // градусник detectkmph(); // скорость detectxs(); // Положение курсора КМ/Ч int now_time = millis(); // текущее время int save = digitalRead(5); // Сигнал подачи питания int analogvalue = analogRead(A0); // Пин вольтметра // Отрисовка экрана 1/300 сек if( now_time >= next_time ){ // если текущее время превысило намеченное время, то next_time = now_time + timeout; // вычисляем время следующего переключения lcdscreen(); } gps.read(); // Читаем данные с получением информации о спутниках в массив i (чтение может занимать больше 1 секунды). Если указать второй параметр gps.read(i,true); то в массиве окажутся данные только тех спутников, которые принимают участие в позиционировании. // формула для конвертирования значения напряжения volt = (analogvalue * 5.0) / 1024.0; input_volt = volt / (r2/(r1+r2)); if (input_volt < 0.1){ input_volt=0.0; } // Яркость экрана analogWrite(led, brightness); // Обработка кнопки, короткое изменение яркости, длинное сброс счётчиков switch( button.Loop() ){ case SB_CLICK: brightness = brightness + fadeAmount; if (brightness == 14 || brightness == 254) { fadeAmount = - fadeAmount ; } break; case SB_LONG_CLICK: odos=0; break; case SB_AUTO_CLICK: //odox=372000; break; } // Определеие пройденного расстояния if(lastlat!=0 && lastlng!=0 && km>0) { double delta = radians((gps.longitude)-lastlng); double sdlong = sin(delta); double cdlong = cos(delta); lat1 = radians(gps.latitude); lat2 = radians(lastlat); double slat1 = sin(lat1); double clat1 = cos(lat1); double slat2 = sin(lat2); double clat2 = cos(lat2); delta = (clat1 * slat2) - (slat1 * clat2 * cdlong); delta = sq(delta); delta += sq(clat2 * sdlong); delta = sqrt(delta); double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong); delta = atan2(delta, denom); distance=delta * 6372795; odo=distance; odot+=distance; odos+=distance; odox = odog + (odot/1000); } lastlng=(gps.longitude); lastlat=(gps.latitude); if (km>but){ but=km; } // Наличие или отсутсвие питания if (save == LOW){ save_f(); } } int detecthas(){ has=(gps.Hours); } int lcdscreen(){ u8g.firstPage(); do{ u8g.setRot180(); u8g.setColorIndex(1); u8g.drawBitmapP( 32, 5, 1, 8, rook_bitmap); u8g.drawBitmapP( 105, 2, 1, 8, satell); u8g.setFont(u8g_font_8x13B); u8g.drawHLine(0, 41, 128); u8g.drawHLine(0, 17, 128); u8g.drawVLine(30, 17, 24); u8g.drawVLine(90, 0, 17); u8g.drawVLine(30, 0, 17); u8g.drawVLine(75, 42, 22); u8g.setPrintPos( 42, 14); u8g.drawHLine(75, 52, 63); u8g.drawFrame(0,0,128,64); if (has < 10){u8g.print(" "); u8g.setPrintPos( 53, 14);u8g.print(has); } else { u8g.print(has); } u8g.setPrintPos( 60, 14); u8g.print(":"); u8g.setPrintPos( 70, 14); if (gps.minutes < 10){u8g.print("0"); u8g.setPrintPos( 80, 14);u8g.print(gps.minutes); } else { u8g.print(gps.minutes); } u8g.setFont(u8g_font_6x10); u8g.setPrintPos( 2, 13); u8g.print(temp); u8g.drawCircle(21, 7, 1.5); u8g.drawStr(24, 13, "C"); u8g.setFont(u8g_font_courB24n); u8g.setPrintPos( (xs), 40); u8g.print(km); u8g.setFont(u8g_font_6x10); u8g.setPrintPos( 8, 28); u8g.print("MAX"); u8g.setPrintPos( 8, 39); u8g.print(but); u8g.setPrintPos( 93, 40); u8g.print("km/h"); u8g.setFont(u8g_font_6x10); u8g.setPrintPos( 2, 51); u8g.print("ODO:"); u8g.setPrintPos( 27, 51); u8g.print(odox); u8g.setPrintPos( 2, 61); u8g.print("SUT:"); u8g.setPrintPos( 27, 61); u8g.print(odos/1000); u8g.setFont(u8g_font_5x8); u8g.setPrintPos( 114, 8); u8g.print(gps.satellites[GPS_ACTIVE]); u8g.setPrintPos( 104, 16); u8g.print(gps.altitude,1); u8g.setPrintPos( 76, 50); if (gps.day<10){ u8g.print("0"); u8g.setPrintPos( 81, 50);u8g.print(gps.day); } else { u8g.print(gps.day); } u8g.setPrintPos( 86, 50); u8g.print("/"); u8g.setPrintPos( 91, 50); if (gps.month<10){ u8g.print("0"); u8g.setPrintPos( 96, 50);u8g.print(gps.month); } else { u8g.print(gps.month); } u8g.setPrintPos( 101, 50); u8g.print("("); u8g.setPrintPos( 106, 50); u8g.print(wd[gps.weekday]); u8g.setPrintPos( 121, 50); u8g.print(")"); u8g.setPrintPos( 83, 61); u8g.print("V"); u8g.setPrintPos( 90, 61); u8g.print(input_volt); } while(u8g.nextPage()); } // Отключение и сохранение данных int save_f(){ analogWrite(led, brightness); EEPROM.put(0, odot); EEPROM.put(4, odos); u8g.firstPage(); do{ u8g.setRot180(); u8g.setFont(u8g_font_8x13B); u8g.setPrintPos( 20, 35); u8g.print("GOOD LUCK!"); } while(u8g.nextPage()); delay (2000); digitalWrite(4, LOW); } // Определие курсора КМ/Ч int detectxs(){ if(km < 10){ xs=(68); } if(km > 9 && km < 100){ xs=(51); } if(km > 99){ xs=(32); } } // Определие скорости int detectkmph(){ km = (gps.speed); } // Определение температуры int detectTemperature(){ byte data[2]; ds.reset(); ds.write(0xCC); ds.write(0x44); if (millis() - lastUpdateTime > TEMP_UPDATE_TIME) { lastUpdateTime = millis(); ds.reset(); ds.write(0xCC); ds.write(0xBE); data[0] = ds.read(); data[1] = ds.read(); temp = (data[1] << 8) + data[0]; temp = temp >> 4; } } [/code]
Если началось ни с того ни с сего, значить, у тебя на 5-м пине всегда LOW
На пятый пин по схеме приходит +5 от отдельного стабилизатора
Я вот подумал может проблема с экраном, так как он медленно рисует внутри самой функции, но до этого рисовал на ура, а другого, что бы подкинуть нет.
А ты померий
Мерил, там высокий уровень, проблема где в прорисовке, если отключить дисплей и его библиотеку, и выводить данные на "монитор порта", то всё работает быстро.
Вот схема, если интересно.
Подозреваю что с GPS летит очень много ненужных данных и контроллер постоянно занят их приёмом. Надо настроить GPS на передачу только нужных пакетов и поиграться с частотой и скоростью таких передач.
По поводу скорости передачи данных, пробовал почти все поддерживаемые (по паспорту), но полные и нормальные данные выдаёт только на 9600, при смене скорости, то время не выдаёт, то скорость не видит, то спутники.
А вот как поменять количество данных я пока не разобрался, НО...
проблема начинается ещё до начала чтения данных с GPS, уже страница приветствия тормозит, а " gps.read();" стоит намного ниже.
Может кто знает как проверить LCD или перешить его как-то можно.
Serial читает данные сразу после его активации. Попробуйте его пока не включать или отключите GPS физически.
Вечером попробую отключить, тем более это не проблема, ну а если действительно поможет, что делать-то дальше, я не смог разобраться в "Птичьем" языке описания протокола NMEA, не на трезвую голову ни с поллитра.
А поможет ( как эксперимент), если я перенесу включение Serial, после страницы приветствия?
SoftwareSerial и 9600 - это не для спидометра. Даже если с экраном справитесь.
А по теме - выкидывайте лишнее рисование и измеряйте ускорение.
Ну со скоростью я ещё поиграю, хотя прошлые попытки мне не понравились,
а вот на счёт рисования, такая мысль приходила в голову, и даже отключал всё рисование кроме цифр, результат то-же, вечером проведу ряд экспериментов, по советам, и обязательно отпишусь.
Скорее всего придётся отключать SoftwareSerial при каждом рисовании на экране.
Скорее всего придётся отключать SoftwareSerial при каждом рисовании на экране.
А вот с этого момента по подробнее, как его отключать и подключат обратно?
Пройденный этап. Для спидометра нужна высокая скорость обновления, что тащит за собой повышенную скорость порта. Где-то до 115200. Софтсериал на 38400 захлебнется. Плюс - большой оверхед на дисплее.
Не понял на счёт "Софтсериал на 38400 захлебнётся", а на 115200 нормально что-ли будет работать?
Ну экран рисуется 2 раза в секунду.
на 115200 тем более
надо делать на аппаратном serial
если загрузка скетчей идет через serial, то надо делать переключатель на дорожке TX и коммутировать сигналы от TX USB-UART и от TX GPS
093
void
loop
()
094
{
095
096
lcdscreen();
//прорисовка экрана
097
098
099
100
101
102
103
// Отрисовка экрана 1/300 сек
104
if
( now_time >= next_time ){
// если текущее время превысило намеченное время, то
105
next_time = now_time + timeout;
// вычисляем время следующего переключения
106
lcdscreen();
107
}
108
Ну экран рисуется 2 раза в секунду.
Да он вроде постоянно рисуется. Верхний вызов лишний ?
На аппаратном Serial, это 0 и 1 (RX,TX), если я правильно понял, переделать не сложно, они у меня свободные, а прошить могу и через программатор USBAsp.
прошить могу и через программатор USBAsp.
Тем более нет смысла в softserial
Упс, просмотрел, раньше рисовался постоянно.
Вот СПАСИБО!!!!!
прошить могу и через программатор USBAsp.
Тем более нет смысла в softserial
просто сериал прописать?
Конструкцией типа if( now_time >= next_time ) я бы пользоваться не советовал. Во избежании так сказать...
Лучше использовать if( now_time - last_time >= timeout) { last_time = now_time ;
И вопрос - а зачем все подпрограммы у Вас int? Вы же ничего не возвращаете.
Конструкцией типа if( now_time >= next_time ) я бы пользоваться не советовал. Во избежании так сказать...
Лучше использовать if( now_time - last_time >= timeout) { last_time = now_time ;
И вопрос - а зачем все подпрограммы у Вас int? Вы же ничего не возвращаете.
Спасибо за совет, но я не понял принципиальной разницы в условии.
Может есть какие "подводные камни" в моём условии, поясните если не трудно.
На счёт "int", старая дурацкая привычка, ни как не отучусь, хорошо хоть "Return" перестал вписывать ))))
Спасибо за совет, но я не понял принципиальной разницы в условии.
Может есть какие "подводные камни" в моём условии, поясните если не трудно.
Почитай за переполнение миллис.
Спасибо за совет, но я не понял принципиальной разницы в условии.
Может есть какие "подводные камни" в моём условии, поясните если не трудно.
Почитай за переполнение миллис.
Спасибо за наводку, прочитал, код исправлю
Коллеги
Воспользовавшись советами в ветке, вчера внёс изменения, а именно:
1 Уменьшил количество данных с GPS до одной строки NMEA_RMC, правда пришлось пожертвовать информацией о спутниках, да и ладно.
2 Спасибо Morroc, указал на косяк в прорисовке, косяк исправлен.
3 Все попытки получить данные по Serial ни к чему не привели, судя по светодиоду данные приходят, но на мониторе порта тишина, перепробовал все методы какие нашёл, пришлось вернуться на SoftSerial, поднял частоту до 57600, пока ошибок или пробелов не было
4 Ну и убрал лишнюю графику с экрана
Промежуточный итог, скорость работы и прорисовки выросла до нормальной, осталось исправить код прорисовки.
Но вот гложет момент с Serial, проверял на разных платформах (2 UNO, 1 Nano168), результат один, светодиод мигает, данных нет.
Дорожку от RX к микросхеме USB-UART надо перерезать - потому что иначе конфликт между TXами !
Приём должен идти от GPS, а вывод в USB ... (управлять GPS при таком соединении не получится)
Проще взять Pro Mini вместо Nano, чем резать.
Дорожку от RX к микросхеме USB-UART надо перерезать - потому что иначе конфликт между TXами !
Приём должен идти от GPS, а вывод в USB ... (управлять GPS при таком соединении не получится)
Спасибо вечером попробую ещё раз,
уточню, от 2 вывода отрезать дорожку на контроллер USB, и оставить только ту, что идет на пин?
sadman41 так ТС зачем то монитор порта нужен ...
Snowhorg я не знаю как именно разведены дорожки на вашем экземпляре ! Оптимально резать рядом с микросхемой USB-UART.
Главное что бы на RX приходил сигнал только с GPS ! Иначе это КЗ когда на TX ах разные уровни сигнала !
Вы так и не написали что тормозило вывод !?
Проще взять Pro Mini вместо Nano, чем резать.
У меня вся схема работает на отдельной плате, там нет контроллера USB, но отладка кода и проверка проходит на платформе, для удобства и контроля.
Есть одна UNO которую не жалко, вот там и отрежу, она как программатор для чипов у меня используется.
sadman41 так ТС зачем то монитор порта нужен ...
Монитор порта нужен только во время отладки, потом чип вообще снимается с платформы и помещается в плату. Но с платы монитора не видно, и пойди пойми что там происходит.
Вы так и не написали что тормозило вывод !?
Судя по всему количество данных с датчика GPS, там было максимум строк
В итоговом скетче вообще отключите вывод в монитор порта - если эти данные попадут в GPS - не факт что они его не "нагнут" !!!
В итоговом скетче вообще отключите вывод в монитор порта - если эти данные попадут в GPS - не факт что они его не "нагнут" !!!
Ну это понятно, я стираю всё что связано с выводом на монитор, нафиг и так программа не маленькая.
Вы столкнулись с особенностью работы SoftwareSerial - работа скетча прерывается по приходу стартового бита и восстанавливается после только после получения всего байта. Если байты идут один за другим, то скетч простаивает 90+% времени. На скорости 9600 - за секунду можно принять всего 960 байт. Сколько байт отсылал ваш GPS модуль по умолчанию мне не известно, но явно больше чем вам было нужно для получения необходимых данных.
Я в таких случаях беру или Мегу или 328PB. Отладился, отключил сериал и залился в целевой 328-й. Ничего резать не надо, портить дорогой (нынче) товар - тоже.
На скорости 9600 - за секунду можно принять всего 960 байт. Сколько байт отсылал ваш GPS модуль по умолчанию мне не известно, но явно больше чем вам было нужно для получения необходимых данных.
Тут ещё вопрос в Update Rate. Если бахнуть 10Hz, то вообще прёт как из поливочного шланга. Всё, конечно, от задачи зависит, но на стандартном 1Hz спидометр на велосипед можно ставить, как мне кажется.
Ну у меня и стоит 10 Hz, правда в описании библиотека написано, что read() читает данные в 2 раза меньше чем передаёт чип, по этому 10 и поставил.
Ставиться спидометр будет на машину, родной помер без возвратно, восстановление стоит очень дорого, нужно коробку полностью разбирать, и по большому спидометр нужен больше ради одометра, скорость я и так мерить умею, по оборотам ))))
портить дорогой (нынче) товар - тоже.
Думаю перемычку поставить, надо замкнул, не надо разомкнул )
C аппаратным Serial основной скетч прерывался бы на доли процента для перемещения аппаратно-принятого байта в буфер и ТС мог и не столкнуться с проблемой отрисовки.
Открыл схему UNO (да думаю во многих так), так вот там на RX-TX стоят 2 резистора, попробую их поменять на диоды в правильном направлении, тогда данные (которые всегда 0 или 1, где 1 это по любому +) будут доходить до чипа, но не будут уходить в контроллер, и от контроллера будут свободно проходить до чипа.
вот схема, если я не первый кто так решил сделать опишите, получилось или нет?
они еще и к питанию подтянуты
Насколько Вам часто нужны данные?
Человеческий глаз, как говорят, воспринимает 25 кадров в секунду (пиктят - 24 кадра)
Вот зачем Вам опрашивать датчики быстрее этого? Вы делаете ИИ?
Насколько Вам часто нужны данные?
Человеческий глаз, как говорят, воспринимает 25 кадров в секунду (пиктят - 24 кадра)
Вот зачем Вам опрашивать датчики быстрее этого? Вы делаете ИИ?
Вообще-то человеческий глаз легко воспринимает и 60-85 кадров в секунду.
Но это совсем не означает, что обновлять показания приборов нужно с той же частотой. В большинстве случаев хватает и 2-х раз в секунду.
Человеческий глаз, как говорят, воспринимает 25 кадров в секунду (пиктят - 24 кадра)
Глаз воспринимает отдельные фотоны.
А зачем вообще подняли тему FPS ? В коде нет речи даже про 4 FPS.
Итак, обратив внимание на все советы и замечания по моему проекту, я внёс изменения в код.
Отрисовка больше не тормозит
Serial таки запустить удалось (без обрезки дорожек на платформе, но тема с диодами пока не закрыта)
Теперь отрисовка каждые 300 millis, скорость обмена 115200.
Мало того, сегодня были проведены "ходовые" испытания, ездил на родник.
Итог, всё отлично,
скорость показывает
расстояние считает,
ну и т.д. и т.п.
Всем большое спасибо за помощь!
Надеюсь на дальнейшее сотрудничество.
на всякий случай ниже код скетча