Что-то у меня не получается. Может вопрос не правильно задаю?
У меня входное напряжение от 0 до 5В, опорное 1.1В.
АЦП принимает значение от 0 до 1023. Как вычислить напряжение (4В, например) при этих условиях? Или так нельзя? о_0
Что-то у меня не получается. Может вопрос не правильно задаю?
У меня входное напряжение от 0 до 5В, опорное 1.1В.
АЦП принимает значение от 0 до 1023. Как вычислить напряжение (4В, например) при этих условиях? Или так нельзя? о_0
Это в простейшем случае.
В реальности, если учесть, что у АЦП паспортная погрешность - 2 lsb, я часто делаю так: выставляю бит ADLAR
(в ADMUX
) и после этого читаю только ADCH
– в нём в этом случае сидят 8 старших битов результата, т.е. я получаю значение с отброшенными двумя младшими битами, которые по паспорту мусорные. Реально работает и читать меньше.
Никак. Входное не должно быть больше опорного - всё, что больше опорного будет 1023.
Хм, а для того чтобы использовать в качестве опорного VCC → нужен свободный пин, так?
Делитель используй
Едрид-мадрид!
Точно! )))
Отдыхать пора ))
да, я понимаю.
если в контексте проблемы ТС в коде из первого поста написать
ISR (ADC_vect) {
analogData = ADCL + (ADCH<<8);
}
протеус перестанет ругаться.
и правильно сделает)
Не понял?! Для чего нужен свободный пин?
analogData = ADC;
Уже говорили.
А вот это уже интересно (хотя не исключаю, что нужно просто идти отдыхать):
while (1) {
uint16_t volt;
// mvRefference - опорное напряжение в милливольтах
// divider - 1024 (или 512 если 9 бит - это бывает на 85-ой тиньке)
// value - попугаи, снятые с АЦП
// результат в милливольтах
// Vmv = (mvRefference * value + divider / 2) / divider;
volt = ((1100L * analogData) + 512L) / 1024;
if (volt > 43120){
PORTB |= (1<<PORTB3);
} else {
PORTB &= ~(1<<PORTB3);
}
}
Светодиод на порту PB3 загорается если значение в IF выставить в 43110 и тухнет, если выставить 43120.
Но этого не может быть! На входе протеус показывает напряжение 0.673484В.
Считаем по формуле какое значение АЦП должно ожидаться на выходе:
1100 → 1023
673 → X
X = (673 * 1023) / 1100;
X = 627;
Подставляем в формулу:
volt = (mvRefference * value + divider / 2) / divider;
volt = (1100 * 627 + 512) / 1024;
volt = 674;
674, а условие срабатывает только при 43120.
Капец какой-то…
Вот уж не думал, что Вам придётся это писать
Дайте полный код, чтобы я смог тупо запустить его у себя не додумывая, что у Вас там ещё написано.
#define F_CPU 1200000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile uint16_t analogData;
ISR (ADC_vect) {
analogData = ADC;
}
int main(void) {
DDRB |= (1<<PORTB3);
PORTB &= ~(1<<PORTB3);
DDRB &= ~(1<<PORTB4);
// Настраиваем работу с ADC (АЦП)
ADMUX |= (1<<REFS0) | (1<<ADLAR) | (1<<MUX1); // опорное напряжение - Internal, левое ориентирование данных, выбран вход ADC2 (на него подается измеряемое напряжение)
ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADIE) | (1<<ADPS2); // АЦП включен, запуск преобразования, режим автоизмерения, прерывание по окончанию преобразования, частота CLK/4
ADCSRB = 0x00; // режим автоизмерения: постоянно запущено
DIDR0 |= (1<<ADC2D); // запрещаем цифровой вход на ноге аналогового входа
sei(); //разрешаем глобально прерывания
while (1) {
uint16_t volt;
// mvRefference - опорное напряжение в милливольтах
// divider - 1024 (или 512 если 9 бит - это бывает на 85-ой тиньке)
// value - попугаи, снятые с АЦП
// результат в милливольтах
// Vmv = (mvRefference * value + divider / 2) / divider;
volt = ((1100L * analogData) + 512L) / 1024;
if (volt > 43100){
PORTB |= (1<<PORTB3);
} else {
PORTB &= ~(1<<PORTB3);
}
}
}
Если отбросить ADCL (оставив только ADCH), то при входящих 0.9 В порог срабатывания 220…230. Бррррр…
Голова кипит (и даже побаливает)…
Ну, в том, что у Вас там бешенные тыщщи, Вы сами виноваты. Что у Вас делает бит ADLAR
в строке 20? Уберите нахрен, будет нормальный результат. Зачем Вы его взводите? Он же форматирует результат влево! Его тогда не так читать надо!
Другое дело, что это не единственная ошибка - оно у Вас срабатывает один раз. Нет фрераннинга. Дать Вам нормальную настройку АЦП? Или проспитесь и сами сделаете?
Ну, ADLAR убрали? Нормальные числа стали?
Да! Ура! ))) Спасибо огромное!
Ну, я на схеме не стал мудрить с делителем – просто запитал потенциометр от 1.1В, также нагло воспользовался тем, что в протеусе светодиоды как рукописи – не горят и упростил схему донельзя:
Всё отлично работает при 50% на потенциометре светодиод ещё не светится, а уже при 51% – включается.
#define F_CPU 1200000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define LED_PIN 3
#define HIGH 1
#define LOW 0
#define OUTPUT 1
#define INPUT 0
#define digitalWrite(pin, val) do { (val) ? PORTB |= (1 << (pin)) : PORTB &= ~(1 << (pin)); } while(false)
#define pinMode(pin, val) do { (val) ? DDRB |= (1 << (pin)) : DDRB &= ~(1 << (pin)); } while(false)
volatile uint16_t analogData;
ISR (ADC_vect) {
analogData = ADC;
}
static inline void adcInit(void) {
ADCSRA =
(1<<ADEN) | // АЦП включен
(1<<ADATE) | // режим автоизмерения
(1<<ADIE) | // прерывание по окончанию преобразования
(1<<ADPS1) | (1<<ADPS0); // делитель частоты - 8 (частота АЦП - 1200 / 8 = 150кГц)
ADMUX =
(1<<REFS0) | // опорное напряжение - Internal 1.1в
(1<<MUX1); // вход ADC2
ADCSRB = 0x00; // режим автоизмерения: Free Running
DIDR0 |= (1<<ADC2D); // запрещаем цифровой вход на ноге аналогового входа
ADCSRA |= (1<<ADSC); // запуск первого преобразования
}
int main(void) {
pinMode(LED_PIN, OUTPUT);
adcInit();
sei(); //разрешаем глобально прерывания
while (true) {
static uint16_t oldData = 0;
cli();
const uint16_t aData = analogData;
sei();
if (oldData != aData) {
oldData = aData;
const uint16_t volt = ((1100L * aData) + 512L) / 1024;
digitalWrite(LED_PIN, volt > 550);
}
}
}