очень медленно работает arduino
- Войдите на сайт для отправки комментариев
Всем привет! мне нужно сделать поворотное устройство для небольшой антенны , чтоб по азимуту и элевации и управлять с пульта. Столкнулся с такой проблемой ,что программа на ардуино выполняется очень медленно. Я в програмировании еще лох, поэтому ума не дам что нетак, до этого что я делал таких проблем не было даже если куча библиоте подключал и создавал много переменных всегда все работало отлично, ардуину пробованл менять думал может с кварцом прблема, но не помогло.
В проекте я использую Arduino nano, OLED 1,3 i2c
#include "U8glib.h" U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); //SDA_A4; SCL_A5; I2C / TWI 1.3" #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> int data[2]; //массив для хранения и передачи данных const uint64_t pipe = 0xF0F1F2F3F4LL; // индитификатор передачи, "труба" RF24 radio(9, 10); // CE, CSN const byte averageFactor = 5; // коэффициент сглаживания показаний // чем выше, тем больше "инерционность" int bat = 0; // переменная батареи фильтрованных значений АЦП float volt; // переменная для напряжения батареи int asimut; int elevation; void setup() { radio.begin(); delay(2); radio.setChannel(9); // канал (0-127) radio.setDataRate(RF24_1MBPS); // скорость, RF24_250KBPS, RF24_1MBPS или RF24_2MBPS // RF24_250KBPS на nRF24L01 (без +) неработает. // меньше скорость, выше чувствительность приемника. radio.setPALevel(RF24_PA_MIN); // мощьность передатчика, RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_MED=-6dBM, radio.openWritingPipe(pipe); // открываем трубу на передач u8g.setFont(u8g_font_8x13); //шрифт } void loop() { int elevation_lcd; int asimut_lcd; int asimut_grad; int elevation_grad; //ЭЛЕВАЦИЯ ВЫЧИСЛЕНИЯ_______________________________ elevation = (elevation * (averageFactor - 1) + analogRead(1)) / averageFactor; // ФИЛЬТРАЦИЯ ЗНАЧЕНИЙ АЦП elevation_lcd = map(elevation, 0, 1018, 0, 124); // вычисление координат указателя elevation_grad = map(elevation, 0, 1018, 0, 90); // вычисление градусов //АЗИМУТ ВЫЧИСЛЕНИЯ_______________________________ asimut = (asimut * (averageFactor - 1) + analogRead(2)) / averageFactor; // ФИЛЬТРАЦИЯ ЗНАЧЕНИЙ АЦП asimut_lcd = map(asimut, 0, 1018, 0, 124); // вычисление координат указателя asimut_grad = map(asimut, 0, 1018, -135, 135); // вычисление градусов //БАТАРЕЯ ВЫЧИСЛЕНИЯ_______________________________ bat = (bat * (averageFactor - 1) + analogRead(3)) / averageFactor; // ФИЛЬТРАЦИЯ ЗНАЧЕНИЙ АЦП volt = bat / 196; // вычисление напряжения //ПЕРЕДАЧА ДАННЫХ_______________________________________ //data[0] = analogRead(1); // фильтрованые значение в массив //data[1] = analogRead(2); // фильтрованые значение в массив //radio.write(&data, sizeof(data)); // отправляем данные и указываем сколько байт пакет //__________________________________________________________ u8g.firstPage(); // начало вывода на дисплей do { //ЭЛЕВАЦИЯ ВЫВОД НА ДИСПЛЕЙ____________________________________________ u8g.drawBox(elevation_lcd, 20, 4, 4); // укозатель u8g.drawRFrame(0, 18, 128, 8, 1); // шкала u8g.drawLine(64, 19, 64, 24); // шкала u8g.drawLine(32, 23, 32, 24); // шкала u8g.drawLine(96, 23, 96, 24); // шкала u8g.setPrintPos(0, 13); u8g.print("ELEVATION"); u8g.setPrintPos(85, 13); u8g.print(elevation_grad); //вывод градусов //АСИМУТ ВЫВОД НА ДИСПЛЕЙ____________________________________________ u8g.setPrintPos(0, 39); u8g.print("ASIMUT"); u8g.drawRFrame(0, 43, 128, 8, 1); // шкала u8g.drawLine(64, 43, 64, 49); // шкала u8g.drawLine(22, 43, 22, 49); // шкала u8g.drawLine(106, 43, 106, 49); // шкала u8g.drawLine(43, 48, 43, 49); // шкала u8g.drawLine(85, 48, 85, 49); // шкала u8g.setPrintPos(64, 39); u8g.print(asimut_grad); // вывод градусов u8g.drawBox(asimut_lcd, 45, 4, 4); // указатель //БАТАРЕЯ ВЫВОД НА ДИСПЛЕЙ____________________________________________ u8g.drawRFrame(0, 55, 15, 8, 1); //значек батареи u8g.drawFrame(14,57,3,4); //значек батареи u8g.drawBox(2, 57, 3, 4); //значек батареи u8g.drawBox(6, 57, 3, 4); //значек батареи u8g.drawBox(10, 57, 3, 4); //значек батареи u8g.setPrintPos(22, 64); u8g.print("RX"); u8g.setPrintPos(70, 64); u8g.print("TX"); u8g.setPrintPos(42, 64); u8g.print(volt, 1); //ЗНАК АНТЕННЫ____________________________________________ u8g.drawLine(127, 4, 127, 12); u8g.drawLine(125, 6, 125, 12); u8g.drawLine(123, 8, 123, 12); u8g.drawLine(121, 10, 121, 12); u8g.drawLine(119, 12, 119, 12); //_____________________________________________________ } while( u8g.nextPage() ); //конец вывода на дисплей }
, nrf24l01. в кочестве датчиков угла поворота два потенциометра. Проблема именно с пультом, после того как подключил библиотеку U8GLIB и нарисовал графику программа цикл проходит примерно за 100мс сужу по морганию диода при отправке в порт, а если начинаю массив перадавать по радио то вообще еще раз в 10 медленее и все лагает, ужас какой то, помогите разобраца я недавно ардуиной занялся.
данные с ацп у меня в коде не 0-1023 так как при усреднении часть значений терялась до примерно 1018, подбирал экспериментально.
На приемной стороне сервы 0-270 25кг к приемной стороне притензий нет.
ПРи таком объеме вывода на дисплей не удивительно, что лагает.
Выводите только то, что не изменилось с первого раза.
я еще не разбирался как с этой библиотекой вывести неподвижные элементы один раз вначале, я пробовал закоментировать неподвижные элементы а оставить то что изменяется, это особо не помогло так практически так же работает я пробовал в порт отправлять , ну уж очень медлено , особенно когда массив пуляю в nrf24, тормоза еще сильнее
Да, прошивка только тем и занята, что рисует на дисплее со страшной скоростью. Совет в посте #1 - самый годный, надо переделывать так, чтобы отрисовывалось только то, что изменилось. Плюс - не стоит даже изменившиеся значения перерисовывать очень часто - достаточно пару раз в секунду, можно даже реже: кмк, это не настолько критичная ко времени информация, чтобы выводить её очень часто.
Есть ещё выход: взять что-нибудь 32х-битное, с более высокой тактовой: например, Arduino Due или STM32.
https://www.youtube.com/watch?v=JOs7_Vmv7K4 так это работает, ужас не думал что столько проблем чтоб отрисовать 128х64
хорошо будим выводить что не меняется один раз, а что меняется только когда меняется. подскажите как реализовать в этой библиотеке чтобы раз в setup часть инфы высести. я попробовал но без цикла do while оно не выводится а с ним оно не остается.
И если не трудно подскажите как лучше реализовать чтоб именно при изменении значений начинало отрисовываться, допустим меняю азимут и отрисовывается только этот градус и ползунок, имею ввиду как условие чтоб выполнялось именно при изменении, я поищу в интернете, но может тут знают люди, голова уже пухнет как это сделать лучше
Есть, кстати, ещё вариант: отказаться от I2C и заюзать параллельный интерфейс (если дисплей позволяет, конечно) - отрисовка будет быстрее.
Насчёт цикла do/while при использовании u8glib - да, всё верно, она так устроена, что без него не будет ничего рисоваться. И задача как раз состоит в том, чтобы делать перерисовку как можно реже. У вас она - БЕЗУСЛОВНАЯ, при КАЖДОМ проходе loop. Первое, что надо сделать - это отрисовывать ТОЛЬКО ТОГДА, когда что-то на экране изменилось. Поверьте - это будет на порядок быстрее работать. Допустим, у вас меняются данные раз в секунду - значит, и перерисовываться будет раз в секунду, а не так, как сейчас - когда МК только и занят отрисовкой.
Плюс - даже на параллельном интерфейсе и восьмибитном 16МГц МК - по опыту, при использовании u8glib не выжать больше, чем десяток FPS. Т.е. максимальное кол-во перерисовок - ограничено совсем маленькой величиной. А у вас - I2C с его килогерцами тактовой ;) Не очень-то всё это дело приспособлено под многия FPS.
Ещё из вариантов: попробовать что-нибудь менее тяжеловесное, чем u8glib - выигрыша, конечно, сильно не будет, но всё возможно.
Но первое, что стоит сделать - это поправить отрисовку. Скажем, в одном из моих проектов Arduino Mega успевает и на 128х64 отрисовывать, и по RS-485 туда/сюда пакеты гонять, и с nRF работать, и с ESP, и с SIM800 - всё это псевдопараллельно, конечно, но - успевает. Потому что с тем же дисплеем - перерисовывается всё только при изменениях.
как по изменению событий отрисовывать эт я почти знаю как сделать , разбирусь. но вот как отрисовать только раз надписи и шкалы какие не меняются что то так и не понял, поискал в нете что то не попалось на глаза, если я не могу поместить часть в setup как же быть? чтоб раз при старте отрисовать и дисплей их хранил
Это только ручками, кмк, т.к. u8glib использует свой экранный буфер и выдаёт его на дисплей. И требует той самой необходимой обвязки в виде вызовов firstPage и nextPage. Короче - плата за универсальность библиотеки - она тащит много разных дисплеев.
Не всё так просто, короче: если вы умножите 128х64, то увидите, что для монохромного дисплея нужно 8192 бита информации, или - целый килобайт буфера, если решать проблему "в лоб". Потом - у каждого контроллера дисплея - свои причуды: адресация и пр.
Короче - нет счастья в подлунном мире, всё требует каких-то жертв и компромиссов. Хотите отрисовку побыстрее - это как минимум SPI надо. Хотите ещё побыстрее? Тогда МК побыстрее берём. Ещё быстрее? Тогда STM32 и FSMC. Ещё быстрее? Купить смартфон и юзать его как визуальную часть, а ардуина пускай телеметрию по тому же MQTT в брокера в локальной сети складывает.
Но пока - я всё же подумал бы над оптимизацией отрисовки: введите флаг изменения данных и вызывайте блок отрисовки на дисплее только тогда, когда данные изменились. Но - не слишком часто, достаточно нескольких раз в секунду. В приведённом ниже псевдокоде отрисовка будет вызываться не чаще чем раз в полсекунды и только тогда, когда данные изменились:
спасибо за советы , опробую в ближайшее время