Обсуждаем контроллеры компании Atmel.
Ответить

Re: CodeVision AVR в вопросах и ответах

Вс фев 28, 2021 21:30:27

Предложу ещё один метод, пригодный для МК, в которых есть АЦП. Я его успешно применял в нескольких устройствах, всё работает идеально.

Обычно в AVR при помощи мультиплексора можно подключить вход АЦП к земле или к внутреннему источнику опорного напряжения. При этом никаких внешних цепей не требуется (желательно повесить конденсатор на AREF, но для генерации случайных чисел можно обойтись и без него).

Итак, алгоритм:
1. Настраиваем АЦП (опорное напряжение - AVCC, тактовая частота - лучше побольше, но в пределах допустимого, разрядность 10 бит).
2. Мультиплексором подключаем вход АЦП к земле.
3. запускаем преобразование.
4. Ждём 10 мкс.
5. Переключаем вход на источник опорного напряжения
6. Без каких либо задержек выполняем 16 преобразований подряд, младшие биты результатов собираем в 16-разрядную переменную.
7. Полученное значение используем как аргумент для srand().
8. Выключаем АЦП, чтобы что-нибудь не поломалось в остальном коде, если вдруг он использует АЦП.

Случайное число появляется за счёт того, что напряжение на выходе мультиплексора не может измениться мгновенно, и АЦП успевает промежуточные значения между 0 В и напряжением опорного источника. В даташите рекомендуют сделать задержку после переключения входа перед следующим преобразованием. А вот если её не делать, то можно получить случайное число.

Пример кода для ATmega8. Для других МК нужно изменить коды входов мультиплексора в соответствии с даташитом.
Код:
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>

#include <stdlib.h>

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.

  ADCSRA = (1 << ADEN) | (0 << ADATE) | (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); //F_CPU / 64
  ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | 0b1111; //GND as ADC input
  ADCSRA |= (1 << ADSC);
  while(ADCSRA & (1 << ADSC));
  _delay_us(10);
  ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | 0b1110; //Vbg as ADC input
  uint16_t result = 0;
  uint8_t tmp;
  uint8_t i;
  for(i = 0; i < 16; i++){
    ADCSRA |= (1 << ADSC);
    while(ADCSRA & (1 << ADSC));
    tmp = ADCL;
    result <<= 1;
    if(tmp & 0x01)
      result |= 0x01;
    tmp = ADCH;
  }

  ADCSRA = 0;

  return result;
}

//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 - случайное число, полученное другим методом.
Последний раз редактировалось *Trigger* Вс фев 28, 2021 22:06:28, всего редактировалось 2 раз(а).

Re: CodeVision AVR в вопросах и ответах

Вс фев 28, 2021 21:43:37

WiseLord писал(а):способ с вычитыванием всей памяти 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...

Re: CodeVision AVR в вопросах и ответах

Вс фев 28, 2021 22:05:57

ARV писал(а): с чего бы скорости изменения напряжения внутри МК меняться?!

Я думаю, тут дело не только скорости нарастания, но и в шумах АЦП, а также работе схемы SAMPLE & HOLD на быстро изменяющемся сигнале.

Накидал простенькую программку для теста. Контроллер - ATmega16.


Вывод в UART:

Безусловно, видны повторяющиеся значения, особенно много значений с нулями на конце и просто нулей. Но можно попытаться брать не младший бит результата, а комбинировать значения как-то иначе (перемешивать биты, сдвигать, XORить). Использовать такой "источник энтропии" непосредственно для генерации случайных чисел нельзя, но в качестве генератора seed он вполне пойдёт.

Я проводил эксперименты с RAM, мне не понравилось. Было очень много повторяющихся значений. Триггеры ячеек RAM имеют тенденцию устанавливаться в каком-то одном состоянии при включении, "плавающих" ячеек сравнительно мало.

Для МК без АЦП этот способ непригоден, конечно. Согласен, это недостаток данного метода.

В итоге я использовал описанный метод с АЦП и XORил полученное значение с XOR всех байт RAM.

Re: CodeVision AVR в вопросах и ответах

Вс фев 28, 2021 22:23:37

ваш метод лучше протестировать иначе: сделать единственный вывод без цикла, и посмотреть, что будет выводиться при каждом включении питания, ведь именно в этом случае важно иметь начальное случайное число - для первичной инициализации rand

Re: CodeVision AVR в вопросах и ответах

Вс фев 28, 2021 22:50:12

Если тестировать с включением питания, то добавятся ещё и разнообразные переходные процессы. Сейчас попробую.

Кстати, неплохие результаты даёт и просто взятие младшего бита при измерении напряжения Vbg с внутренним ИОН:



Это, наверное, даже лучше варианта с переключением мультиплексора.

Добавлено after 21 minute 6 seconds:
Вот так получается, если вызвать adc_get_random() в исходной версии сразу после подачи питания:
Код:
0x402D 0x8008 0x2000 0x4000 0x8010 0x0800 0x1000 0x0012 0x0000 0x0010 0x8080 0x2040 0x8100 0x8800 0x4000 0x0040 0x0000 0x0000 0x8000 0xCC00 0x8000 0x6000


После добавления задержки в 500 мс после включения и убирания задержки 10 мкс из adc_get_random():
Код:
0xD24B 0x92C1 0x9609 0xB349 0xB249 0xDB2C 0xD96C 0x9249 0x9249 0x9249 0x9249 0x9241 0xD249 0x92C9 0x9249 0x9249 0x9249 0xD92C 0xF92D 0xD96E 0xB24B 0x924B 0x9249 0x1249 0xB249 0x9249 0xD459 0x9249 0xD019 0x9369 0x9249 0x924A


Тут есть довольно широкое поле для экспериментов. Не так важна конкретная реализация, как сам принцип использования АЦП в немного нестандартных режимах для получения случайных чисел.

Re: CodeVision AVR в вопросах и ответах

Пн мар 01, 2021 00:42:51

ARV писал(а):не EEPROM, а RAM
Да, описка. Естественно, RAM имел в виду, как Вы раньше и описывали этот способ.

Re: CodeVision AVR в вопросах и ответах

Пн мар 01, 2021 11:15:57

я пишу в CVAVR... выдает ошибки
Ну ё-маё, блин... Вы как программу то пишите ?
Неужели, приведённый мной кусок кода, Вам вообще ни о чём не говорит ? Он же прост, как 2 копейки ... :facepalm:

Re: CodeVision AVR в вопросах и ответах

Ср мар 03, 2021 05:54:21

спасибо все работает!
но меня мучает вопрос, что тут написано? :facepalm:
для неопытного CVAVR-щика можно делать так:
Код:
__eeprom int srand_val;

void main(void){
  srand(srand_val);
  srand_val = rand();
  // дальше работа, как задумано
}
этот способ более прост и достаточно "непредсказуем".
.

__eeprom - читаем все ячейки ? энергонезависимой памяти
и сохраняем сумму ? в переменной int srand_val;
так?

я не использую EEPROM значит там и ни чего не меняется... откуда случайное число берется?
ну пусть там какой то мусор записан, но он же статичен и не меняется,
а если я в программе AVRDUDE_PROG 3.3 нажму стереть EEPROM то там в ячейки 00 будут и тогда этот метод уже работать не будет? :shock:

а наверно понял это мы записываем в ячейку int srand_val; EEPROM (srand_val = rand();) а потом читаем srand(srand_val); из нее . так?

Re: CodeVision AVR в вопросах и ответах

Ср мар 03, 2021 09:18:34

Serzh2000 писал(а):что тут написано?
Serzh2000, а вы не пробовали немного почитать книжки про язык Си и документацию про ваш CVAVR? как можно писать программы, не имея ни малейшего понятия о том, как это делается, что такое язык программирования и из каких частей формируются строки программ?!
Serzh2000 писал(а):__eeprom int srand_val;
здесь всего-навсего описана "переменная" в EEPROM типа int, в которой хранится "стартовое" значение для настройки генератора псевдослучаной последовательности
Serzh2000 писал(а):я не использую EEPROM
теперь используете
Serzh2000 писал(а):откуда случайное число берется?
оно заносится в "переменную" srand_val вот здесь:
Serzh2000 писал(а):srand_val = rand();
Serzh2000 писал(а):нажму стереть EEPROM
принципиально ничего не изменится, просто генератор псевдослучайных чисел настроится на некую последовательность "0".
Serzh2000 писал(а):а наверно понял
даже удивительно! а с самого начала подумать нельзя было?

Re: CodeVision AVR в вопросах и ответах

Чт мар 04, 2021 19:13:30

unsigned char crc = 0;
unsigned char *p_mem = (unsigned char*) 0;
for( i=0; i<MAX_RAM; i++) crc += p_mem[i];
srand(crc);

я в первый раз не вник в предложенный Вами Аlex вариант простой как "две копейки"
Ну ё-маё, блин... Вы как программу то пишите ?
Неужели, приведённый мной кусок кода, Вам вообще ни о чём не говорит ? Он же прост, как 2 копейки ... :facepalm:

прошил атмегу 8 ... включил выключил и сново включил и так совпало, что звезда с одного итого же луча засветилась
затем посмотрел в протеусе число= crc не меняется это и привело меня к неправильному выводу :facepalm:

по совету ARV
Serzh2000, а вы не пробовали немного почитать книжки про язык Си и документацию про ваш CVAVR? как можно писать программы, не имея ни малейшего понятия о том, как это делается, что такое язык программирования и из каких частей формируются строки программ?!

почитал, подумал, вникнул в суть написанного :roll: прошил ардуино этим кодом и в мониторе порта увидел действительно crc меняется! :))) наверно протеусу не под силу это. :dont_know:

... залил в атмегу 8 все работает как надо спасибо :beer: и прошу прощения за за свою бестолковость :oops:

осталось попробовать третий вариант который предложил *Trigger* :wink:

Re: CodeVision AVR в вопросах и ответах

Чт мар 04, 2021 22:00:52

Serzh2000 писал(а):затем посмотрел в протеусе число= crc не меняется
Потому что это - протеус. Нужно понимать, что это не железо, и все значения регистров там при включении - не рандомные.

Вы, похоже, просто не поняли принцип :dont_know:

Re: CodeVision AVR в вопросах и ответах

Чт мар 18, 2021 20:34:03

добрый вечер! ткните носом на новую версию CodeVision с таблеткой. что-то я начал наблюдать утечку памяти у этой IDE хочу обновиться

Re: CodeVision AVR в вопросах и ответах

Чт мар 18, 2021 22:22:46

держи, дружище :)))
https://radioaktiv.ru/loads/softf/compi ... r-312.html

Re: CodeVision AVR в вопросах и ответах

Пт мар 19, 2021 08:27:58

держи, дружище :)))
тонкий подкол. 3.12 - версия 2014 года у меня как раз такая и стоит) http://www.hpinfotech.ro/cvavr-revision3.html

Re: CodeVision AVR в вопросах и ответах

Пт мар 19, 2021 09:16:18

Народ привет! Сижу ковыряюсь с 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, мой код
Изображение

Второе как отвечает работает библиотека ардуино, данные принимаются адекватные
Изображение

Re: CodeVision AVR в вопросах и ответах

Пт мар 19, 2021 22:55:45

Может задержка в 10мкС мала?

Re: CodeVision AVR в вопросах и ответах

Сб мар 20, 2021 07:44:28

Может задержка в 10мкС мала?

удалось решить проблему, подсказали
Код:
MSB=i2c_read(1);                //читаем старший байт
LSB=i2c_read(0);                //читаем младший байт

все встало на свои места

Re: CodeVision AVR в вопросах и ответах

Вт мар 23, 2021 10:31:29

у CVAVR есть аналог __no_init ?

Re: CodeVision AVR в вопросах и ответах

Вт апр 27, 2021 18:01:17

Ребят подскажите,где скачать СodeVision,у которого нет ограничение компиляции в 4кб

Re: CodeVision AVR в вопросах и ответах

Вс май 16, 2021 09:49:53

Объясните, пожалуйста, что означают записи такого вида:

TCCR2=(1<<PWM2) | (1<<COM21) | (0<<COM20) | (1<<CTC2) | (0<<CS22) | (0<<CS21) | (0<<CS20);

Вроде как регистры содержат шестнадцатеричное число?

Добавлено after 2 minutes 30 seconds:
Аа... наверно можно и восьмибитное число писать? Каждая запись в строчке - это бит? Тогда не понятно откуда взялись буквенные обозначения? Константы?
Ответить