Предложу ещё один метод, пригодный для МК, в которых есть АЦП. Я его успешно применял в нескольких устройствах, всё работает идеально.
Обычно в AVR при помощи мультиплексора можно подключить вход АЦП к земле или к внутреннему источнику опорного напряжения. При этом никаких внешних цепей не требуется (желательно повесить конденсатор на AREF, но для генерации случайных чисел можно обойтись и без него).
Итак, алгоритм: 1. Настраиваем АЦП (опорное напряжение - AVCC, тактовая частота - лучше побольше, но в пределах допустимого, разрядность 10 бит). 2. Мультиплексором подключаем вход АЦП к земле. 3. запускаем преобразование. 4. Ждём 10 мкс. 5. Переключаем вход на источник опорного напряжения 6. Без каких либо задержек выполняем 16 преобразований подряд, младшие биты результатов собираем в 16-разрядную переменную. 7. Полученное значение используем как аргумент для srand(). 8. Выключаем АЦП, чтобы что-нибудь не поломалось в остальном коде, если вдруг он использует АЦП.
Случайное число появляется за счёт того, что напряжение на выходе мультиплексора не может измениться мгновенно, и АЦП успевает промежуточные значения между 0 В и напряжением опорного источника. В даташите рекомендуют сделать задержку после переключения входа перед следующим преобразованием. А вот если её не делать, то можно получить случайное число.
Пример кода для ATmega8. Для других МК нужно изменить коды входов мультиплексора в соответствии с даташитом.
uint16_t adc_get_random(void){ //This is a tricky way to generate a random number. //First AVCC is selected as reference, and GND is selected as input, the conversion is performed. //Then the input is changed to Vbg, and WITHOUT ANY DELAY 16 conversions are performed. //Because of the voltage on the MUX output can't change immediately, random numbers are generated.
//Usage example int main(void){ //... srand(adc_get_random()); //... DDRB = 0xFF; while(1){ PORTB = rand() & 0xFF; _delay_ms(1000); //... } }
Код для avr-gcc, но изменить под CVAVR его очень легко.
Дополнительно можно скомбинировать этот способ с основанным, например, на начальном состоянии RAM. Достаточно в качестве аргумента srand() указать, например,
Код:
adc_get_random() ^ seed
где seed - случайное число, полученное другим методом.
_________________ Этот пост оказался полезен? Не поленись, нажми слева!
Куплю индикаторы ИТС-1А, ИТС-1Б, ИГВ1-8х5Л, ИГПС1-222/7, ИГПС1-111/7 и подобные.
Последний раз редактировалось *Trigger* Вс фев 28, 2021 22:06:28, всего редактировалось 2 раз(а).
способ с вычитыванием всей памяти EEPROM и получением некоторой "контрольной" суммы
не EEPROM, а RAM - после подачи питания она будет содержать случайные биты, а вычисление "контрольной суммы" даст "размазывание" этих битов по "непредсказуемым" позициям в числе, передаваемом в srand
для неопытного CVAVR-щика можно делать так:
Код:
__eeprom int srand_val;
void main(void){ srand(srand_val); srand_val = rand(); // дальше работа, как задумано }
этот способ более прост и достаточно "непредсказуем".
*Trigger* писал(а):
Случайное число появляется за счёт того, что напряжение на выходе мультиплексора не может измениться мгновенно, и АЦП успевает промежуточные значения между 0 В и напряжением опорного источника
Добавлено after 5 minutes 40 seconds: и да, по сравнению с мной предлагаемым вариантом подсчета CRC области RAM, ваш способ гораздо сложнее и неприменим для attiny2313...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
uint16_t adc_get_random(void){ //This is a tricky way to generate a random number. //First AVCC is selected as reference, and GND is selected as input, the conversion is performed. //Then the input is changed to Vbg, and WITHOUT ANY DELAY 16 conversions are performed. //Because of the voltage on the MUX output can't change immediately, random numbers are generated.
Безусловно, видны повторяющиеся значения, особенно много значений с нулями на конце и просто нулей. Но можно попытаться брать не младший бит результата, а комбинировать значения как-то иначе (перемешивать биты, сдвигать, XORить). Использовать такой "источник энтропии" непосредственно для генерации случайных чисел нельзя, но в качестве генератора seed он вполне пойдёт.
Я проводил эксперименты с RAM, мне не понравилось. Было очень много повторяющихся значений. Триггеры ячеек RAM имеют тенденцию устанавливаться в каком-то одном состоянии при включении, "плавающих" ячеек сравнительно мало.
Для МК без АЦП этот способ непригоден, конечно. Согласен, это недостаток данного метода.
В итоге я использовал описанный метод с АЦП и XORил полученное значение с XOR всех байт RAM.
_________________ Этот пост оказался полезен? Не поленись, нажми слева!
Куплю индикаторы ИТС-1А, ИТС-1Б, ИГВ1-8х5Л, ИГПС1-222/7, ИГПС1-111/7 и подобные.
ваш метод лучше протестировать иначе: сделать единственный вывод без цикла, и посмотреть, что будет выводиться при каждом включении питания, ведь именно в этом случае важно иметь начальное случайное число - для первичной инициализации rand
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Тут есть довольно широкое поле для экспериментов. Не так важна конкретная реализация, как сам принцип использования АЦП в немного нестандартных режимах для получения случайных чисел.
_________________ Этот пост оказался полезен? Не поленись, нажми слева!
Куплю индикаторы ИТС-1А, ИТС-1Б, ИГВ1-8х5Л, ИГПС1-222/7, ИГПС1-111/7 и подобные.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
void main(void){ srand(srand_val); srand_val = rand(); // дальше работа, как задумано }
этот способ более прост и достаточно "непредсказуем". .
__eeprom - читаем все ячейки ? энергонезависимой памяти и сохраняем сумму ? в переменной int srand_val; так?
я не использую EEPROM значит там и ни чего не меняется... откуда случайное число берется? ну пусть там какой то мусор записан, но он же статичен и не меняется, а если я в программе AVRDUDE_PROG 3.3 нажму стереть EEPROM то там в ячейки 00 будут и тогда этот метод уже работать не будет?
а наверно понял это мы записываем в ячейку int srand_val; EEPROM (srand_val = rand();) а потом читаем srand(srand_val); из нее . так?
Serzh2000, а вы не пробовали немного почитать книжки про язык Си и документацию про ваш CVAVR? как можно писать программы, не имея ни малейшего понятия о том, как это делается, что такое язык программирования и из каких частей формируются строки программ?!
Serzh2000 писал(а):
__eeprom int srand_val;
здесь всего-навсего описана "переменная" в EEPROM типа int, в которой хранится "стартовое" значение для настройки генератора псевдослучаной последовательности
Serzh2000 писал(а):
я не использую EEPROM
теперь используете
Serzh2000 писал(а):
откуда случайное число берется?
оно заносится в "переменную" srand_val вот здесь:
Serzh2000 писал(а):
srand_val = rand();
Serzh2000 писал(а):
нажму стереть EEPROM
принципиально ничего не изменится, просто генератор псевдослучайных чисел настроится на некую последовательность "0".
Serzh2000 писал(а):
а наверно понял
даже удивительно! а с самого начала подумать нельзя было?
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
я в первый раз не вник в предложенный Вами Аlex вариант простой как "две копейки"
Цитата:
Ну ё-маё, блин... Вы как программу то пишите ? Неужели, приведённый мной кусок кода, Вам вообще ни о чём не говорит ? Он же прост, как 2 копейки ...
прошил атмегу 8 ... включил выключил и сново включил и так совпало, что звезда с одного итого же луча засветилась затем посмотрел в протеусе число= crc не меняется это и привело меня к неправильному выводу
по совету ARV
Цитата:
Serzh2000, а вы не пробовали немного почитать книжки про язык Си и документацию про ваш CVAVR? как можно писать программы, не имея ни малейшего понятия о том, как это делается, что такое язык программирования и из каких частей формируются строки программ?!
почитал, подумал, вникнул в суть написанного прошил ардуино этим кодом и в мониторе порта увидел действительно crc меняется! наверно протеусу не под силу это.
... залил в атмегу 8 все работает как надо спасибо и прошу прощения за за свою бестолковость
осталось попробовать третий вариант который предложил *Trigger*
Заголовок сообщения: Re: CodeVision AVR в вопросах и ответах
Добавлено: Пт мар 19, 2021 09:16:18
Встал на лапы
Зарегистрирован: Пт мар 19, 2021 08:58:45 Сообщений: 103
Рейтинг сообщения:0
Народ привет! Сижу ковыряюсь с INA226 хочу подружить с atmega8. Не могу правильно считать старший и младший байт, на логическом анализаторе после чтения старшего байта видно что NACK - как я понимаю нет подтверждения но мастера. Что не так делаю? Особо примеров перед глаза не нашлось...
Код:
//Функция чтения int16_t read2Byte(uint8_t addr, uint8_t deviceAddr){ // чтение 2 байта по адресу I2C int16_t data; //16-bit uint8_t MSB, LSB; //8-bit i2c_start(); //Кидаем команду "Cтарт" на шину I2C i2c_write(deviceAddr<<1); //Кидаем на шину адрес INA226 = 10000000 i2c_write(addr); //Кидаем какой регистр хотим читать i2c_stop(); delay_us(10); i2c_start(); i2c_write((deviceAddr<<1)+1); //Обращаемся к INA226 в режиме чтения = 10000001 MSB=i2c_read(0); //читаем старший байт LSB=i2c_read(1); //читаем младший байт i2c_stop(); //Посылаем команду "Cтоп" data=MSB; data = (data << 8)+LSB; //Склеиваем data= data << 8/LSB; или data= word(MSB, LSB); return data; //Возвращаем значение прочитанного }
Перфое фото нет ACK, мой код
Второе как отвечает работает библиотека ардуино, данные принимаются адекватные
Вроде как регистры содержат шестнадцатеричное число?
Добавлено after 2 minutes 30 seconds: Аа... наверно можно и восьмибитное число писать? Каждая запись в строчке - это бит? Тогда не понятно откуда взялись буквенные обозначения? Константы?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 24
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения