Но, я, как человек ленивый, Atmel Studio ставить не хочу, считать всякие фьюзы - тоже. Поэтому буду менять PROGMEM скетчем, созданным прямо в Arduino IDE. Так как изменение данных в PROGMEM доступно только из области бутлоадера, без дополнительных телодвижений, конечно, не обойтись, т. Но для человека, умеющего копировать файлы, обладающего USBasp и пятью минутами времени, нет ничего невозможного.
PROGMEM change demo
System is not registered. Enter registration name: SuperUser
Erasing flash page
Writing to temporary flash buffer
Writing buffer to flash
Write done, reset MCU
PROGMEM change demo
System is registered to: SuperUser
PROGMEM change demo
System is registered to: SuperUser
progmem_change.ino:
#include "optiboot.h"
#include <avr/pgmspace.h>
const char registrationInfo[SPM_PAGESIZE] __attribute__ (( aligned(SPM_PAGESIZE) )) PROGMEM = {'\0'};
uint8_t workBuffer[SPM_PAGESIZE];
void printRegistrationInfo() {
for (uint16_t i = 0x00; SPM_PAGESIZE > i; i++) {
uint8_t currentByte = pgm_read_byte(®istrationInfo[i]);
if (!currentByte) {
return;
}
Serial.write(currentByte);
}
}
void doRegistration() {
uint16_t i = 0x00, data = 0x00;
uint8_t currentByte = 0x00;
// Take info
while ((SPM_PAGESIZE - 1) > i && currentByte != '\n') {
if (0x00 < Serial.available()) {
currentByte = Serial.read();
Serial.write(currentByte);
workBuffer[i] = currentByte;
i++;
}
}
workBuffer[i] = '\0';
delay(100);
// Erasing FLASH page
Serial.println(F("\nErasing flash page"));
// wait for sending all text via serial
delay(100);
optiboot_page_erase((optiboot_addr_t)(void*) ®istrationInfo[0]);
// Copy RAM buffer to temporary flash buffer
Serial.println(F("Writing to temporary flash buffer"));
delay(100); // wait for sending all text via serial
for (i = 0x00; SPM_PAGESIZE > i; i++) {
if (!(i & 0x01)) { // we must write WORDs
data = workBuffer[i];
} else {
data += ((uint16_t)workBuffer[i] << 8);
optiboot_page_fill((optiboot_addr_t)(void*) ®istrationInfo[i], data);
}
}
// Writing temporary buffer to FLASH
Serial.println(F("Writing buffer to flash"));
delay(100); // wait for sending all text via serial
optiboot_page_write((optiboot_addr_t)(void*) ®istrationInfo[0]);
Serial.println("Write done, reset MCU\n");
delay(100); // wait for sending all text via serial
asm volatile ("jmp 0");
}
void setup() {
Serial.begin(115200);
Serial.println(F("PROGMEM change demo"));
Serial.print(F("System is "));
if ('\0' == pgm_read_byte(®istrationInfo[0])) {
Serial.print(F("not registered. Enter registration name: "));
doRegistration();
} else {
Serial.print(F("registered to: "));
printRegistrationInfo();
}
}
void loop() {}
optiboot.h:
/* Optiboot 'header' file.
*
* June 2015 by Marek Wodzinski, https://github.com/majekw
* Released to public domain
*
* This header file gives possibility to use SPM instruction
* from Optiboot bootloader memory.
*
* There are 3 convenient functions available here:
* optiboot_page_erase - to erase FLASH page
* optiboot_page_fill - to put words into temporary buffer
* optiboot_page_write - to write contents of temporary buffer into FLASH
*
* For some hardcore users, you could use 'do_spm' as raw entry to
* bootloader spm function.
*/
#ifndef _OPTIBOOT_H_
#define _OPTIBOOT_H_ 1
#include <avr/boot.h>
/*
* Main 'magic' function - enter to bootloader do_spm function
*
* address - address to write (in bytes) but must be even number
* command - one of __BOOT_PAGE_WRITE, __BOOT_PAGE_ERASE or __BOOT_PAGE_FILL
* data - data to write in __BOOT_PAGE_FILL. In __BOOT_PAGE_ERASE or
* __BOOT_PAGE_WRITE it control if boot_rww_enable is run
* (0 = run, !0 = skip running boot_rww_enable)
*
*
* Contents of bootloader's do_spm function, just for reference:
*
* static void do_spm(uint16_t address, uint8_t command, uint16_t data) {
* // Do spm stuff
* asm volatile (
* " movw r0, %3\n"
* " out %0, %1\n"
* " spm\n"
* " clr r1\n"
* :
* : "i" (_SFR_IO_ADDR(__SPM_REG)),
* "r" ((uint8_t)command),
* "z" ((uint16_t)address),
* "r" ((uint16_t)data)
* : "r0"
* );
*
* // wait for spm to complete
* // it doesn't have much sense for __BOOT_PAGE_FILL,
* // but it doesn't hurt and saves some bytes on 'if'
* boot_spm_busy_wait();
* #if defined(RWWSRE)
* // this 'if' condition should be: (command == __BOOT_PAGE_WRITE || command == __BOOT_PAGE_ERASE)...
* // but it's tweaked a little assuming that in every command we are interested in here, there
* // must be also SELFPRGEN set. If we skip checking this bit, we save here 4B
* if ((command & (_BV(PGWRT)|_BV(PGERS))) && (data == 0) ) {
* // Reenable read access to flash
* boot_rww_enable();
* }
* #endif
* }
*
*/
/*
* This 'typedef' (in following line) and 'const' (few lines below) are a way to define external function at some arbitrary address
*/
typedef void (*do_spm_t)(uint16_t address, uint8_t command, uint16_t data);
/*
* Devices with 64KB of flash or more have larger bootloader area (1KB) (they are BIGBOOT targets),
* so entry address in these chips is different from smaller ones.
*/
#if FLASHEND > 65534
const do_spm_t do_spm = (do_spm_t)((FLASHEND-1023+2)>>1);
#else
const do_spm_t do_spm = (do_spm_t)((FLASHEND-511+2)>>1);
#endif
/*
* Devices with more than 64KB of flash:
* - have RAMPZ register :-)
* - need larger variable to hold address (pgmspace.h uses uint32_t)
*
* To not do many ifdefs and don't confuse users I declared new 'always valid'
* type to declare address: optiboot_addr_t.
*/
#ifdef RAMPZ
typedef uint32_t optiboot_addr_t;
#else
typedef uint16_t optiboot_addr_t;
#endif
/*
* The same as do_spm but with disable/restore interrupts state
* required to succesfull SPM execution
*
* On devices with more than 64kB flash, 16 bit address is not enough,
* so there is also RAMPZ used in that case.
*/
void do_spm_cli(optiboot_addr_t address, uint8_t command, uint16_t data) {
uint8_t sreg_save;
sreg_save = SREG; // save old SREG value
asm volatile("cli"); // disable interrupts
#ifdef RAMPZ
RAMPZ=(address>>16) & 0xff; // address bits 23-16 goes to RAMPZ
do_spm((address & 0xffff),command,data); // do_spm accepts only lower 16 bits of address
#else
do_spm(address,command,data); // 16 bit address - no problems to pass directly
#endif
SREG=sreg_save; // restore last interrupts state
}
/*
* Erase page in FLASH
*/
void optiboot_page_erase(optiboot_addr_t address) {
do_spm_cli(address,__BOOT_PAGE_ERASE,0);
}
/*
* Write word into temporary buffer
*/
void optiboot_page_fill(optiboot_addr_t address, uint16_t data) {
do_spm_cli(address,__BOOT_PAGE_FILL,data);
}
/*
* Write temporary buffer into FLASH
*/
void optiboot_page_write(optiboot_addr_t address) {
do_spm_cli(address,__BOOT_PAGE_WRITE,0);
}
#endif /* _OPTIBOOT_H_ */
Все благодарности отсылаем Marek Wodzinski. Ну и мне немножко за переработанную демку.
Вам захотелось вывести на ленту пиксельных светодиодов что-то как не поддающееся математическому описанию, так и не являющееся полнейшим хаосом по рандомайзу, посему сохранённое в PROGMEM?
Вывод через FastLED или Adafruit Neopixel с перегрузкой данных из PROGMEM в RAM тосклив, безрадостен и тратит драгоценный ресурс контроллера?
Выход есть - прямой стриминг через LPM на страйп! Отщипнем кусочек от библиотеки Adafruit Neopixel, плюнем, дунем, кое-что заменим и вуаля:
Sketch uses 1106 bytes (3%) of program storage space. Maximum is 30720 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.
Хочу предупредить последователей, что нет гарантии корректной работы последовательных вызовов функции битстрима для заполнения страйпа фрагментами массивов на всех платах с AVR. На моей Freeduino иногда выходят странные спецэффекты.
Вывод одного массива работает, в этом я более-менее уверен. Только не забывайте о том, что перед началом вывода нужно сделать сброс чипу WS2818 через установку состояния LOW на DIN в течении 50мкс минимум.
И я против замены православного delay на конструкцию с millis().
И я против замены православного delay на конструкцию с millis().
Сделал скетч на 4 эффекта, вернул delay, проверил на уно с мелким чипом и на про мини 168 с ещё более мелким. Просьба: граждане-товарищи, у кого есть ленты, ардуины и возможности, проверьте пожалуйста скетч на предмет корректной работы последовательных вызовов функции битстрима с убранным сбросом чипа ws2812b, а то ОЧЕНЬ надоели "штатные библиотеки" со скрытым пожиранием динамической памяти ( когда в скетче используется только 70 процентов дин. памяти, а он не работает ).
Не знаю, скорее надо привыкнуть к манере иной написания. Пару дней назад, когда задумался над этим написал для сравнения два скетча на один эффект - с библиотекой и без :)
/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
int R=0;int G=0;int B=0;//
int t=75;//
///RGB
void setup() {
}
void loop() {
for (int ti = 0; ti < line_; ti++) {
for (int ni = 0; ni < line_; ni++) {
cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
WS2812bOut(dataPin, R, G, B);
}
delay(t);
}
}
///////////////////////////////////////
void cvet (int it,int in){
if(it==in){R=0;G=10;B=0;}else{R=0;G=0;B=0;}//бегущий по ленте зелёный пиксель
}
//////////////////////////////////////
:)
Спустя столько лет до меня стали доходить пророческие слова Логика из последнего сообщения темы:
/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
int R=0;int G=0;int B=0;//
int t=100;//
///RGB
void setup() {
}
void loop() {
for (int ti = 0; ti < line_; ti++) {
for (int ni = 0; ni < line_; ni++) {
cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
WS2812bOut(dataPin, R, G, B);
}
delay(t);
}
}
///////////////////////////////////////
void cvet (int it,int in){
// if(it==in){R=0;G=10;B=0;}else{R=0;G=0;B=0;}//бегущий по ленте -> зелёный пиксель ->
int mnogo=6; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;// бегущая по ленте <-палитра от зелёного до красного (переход из 6 штук)<-
}
//////////////////////////////////////
Придумал обалденный эффект (одной строчкой всего задаётся). Переход палитры определяется переменной mnogo. Всё работает как задумано, НО! если брать значение 8,16 и т.д. выскакивает запись при компиляции - ошибка для платы ... Почему так для этих чисел?
/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
int R=0;int G=0;int B=0;//
int t=100;//
///RGB
void setup() {
}
void loop() {
for (int ti = 0; ti < line_; ti++) {
for (int ni = 0; ni < line_; ni++) {
cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
WS2812bOut(dataPin, R, G, B);
}
delay(t);
}
}
///////////////////////////////////////
void cvet (int it,int in){
// if(it==in){R=0;G=10;B=0;}else{R=0;G=0;B=0;}//бегущий по ленте -> зелёный пиксель ->
int mnogo=6; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;// бегущая по ленте <-палитра от зелёного до красного (переход из 6 штук)<-
}
//////////////////////////////////////
Выскакивает и всё тут:
/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
int R=0;int G=0;int B=0;//
int t=100;//
///RGB
void setup() {
}
void loop() {
for (int ti = 0; ti < line_; ti++) {
for (int ni = 0; ni < line_; ni++) {
cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
WS2812bOut(dataPin, R, G, B);
}
delay(t);
}
}
///////////////////////////////////////
void cvet (int it,int in){
// if(it==in){R=0;G=10;B=0;}else{R=0;G=0;B=0;}//бегущий по ленте -> зелёный пиксель ->
int mnogo=8; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;// бегущая по ленте <-палитра от зелёного до красного (переход из 6 штук)<-
}
//////////////////////////////////////
Ну, понять-то можно, но не люблю я этот inline-assembler, если надо больше одной строки написать. Предпочитаю отдельный файл и там на чистом ассемблере нужные функции, а из С/С++ их вызывать. Можно использовать макросы, структуры и прочие ассемблерные вкусняшки, которые в inline недоступны.
и не лень вам "письками меряться", че там отображать то....при разрешении 128*64*1бит цветности вшивый килобайт данных выплюнуть в порт.
Вообще-то отказ от буфера обычно вызван не соображениями скорости (хотя i2c на стандартных 100 кГц - тоже далеко не 60 fps), а соображениями экономии памяти.
У меня оба Ваши примера нормально компилируются. Без всяких сообщений
Пробовал разные варианты переборов эффектов и при таком все ошибки исчезли почему то:
/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
byte R=0; byte G=0; byte B=0;//составляющие цвета пикселя
int t=75;// пауза между кадрами
byte effekt=1;// номер эффекта
///RGB
void setup() {
}
void loop() {
effekt=random(1,5);//псевдослучайный выбор эффекта
///
for (int ti = 0; ti < line_; ti++) {//перебор номеров кадров в ленте
for (int ni = 0; ni < line_; ni++) {//перебор номеров пикселей в ленте
cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
WS2812bOut(dataPin, R, G, B);//функция вывода данных цвета для текущего номера пикселя
}
delay(t);
}
///
}
///////////////////////////////////////
void cvet (int it,int in){
switch (effekt) {
case 1:
if(in==it){R=0;G=14;B=2;}else{R=7;G=1;B=0;}//бегущий по оранжевой ленте -> цвета бирюзового пиксель ->
break;
case 2:
{ byte mnogo=8; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;}// бегущая по ленте <-палитра от зелёного до красного (переход из 8 штук)<-
break;
case 3:
if(in<=it){R=5;G=0;B=10;}else{R=0;G=10;B=0;}// ->полоса фиолетового цвета набегает на полосу зелёного ->
break;
case 4:
if(in%(it+1)==0){R=15;G=15;B=10;}else{R=7;G=1;B=1;}// -> выстрел белыми пикселями с их взаиморазлётом -> на розовом фоне
break;
default:
R=0;G=0;B=0;//выключаем пиксели если не выбран эффект
}
}
//////////////////////////////////////
Простите, я всё никак не могу понять в чём дело. Подробно о проблеме пишет так "иде":
C:\Users\MDI\AppData\Local\Temp\cc6t7Nyf.s: Assembler messages:
C:\Users\MDI\AppData\Local\Temp\cc6t7Nyf.s:611: Error: register number above 15 required
lto-wrapper: C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-gcc returned 1 exit status
c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.9.2/../../../../avr/bin/ld.exe: error: lto-wrapper failed
collect2.exe: error: ld returned 1 exit status
exit status 1
Ошибка компиляции для платы Arduino Pro or Pro Mini.
Просто выходит мало написать правильно скетч, его ещё надо написать в правильном "иде"? А какая у Вас версия? Я в нём год - полтора назад только одну строчку исправлял, касательно работы с HC-05.
Порой очень хочется изменить значение переменной, расположенной в области PROGMEM.
Это можно сделать вот так, например: https://mon.im/2014/11/modifying-avr-progmem-at-runtime.html
Но, я, как человек ленивый, Atmel Studio ставить не хочу, считать всякие фьюзы - тоже. Поэтому буду менять PROGMEM скетчем, созданным прямо в Arduino IDE. Так как изменение данных в PROGMEM доступно только из области бутлоадера, без дополнительных телодвижений, конечно, не обойтись, т. Но для человека, умеющего копировать файлы, обладающего USBasp и пятью минутами времени, нет ничего невозможного.
Итак:
1) берем специально обученный optiboot: https://raw.githubusercontent.com/majekw/optiboot/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex
2) Вжигаем бутлоадер в вашу Uno/Nano/Pro mini через Arduino IDE;
3) Компилируем и загружаем демку (файлы ниже);
...
42) Profit!
progmem_change.ino:
optiboot.h:
Все благодарности отсылаем Marek Wodzinski. Ну и мне немножко за переработанную демку.
Спасибо. Я уже решил - вообще не на Си - ни на каком :)
Может, суржик? :)
А тема-то, кстати, весьма качественная. Да-а-а, и "в нашу гавань заходили корабли" :-)
Вам захотелось вывести на ленту пиксельных светодиодов что-то как не поддающееся математическому описанию, так и не являющееся полнейшим хаосом по рандомайзу, посему сохранённое в PROGMEM?
Вывод через FastLED или Adafruit Neopixel с перегрузкой данных из PROGMEM в RAM тосклив, безрадостен и тратит драгоценный ресурс контроллера?
Выход есть - прямой стриминг через LPM на страйп! Отщипнем кусочек от библиотеки Adafruit Neopixel, плюнем, дунем, кое-что заменим и вуаля:
Я не великий специалист в AVR assembler, так что если подправите - будет великолепно.
P.S. wdrakula, я помню, что array size модно через темплейт, но макрос ближе лежал.
Минималистично получилось, а главное без буфера и ограничений.
Хочу предупредить последователей, что нет гарантии корректной работы последовательных вызовов функции битстрима для заполнения страйпа фрагментами массивов на всех платах с AVR. На моей Freeduino иногда выходят странные спецэффекты.
Вывод одного массива работает, в этом я более-менее уверен. Только не забывайте о том, что перед началом вывода нужно сделать сброс чипу WS2818 через установку состояния LOW на DIN в течении 50мкс минимум.
И я против замены православного delay на конструкцию с millis().
Сделал скетч на 4 эффекта, вернул delay, проверил на уно с мелким чипом и на про мини 168 с ещё более мелким. Просьба: граждане-товарищи, у кого есть ленты, ардуины и возможности, проверьте пожалуйста скетч на предмет корректной работы последовательных вызовов функции битстрима с убранным сбросом чипа ws2812b, а то ОЧЕНЬ надоели "штатные библиотеки" со скрытым пожиранием динамической памяти ( когда в скетче используется только 70 процентов дин. памяти, а он не работает ).
lilik https://wokwi.com/projects/328014892704465492 самый быстрый вывод. Поменять ОЗУ на PROGMEM и всё.
Просто добавить PROGMEM к массиву, не меняя кода?
:)
Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"
Этого не достаточно конечно. Без LPM не заработает ...
:)
Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"
Так это же для массива в ОЗУ. Под PROGMEM надо подшаманить чутка...
:)
Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"
Так это же для массива в ОЗУ. Под PROGMEM надо подшаманить чутка...
А смысл? Sadman41 уже сделал функцию для работы непосредственно с "динамичными и статичными массивами".
Вопрос был в частном случае применения с исключением и самих массивов в работе с лентой, т.е.
насколько работоспособна конструкция, включающая всю цепочку светодиодов:
а не первый в режиме мигания:
Вот о чём я просил. Т.е. работает код как надо у кого-то ещё кроме меня или нет.
Вот это тест проще на восприятие:
Друзья, я поместил сюда свой пост только потому, что он затрагивает PGM и это соответствует теме.
А спорить как лучше и правильней выкидывать байты в страйп можно бесконечно...
lilik вы посмотрите какой код порождается при вызове функций с таким количеством параметров !
Не знаю, скорее надо привыкнуть к манере иной написания. Пару дней назад, когда задумался над этим написал для сравнения два скетча на один эффект - с библиотекой и без :)
В моём исполнении они мало отличаются.
:)
Спустя столько лет до меня стали доходить пророческие слова Логика из последнего сообщения темы:
https://arduino.ru/forum/programmirovanie/upravlenie-adresnoi-svetodiodn...
Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...
Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...
Я в прошлом году пробовал, дошло до рисования окружности, но слишком долго и затея была заброшена.
Не на одних окружностях мир держится ...
Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...
Тебя еще на форуме не было, а библиотека с таким способом отображения уже была: http://arduino.ru/forum/proekty/asoled-kompaktnaya-biblioteka-dlya-oled-...
и не лень вам "письками меряться", че там отображать то....при разрешении 128*64*1бит цветности вшивый килобайт данных выплюнуть в порт.
Не на одних окружностях мир держится ...
это уже философский вопрос )))
:)
Вообще тема безбуферной жизни весьма актуальна сегодня не только в лентах и экранчиках.
Придумал обалденный эффект (одной строчкой всего задаётся). Переход палитры определяется переменной mnogo. Всё работает как задумано, НО! если брать значение 8,16 и т.д. выскакивает запись при компиляции - ошибка для платы ... Почему так для этих чисел?
Куда и как брать? Приведите код в котором "выскакивает" и в котором "не выскакивает".
Не выскакивает и скетч работает:
Выскакивает и всё тут:
красиво однако, но как это понять?
я тут с полгода назад пытался асм освоить - не так-то это просто. В тестовом скетче работает, а как вставляешь в реальную программу - фиг вам....
PS это я так, не обращайте внимания...
Не выскакивает и скетч работает:
Скетч неполный (в обоих случаях). Функция WS2812bOut не определена.
Если же её вызов закомментировать, то у меня ничего "не выскакивает" ни в одном, ни в другом.
красиво однако, но как это понять?
Ну, понять-то можно, но не люблю я этот inline-assembler, если надо больше одной строки написать. Предпочитаю отдельный файл и там на чистом ассемблере нужные функции, а из С/С++ их вызывать. Можно использовать макросы, структуры и прочие ассемблерные вкусняшки, которые в inline недоступны.
Не выскакивает и скетч работает:
Скетч неполный (в обоих случаях). Функция WS2812bOut не определена.
Если же её вызов закомментировать, то у меня ничего "не выскакивает" ни в одном, ни в другом.
Забыл в угаре экспериментов, функция отдельным ino приложена в папку основного скетча. Она видимо на всё и влияет.
Так лучше. Теперь функция определена.
У меня оба Ваши примера нормально компилируются. Без всяких сообщений
У меня Arduino ide 1.8.2
Наблюдается ещё более интересное:
if(in<=it){R=15;G=2;B=0;}else{R=0;G=0;B=15;}//
Вот такая строка-условие эффекта пройдёт, а ниже уже нет
if(in<=it){R=15;G=2;B=0;}else{R=0;G=0;B=20;}//
Их отличие: в верхней для RGB комбинация из 3 чисел, в нижней из 4.
и не лень вам "письками меряться", че там отображать то....при разрешении 128*64*1бит цветности вшивый килобайт данных выплюнуть в порт.
Вообще-то отказ от буфера обычно вызван не соображениями скорости (хотя i2c на стандартных 100 кГц - тоже далеко не 60 fps), а соображениями экономии памяти.
Так лучше. Теперь функция определена.
У меня оба Ваши примера нормально компилируются. Без всяких сообщений
Пробовал разные варианты переборов эффектов и при таком все ошибки исчезли почему то:
Не иначе как благодать снизошла...
:)
Снизошла и ушла.
Вот красивый вариант мигалки, но стоит закоментить строку с рандомным выбором номера эффекта и выскакивает ошибка.
Ну, Вы хоть номер строки говорите, чего ж Вы издеваетесь над людями то?
Если строка №14, то у меня проблемы нет. Комментирую и всё компилируется.
Простите, я всё никак не могу понять в чём дело. Подробно о проблеме пишет так "иде":
Просто выходит мало написать правильно скетч, его ещё надо написать в правильном "иде"? А какая у Вас версия? Я в нём год - полтора назад только одну строчку исправлял, касательно работы с HC-05.
Обновите IDE.