Доброго времени. Друзья, возник вопрос по одновременному считыванию сигнала с аналоговых портов при управлении регистрами. Есть код для опроса одного канала: Код (C++): int analogValue = 0; // значение аналогового сигнала void setup() { Serial.begin(9600); DDRC = 0b00000000; // режиме порта С "INTPUT" DIDR0=0b00111101; //выключаем разряды порта С, кроме ADC1 PORTC=0b00000010; на ADC1 поключаем подтягивающий резистор ADMUX =0b01000001; // канал ADC1, используем внутреннее опорное напр.= 5В ADCSRA = 0xAF; // включаем АЦП, разрешаем прерывания, делитель = 128 ADCSRB = 0x40; // включаем АЦП, каналы MUX, режим скользящей выборки bitWrite(ADCSRA, 6, 1); // Запускаем преобразование установкой бита 6 (=ADSC) в ADCSRA sei(); // устанавливаем флаг прерывания } void loop() { } /*** Процедура обработки прерывания АЦП ***/ ISR(ADC_vect) { analogValue = ADCL; // сохраняем младший байт результата АЦП analogValue += ADCH << 8; // сохраняем старший байт АЦП Serial.println(analogValue);// выводим значение в порт } Проблема в том, что затрудняюсь добавить опрос еще одного канала. Вопрос: как прописать: - после окончания преобразования на первом канале АЦП, вывести значение преобразования в сериал-порт (это в коде прописано); - начать преобразование на втором канале; - после окончания преобразования на втором канале АЦП, вывести значение преобразования в сериал-порт. - начать цикл заново. Т.е. заставить мультиплексор переключаться между разрядами порта.
Вопрос: для чего DDRC = 0b00000000; // режиме порта С "INTPUT"-он и так там по умолчанию Зачем DIDR0=0b00111101; //выключаем разряды порта С, кроме ADC1 если вы хотите заюзать 2 канала АЦП и вообще зачем выключать?Пусть будут-вдруг вам захочется 3-4 канала сделать. Зачем опрос сделан из прерывания?Не проще ли в void loop неспеша и методично опрашивать оба датчика по-очереди и данные выводить в USART или куда там Вам ещё надо?Да и зачем вообще вся эта Канитель Код (C++): DDRC = 0b00000000; // режиме порта С "INTPUT" DIDR0=0b00111101; //выключаем разряды порта С, кроме ADC1 PORTC=0b00000010; на ADC1 поключаем подтягивающий резистор ADMUX =0b01000001; // канал ADC1, используем внутреннее опорное напр.= 5В ADCSRA = 0xAF; // включаем АЦП, разрешаем прерывания, делитель = 128 ADCSRB = 0x40; // включаем АЦП, каналы MUX, режим скользящей выборки bitWrite(ADCSRA, 6, 1); // Запускаем преобразование установкой бита 6 (=ADSC) в ADCSRA sei(); // устанавливаем флаг прерывания } void loop() { } /*** Процедура обработки прерывания АЦП ***/ ISR(ADC_vect) { analogValue = ADCL; // сохраняем младший байт результата АЦП analogValue += ADCH << 8; // сохраняем старший байт АЦП Serial.println(analogValue);// выводим значение в порт } если можно использовать так Val1 = analogRead(A2); // Читаем со второй ноги аналогово входа напряжение падающей волны Val2 = analogRead(A1); // Читаем с первой ноги аналогово входа напряжение отраженной волны Цэж Ардуино!
Пока всех знаний о всех тонкостях управления выводами регистрами я не имею, поэтому такие вот ошибки возникают. Но вопрос остался: как грамотно прописать управление мультиплексором при считывании информации с нескольких каналов? Тот скетч привел в качестве примера считывания с одного канала.
а у вас ваш код работает? У меня сомнения, поскольку прерывание ISR(ADC_vect) уже задействовано в ардуиновских функциях. А по сути вопроса - меняете в теле в регистре ADMUX младшие биты, они и отвечают за номер мультиплексируемого входа.
Посмотрите в сторону аппаратного решения. Такой АЦП снимает показания с ноги наааамного быстрее, можно сказать что со всех ног одновременно.
Вот один из вариантов реализации ADC для Arduino на AVR (поддерживает Atmega328, Atmega32u4, Atmega2560). Сам код - https://github.com/SimpleRov/AVR/tree/master/ADC. Принцип работы. 1. Инициализация ADC - void AdcInit(), тут все понятно из кода. 2. Смена входов мультиплексора - void SetAdcPin(uint8_t adcInput). Параметр adcInput номер входа Arduino, чтобы переключиться на входа Arduino - A0, передаем 0 и т.д. В начале происходит проверка, выбран новый вход Arduino или аналогичный предыдущему чтению порта. Если да, смена входа мультиплексора с небольшой задержкой для стабилизации значений, если нет, переходим к следующему шагу - запуск преобразования ADC - StartConversionAdc(). 2.а. В настройках инициализация ADC, мы настроили прерывание по завершению преобразования. 3. Проверяем закончено преобразование и готовы ли данные - uint8_t AdcReadyToRead(). 4. Получаем значение - uint16_t GetAdcValue(). И так по кругу, пункт 1, первый порт 2, 2a, 3, 4, другой порт 2, 2a, 3, 4 и т.д. Вот пример работы. Функция аналогичная analogRead - AnalogPinRead(uint8_t pin, uint16_t* adcValue). Код (C++): static uint8_t AnalogPinRead(uint8_t pin, uint16_t* adcValue) { SetAdcPin(pin); if (AdcReadyToRead()) { *adcValue = GetAdcValue(); return 1; } return 0; } 2 канала по очереди, просто вызываем loop. Код (C++): void AdcSensorsRead() { static uint8_t stepAdcSelect = 0; static uint16_t analogPinValue = 0; if (!stepAdcSelect) { if (AnalogPinRead(0, &analogPinValue)) { DEBUG_PRINT(F("Value A0 - ")); DEBUG_PRINTLN(analogPinValue); stepAdcSelect = 1; } } if (stepAdcSelect == 1) { if (AnalogPinRead(1, &analogPinValue)) { DEBUG_PRINT(F("Value A1 - ")); DEBUG_PRINTLN(analogPinValue); stepAdcSelect = 0; } } } UPD. Он же без библиотеки. - http://forum.amperka.ru/threads/Простые-примеры-adc-1-wire.6438/.
Интересный код, спасибо, позаимствовал его и обернул в класс Код (C++): // Библиотека работы с ADC #include "ADC.h" // Переменные для работы с ADC // Переменная класса внутреннего АЦП InternalAdc internalAdc; // /Переменные для работы с ADC void setup() { // put your setup code here, to run once: Serial.begin(115200); // 1. Инициализация ADC - void AdcInit(), тут все понятно из кода. internalAdc.AdcInit(); } void loop() { // put your main code here, to run repeatedly: AdcSensorsRead(); } // И так по кругу, пункт 1, первый порт 2, 2a, 3, 4, другой порт 2, 2a, 3, 4 и т.д. Вот пример работы. Функция аналогичная analogRead - AnalogPinRead(uint8_t pin, uint16_t* adcValue). uint8_t AnalogPinRead(uint8_t pin, uint16_t* adcValue) { // 2. Смена входов мультиплексора - void SetAdcPin(uint8_t adcInput). // Параметр adcInput номер входа Arduino, чтобы переключиться на входа Arduino - A0, передаем 0 и т.д. // В начале происходит проверка, выбран новый вход Arduino или аналогичный предыдущему чтению порта. // Если да, смена входа мультиплексора с небольшой задержкой для стабилизации значений, если нет, переходим к следующему шагу - запуск преобразования ADC - StartConversionAdc(). // 2.а. В настройках инициализация ADC, мы настроили прерывание по завершению преобразования. internalAdc.SetAdcPin(pin); // 3. Проверяем закончено преобразование и готовы ли данные - uint8_t AdcReadyToRead(). if (internalAdc.AdcReadyToRead()) { // 4. Получаем значение - uint16_t GetAdcValue(). *adcValue = internalAdc.GetAdcValue(); return 1; } return 0; } // 2 канала по очереди void AdcSensorsRead() { static uint8_t stepAdcSelect = 0; static uint16_t analogPinValue = 0; if (!stepAdcSelect) { if (AnalogPinRead(2, &analogPinValue)) { Serial.print(F("Value A2 - ")); Serial.println(analogPinValue); stepAdcSelect = 1; } } if (stepAdcSelect == 1) { if (AnalogPinRead(4, &analogPinValue)) { Serial.print(F("Value A4 - ")); Serial.println(analogPinValue); stepAdcSelect = 0; } } }