Предложу ещё один метод, пригодный для МК, в которых есть АЦП. Я его успешно применял в нескольких устройствах, всё работает идеально.
Обычно в 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: Аа... наверно можно и восьмибитное число писать? Каждая запись в строчке - это бит? Тогда не понятно откуда взялись буквенные обозначения? Константы?
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения