Но, я, как человек ленивый, 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:
#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:
Все благодарности отсылаем Marek Wodzinski. Ну и мне немножко за переработанную демку.
Спасибо. Я уже решил - вообще не на Си - ни на каком :)
Может, суржик? :)
А тема-то, кстати, весьма качественная. Да-а-а, и "в нашу гавань заходили корабли" :-)
Вам захотелось вывести на ленту пиксельных светодиодов что-то как не поддающееся математическому описанию, так и не являющееся полнейшим хаосом по рандомайзу, посему сохранённое в PROGMEM?
Вывод через FastLED или Adafruit Neopixel с перегрузкой данных из PROGMEM в RAM тосклив, безрадостен и тратит драгоценный ресурс контроллера?
Выход есть - прямой стриминг через LPM на страйп! Отщипнем кусочек от библиотеки Adafruit Neopixel, плюнем, дунем, кое-что заменим и вуаля:
// LED bar on pin 6 uint8_t dataPin = 6; // 3 frame for 8 LED bar const byte frame[][24] PROGMEM = { // GR BB RG { 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 }, // RG BB GR { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, }, // RB GG BR { 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, } }; uint32_t pause = 500; #define arraySize(_array) ( sizeof(_array) / sizeof(*_array) ) // Push bits to stripe static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize) { volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)_data; uint8_t pinMask; port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); hi = *port | pinMask; lo = *port & ~pinMask; next = lo; /* // WS2812 RESET command digitalWrite(dataPin, LOW); delayMicroseconds(50); */ // Some kind of magic here, thanx to Adafruit Neopixel source noInterrupts(); asm volatile ( "lpm r0, Z+" "\n\t" "head20P:" "\n\t" "st %a[port], %[hi]" "\n\t" "sbrc r0, 7" "\n\t" "mov %[next], %[hi]" "\n\t" "dec %[bit]" "\n\t" "st %a[port], %[next]" "\n\t" "mov %[next] , %[lo]" "\n\t" "breq nextbyte20P" "\n\t" "rol r0" "\n\t" "rjmp .+0" "\n\t" "nop" "\n\t" "st %a[port], %[lo]" "\n\t" "nop" "\n\t" "rjmp .+0" "\n\t" "rjmp head20P" "\n\t" "nextbyte20P:" "\n\t" "ldi %[bit] , 8" "\n\t" "lpm r0, Z+" "\n\t" "st %a[port], %[lo]" "\n\t" "sbiw %[count], 1" "\n\t" "brne head20P" "\n\t" : [port] "+e" (port), [bit] "+d" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : "z" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } void setup() { digitalWrite(dataPin, LOW); pinMode(dataPin, OUTPUT); } void loop() { for (uint8_t i = 0; arraySize(frame) > i; i++ ) { WS2812bOut_P(dataPin, frame[i], sizeof(frame[0x00])); delay(pause); } }Я не великий специалист в AVR assembler, так что если подправите - будет великолепно.
P.S. wdrakula, я помню, что array size модно через темплейт, но макрос ближе лежал.
Минималистично получилось, а главное без буфера и ограничений.
///////////////////////////////////// /// тест ws2812b //////////////////////////////////// #define line_ 33 uint8_t dataPin_1 = 6; int dt=75;// int t=400;//пауза const byte k=7;//яркость long Y=0;// int n=0;// /// GRB const byte data_1[]PROGMEM = {0,k,0, k,0,0, 0,0,k, k,k,0, 0,k,k, k,0,k }; // палитра цветов const byte data_2[line_*3]PROGMEM = {};// пусто-сброс void setup() { pinMode(dataPin_1, OUTPUT); pusto(); } void loop() { // эффект 1 for(int i=1;i<(line_+1);i++){ WS2812bOut_P(dataPin_1, &(data_1[3*0]),3*(1) );//красный } delay_(t); pusto(); for(int i=1;i<(line_+1)/1.2;i++){ WS2812bOut_P(dataPin_1, &(data_1[3*1]),3*(1) );//зелёный } delay_(t); pusto(); for(int i=1;i<(line_+1)/1.5;i++){ WS2812bOut_P(dataPin_1, &(data_1[3*2]),3*(1) );//синий } delay_(t); pusto(); for(int i=1;i<(line_+1)/2;i++){ WS2812bOut_P(dataPin_1, &(data_1[3*3]),3*(1) );//жёлтый } delay_(t); pusto(); for(int i=1;i<(line_+1)/3;i++){ WS2812bOut_P(dataPin_1,&(data_1[3*4]),3*(1) );//сиреневый } delay_(t); pusto(); for(int i=1;i<(line_+1)/5;i++){ WS2812bOut_P(dataPin_1, &(data_1[3*5]),3*(1) );//голубой } delay_(t); } ////////////////////////////////////////////////////// #define arraySize(_array) ( sizeof(_array) / sizeof(*_array) ) // Push bits to stripe static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize) { volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)(_data ); uint8_t pinMask; port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); hi = *port | pinMask; lo = *port & ~pinMask; next = lo; /* // WS2812 RESET command digitalWrite(dataPin, LOW); delayMicroseconds(50); */ // Some kind of magic here, thanx to Adafruit Neopixel source noInterrupts(); asm volatile ( "lpm r0, Z+" "\n\t" "head20P:" "\n\t" "st %a[port], %[hi]" "\n\t" "sbrc r0, 7" "\n\t" "mov %[next], %[hi]" "\n\t" "dec %[bit]" "\n\t" "st %a[port], %[next]" "\n\t" "mov %[next] , %[lo]" "\n\t" "breq nextbyte20P" "\n\t" "rol r0" "\n\t" "rjmp .+0" "\n\t" "nop" "\n\t" "st %a[port], %[lo]" "\n\t" "nop" "\n\t" "rjmp .+0" "\n\t" "rjmp head20P" "\n\t" "nextbyte20P:" "\n\t" "ldi %[bit] , 8" "\n\t" "lpm r0, Z+" "\n\t" "st %a[port], %[lo]" "\n\t" "sbiw %[count], 1" "\n\t" "brne head20P" "\n\t" : [port] "+e" (port), [bit] "+d" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : "z" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } ////////////////////////////////////////////////////// void delay_(int T){ Y=millis(); while(millis()-Y<T){ } // n++;if(n>100){n=0;t=t+10;if(t>40){t=10;}} } ///////////////////////////////////// void pusto(){ WS2812bOut_P(dataPin_1, &(data_2[0]),3*(line_) );// delayMicroseconds(dt); } /////////////////////////////////////Хочу предупредить последователей, что нет гарантии корректной работы последовательных вызовов функции битстрима для заполнения страйпа фрагментами массивов на всех платах с AVR. На моей Freeduino иногда выходят странные спецэффекты.
Вывод одного массива работает, в этом я более-менее уверен. Только не забывайте о том, что перед началом вывода нужно сделать сброс чипу WS2818 через установку состояния LOW на DIN в течении 50мкс минимум.
И я против замены православного delay на конструкцию с millis().
Сделал скетч на 4 эффекта, вернул delay, проверил на уно с мелким чипом и на про мини 168 с ещё более мелким. Просьба: граждане-товарищи, у кого есть ленты, ардуины и возможности, проверьте пожалуйста скетч на предмет корректной работы последовательных вызовов функции битстрима с убранным сбросом чипа ws2812b, а то ОЧЕНЬ надоели "штатные библиотеки" со скрытым пожиранием динамической памяти ( когда в скетче используется только 70 процентов дин. памяти, а он не работает ).
///////////////////////////////////// /// тест ws2812b //////////////////////////////////// #define line_ 33 uint8_t dataPin_1 = 6; int dt = 75; // int t = 30; //пауза const byte k = 7; //яркость long Y = 0; // /// GRB const byte data_1[]PROGMEM = {0, k, 0, k, 0, 0, 0, 0, k, k, k, 0, 0, k, k, k, 0, k }; // палитра цветов const byte data_2[line_ * 3]PROGMEM = {}; // пусто-сброс void setup() { pinMode(dataPin_1, OUTPUT); pusto(); } void loop() { // эффект 1 for (int j = 0; j < 6; j++) { for (int i = 1; i < (line_ + 1); i++) { WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); //перебор цветов WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); delay(t); pusto(); } } // эффект 2 for (int n = 0; n < 6; n++) { for (int j = 1; j < (line_ + 1); j++) { for (int i = 1; i <= j; i++) { WS2812bOut_P(dataPin_1, &(data_1[3 * n]), 3 * (1) ); } delay(t); } } // эффект 3 pusto(); int w = 0; int n = 0; while (w < 12) { n = random(0, 6); for (int i = 1; i < (line_ + 1); i++) { WS2812bOut_P(dataPin_1, &(data_1[3 * n]), 3 * (1) ); } delay(20 * t); w++; } // эффект 4 w = 0; while (w < 6) { for (int i = line_; i >= 1; i--) { WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); delay(1.5 * t); } for (int i = 1; i < (line_ + 1); i++) { WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); delay(t); } w++; } } ////////////////////////////////////////////////////// #define arraySize(_array) ( sizeof(_array) / sizeof(*_array) ) // Push bits to stripe static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize) { volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)(_data ); uint8_t pinMask; port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); hi = *port | pinMask; lo = *port & ~pinMask; next = lo; /* // WS2812 RESET command digitalWrite(dataPin_1, LOW); delayMicroseconds(50); */ // Some kind of magic here, thanx to Adafruit Neopixel source noInterrupts(); asm volatile ( "lpm r0, Z+" "\n\t" "head20P:" "\n\t" "st %a[port], %[hi]" "\n\t" "sbrc r0, 7" "\n\t" "mov %[next], %[hi]" "\n\t" "dec %[bit]" "\n\t" "st %a[port], %[next]" "\n\t" "mov %[next] , %[lo]" "\n\t" "breq nextbyte20P" "\n\t" "rol r0" "\n\t" "rjmp .+0" "\n\t" "nop" "\n\t" "st %a[port], %[lo]" "\n\t" "nop" "\n\t" "rjmp .+0" "\n\t" "rjmp head20P" "\n\t" "nextbyte20P:" "\n\t" "ldi %[bit] , 8" "\n\t" "lpm r0, Z+" "\n\t" "st %a[port], %[lo]" "\n\t" "sbiw %[count], 1" "\n\t" "brne head20P" "\n\t" : [port] "+e" (port), [bit] "+d" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : "z" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } ///////////////////////////////////// void pusto() { WS2812bOut_P(dataPin_1, &(data_2[0]), 3 * (line_) ); // delayMicroseconds(dt); } /////////////////////////////////////lilik https://wokwi.com/projects/328014892704465492 самый быстрый вывод. Поменять ОЗУ на PROGMEM и всё.
Просто добавить PROGMEM к массиву, не меняя кода?
:)
Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"
Этого не достаточно конечно. Без LPM не заработает ...
:)
Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"
Так это же для массива в ОЗУ. Под PROGMEM надо подшаманить чутка...
:)
Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"
Так это же для массива в ОЗУ. Под PROGMEM надо подшаманить чутка...
А смысл? Sadman41 уже сделал функцию для работы непосредственно с "динамичными и статичными массивами".
Вопрос был в частном случае применения с исключением и самих массивов в работе с лентой, т.е.
насколько работоспособна конструкция, включающая всю цепочку светодиодов:
а не первый в режиме мигания:
Вот о чём я просил. Т.е. работает код как надо у кого-то ещё кроме меня или нет.
///////////////////////////////////// /// тест ws2812b //////////////////////////////////// #define line_ 33 uint8_t dataPin_1 = 6; int dt = 75; // int t = 30; //пауза const byte k = 7; //яркость /// GRB const byte data_1[]PROGMEM = {0, k, 0, k, 0, 0, 0, 0, k, k, k, 0, 0, k, k, k, 0, k, k/3,2*k,0}; // палитра цветов const byte data_2[line_ * 3]PROGMEM = {}; // пусто-сброс void setup() { pinMode(dataPin_1, OUTPUT); pusto(); } void loop() { // эффект 1 for (int j = 0; j < 6; j++) { for (int i = 1; i < (line_ + 1); i++) { WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); //перебор цветов WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); delay(t); pusto(); } } // эффект 2 for (int n = 0; n < 6; n++) { for (int j = 1; j < (line_ + 1); j++) { for (int i = 1; i <= j; i++) { WS2812bOut_P(dataPin_1, &(data_1[3 * n]), 3 * (1) ); } delay(t); } } // эффект 3 pusto(); int w = 0; int n = 0; while (w < 12) { n = random(0, 6); for (int i = 1; i < (line_ + 1); i++) { WS2812bOut_P(dataPin_1, &(data_1[3 * n]), 3 * (1) ); } delay(20 * t); w++; } // эффект 4 w = 0; while (w < 4) { for (int i = line_; i >= 1; i--) { WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); delay(2.5 * t); } for (int i = 1; i < (line_ + 1); i++) { WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) ); delay(t); } w++; } // эффект 5 w = 0; while (w < 6) { for (int j = 0; j < 1.5*(line_ + 1); j++) { for (int i = 0; i <=j; i++) { WS2812bOut_P(dataPin_1, &(data_1[3 * 2]), 3 * (1) ); } for (int i = 0; i <=j; i++) { WS2812bOut_P(dataPin_1, &(data_1[3 * 6]), 3 * (1) ); } for (int i = 0; i <=j; i++) { WS2812bOut_P(dataPin_1, &(data_1[3 * 2]), 3 * (1) ); } delay(t); } w++; } } ////////////////////////////////////////////////////// #define arraySize(_array) ( sizeof(_array) / sizeof(*_array) ) // Push bits to stripe static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize) { volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)(_data ); uint8_t pinMask; port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); hi = *port | pinMask; lo = *port & ~pinMask; next = lo; /* // WS2812 RESET command digitalWrite(_dataPin, LOW); delayMicroseconds(50); */ // Some kind of magic here, thanx to Adafruit Neopixel source noInterrupts(); asm volatile ( "lpm r0, Z+" "\n\t" "head20P:" "\n\t" "st %a[port], %[hi]" "\n\t" "sbrc r0, 7" "\n\t" "mov %[next], %[hi]" "\n\t" "dec %[bit]" "\n\t" "st %a[port], %[next]" "\n\t" "mov %[next] , %[lo]" "\n\t" "breq nextbyte20P" "\n\t" "rol r0" "\n\t" "rjmp .+0" "\n\t" "nop" "\n\t" "st %a[port], %[lo]" "\n\t" "nop" "\n\t" "rjmp .+0" "\n\t" "rjmp head20P" "\n\t" "nextbyte20P:" "\n\t" "ldi %[bit] , 8" "\n\t" "lpm r0, Z+" "\n\t" "st %a[port], %[lo]" "\n\t" "sbiw %[count], 1" "\n\t" "brne head20P" "\n\t" : [port] "+e" (port), [bit] "+d" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : "z" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } ///////////////////////////////////// void pusto() { WS2812bOut_P(dataPin_1, &(data_2[0]), 3 * (line_) ); // delayMicroseconds(dt); } /////////////////////////////////////Вот это тест проще на восприятие:
///////////////////////////////////// /// тест ws2812b //////////////////////////////////// uint8_t dataPin = 6; ///RGB void setup() {} void loop() { //мигалка палитра на 6 пикселей WS2812bOut(dataPin,5,0,0); WS2812bOut(dataPin,0,5,0); WS2812bOut(dataPin,0,0,5); WS2812bOut(dataPin,5,5,0); WS2812bOut(dataPin,0,5,5); WS2812bOut(dataPin,5,0,5);//самый удалённый от начала ленты пиксель delay(200); WS2812bOut(dataPin,0,0,0); WS2812bOut(dataPin,0,0,0); WS2812bOut(dataPin,0,0,0); WS2812bOut(dataPin,0,0,0); WS2812bOut(dataPin,0,0,0); WS2812bOut(dataPin,0,0,0);//самый удалённый от начала ленты пиксель delay(200); } ////////////////////////////////////////////////////// static void WS2812bOut(const uint8_t _dataPin,uint8_t R,uint8_t G,uint8_t B ) { uint8_t _data[]={G,R,B}; uint16_t _dataSize = 3; volatile uint8_t hi, lo, next, currentByte, currentBit = 0x08, *port, *ptrData = _data; uint8_t pinMask; digitalWrite(_dataPin, LOW); pinMode(_dataPin, OUTPUT); port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); currentByte = *ptrData++; hi = *port | pinMask; lo = *port & ~pinMask; next = lo; noInterrupts(); asm volatile ( "head20:" "\n\t" // Clk Pseudocode (T = 0) "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) "dec %[bit]" "\n\t" // 1 bit-- (T = 5) "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) "rjmp .+0" "\n\t" // 2 nop nop (T = 12) "nop" "\n\t" // 1 nop (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "rjmp .+0" "\n\t" // 2 nop nop (T = 18) "rjmp head20" "\n\t" // 2 -> head20 (next bit out) "nextbyte20:" "\n\t" // (T = 10) "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) "brne head20" "\n" // 2 if(i != 0) -> (next byte) : [port] "+e" (port), [byte] "+r" (currentByte), [bit] "+r" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : [ptr] "e" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } //////////////////////////////////////////////////////Друзья, я поместил сюда свой пост только потому, что он затрагивает PGM и это соответствует теме.
А спорить как лучше и правильней выкидывать байты в страйп можно бесконечно...
lilik вы посмотрите какой код порождается при вызове функций с таким количеством параметров !
Не знаю, скорее надо привыкнуть к манере иной написания. Пару дней назад, когда задумался над этим написал для сравнения два скетча на один эффект - с библиотекой и без :)
В моём исполнении они мало отличаются.
///////////////////////////////////// /// тест ws2812b //////////////////////////////////// #define line_ 33 uint8_t dataPin_1 = 6; int dt=75;// int t=400;//пауза const byte k=7;//яркость long Y=0;// int n=0;// /// GRB const byte data_1[]PROGMEM = {0,k,0, k,0,0, 0,0,k, k,k,0, 0,k,k, k,0,k }; // палитра цветов const byte data_2[line_*3]PROGMEM = {};// пусто-сброс void setup() { pinMode(dataPin_1, OUTPUT); pusto(); } void loop() { // эффект 1 for(int i=1;i<(line_+1);i++){ WS2812bOut_P(dataPin_1, &(data_1[3*0]),3*(1) );//красный } delay_(t); pusto(); for(int i=1;i<(line_+1)/1.2;i++){ WS2812bOut_P(dataPin_1, &(data_1[3*1]),3*(1) );//зелёный } delay_(t); pusto(); for(int i=1;i<(line_+1)/1.5;i++){ WS2812bOut_P(dataPin_1, &(data_1[3*2]),3*(1) );//синий } delay_(t); pusto(); for(int i=1;i<(line_+1)/2;i++){ WS2812bOut_P(dataPin_1, &(data_1[3*3]),3*(1) );//жёлтый } delay_(t); pusto(); for(int i=1;i<(line_+1)/3;i++){ WS2812bOut_P(dataPin_1,&(data_1[3*4]),3*(1) );//сиреневый } delay_(t); pusto(); for(int i=1;i<(line_+1)/5;i++){ WS2812bOut_P(dataPin_1, &(data_1[3*5]),3*(1) );//голубой } delay_(t);pusto(); } ////////////////////////////////////////////////////// #define arraySize(_array) ( sizeof(_array) / sizeof(*_array) ) // Push bits to stripe static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize) { volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)(_data ); uint8_t pinMask; port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); hi = *port | pinMask; lo = *port & ~pinMask; next = lo; /* // WS2812 RESET command digitalWrite(dataPin, LOW); delayMicroseconds(50); */ // Some kind of magic here, thanx to Adafruit Neopixel source noInterrupts(); asm volatile ( "lpm r0, Z+" "\n\t" "head20P:" "\n\t" "st %a[port], %[hi]" "\n\t" "sbrc r0, 7" "\n\t" "mov %[next], %[hi]" "\n\t" "dec %[bit]" "\n\t" "st %a[port], %[next]" "\n\t" "mov %[next] , %[lo]" "\n\t" "breq nextbyte20P" "\n\t" "rol r0" "\n\t" "rjmp .+0" "\n\t" "nop" "\n\t" "st %a[port], %[lo]" "\n\t" "nop" "\n\t" "rjmp .+0" "\n\t" "rjmp head20P" "\n\t" "nextbyte20P:" "\n\t" "ldi %[bit] , 8" "\n\t" "lpm r0, Z+" "\n\t" "st %a[port], %[lo]" "\n\t" "sbiw %[count], 1" "\n\t" "brne head20P" "\n\t" : [port] "+e" (port), [bit] "+d" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : "z" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } ////////////////////////////////////////////////////// void delay_(int T){ Y=millis(); while(millis()-Y<T){ } // n++;if(n>100){n=0;t=t+10;if(t>40){t=10;}} } ///////////////////////////////////// void pusto(){ WS2812bOut_P(dataPin_1, &(data_2[0]),3*(line_) );// delayMicroseconds(dt); } /////////////////////////////////////#include "Adafruit_NeoPixel.h" #define LED_COUNT1 33 #define LED_PIN1 6 int k=5;// int t=400;// Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(LED_COUNT1, LED_PIN1, NEO_GRB + NEO_KHZ800);// Создаем переменную strip для управления нашей лентой. void setup () { strip1.begin(); pusto(); } void loop () { // эффект 1 for(int i=0;i<(LED_COUNT1);i++){ strip1.setPixelColor(i, k, 0, 0); // ;//красный } strip1.show(); delay(t); pusto(); for(int i=0;i<(LED_COUNT1)/1.2;i++){ strip1.setPixelColor(i, 0, k, 0); //зелёный } strip1.show(); delay(t); pusto(); for(int i=0;i<(LED_COUNT1)/1.5;i++){ strip1.setPixelColor(i, 0, 0, k);//синий } strip1.show(); delay(t); pusto(); for(int i=0;i<(LED_COUNT1)/2;i++){ strip1.setPixelColor(i, k, k, 0);//жёлтый } strip1.show(); delay(t); pusto(); for(int i=0;i<(LED_COUNT1)/3;i++){ strip1.setPixelColor(i, k, 0, k);//сиреневый } strip1.show();delay(t); pusto(); for(int i=0;i<(LED_COUNT1)/5;i++){ strip1.setPixelColor(i, 0, k, k);//голубой } strip1.show(); delay(t); pusto(); } ////////////////////////////////// void pusto(){ ////////// выключение пикселей for (int i = 0; i < LED_COUNT1; i++) { strip1.setPixelColor(i, 0, 0, 0); // } strip1.show(); } ////////////////////////////////////////////////////////////////////// /// примеры для 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;}//бегущий по ленте зелёный пиксель } //////////////////////////////////////:)
Спустя столько лет до меня стали доходить пророческие слова Логика из последнего сообщения темы:
https://arduino.ru/forum/programmirovanie/upravlenie-adresnoi-svetodiodn...
Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...
Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...
Я в прошлом году пробовал, дошло до рисования окружности, но слишком долго и затея была заброшена.
Не на одних окружностях мир держится ...
Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...
Тебя еще на форуме не было, а библиотека с таким способом отображения уже была: http://arduino.ru/forum/proekty/asoled-kompaktnaya-biblioteka-dlya-oled-...
и не лень вам "письками меряться", че там отображать то....при разрешении 128*64*1бит цветности вшивый килобайт данных выплюнуть в порт.
Не на одних окружностях мир держится ...
это уже философский вопрос )))
:)
Вообще тема безбуферной жизни весьма актуальна сегодня не только в лентах и экранчиках.
///////////////////////////////////// /// примеры для 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 штук)<- } //////////////////////////////////////красиво однако, но как это понять?
asm volatile ( "lpm r0, Z+" "\n\t" "head20P:" "\n\t" "st %a[port], %[hi]" "\n\t" "sbrc r0, 7" "\n\t" "mov %[next], %[hi]" "\n\t" "dec %[bit]" "\n\t" "st %a[port], %[next]" "\n\t" "mov %[next] , %[lo]" "\n\t" "breq nextbyte20P" "\n\t" "rol r0" "\n\t" "rjmp .+0" "\n\t" "nop" "\n\t" "st %a[port], %[lo]" "\n\t" "nop" "\n\t" "rjmp .+0" "\n\t" "rjmp head20P" "\n\t" "nextbyte20P:" "\n\t" "ldi %[bit] , 8" "\n\t" "lpm r0, Z+" "\n\t" "st %a[port], %[lo]" "\n\t" "sbiw %[count], 1" "\n\t" "brne head20P" "\n\t" : [port] "+e" (port), [bit] "+d" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : "z" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); }я тут с полгода назад пытался асм освоить - не так-то это просто. В тестовом скетче работает, а как вставляешь в реальную программу - фиг вам....
PS это я так, не обращайте внимания...
Не выскакивает и скетч работает:
Скетч неполный (в обоих случаях). Функция WS2812bOut не определена.
Если же её вызов закомментировать, то у меня ничего "не выскакивает" ни в одном, ни в другом.
красиво однако, но как это понять?
Ну, понять-то можно, но не люблю я этот inline-assembler, если надо больше одной строки написать. Предпочитаю отдельный файл и там на чистом ассемблере нужные функции, а из С/С++ их вызывать. Можно использовать макросы, структуры и прочие ассемблерные вкусняшки, которые в inline недоступны.
Не выскакивает и скетч работает:
Скетч неполный (в обоих случаях). Функция WS2812bOut не определена.
Если же её вызов закомментировать, то у меня ничего "не выскакивает" ни в одном, ни в другом.
Забыл в угаре экспериментов, функция отдельным ino приложена в папку основного скетча. Она видимо на всё и влияет.
///////////////////////////////////////////////////////////////////////////////////////////////// static void WS2812bOut(const uint8_t _dataPin, uint8_t R, uint8_t G, uint8_t B ) { uint8_t _data[] = {G, R, B}; uint16_t _dataSize = 3; volatile uint8_t hi, lo, next, currentByte, currentBit = 0x08, *port, *ptrData = _data; uint8_t pinMask; digitalWrite(_dataPin, LOW); pinMode(_dataPin, OUTPUT); port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); currentByte = *ptrData++; hi = *port | pinMask; lo = *port & ~pinMask; next = lo; noInterrupts(); asm volatile ( "head20:" "\n\t" // Clk Pseudocode (T = 0) "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) "dec %[bit]" "\n\t" // 1 bit-- (T = 5) "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) "rjmp .+0" "\n\t" // 2 nop nop (T = 12) "nop" "\n\t" // 1 nop (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "rjmp .+0" "\n\t" // 2 nop nop (T = 18) "rjmp head20" "\n\t" // 2 -> head20 (next bit out) "nextbyte20:" "\n\t" // (T = 10) "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) "brne head20" "\n" // 2 if(i != 0) -> (next byte) : [port] "+e" (port), [byte] "+r" (currentByte), [bit] "+r" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : [ptr] "e" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } ///////////////////////////////////////////////////////Так лучше. Теперь функция определена.
У меня оба Ваши примера нормально компилируются. Без всяких сообщений
У меня 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), а соображениями экономии памяти.
Так лучше. Теперь функция определена.
У меня оба Ваши примера нормально компилируются. Без всяких сообщений
Пробовал разные варианты переборов эффектов и при таком все ошибки исчезли почему то:
///////////////////////////////////// /// примеры для 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;//выключаем пиксели если не выбран эффект } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void WS2812bOut(const uint8_t _dataPin, uint8_t R, uint8_t G, uint8_t B ) { uint8_t _data[] = {G, R, B}; uint16_t _dataSize = 3; volatile uint8_t hi, lo, next, currentByte, currentBit = 0x08, *port, *ptrData = _data; uint8_t pinMask; digitalWrite(_dataPin, LOW); pinMode(_dataPin, OUTPUT); port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); currentByte = *ptrData++; hi = *port | pinMask; lo = *port & ~pinMask; next = lo; noInterrupts(); asm volatile ( "head20:" "\n\t" // Clk Pseudocode (T = 0) "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) "dec %[bit]" "\n\t" // 1 bit-- (T = 5) "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) "rjmp .+0" "\n\t" // 2 nop nop (T = 12) "nop" "\n\t" // 1 nop (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "rjmp .+0" "\n\t" // 2 nop nop (T = 18) "rjmp head20" "\n\t" // 2 -> head20 (next bit out) "nextbyte20:" "\n\t" // (T = 10) "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) "brne head20" "\n" // 2 if(i != 0) -> (next byte) : [port] "+e" (port), [byte] "+r" (currentByte), [bit] "+r" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : [ptr] "e" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } ///////////////////////////////////////////////////////Не иначе как благодать снизошла...
:)
Снизошла и ушла.
Вот красивый вариант мигалки, но стоит закоментить строку с рандомным выбором номера эффекта и выскакивает ошибка.
///////////////////////////////////// /// примеры для 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,11);//псевдослучайный выбор эффекта /// 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=9; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;}// бегущая по ленте <-палитра от зелёного до красного (переход из 9 штук)<- 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; case 5: if(in==line_-it||in+1==line_-it||in+2==line_-it||in+3==line_-it||in+4==line_-it){R=15;G=3;B=0;}else{R=0;G=0;B=7;}//бегущий по синей ленте -> цвета оранжевого 5 пикселей -> break; case 6: { byte mnogo=10; R=5*((in+it%mnogo)%mnogo);G=0;B=5*((mnogo-1-(in+it%mnogo)%mnogo));}// бегущая по ленте <-палитра от синего до красного (переход из 10 штук)<- break; case 7: if(in<=line_-it){R=10;G=10;B=0;}else{R=0;G=7;B=7;}// <-полоса голубого цвета набегает на полосу жёлтого <- break; case 8: if(in%(it+1)==0){R=15;G=15;B=10;}else{R=0;G=2;B=2;}// -> выстрел белыми пикселями с их взаиморазлётом -> на голубом фоне break; case 9: { byte mnogo=32; R=3;G=1*(mnogo-1-(it%mnogo));B=1*((it%mnogo));}// плавный переход цвета ленты от "зеленоватого к синеватому" break; case 10: { byte mnogo=32; R=1*(mnogo-1-(it%mnogo));G=1;B=1*((it%mnogo));}// плавный переход цвета ленты от "красноватого к синеватому" break; default: R=0;G=0;B=0;//выключаем пиксели если не выбран эффект } } ////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// static void WS2812bOut(const uint8_t _dataPin, uint8_t R, uint8_t G, uint8_t B ) { uint8_t _data[] = {G, R, B}; uint16_t _dataSize = 3; volatile uint8_t hi, lo, next, currentByte, currentBit = 0x08, *port, *ptrData = _data; uint8_t pinMask; digitalWrite(_dataPin, LOW); pinMode(_dataPin, OUTPUT); port = portOutputRegister(digitalPinToPort(_dataPin)); pinMask = digitalPinToBitMask(_dataPin); currentByte = *ptrData++; hi = *port | pinMask; lo = *port & ~pinMask; next = lo; noInterrupts(); asm volatile ( "head20:" "\n\t" // Clk Pseudocode (T = 0) "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) "dec %[bit]" "\n\t" // 1 bit-- (T = 5) "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) "rjmp .+0" "\n\t" // 2 nop nop (T = 12) "nop" "\n\t" // 1 nop (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "rjmp .+0" "\n\t" // 2 nop nop (T = 18) "rjmp head20" "\n\t" // 2 -> head20 (next bit out) "nextbyte20:" "\n\t" // (T = 10) "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) "nop" "\n\t" // 1 nop (T = 16) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) "brne head20" "\n" // 2 if(i != 0) -> (next byte) : [port] "+e" (port), [byte] "+r" (currentByte), [bit] "+r" (currentBit), [next] "+r" (next), [count] "+w" (_dataSize) : [ptr] "e" (ptrData), [hi] "r" (hi), [lo] "r" (lo) ); interrupts(); } ///////////////////////////////////////////////////////Ну, Вы хоть номер строки говорите, чего ж Вы издеваетесь над людями то?
Если строка №14, то у меня проблемы нет. Комментирую и всё компилируется.
Простите, я всё никак не могу понять в чём дело. Подробно о проблеме пишет так "иде":
Просто выходит мало написать правильно скетч, его ещё надо написать в правильном "иде"? А какая у Вас версия? Я в нём год - полтора назад только одну строчку исправлял, касательно работы с HC-05.
Обновите IDE.