очень медленно работает arduino

Alex36
Offline
Зарегистрирован: 11.04.2019

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

В проекте я использую 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кг  к приемной стороне притензий нет.

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

ПРи таком объеме вывода на дисплей не удивительно, что лагает.

Выводите только то, что не изменилось с первого раза.

Alex36
Offline
Зарегистрирован: 11.04.2019

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

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Да, прошивка только тем и занята, что рисует на дисплее со страшной скоростью. Совет в посте #1 - самый годный, надо переделывать так, чтобы отрисовывалось только то, что изменилось. Плюс - не стоит даже изменившиеся значения перерисовывать очень часто - достаточно пару раз в секунду, можно даже реже: кмк, это не настолько критичная ко времени информация, чтобы выводить её очень часто.

Есть ещё выход: взять что-нибудь 32х-битное, с более высокой тактовой: например, Arduino Due или STM32.

Alex36
Offline
Зарегистрирован: 11.04.2019

https://www.youtube.com/watch?v=JOs7_Vmv7K4 так это работает, ужас не думал что столько проблем чтоб отрисовать 128х64
хорошо будим выводить что не меняется один раз, а что меняется только когда меняется. подскажите как реализовать в этой библиотеке чтобы раз в setup часть инфы высести. я попробовал но без цикла do while оно не выводится а с ним оно не остается.
И если не трудно подскажите как лучше реализовать чтоб именно при изменении значений начинало отрисовываться, допустим меняю азимут и отрисовывается только этот градус и ползунок, имею ввиду как условие чтоб выполнялось именно при изменении, я поищу в интернете, но может тут знают люди, голова уже пухнет как это сделать лучше

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Есть, кстати, ещё вариант: отказаться от I2C и заюзать параллельный интерфейс (если дисплей позволяет, конечно) - отрисовка будет быстрее.

Насчёт цикла do/while при использовании u8glib - да, всё верно, она так устроена, что без него не будет ничего рисоваться. И задача как раз состоит в том, чтобы делать перерисовку как можно реже. У вас она - БЕЗУСЛОВНАЯ, при КАЖДОМ проходе loop. Первое, что надо сделать - это отрисовывать ТОЛЬКО ТОГДА, когда что-то на экране изменилось. Поверьте - это будет на порядок быстрее работать. Допустим, у вас меняются данные раз в секунду - значит, и перерисовываться будет раз в секунду, а не так, как сейчас - когда МК только и занят отрисовкой.

Плюс - даже на параллельном интерфейсе и восьмибитном 16МГц МК - по опыту, при использовании u8glib не выжать больше, чем десяток FPS. Т.е. максимальное кол-во перерисовок - ограничено совсем маленькой величиной. А у вас - I2C с его килогерцами тактовой ;) Не очень-то всё это дело приспособлено под многия FPS.

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

Но первое, что стоит сделать - это поправить отрисовку. Скажем, в одном из моих проектов Arduino Mega успевает и на 128х64 отрисовывать, и по RS-485 туда/сюда пакеты гонять, и с nRF работать, и с ESP, и с SIM800 - всё это псевдопараллельно, конечно, но - успевает. Потому что с тем же дисплеем - перерисовывается всё только при изменениях.

Alex36
Offline
Зарегистрирован: 11.04.2019

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

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Alex36 пишет:
но вот как отрисовать только раз надписи и шкалы какие не меняются что то так и не понял, поискал в нете что то не попалось на глаза, если я не могу поместить часть в setup как же быть? чтоб раз при старте отрисовать и дисплей их хранил

Это только ручками, кмк, т.к. u8glib использует свой экранный буфер и выдаёт его на дисплей. И требует той самой необходимой обвязки в виде вызовов firstPage и nextPage. Короче - плата за универсальность библиотеки - она тащит много разных дисплеев.

Не всё так просто, короче: если вы умножите 128х64, то увидите, что для монохромного дисплея нужно 8192 бита информации, или - целый килобайт буфера, если решать проблему "в лоб". Потом - у каждого контроллера дисплея - свои причуды: адресация и пр.

Короче - нет счастья в подлунном мире, всё требует каких-то жертв и компромиссов. Хотите отрисовку побыстрее - это как минимум SPI надо. Хотите ещё побыстрее? Тогда МК побыстрее берём. Ещё быстрее? Тогда STM32 и FSMC. Ещё быстрее? Купить смартфон и юзать его как визуальную часть, а ардуина пускай телеметрию по тому же MQTT в брокера в локальной сети складывает. 

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

bool needRedraw = false;
uint32_t lastRedrawAt = 0;

void loop()
{
  if(данные_изменились)
	needRedraw = true;


  if(needRedraw && millis() - lastRedrawAt > 500)
  {
	needRedraw = false;

	u8.firstPage();
	do
	{
		// тут рисуем
	} while(u8.nextPage());

	lastRedrawAt = millis();
  }
}

 

Alex36
Offline
Зарегистрирован: 11.04.2019

спасибо за советы , опробую в ближайшее время