вместе не работают библиотеки adafruit_neopixel и VirtualWire (RadioHead )
- Войдите на сайт для отправки комментариев
Здравствуйте. Столкнулся с проблемой взаимодействия библиотеки для ленты WS2812 и rf передатчика на 433 Mhz. Выяснил, что библиотеки используют одинаковое прерывание по Timer1. Как подправить одну из этих библиотек на работу с Timer2, найти не смог. Товарищи с буржуйских форумов советуют продвинутую библиотеку RadioHead, работающую практически с любыми RF передатчиками (за исключением esp ). В этой библиотеке есть возможность, раскоментировав один define из файла *.cpp переключить ее на работу с таймером 2. Внимательно прочел, сделал все как по феншую, но та же беда в работе скетча.
Как только раскоменчиваю строчку pixels.show(); для отображения WS2812 ленты, приемная часть затыкается и ни одного пакета по радиоканалу на ардуинку более не проходит.
Прошу помощи для наладки взаимодействия цветной LED ленты и rf передатчика.
Any suggastions?
В виртуалвайр очень простая работа с таймером, его просто заводят, чтобы он дергался с определённой частотой и всё. Переделать легко, если Вы умеете работать с таймерами.
Я переделывал её на второй таймер, но мне нужен был только приёмник (передатчик не был нужен). И ещё, я намертво забил туда скорость передачи 2000 (убрал параметр).
Если такое решение (только для приёмника и с фиксированной скоростью) устроит, могу дать.
Мне как раз нужен приемник и 2000 бод приемлемая скорость! В принципе мог бы и сам посидеть вспомнить регистры, но буду благодарен за Вашу библиотеку :)
Ну, давайте, потихоньку. Чтобы Вы могли запустить мои примеры. Вам нужны мои файлы.
Значит у меня есть два файла, которые надо расположить как библиотеки:
1. FS1000A.h - это просто небольшая обёртка вокруг VirtualWire. Мне удобнее работать с нею, чем в оригинальной VirtualWire. Посмотрите на её функции - поймёте почему. Она нуждается в оригинальной VirtualWire и всё делает через неё. Там ничего не поменено. Эту "библиотеку" использует передатчик из моего примера.
2. FS1000A_V.h - этот файл уже включает в себя переделанную VirtualWire, т.е. оригинальная VirtualWire ему не нужна. Реализован только приёмник. Всё работает на втором таймере. Эту "библиотеку" использует приёмник из моего примера.
Ещё раз, эти файлы ставим как библиотеки (в сответсвующие папки).
Вот все файлы.
FS1000A.h
#ifndef FS1000A_h #define FS1000A_h #include <VirtualWire.h> ////////////////////////////////////////////////////////////////////////////////////// // // ФУНКЦИИ ПЕРЕДАТЧИКА // /////////////////////////////////////////////////// // // Инициализация передатчика // inline static void FS1000A_Init(const int8_t pin) { pinMode(pin, OUTPUT); vw_set_ptt_inverted(true); vw_setup(2000); vw_set_tx_pin(pin); } /////////////////////////////////////////////////// // // Ждать завершения передачи сообщения // inline static void FS1000A_WaitForTransmission(void) { vw_wait_tx(); } /////////////////////////////////////////////////// // // Отправить сообщение из буфера buf длиной len // если waitForTransmission - true, то дождаться завершения отправки // иначе вернуться сразу же. // inline static void FS1000A_Send(const byte * buf, const byte len, const bool waitForTransmission = true) { vw_send((byte *)buf, (byte)len); if (waitForTransmission) FS1000A_WaitForTransmission(); } /////////////////////////////////////////////////// // // Отправить строку s без завершающего 0 // если waitForTransmission - true, то дождаться завершения отправки // иначе вернуться сразу же. // inline static void FS1000A_Send(const char * s, const bool waitForTransmission = true) { FS1000A_Send((const byte *) s, strlen(s), waitForTransmission); } /////////////////////////////////////////////////// // // Возвращает true если идёт передача // inline bool FS1000A_InProgress(void) { return vx_tx_active(); } ////////////////////////////////////////////////////////////////////////////////////// // // ФУНКЦИИ ПРИЁМНИКА // /////////////////////////////////////////////////// // // Инициализация приёмника // inline static void XY_MK_5V_Init(const int8_t pin) { vw_set_ptt_inverted(true); vw_setup(2000); vw_set_rx_pin(pin); } /////////////////////////////////////////////////// // // Включаем "слушание" эфира // inline static void XY_MK_5V_Start(void) { vw_rx_start(); } /////////////////////////////////////////////////// // // Выключаем "слушание" эфира // inline static void XY_MK_5V_Stop(void) { vw_rx_stop(); } /////////////////////////////////////////////////// // // Возвращает true если пришло сообщение // inline static bool XY_MK_5V_Available(void) { return vw_have_message(); } /////////////////////////////////////////////////// // // Ждёт прихода сообщения указанное количество миллисекунд (если 0, то ждёт бесконечно) // Возвращает true если дождалась и false в противном случае. // inline static bool XY_MK_5V_WaitForMessage(unsigned long milliseconds = 0) { if (milliseconds) return vw_wait_rx_max(milliseconds); vw_wait_rx(); return true; } /////////////////////////////////////////////////// // // Получает сообщение в буфер buf. // Максимальная длина буфера должна находится в *len // по завершении в *len будет реальная длина полученного сообщения // возвращает true если сообщение получено нормально // inline static bool XY_MK_5V_ReceiveMessage(byte * buf, byte * len) { return vw_get_message(buf, len); } inline static bool XY_MK_5V_ReceiveMessage(char * s, byte * len) { return XY_MK_5V_ReceiveMessage((byte *) s, len); } #endif // FS1000AFS1000A_V.h
#ifndef FS1000A_V_h #define FS1000A_V_h #include <arduino.h> #include <stdint.h> static inline uint16_t _crc_ccitt_update (uint16_t crc, uint8_t data) { data ^= crc & 0xff; data ^= data << 4; return ((((uint16_t)data << 8) | (crc >> 8)) ^ (uint8_t)(data >> 4) ^ ((uint16_t)data << 3)); } #undef abs #undef double #undef round #define VW_MAX_MESSAGE_LEN 30 #define VW_MAX_PAYLOAD VW_MAX_MESSAGE_LEN-3 #define VW_RX_RAMP_LEN 160 #define VW_RX_SAMPLES_PER_BIT 8 #define VW_RAMP_INC (VW_RX_RAMP_LEN/VW_RX_SAMPLES_PER_BIT) #define VW_RAMP_TRANSITION VW_RX_RAMP_LEN/2 #define VW_RAMP_ADJUST 9 #define VW_RAMP_INC_RETARD (VW_RAMP_INC-VW_RAMP_ADJUST) #define VW_RAMP_INC_ADVANCE (VW_RAMP_INC+VW_RAMP_ADJUST) #define VW_HEADER_LEN 8 // The digital IO pin number of the receiver data static uint8_t vw_rx_pin = 11; // Current receiver sample static uint8_t vw_rx_sample = 0; // Last receiver sample static uint8_t vw_rx_last_sample = 0; static uint8_t vw_rx_pll_ramp = 0; static uint8_t vw_rx_integrator = 0; static uint8_t vw_rx_active = 0; // Flag to indicate that a new message is available static volatile uint8_t vw_rx_done = 0; // Flag to indicate the receiver PLL is to run static uint8_t vw_rx_enabled = 0; // Last 12 bits received, so we can look for the start symbol static uint16_t vw_rx_bits = 0; // How many bits of message we have received. Ranges from 0 to 12 static uint8_t vw_rx_bit_count = 0; // The incoming message buffer static uint8_t vw_rx_buf[VW_MAX_MESSAGE_LEN]; // The incoming message expected length static uint8_t vw_rx_count = 0; // The incoming message buffer length received so far static volatile uint8_t vw_rx_len = 0; // Number of bad messages received and dropped due to bad lengths static uint8_t vw_rx_bad = 0; // Number of good messages received static uint8_t vw_rx_good = 0; // 4 bit to 6 bit symbol converter table // Used to convert the high and low nybbles of the transmitted data // into 6 bit symbols for transmission. Each 6-bit symbol has 3 1s and 3 0s // with at most 3 consecutive identical bits static uint8_t symbols[] = { 0xd, 0xe, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x32, 0x34 }; // Compute CRC over count bytes. // This should only be ever called at user level, not interrupt level static uint16_t vw_crc(uint8_t *ptr, uint8_t count) { uint16_t crc = 0xffff; while (count-- > 0) crc = _crc_ccitt_update(crc, *ptr++); return crc; } // Convert a 6 bit encoded symbol into its 4 bit decoded equivalent static uint8_t vw_symbol_6to4(uint8_t symbol) { uint8_t i; // Linear search :-( Could have a 64 byte reverse lookup table? for (i = 0; i < 16; i++) if (symbol == symbols[i]) return i; return 0; // Not found } // Set the pin number for input receiver data inline void vw_set_rx_pin(uint8_t pin) { vw_rx_pin = pin; } // Set the output pin number for transmitter PTT enable //inline void vw_set_ptt_pin(uint8_t pin) { // vw_ptt_pin = pin; //} // Set the ptt pin inverted (low to transmit) //void vw_set_ptt_inverted(uint8_t inverted) { // vw_ptt_inverted = inverted; //} // Called 8 times per bit period // Phase locked loop tries to synchronise with the transmitter so that bit // transitions occur at about the time vw_rx_pll_ramp is 0; // Then the average is computed over each bit period to deduce the bit value void vw_pll() { // Integrate each sample if (vw_rx_sample) vw_rx_integrator++; if (vw_rx_sample != vw_rx_last_sample) { // Transition, advance if ramp > 80, retard if < 80 vw_rx_pll_ramp += ((vw_rx_pll_ramp < VW_RAMP_TRANSITION) ? VW_RAMP_INC_RETARD : VW_RAMP_INC_ADVANCE); vw_rx_last_sample = vw_rx_sample; } else { // No transition // Advance ramp by standard 20 (== 160/8 samples) vw_rx_pll_ramp += VW_RAMP_INC; } if (vw_rx_pll_ramp >= VW_RX_RAMP_LEN) { // Add this to the 12th bit of vw_rx_bits, LSB first // The last 12 bits are kept vw_rx_bits >>= 1; // Check the integrator to see how many samples in this cycle were high. // If < 5 out of 8, then its declared a 0 bit, else a 1; if (vw_rx_integrator >= 5) vw_rx_bits |= 0x800; vw_rx_pll_ramp -= VW_RX_RAMP_LEN; vw_rx_integrator = 0; // Clear the integral for the next cycle if (vw_rx_active) { // We have the start symbol and now we are collecting message bits, // 6 per symbol, each which has to be decoded to 4 bits if (++vw_rx_bit_count >= 12) { // Have 12 bits of encoded message == 1 byte encoded // Decode as 2 lots of 6 bits into 2 lots of 4 bits // The 6 lsbits are the high nybble uint8_t this_byte = (vw_symbol_6to4(vw_rx_bits & 0x3f)) << 4 | vw_symbol_6to4(vw_rx_bits >> 6); // The first decoded byte is the byte count of the following message // the count includes the byte count and the 2 trailing FCS bytes // REVISIT: may also include the ACK flag at 0x40 if (vw_rx_len == 0) { // The first byte is the byte count // Check it for sensibility. It cant be less than 4, since it // includes the bytes count itself and the 2 byte FCS vw_rx_count = this_byte; if (vw_rx_count < 4 || vw_rx_count > VW_MAX_MESSAGE_LEN) { // Stupid message length, drop the whole thing vw_rx_active = false; vw_rx_bad++; return; } } vw_rx_buf[vw_rx_len++] = this_byte; if (vw_rx_len >= vw_rx_count) { // Got all the bytes now vw_rx_active = false; vw_rx_good++; vw_rx_done = true; // Better come get it before the next one starts } vw_rx_bit_count = 0; } } // Not in a message, see if we have a start symbol else if (vw_rx_bits == 0xb38) { // Have start symbol, start collecting message vw_rx_active = true; vw_rx_bit_count = 0; vw_rx_len = 0; vw_rx_done = false; // Too bad if you missed the last message } } } void vw_setup() { uint16_t nticks = 125; // number of prescaled ticks needed uint8_t prescaler = 2; TCCR2A = _BV(WGM21); // Output Compare pins disconnected, CTC mode TCCR2B = prescaler; OCR2A = nticks; TIMSK2 |= _BV(OCIE2A); pinMode(vw_rx_pin, INPUT); } // Get the last message received (without byte count or FCS) // Copy at most *len bytes, set *len to the actual number copied // Return true if there is a message and the FCS is OK uint8_t vw_get_message(uint8_t* buf, uint8_t* len) { uint8_t rxlen; // Message available? if (!vw_rx_done) return false; // Wait until vw_rx_done is set before reading vw_rx_len // then remove bytecount and FCS rxlen = vw_rx_len - 3; // Copy message (good or bad) if (*len > rxlen) *len = rxlen; memcpy(buf, vw_rx_buf + 1, *len); vw_rx_done = false; // OK, got that message thanks // Check the FCS, return goodness return (vw_crc(vw_rx_buf, vw_rx_len) == 0xf0b8); // FCS OK? } ISR(TIMER2_COMPA_vect) { if (vw_rx_enabled) { vw_rx_sample = digitalRead(vw_rx_pin); vw_pll(); } } ////////////////////////////////////////////////////////////////////////////////////// // // ФУНКЦИИ ПРИЁМНИКА // /////////////////////////////////////////////////// // // Инициализация приёмника // inline static void receiverInit(const int8_t pin) { // vw_set_ptt_inverted(true); vw_setup(); vw_set_rx_pin(pin); } /////////////////////////////////////////////////// // // Включаем "слушание" эфира // inline static void receiverStart(void) { if (!vw_rx_enabled) { vw_rx_enabled = true; vw_rx_active = false; // Never restart a partial message } } /////////////////////////////////////////////////// // // Выключаем "слушание" эфира // inline static void receiverStop(void) { vw_rx_enabled = false; } /////////////////////////////////////////////////// // // Возвращает true если пришло сообщение // inline static bool receiverAvailable(void) { return vw_rx_done; } /////////////////////////////////////////////////// // // Ждёт прихода сообщения указанное количество миллисекунд (если 0, то ждёт бесконечно) // Возвращает true если дождалась и false в противном случае. // inline static bool receiverWaitForMessage(unsigned long milliseconds = 0) { if (milliseconds) { unsigned long start = millis(); while (!vw_rx_done && ((millis() - start) < milliseconds)); return vw_rx_done; } while (!vw_rx_done); return true; } /////////////////////////////////////////////////// // // Получает сообщение в буфер buf. // Максимальная длина буфера должна находится в *len // по завершении в *len будет реальная длина полученного сообщения // возвращает true если сообщение получено нормально // inline static bool receiverGetMessage(byte * buf, byte * len) { return vw_get_message(buf, len); } inline static bool receiverGetMessage(char * s, byte * len) { const byte ln = *len; const bool res = receiverGetMessage((byte *) s, len); if (ln > *len) *(s + (*len)++) = '\0'; return res; } #endif // FS1000A_V_hПример - передатчик
#include <VirtualWire.h> #include <FS1000A.h> void setup(void) { FS1000A_Init(A2); // пин передатчика } void loop(void) { FS1000A_Send("Hello, Dolly!"); delay (1000); }Пример - приёмник
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; } #include <FS1000A_V.h> void setup(void) { Serial.begin(115200); Serial << "Fun begins\n"; receiverInit(A2); // Пин приёмника receiverStart(); } void loop(void) { if (receiverAvailable()) { char s[32]; byte len = 32; receiverGetMessage(s, & len); Serial << s << "\n"; } }Спаисбо! Попробую) Если не стартанет, буду уже тогда перепиливать собственноручно либу =)
надеюсь, все получится.
Удивительно... даже с вашей библиотекой не хотит работать. Как только раскоменчиваю строчку //pixels.sow(); отвечающую за вывод инфы в ленту, так сразу затыкается передача по rf.
Нашел даже другую библиотеку якобы не использующую прерываний. История та же. Как только вывод инфы на ленту, приемник словно засыпает ))
Третью ночь победить не могу.
Похоже, что Ваша библиотека для WS2812 использует и первый, и второй таймеры (так, например, себя ведёт библиотека для TLC5940).
Дайте мне ссылку на Вашу библиотеку, я посмотрю какого ей надо.
Самая распространенная для ws2812
вот описание https://www.adafruit.com/category/168
вот сырцы https://github.com/adafruit/Adafruit_NeoPixel
сейчас когда я чуть больше нагрузил выводом анимации ленту, у меня даже подвисать система начала и датчики иногда подвисают. Думаю, может там уже стек оверфлов происходит.
Библиотечка по ходу кушает не малые ресурсы.
Ну, так понятно.
Во-первых, таймеры они не используют, поэтому забудьте наши заморочки с таймерами.
Во-вторых, посмотрите на функцию show (особенно на строку 135 в файле "Adafruit_NeoPixel.cpp") - они там тупо запрещают людбые прерывания, поскольку им нужен точный тайминг.
Разумеется, приёмник работать не будет, т.к. ему прерывания нужны.
спасибо очень дельно!
Что нибудь посоветовать сможете ?
Что нибудь посоветовать сможете ?
Использовать ленту и передатчик поочерёдно.
Что нибудь посоветовать сможете ?
Не могу, потому, что не знаю Вашей задачи. Можно, например, на передатчик взять отдельный маленький контроллер (ATtiny45, например). Или наоборот, на ленту. Но не зная задачи как посоветуешь?
менябы устроила хотя бы периодическая отправка получение данных в промежутках между выводом на ленту.. на сколько я понимаю, прерывания снова разрешаютмя по окончании отправки пакета данных на ленту, но у меня пакеты шлютмя так часто, что библиотека получения rf данных не успевает проглотить даже 1 пакет.
Беда) Если я буду использовать одну ардуину для полно загрузки вывода инфы на RGB ленту, а вторую приконекчу к ней для ретрансляции пакетов с радиоканала, какой тип соединения между ардуинами бнаиболее стабильно будет работать, на ваш взгляд? Там UART тоже живет на прерываниях по ходу... Как на счет I2C или SPI ?
Задача получить данные по беспроводному соединению, обработать их и вывести на ленту определенную динамику в зависимости от входящих данных.
Да, зачем вторая ардуина? На приёмник выше крыши хватит крохотулечки типа ATtiny45. Для связи, опять же я не знаю какие пины у Вас чем заняты, но я бы использовал SPI, а если нет возможности, то программный SPI. Ну, можно сделать полный "самогон" на двух пинах - по сути тот же SPI, но без выбора слэйва - чего его выбирать, когда он один?
Главная ардуина работает с лентой, а когда у неё есть время, соединяется у ATtiny и та её всё. что успело прийти отдаёт. Главна делает что нужно с лентой и опять спрашивает. Ну, и так далее.
Задача получить данные по беспроводному соединению, обработать их и вывести на ленту определенную динамику в зависимости от входящих данных.
И в чём проблема? Получил данные, вывел на ленту и ждёшь опять новых данных.
И в чём проблема? Получил данные, вывел на ленту и ждёшь опять новых данных.
Я понимаю проблему так: пока выводишь на ленту (с выключенным приёмником) можно пропустить, пришедшие данные.
Если я правильно понимаю, проблема в том, что данные вообще перестают гнаться, ибо вывод на ленту довольно часто происходит. Там достаточно динамичные световые эффекты. Программа на свичах написана, получается за одну итерацию цикла выполняется буквально строчек 20 кода (если отбросить приемную часть) и вывод на ленту.
Мне даже не хватает производительности, ардуина не успевает отрисовать то, что задумано.
данные не критично чтобы были пропущены. Они вообще не принимаются со стандартной библиотекой. а с самопалом алгоритм получится такой - после отправки на ленту данных, мне надо обратиться к тиньке и спросить у нее, что там у нас пришло. Тинька будет просто датчик расстояния опрашивать.
Здравствуйте. У меня та же проблема - светодиоды WS2812B и радиомодуль fs1000a (приемник).
Нужно менять анимацию на лету, как только получается управляющий сигнал.
Бился уже 3 ночи над этой проблемо, выявил конфликт библиотек и так же, как и вы застрял...
Вам удалось все же подружить их или это из области фантастики? Смогли победить ситуацию?
А какой именно конфликт для Вас критичен? Если по таймеру, так fs1000a относительно несложно на другой таймер переводится.
У меня приемник xy-mk-5v, который идет в комплекте с передатчиком fs1000a на 433Мгц.
Я работаю через Adafruit с матрице из светодиодов.
И в процессе выполнения анимации матрицей при подаче сигнала на приемник анимация должна меняться на другую.
Так вот суть конфликта заключается в том, что библиотека Adafruit при выполнении команды отображения изображения на матрице matrix.show() глушит приемник, т.е. его Ардуина в принципе не видит, идет ли с нее сигнал.
Как решить этот вопрос без привлечения стороннего микроконтроллера я так и не нашел ответа. Потому и спрашиваю здесь, т.к. судя по всему тут разбирается подобная проблема.
Здравствуйте. Тема не такая уж длинная, почитайте все сообщения. Проблем может быть две:
Либо работают на одном и том же таймере библиотеки приемника и адафрут, тогда Евгений вам подсказку дал - перевести нужно библиотеку на другой таймер.
Либо проблема в другом.. где то натыкался на инфу, что адафрутовская библиотека вообще запрещает какие либо прерывания во время своей отработки. Тогда тут решение вопроса по пути наименьшего сопротивления - использование двух ардуин. Либо читайте коменты выше.
Да, я прочитал изначально всю тему. И скачал переделанные файлы. Попробую их потестить. Я изначально сам пришел к двум вариантам решения, но оба они имеют свои минусы и требуют дополнительного железа:
1. (самый хреновый вариант) на передатчике делать условие при котором будет выполняться анимация. Т.е. приемник получает некую переменную, в результате которой разрешает делать анимацию. Если нет переменной, то анимцию делать низя. В этом варианте главный минус - медленная работа анимации, т.к. ее выполнение зависит от сигнала. Да и порой буджет мигание. В общем эта была первая идея. Она мне сразу не понравилась, но все же идея!
2. (тот, который здесь представлен, как альтернативный) использовать отдельный микроконтроллер (atTiny85) для работы с радиомодулем и при получении команды, командывать ардуиной через тот же Digital pin (режим работы кнопки).
И вот я все еще питаю надежду, что удасться подружить две библиотеки, чтобы не пришлось городить лишний огород из железяк.
З.Ы.: мне удалось сделать передатчик на atTiny85 с библиотекой VW. А вот приемник что-то работать отказывается... Ночь потратил - не победил.
Вроде ж выше уже выяснили, что таймеры не при делах. Там проблема в том, что библиотека ws прерывания запрещает. Т.е. одновременно они не живут. Либо надо использовать другую библиотеку, либосерь5зно переделывать эту.
Я использовал ранее FastLED, но она жрет непомерно оператики и к тому же весьма скудна в графической реализации. Так что Adafruit я пока что альтернативы не нашел к сожалению. Она тут лучшая.
Прийдется, видать, все же реализовывать обходной маневр со вторым МК.
Смотри на приемные пины, там может быть попутана распиновка ( китайцы косячно маску наложили ). Распиновка в таком порядке: земля, питание, сигнал ( иногда у них попутаны местами питание и сигнал, be carefull ))
у меня даже с фастлед библиотекой не запустился RF приемник))
да у меня с распиновкой все гуд.
я сначала тестил на ардуине. на ней скетч отточил - все работает.
потом в сктече меняю пин ресивера на соответствующий у atTiny.
и фигушки...
Самое неудобное, что у atTiny нет возможности просматривать сериал потр.
Я сегодня-завтра подрублю к нему отдеьлный LCD экран и гтогда попытаюсь глянуть. что вообще он ловит.
Тут еще важно понять к какому пину его подключать. Уже вроде все перепробовал.
Я тут по приемнику сделал отдельную тему в форуме:
http://arduino.ru/forum/programmirovanie/pomogite-podruzhit-attiny85-i-xy-mk-5v-priemnik-fs1000a
Гляньте, может какие идеи появятся.
Всем заранее спасибо