Чтение с EEPROM и запись на адресный светодиод с ограниченными соединениями
Обновить Код тактовой частоты был изменен в соответствии с предложением @timemage из - за невозможности уменьшить проводную библиотеку до уровня ниже 30304 Гц. К сожалению проблемы все еще сохраняются: Ничего не распечатывается на серийный и светодиод работает только после отключения и повторного подключения схемы(перестает обновляться после сброса arduino)..
Обновить Спасибо за все ответы. Я оставил схему прежней и использовал следующий код, где я попытался уменьшить тактовую частоту i2c до 1 кГц, но, к сожалению, не повезло.EEPROM ничего не возвращает, и пиксель изначально не работает, только когда я отключаю цепь(это просто, потому что я использую магнитный USB-разъем), он, кажется, работает нормально(пока я не перезапущу arduino). Если все сходятся во мнении, что мне может повезти больше, если я изменю библиотеку, то я могу заглянуть в нее, хотя это звучит немного не по-моему...
#include <Wire.h>
#define disk1 0x50 //Адрес микросхемы eeprom
unsigned int address0 = 0; //адрес для хранения данных
#include <Adafruit_NeoPixel.h>
//пикселы pin
#define sda_pin A4
#define scl_pin A5
Adafruit_NeoPixel strip(1, sda_pin, NEO_GRB + NEO_KHZ800);
void setup() {
Serial.begin(9600);
Wire.begin();
////ОБНОВЛЕННЫЙ КОД ДЛЯ СНИЖЕНИЯ ТАКТОВОЙ ЧАСТОТЫ I2C ДО 1 КГЦ////
TWSR |= 0x03; // выбрал прескалер деления на 64
TWBR = 0x80; // ближе всего к 1 кГц снизу при 16 МГц с прескалером /64.
Serial.println(readEEPROM(disk1, address0), DEC);
Wire.end();
pinMode(scl_pin, INPUT);
strip.begin(); // ИНИЦИАЛИЗИРОВАТЬ объект NeoPixel strip (ОБЯЗАТЕЛЬНО)
strip.show(); // Отключите все пиксели как МОЖНО СКОРЕЕ
strip.setBrightness(100); // Установить ЯРКОСТЬ примерно на 1/5 (max = 255)
}
void loop() {
rainbow(10);
}
void rainbow(int wait) {
static unsigned long timer = 0;
static long firstPixelHue = 0;
if (millis() - timer > wait) {
timer = millis();
for (int i = 0; i < strip.numPixels(); i++) { // Для каждого пикселя в полосе...
int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
}
strip.show(); // Обновить полосу новым содержимым
if (firstPixelHue < 5 * 65536) { //incrememnt
firstPixelHue += 256;
} else firstPixelHue = 0; //сброс
}
}
byte readEEPROM(int deviceaddress, unsigned int eeaddress )
{
byte rdata = 0xFF;
const uint8_t i2c_base_address = 0x50;
const uint8_t upper_three_eeprom_adress_bits = (eeaddress >> 8) & 0x7;
const uint8_t i2c_address = i2c_base_address | upper_three_eeprom_adress_bits;
Wire.beginTransmission(i2c_address);
Wire.write(eeaddress & 0xFF); // адрес LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress, 1);
if (Wire.available()) rdata = Wire.read();
return rdata;
}
ОРИГИНАЛЬНОЕ СООБЩЕНИЕ:
Я создал схему, которая включает в себя AT24C16 EEPROM, который мне нужно только читать, и адресуемый светодиод (WS2812 IC), с которым я буду разговаривать (используя Arduino Nano).
Мое первоначальное намерение состояло в том, чтобы прикрепить DIN-штифт светодиода либо к SCL, либо к SDA. Я подумал, что, поскольку мне нужно только один раз прочитать EEPROM (а затем управлять светодиодом), я смогу поделиться соединением. После создания схемы это оказалось неверным предположением.
Я ограничен 4 (сетями?) итого из-за адаптера, который я использую между Arduino Nano и остальной схемой (перепрофилированный магнитный 4-проводной USB-кабель). Может ли кто-нибудь предложить настройку, которая позволила бы мне только с этими 4 соединениями читать из EEPROM и записывать на светодиод? Как я уже упоминал, мне нужно только одно чтение из EEPROM, чтобы идентифицировать его, и тогда я буду писать только в пиксель. Большое спасибо!
Прилагается схема.
@user2105725, 👍0
Обсуждение5 ответов
AT24C16 - это устройство шины I2C, а WS2812 - нет. Если вы можете терпеть паразитные выходы на светодиодах WS2812, вы можете прочитать AT24C16 с помощью I2C, правильно адресуя устройство. WS2812 будет "слушать" и может отображать вещи, когда этот трафик проходит мимо него.
Когда вы закончите с AT24C16, вам, вероятно, нужно будет отключить контроллер I2C (предполагая, что вы используете его), а затем удерживать линию SCL ВЫСОКО, а затем общаться с WS2812, используя только линию SDA. AT24C16 будет игнорировать этот трафик, не относящийся к I2C, потому что линия SCL в этой точке статична.
мое первоначальное мышление состояло в том, что во время чтения EEPROM могут быть некоторые "паразитные выходы" от светодиода, но поскольку это занимает совсем немного времени, все будет в порядке. к сожалению, EEPROM не может читать, когда пиксель подключен в соответствии со схемой., @user2105725
Это просто халтурная идея, как вы могли бы решить эту проблему.
Уменьшите частоту I2C ниже 10 кГц или - поскольку вы хотите прочитать eeprom только один раз при запуске - даже до 1 кГц. Таким образом, WS2812 увидит серию низких импульсов длительностью >50us, которые он должен принять в качестве сигнала сброса. Практически WS2812 проигнорирует такой сигнал.
Но есть и другая проблема: EEPROM будет время от времени писать на шину всякий раз, когда получит что-то похожее на свой адрес. Это, в свою очередь, может
- вмешиваться в коммуникацию WS2812.
- повредите интерфейс I2C EEPROM, если вы управляете WS2812 с помощью push/pull сигнала (установив gpios HIGH/LOW).
Было бы безопасно управлять WS2812s с открытым сигналом стока (переключение между низким и ВХОДНЫМ сигналами), но это может потребовать внесения изменений в библиотеку WS2812. В любом случае вы должны использовать линию SDA для управления WS2812, и при управлении светом на SCL не должно быть сигнала (EEPROM не будет общаться, если не получит тактового сигнала). Проще всего было бы полностью отключить I2C, как только он вам больше не понадобится, и явно установить вывод SCL в режим ввода. Тогда вы должны быть в порядке, используя SDA в обычном режиме push/pull, и библиотека должна работать как обычно.
привет, большое спасибо за это,я обновил свой вопрос в ответ., @user2105725
Это не будет работать с 24Cxx EEPROMS.
Шина I2C работает следующим образом:
- Мастер записывает адрес.
- Ведомый берет на себя линию SDA и тянет ее высоко или низко, чтобы указать ACK или NAK.
- Мастер выписывает команду для считывания с адреса.
- Снова Подчиненный берет на себя ПДД и выполняет команду.
- Ведущий продолжает пульсировать SCL, в то время как Ведомый передает данные в SDA.
- После каждого байта (или слова) Мастер должен взять на себя ПДД, чтобы подтвердить, что данные были получены.
Таким образом, нет никакого способа сказать EEPROM просто выбросить все свои данные на шину без того, чтобы кто-то активно слушал и действовал. Что, в свою очередь, изменяет данные на шине.
Он может работать с 25Cxx EEPROMS.
Вам понадобится что-то другое, имеющее гораздо более простую схему связи.
Например, 25Cxx, использующий SPI, поддерживает чтение в последовательности без постоянного действия. Вам придется просто инициализировать чтение и продолжать синхронизацию на SCK. Никаких туда - сюда.
Данные будут последовательно выводиться в МИСО.
Но тогда вам все равно придется правильно рассчитать время. WS2812 не очень снисходителен в этом отношении. Вот почему большинство людей используют библиотеки, в которых есть ручной ассемблерный код, чтобы правильно определить время.
И я знаю, о чем говорю, так как сам кое-что написал (не подходит никому, кроме меня).
https://kwasi-ich.de/blog/2019/11/15/pwm_rider/
"Не будет работать с 24Cxx EEPROMS" - я думаю, что это так, как я написал в своем ответе, @Sim Son
"EEPROM просто вырвет все свои данные на шину без того, чтобы кто-то активно слушал и действовал" - здесь никто не будет действовать, WS2812-это не устройства I2C, а другие устройства I2C не будут действовать, если они не будут адресованы, @Sim Son
Да, я неправильно понял это намерение. Я думал, что данные для WS2812 должны поступать из EEPROM непосредственно через SDA. MCU сообщает EEPROM выводить свои данные на шину, где будет прослушиваться WS2812., @Kwasmich
Проблема setClock(1000)
Это своего рода материал для ответов, но он должен быть дополнением к другим ответам, которые более непосредственно касаются вашего вопроса, и, я думаю, довольно хорошо, хотя сейчас я не могу это проверить. Поэтому, если вы найдете это полезным, проголосуйте за него, но отметьте одного из других, если эта настройка заставит его работать.
Специально для того, чтобы рассмотреть этот контент в вашем обновлении:
Я попытался уменьшить тактовую частоту I2C до 1 кГц, но, к сожалению , не повезло.
А ваша реплика:
Wire.setClock(1000);
Мне было любопытно узнать, как именно
setClock сопоставляет свой аргумент со значениями параметров генерации тактовой частоты в аппаратных регистрах и не может ли 1 кГц быть слишком медленным для AVR, работающего на частоте 16 МГц. То есть, возможно, нижняя граница может быть, скажем, 50 кГц, при которой я бы предложил немного стучащую библиотеку I2C в комментарии к вашему вопросу; однако это не так.
Исследуя это, я обнаружил, что setClock
не может сделать ничего разумного в библиотеке AVR Arduino core, если дать аргумент ниже 30304
. Запрашиваемые скорости ниже этой цифры приводят к тому, что скорости намного выше этой из-за того, как они вычисляют тактовую частоту с помощью прескалера TWI/I2C/"Wire" (TWPS1
и TWPS0
в TWSR
) и регистра скорости передачи битов (TWBR
).
Я покопался, чтобы посмотреть, что заставляет setClock
вести себя плохо для низких ставок, и в этом нет ничего особенного. Прескалер I2C/Wire настроен на деление на 1 и остается таким образом. setClock
вызывает twi_setFrequency
, который вычисляет TWBR с
использованием этого выражения:
TWBR = ((F_CPU / frequency) - 16) / 2;
При частоте 30304 Гц и выше это генерирует что-то в пределах 1% от желаемой частоты. Вдоль оси x-запрашиваемая скорость. Ось y показывает эффективную ставку. Неудивительно, что примерно линейно.
Но ниже 30304 Гц все идет боком. Значения 30303 или меньше при вводе в это выражение пытаются вычислить TWBR 256 или больше. Но это 8-битный регистр, так что он переворачивается. Чтобы предотвратить это, необходимо выбрать другой прескалер. Но это не так, и в результате возникает следующее сумасшествие:
То, что setClock(1000)
на самом деле делает в вашем коде, - это установка частоты 125 кГц; Я проверил это в области видимости.
Предложение
Вы можете получить приблизительную тактовую частоту 1 кГц, вручную настроив аппаратные регистры самостоятельно, заменив строку setClock следующей:
TWSR |= 0x03; // выбрал прескалер деления на 64
TWBR = 0x80; // ближе всего к 1 кГц снизу при 16 МГц с прескалером /64.
Это должно дать вам скорость TWI/I2C около 975,61 Гц. В таблице данных для ATmega328P вы увидите, что это выбор прескалера divide-by-64 и взятие 128 тиков. Вы можете найти уравнение в таблице данных, которое, если вы заполните эти значения и тактовую частоту UNO, даст выражение 16e6 / (16 + 2 * 0x80 * 64), что даст вам цифру 975.61 выше. Я убедился, что это примерно так же, как на прицеле.
Попробуй это сделать. Посмотрите, когда вы это сделаете, не сработает ли для вас один из ответов. Я ожидаю, что так оно и будет.
Еще раз спасибо за такое тщательное расследование, оно чрезвычайно ценится. К сожалению, проблема все еще сохраняется, я обновил свой вопрос в ответ., @user2105725
Мои рабочие данные по запросу
Настройка
Итак, настройка такая же, как и у вас, что у вас есть в своих основах:
Код-это ваш код с настройкой почти на 1 кГц. Тем не менее, я считаю, что я также протестировал его по умолчанию, и это тоже сработало. В любом случае изображения, которые показывают изменение светодиода, были сделаны во время настройки 1 кГц.
UNO и Nano функционально идентичны для этого. Они используют разные последовательные приемопередатчики, которые ни к чему не имеют никакого отношения. Nano обычно будет иметь более низкий "5V", чем UNO, при питании от USB из-за того, что Nano использует диод, где UNO имеет FET. Что тоже вряд ли имеет значение. В остальном это одно и то же устройство с точки зрения настройки.
24LC02B использует те же распиновку, адрес I2C и командные последовательности, что и ваш AT24C16. Это меньшая память, но это не имеет значения; мы читаем с адреса 0. Я не счел нужным добавлять внешние подтягивающие резисторы, и это сработало, поэтому казалось ненужным добавлять их, чтобы продемонстрировать, что это может работать, так как добавление их должно только улучшить его шансы на правильную работу.
Светодиоды-это кольцо Adafruit ADA1643 12 Neopixel. Мы оба используем первый светодиод струны, на самом деле не имеет значения, насколько он длинный. Мы освещаем только один "пиксель", поэтому я просто запитал его от USB. Понятия не имею, что ты там делаешь. Но для одного зажженного светодиода я сомневаюсь, что разница там будет иметь большое значение.
Вы увидите резистор, соединяющий SDA в EEPROM с адресуемым светодиодом(светодиодами). Я положил это туда на случай, если по какой-то случайности EEPROM может управлять SDA низко, в то время как адресуемый светодиодный код управляет светодиодной линией передачи данных высоко. пока. Я сомневаюсь, что это может произойти, но это была мелочь. Как бы то ни было, я действительно запустил его ненадолго без него в серии, и он также отлично работал таким образом. Я говорю вам это только для того, чтобы у вас была вся информация, а не потому, что считаю ее важной.
Выполняется
Он выводит 72. Это первое значение в моем EEPROM. В основном "H" из "Hello world". А затем он переходит к циклическому прохождению первого адресуемого светодиода набора через все цвета.
Изображения конфигурации
Хорошо, еще раз спасибо, что нашли время сделать это, я в долгу перед вами! Я попробовал вашу точную настройку и ... все равно не сработало! Но...по наитию я решил сменить светодиод, и это сработало! Оказывается, у меня есть 2 адресуемые светодиодные ленты, одна из которых 60 светодиодов / метр, а другая 30 светодиодов / метр. 60/м работают, а 30/м-нет! как же это странно(и неприятно)!? итак, теперь это словесно, хотя и довольно запутанно. Есть ли у вас какие-либо предложения о том, как я должен обновить это наиболее полезным способом? должен ли я создать другой ответ или он слишком грубый?, @user2105725
Может быть, [это](https://github.com/adafruit/Adafruit_NeoPixel/blob/1.2.2/Adafruit_NeoPixel.h#L110) - это все, что ты видишь., @timemage
- Является ли использование malloc() и free() действительно плохой идеей для Arduino?
- Как читать и записывать EEPROM в ESP8266
- Какой реальный срок службы EEPROM?
- Как запомнить значения переменных после перезагрузки платы Arduino Uno R3
- Получить доступ к EEPROM ATtiny с помощью кода Arduino?
- Управлять несколькими полосками WS2812B с разным количеством светодиодов.
- Очистка EEPROM
- Как сохранить переменную с плавающей запятой в EEPROM
Проблема может заключаться в том, что входное сопротивление WS2812 достаточно низкое, чтобы потянуть слабый подтягивающий резистор 35 Ком ниже напряжения, необходимого для считывания EEPROM как ВЫСОКОГО. Сначала я бы еще раз попробовал использовать подтягивающие резисторы надлежащего значения для I2C. Что-то вроде 1 Кома. После этого вы можете попробовать добавить буферную схему на вход WS2812s., @Gerben
Похоже, у вас уже есть совершенно хорошие ответы, но мне любопытно, что вы имели в виду под "это доказало неверное предположение". Предположительно, вы сделали что-то, что послужило доказательством. Что именно это было?, @timemage
схема работала(могла читать EEPROM), а затем я добавил светодиод, и он перестал работать(больше не мог читать EEPROM или управляющий светодиод)., @user2105725
ps. спасибо за все эти ответы, очень интересно, я не смог протестировать сегодня, но вернусь к вам, как только сделаю это), @user2105725
Попробуйте исправить предложение setClock в моем "ответе", и если это не заставит один из правильных ответов работать на вас., @timemage
Я использовал ваш код с кольцом 24LC02B, UNO и 12 "NeoPixel", что эквивалентно тому, что у вас есть в этом тесте. В моей настройке ваш код печатает первый байт EEPROM, а затем окрашивает первый светодиод RGB. Насколько я могу судить, это ожидаемый результат., @timemage
Sth different: вы знаете, что atmega328 имеет внутренний eeprom, верно? Есть ли у вас причина использовать внешний eeprom? Просто спрашиваю..., @Sim Son
У вас действительно есть подтягивания на автобусных линиях? Я не вижу причин, по которым eeprom не должен читаться при подключении WS2812, так что это может быть основной проблемой для решения, @Sim Son
привет, да, я знаю об этом. я использую eeprom как средство идентификации заменяемых модулей. сначала у меня были физические подтягивания,но я слышал, что библиотека проводов использует внутренние подтягивания, поэтому я удалил их, и схема работала нормально(для чтения eeprom, перед добавлением пикселя). я только что попробовал добавить их снова, и ситуация осталась прежней..., @user2105725
Если хотите, я могу изложить свою установку в ответе, но сомневаюсь, что из нее можно чему-то научиться. UNO в значительной степени электрически такой же, как Nano, по крайней мере, во всех отношениях, имеющих отношение к тесту. 24LC02B, который я использую, имеет тот же вывод, тот же адрес I2C и те же "команды", что и ваше устройство. Просто у него меньше памяти. Я не стал утруждать себя установкой подтягиваний на шину I2C, потому что внутренних устройств было достаточно, чтобы заставить код работать и доказать, что это можно сделать., @timemage
Что ж, полагаю, нет ничего плохого в том, чтобы попытаться. кроме этого, единственное, что я могу придумать, - это купить именно этот чип и попытаться воспроизвести его. Мне нужно только использовать eeprom в качестве средства идентификации модулей, поэтому подойдет любая микросхема., @user2105725