Помощь в разборе кода
- Войдите на сайт для отправки комментариев
Пнд, 07/12/2020 - 21:34
Всем доброго дня.
Скачал код, который позволяет измерить напряжение питания ардуино на основе внутреннего источника опорного напряжения. Но возникла куча вопросов:
1. Что бы использовать источник 1.1В нужно Биты 7-6 REFS1 и REFS0 в Регистре ADMUX установить в 1, но в коде ставится только REFS0
2. Вывод 7 есть на atmega328 в smd исполнении, но нет в DIP. Где тогда происходит измерение?
3. По завершению кода не надо ли переключиться на входное напряжение в качестве опорного?
Спасибо.
void setup() { Serial.begin(9600); Serial.println("start"); Serial.println(readVcc()); } void loop() { } long readVcc() { //https://sites.google.com/site/100voltsamper/mikrokontroller-razbor-poleetov/acp-v-atmega328p-pod-kakim-sousom-ego-neobhodimo-podavat // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference // Зададим уставки препроцессора: #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Если "тип котроллера" или "тип контроллера"..., то ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) // Сокращ. if else ADMUX = _BV(MUX5) | _BV(MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); #else // т.к. контроллера "__AVR_ATmega328P__" нет в условиях, то выполняем следующую строку: ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // (| - Оператор побитового включающего или, ADMUX - Регистр настройки мультиплексора АЦП) // _BV()поразрядный сдвиг // _BV(REFS0) пишем 1 в REFS0, получаем REFS1=0 (по умолчанию), REFS0=1, т.о. Подключено напряжение питания AVcc //Биты 3-0 MUX3, MUX2, MUX1 и MUX0. Данная группа битов определяет какой вход будет активен в качестве входа для АЦП. //номера пина входного канала 0111 ADC7 , этот пин вроде стандартно в ардуино не используется, хотя есть на SMD atmega328 //т.о. получаем, что контроллер настроен на считывание внешнего питания на 7 пине. (???) #endif delay(75); // Wait for Vref to settle // ждем стабилизации опорного напряжения (возможно при вызове кода после секунды работы контроллера задержка не требуется?) ADCSRA |= _BV(ADSC); // Start conversion //ADCSRA - Регистр управления и статуса А,|= запишем 1, данный бит включает режим преобразования входного аналогового сигнал в двоичный код, затем опять становится 0 while (bit_is_set(ADCSRA,ADSC)); // measuring //Проёверка на включенность (1) бита, когда включается 0, измерение закончено, выходим из цикла /*Полученный результат преобразования записывается в 2 регистра ADCH и ADCL. В зависимости от направления выравнивания преобразования старшийе и младшие разряды заносятся в разные регистры*/ uint8_t low = ADCL; // must read ADCL first - it then locks ADCH uint8_t high = ADCH; // unlocks both long result = (high<<8) | low; // объединяем значения тсаршего и младшего бита, что бы получить значение. result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 // вычисляем результат return result; // Vcc in millivolts возвращаем результат }
Если взглянуть в приведенный вами код, то можно там увидеть -
13
// Read 1.1V reference against AVcc
14
// set the reference to Vcc and the measurement to the internal 1.1V reference
что означает, что измерятся напряжение на внутреннем источнике опорного напряжения, когда для АЦП опорным явялется AVcc
И тогда все становится ясным
1. "ставится только REFS0" -> Источник опорного напряжения AVcc
2. "Вывод 7" это_BV(MUX2) | _BV(MUX1) | _BV(MUX0) а
_BV(MUX3) | _BV(MUX2) | _BV(MUX1) это подключение на измерение внутреннего источнока 1.1В. Измерение происходит внутри
3. Не надо, так как оно уже итак есть
Спасибо!
Еще хотел уточнить, строка 33 нужна только при первом запуске функции, потом (или если до вызова функции) прошло достаточно времени, то задержка не нужна?
Если я правильно понимаю, то здесь мы ждем стабилизации напряжения на внутреннем источнике 1,1В, которое после того как установится (после запуска контроллера) не меняется, не отключается и вообще не меняется за весь период работы.
Если я правильно понимаю, то здесь мы ждем стабилизации напряжения на внутреннем источнике 1,1В, которое после того как установится (после запуска контроллера) не меняется, не отключается и вообще не меняется за весь период работы.
Не совсем. Источник опорного напряжения 1.1В достаточно высокоомный. Поэтому после переключения на него канала АЦП нужно подождать пока зарядится входной измерительный конденсатор. Если потом каналы АЦП не переключаются, то при последующиъ измерениях можно задержку не делать. И по любому 75 миллисекунд это перебор. Одной-двух вполне достаточно.
Если я правильно понимаю, то здесь мы ждем стабилизации напряжения на внутреннем источнике 1,1В, которое после того как установится (после запуска контроллера) не меняется, не отключается и вообще не меняется за весь период работы.
Не совсем. Источник опорного напряжения 1.1В достаточно высокоомный. Поэтому после переключения на него канала АЦП нужно подождать пока зарядится входной измерительный конденсатор. Если потом каналы АЦП не переключаются, то при последующиъ измерениях можно задержку не делать. И по любому 75 миллисекунд это перебор. Одной-двух вполне достаточно.
Благодарю, уменьшу задержку до 3 миллисекунд.
P.S. пробовал убрать задержку, при первом запуске показывает заниженное напряжение питания, потом нормально, при задержке хотя бы в 1 миллисекунду показывает корректно.
пробовал убрать задержку, при первом запуске показывает заниженное напряжение питания, потом нормально, при задержке хотя бы в 1 миллисекунду показывает корректно.
можно вовсе выкинуть задержку и просто повторить строчки 34 и 35 дважды
Выкинуть задержку, и поставить мусорный код, который задерживает выполнение. Можно, конечно. Только зачем.
На данный момент задержку реализовал так:
На данный момент задержку реализовал так:
чем это отличается от delay(5)?
Ну в принципе особо ничем. Но delay() мне не нравится на уровне веры, а способа лучше дождаться выравнивания напряжения я не знаю.
Понимаешь ли. В стандартном delay(), унутре, есть вызов функции yield(), что дает знающим людям хотя бы видимость неблокирующей задершки. В твоём while этого совсем нихрена нет.
Не так страшен delay() как неверующие в него, отрицающие и изгоняющие его. :)
Понимаешь ли. В стандартном delay(), унутре, есть вызов функции yield(), что дает знающим людям хотя бы видимость неблокирующей задершки. В твоём while этого совсем нихрена нет.
Не так страшен delay() как неверующие в него, отрицающие и изгоняющие его. :)
Не знал такого, никогда не встречал описания реализации delay(), везде написано только, что delay() зло и используйте millis()
А если так?
На данный момент задержку реализовал так:
чем это отличается от delay(5)?
Отличается принципиально: delay(5) обеспечивает точность интервала где-то 0.05% в используемых единицах, а вышеприведенный код - хуже 20%.
да ему точность задершки, я думаю, не так уж и важна. Наерна.
Какая разность скока налили, 400 капель, или 402.
Понимаешь ли. В стандартном delay(), унутре, есть вызов функции yield(), что дает знающим людям хотя бы видимость неблокирующей задершки.
Ну почему, обязательно, видимость? На ЕСП можно создать несколько threads и тогда delay будет реально отдавать время другим потокам.
Заставь дурака богу молиться.
Понимаешь ли. В стандартном delay(), унутре, есть вызов функции yield(), что дает знающим людям хотя бы видимость неблокирующей задершки.
На ЕСП можно создать несколько threads и тогда delay будет реально отдавать время другим потокам.
Я в ESP "не селен".
Я в ESP "не селен".
Там на самом деле FreeRTOS крутится, а "ардуино" это просто отдельный поток. Но никто не запрещает прямо из него создавать другие.
Какая разность скока налили, 400 капель, или 402.
Не скажи, 400 и 320 - разница есть.
Я конечно прошу пардона, что столь бесцеремонно прерываю разговор гуру, но будут ли комментарии к посту №12 или предложения, ссылки, намеки, как правильно организовать задержку?
Я конечно прошу пардона, что столь бесцеремонно прерываю разговор гуру, но будут ли комментарии к посту №12 или предложения, ссылки, намеки, как правильно организовать задержку?
Так ещё раньше сказали - просто поставь delay и непарься. В данном случае принципиальной разницы нет.
как правильно организовать задержку?
так вроде все уже ответили - код #12 полностью аналогичен строчке
delay(5)
так зачем усложнять?
Замена delay() через while() - типичная ошибка новичков, тупо зазубривших "делей = плохо", но абсолютно не понимающих, зачем вообще нужны миллис
В этом коде применение миллис абсолютно ничего не дает.
как правильно организовать задержку?
так вроде все уже ответили - код #12 полностью аналогичен строчке
delay(5)
так зачем усложнять?
Замена delay() через while() - типичная ошибка новичков, тупо зазубривших "делей = плохо", но абсолютно не понимающих, зачем вообще нужны миллис
В этом коде применение миллис абсолютно ничего не дает.
Ок, понял. Благодарю за помощь.