Не получается инициализировать несколько датчиков одновременно для ардуинки

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Здравствуйте, уважаемые форумчане. Второй день не могу закончить по-человечески программу. Суть в том, что 3 датчика MQ-2 должны опрашиваться микроконтроллером. Результаты выводятся на дисплей 1602A. При фиксировании задымления одним из датчиков реле замыкает нагрузку из вентиляторов. Я перенастроил АЦП для более быстрого преобразования сигналов, поступающих с датчиков. Суть же проблемы, с которой я сталкиваюсь, в том, что на всех аналоговых пинах фиксируется одно и то же значение, как бы я не проворачивал это дело. 

Вот фрагмент кода для обработки прерывания от АЦП: 

Moderator : пожалуйста, вставьте код правильно (возможно, новым сообщением в тему), 
 

Выручайте, уважаемые специалисты! На дисплей я вывожу пока limit1 и limit2, получается вот такой ужас :( 

По датчикам, у меня подключен только один MQ-2 к А0, но подключая датчик звука к А1, я наблюдаю ту же картину( 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Прочитайте тему http://arduino.ru/forum/obshchii/pesochnitsa-dlya-vsekh-novichkov и попробуйте задать вопрос правильно.

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Извиняюсь. Вот фрагмент из обработчика прерываний и loop: 


Извиняюсь. Вот фрагмент из обработчика прерываний и loop: 

//Обработчик прерываний от АЦП

ISR(ADC_vect){
    rezultat = ADCH; //Отображаем 8 бит, отсекая два из ADCL
    switch (analogPin)     //Каждому из пинов соответствует своя переменная
    {
      case A0:
      limit1 = rezultat;
      case A1: 
      limit2 = rezultat; 
      case A2:
      limit3 = rezultat; 
    }
 
    
     analogPin += 1;               //Перебираем пины по кругу, в конце возвращаемся к A0
  if (analogPin > A4) {
    analogPin = A0;
  };
 
  ADMUX = analog_ref | (analogPin & 0x07); //Устанавливаем новый вход для преобразования
   
}


//loop

void loop() {


lcd.setCursor(1,1);
lcd.print(limit1);
lcd.setCursor(10,1);
lcd.print(limit2);


if ((limit1<50) & (limit2<50) & (limit3<50))
 { PORTD = B00000000; //Регистр сброшен, все в норме } 

else {if ((limit1>80) || (limit2>80) || (limit3>80)) 
{ PORTD |=B11111000 //Установка битов, включение реле

}

}

}

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не вижу настроек ADC и также не вижу чему равна переменная/константа analog_ref. Потому не могу сказать взводится ли бит ADLAR. Если нет, то считывание значения ADC написано неверно.

-NMi-
Offline
Зарегистрирован: 20.08.2018

Зачем так "извращённо" издеваться над АЦП? Опрашивай их потихоньку в основном лупе и будет всё работать.

PS: АЦП обрабатывают через ISR таким способом только тогда, когда нужно отслеживать или анализировать состояние нескольких входов АЦП за единицу времени. Например,раз в 1 сек. 5 входов или 100 раз в секунду и т.д.  Так-что в именно этом коде - это лишнее.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Snova_Sumerki пишет:

Я перенастроил АЦП для более быстрого преобразования сигналов, поступающих с датчиков.

А какой в этом смысл?

Вы пытаетесь сэкономить несколько десятков мкс на опросе датчиков и тут же тратите в несколько сотен раз больше времени для вывода на дисплей.

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

почему? у меня ведь выводятся беспрерывно показания, без задержек, или все-таки есть какие-то задержки, просто я не замечал?..  Serial.print и lcd.print аккуратно координируются вроде, без отставаний, я так проверял...

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Получается, желательно отказаться от изменения параметров обработчика прерываний? Я понял, спасибо. Да я только просто разбираться начал, вычитал все здесь: https://codius.ru/articles/

То есть нужно в обработчике прерываний просто 

rezultat = ADCH;

оставить, а в loop уже поочередный опрос датчиков сделать? 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы, по-прежнему, не показали своих настроек ADC, потому разговор идёт "языком по голому заду".

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020
  ADCSRA = 0;             
  ADCSRB = 0;           
  ADMUX |= (1<<REFS0);
  
  ADMUX |= (1 << ADLAR);   
                        
                          
  analog_ref = ADMUX; //analog_ref описывается как глобальная переменная со значением DEFAULT
                                      //Она нужна для хранения настроек ADMUX при переключении пина

  ADMUX |= (0 & 0x07);    
  ADMUX |= (0 & 0x08);    
  ADMUX |= (0 & 0x09);    
  
  ADCSRA |= (1 << ADPS2);                   
  ADCSRA &= ~((1 << ADPS1) | (1 << ADPS0));  
  
  ADCSRA |= (1 << ADATE); 
  ADCSRB &= ((1<<ADTS2) & (1<<ADTS1) &(1<<ADTS0));
  ADCSRA |= (1 << ADIE);  
  ADCSRA |= (1 << ADEN);  
  ADCSRA |= (1 << ADSC);  

 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Суть проблемы в том, что мне надо сменить вход мультиплексора для нового преобразования, потом снова в обработчик прерываний, потом меняем опять вход мультиплексора, опять преобразуем и в обработчик прерываний и т.д., а потом заново, с A0 начинаем

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

В строке №3 ошибка. Среда Ардуино сама конфигурирует ADMUX, Вы хотите переконфигурировать его под себя, но зачем-то сохраняете старую конфигурацию. Замените на присваивание.

Далее, не вижу где Вы запускаете считывание ADC. Из Вас код по строчке клещами тянуть?

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Понял, исправил. Ну как, вот в последней строке

ADCSRA |= (1 << ADSC);

это разве не запуск преобразования? 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Вот для одного датчика у меня прекрасно все работает, для нескольких начинается *crazy dance* микроконтроллера

nik182
Offline
Зарегистрирован: 04.05.2015

Соглашусь с #4. Родной analogRead около 100 микросекунд. Вывод символа на экран тоже этих масштабов. Весь цикл опроса датчиков и вывод на экран займёт не больше миллисекунды. Время реакции датчика на задымление в сотни раз больше. Зачем устраивать головную боль? Если учиться, то надо взять мануал на процессор и написать программу как там рекомендуют. Если сделать устройство, то надо рассмотреть параметры всех составляющих и выбрать наиболее простой путь реализации. В данном случае, гнаться за скоростью обработки - показать свою не состоятельность как инженера.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Snova_Sumerki пишет:

Понял, исправил. Ну как, вот в последней строке

ADCSRA |= (1 << ADSC);

это разве не запуск преобразования? 

Однократный. Как Вы запускаете его после прерывания?

В общем, если Вы ещё не поняли, выкладывайте код полностью (разумеется, сократив его до минимального, на котором видна проблема) или разбирайтесь сами 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Я понял, тогда переделаю, уберу обработчик прерываний и сделаю через analogRead в loop. Спасибо. 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Я не знаю. У меня ведь ADC работает в режиме free running mode. А касательно обработчика, я думал, он самостоятельно при таком режиме ADC завершает работу. Да и потом, нужно ли завершать его работу при непрерывной обработке входящих сигналов?.. Считывается себе и считывается, работает обработчик и работает, это ведь телу программы (loop) не мешает....

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

А. Я понял, вы имеете ввиду, что я в Setup установил флаг запуска ADC. Ну хорошо, я тогда уже сам попробую разобраться, не могу полностью код выложить, извините. По антиплагиату потом не пройдет. 

-NMi-
Offline
Зарегистрирован: 20.08.2018

Snova_Sumerki пишет:

Суть проблемы в том, что мне надо сменить вход мультиплексора для нового преобразования, потом снова в обработчик прерываний, потом меняем опять вход мультиплексора, опять преобразуем и в обработчик прерываний и т.д., а потом заново, с A0 начинаем

ЕслиУж так нужно "выпендиццо" тогда делаешь ADC Free Running mode. В ISR по окончанию преобразования запоминаешь результат, меняешь канал АЦП и поехал. В таком режиме АЦП будет работать на максимуме своих возможностей и аппаратно, оОочень мало занимая процессорного времени. Но, сцуко, атомарность будет засадой )))

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Извините, а не могли бы вы показать в коде, как это сделать? Просто вроде стоит free running mode, но АЦП втупую не хочет прикасаться к другим пинам, в итоге на выходе переменная rezultat присваивается и первому, и второму, и третьему пину одна и та же :( 

-NMi-
Offline
Зарегистрирован: 20.08.2018

Вот в качестве примера опрос джойстика по трём каналам в прерывании ADC.

Сверху: берём результат преобразования.

Дальше, разбрасываем по трём разным переменным. У меня в этом примере использован AutoTriggering от таймера, опрос 60 раз в секунду, соответственно, 20 раз в секунду на канал. Работает уже не один год. (это только махонький кусочек кода...)

      in r0,adcl
      in r1,adch

      lds r16,{Adc_input_channel}                          
      cpi r16,00
      breq adcc_int_joy_x
      cpi r16,01
      breq adcc_int_joy_y
      cpi r16,02
      breq adcc_int_joy_b
 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Да, мне очень нужно выпендриться..)) от этого зависит оценка по курсовой.... Так бы я через analogRead спокойненько все сделал и не мучил бы ни себя, ни вас..

-NMi-
Offline
Зарегистрирован: 20.08.2018

В таком случае сделай всё на прерываниях и на асме. В main будет только одна строчка, типа если (flag) то реле On иначе Off. Гарантирую, шо препод(ша) акуеет!!!

Да, забыл, заголовок на чистом С сделай, кодевижн или джумпстарт позволяют конфиг проца сделать оОочень лаконичный!!!

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Ахахаха, нет, я изначально отказался на восьмой меге делать, потому что терпеть не могу на асме все, что можно и нельзя, инициализировать, адресовать и т.д. и т.п )) Еле лабы закрыл по нему в прошлом семестре.

Спасибо большое всем за ответы и помощь, буду пробовать по-разному, уже логика и здравый смысл отключились!) Буду перебирать варианты, руководствуясь принципом "А вдруг заработает" :D

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Snova_Sumerki пишет:
не могу полностью код выложить

Но при этом от других требуется

Snova_Sumerki пишет:
а не могли бы вы показать в коде, как это сделать?

В общем, разбирайтесь сами.

-NMi-
Offline
Зарегистрирован: 20.08.2018

Snova_Sumerki пишет:

потому что терпеть не могу на асме

Буду перебирать варианты, руководствуясь принципом "А вдруг заработает" :D

Этт ты зря... На асме можно творить чудеса.

Принцип не плох, время только много занимает.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, можно и фри-раннинг, только ADMUX нужно вовремя обновлять, а не когда попало, как у ТС. А так получается, что читается всё время с одного и того же канала, т.к. DMUX реально не изменяется.

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Понимаю. Но сейчас банально нехватка времени сказывается. А так у меня стмка в пути с Китая, я буду на асме ее кодить 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Да я уже и так пробовал обновлять, ни в какую просто 

switch (ADMUX) {
    case 0xC0:
      limit2 = Result;
      ADMUX = 0xC1;
      break;
    case 0xC1:
      limit1= Result;
      ADMUX = 0xC0;
      break;
    default:

    break;
  }
  ADCSRA |= 1<<ADSC;
}

 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

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

#include <LiquidCrystal_I2C.h>
 int result;
 int porog1,porog2,porog3;

    

LiquidCrystal_I2C lcd(0x27,16,2);
                 
void setup() {
  
 lcd.init();                      // Инициализация дисплея  
 lcd.backlight();                 // Подключение подсветки
 lcd.setCursor(0,0);              // Установка курсора в начало первой строки
}

void ADC_IN () {
 
// настройка регистра
  ADCSRA |= 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0; // предделитель на 128
  ADCSRA |= 1<<ADIE;                        // разрешаем прерывание
  ADCSRA |= 1<<ADEN;                        // разрешаем работу АЦП

  ADMUX |= 1<<REFS0;
// настройка регистра

  sei();

// запускаем первое АЦ-преобразование
  ADCSRA |= 1<<ADSC;
}

  


void loop() {

 ADC_IN(); 
 

lcd.setCursor(1,1);
lcd.print(porog1);
lcd.setCursor(10,1);
lcd.print(porog2);

  
}


ISR(ADC_vect) {
  uint8_t lowByte;
  uint16_t Result;

// 1. считываем младший и старший байты результата АЦ-преобразования и образуем из них 10-битовый результат
  lowByte = ADCL;
  Result = ADCH<<8 | lowByte;

// 2. В зависимости от номера канала ADC сохраняем результат в правильной ячейке памяти и настраиваем номер канала для следующего преобразования
  switch (ADMUX) {
    case 0xC0:
      porog2 = Result;
      ADMUX = 0xC1;
      break;
    case 0xC1:
      porog1 = Result;
      ADMUX = 0xC0;
      break;
    default:
//Default code
    break;
  }
// 3. запускаем новое АЦ-преобразование
  ADCSRA |= 1<<ADSC;
}

      
  


  

 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Предделитель я потом поменяю, мне пока просто надо, чтобы это все заработало

-NMi-
Offline
Зарегистрирован: 20.08.2018

Snova_Sumerki пишет:

А так у меня стмка в пути с Китая, я буду на асме ее кодить 

Дануна. Там шоб светадиодоммаргнуть нуно тышшустрок написАтЪ )))

Вот на "тяжёлых" процах ассемблер - это уже лишнее )))

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

А, ну просто для себя попробую хотя бы)) 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы не вовремя обновляете ADMUX - слишком рано. Читайте даташит

ADMUX can be safely updated in the following ways:
a. When ADATE or ADEN is cleared.
b. During conversion, minimum one ADC clock cycle after the trigger event.
c. After a conversion, before the Interrupt Flag used as trigger source is cleared.
 
Вас, очевидно, интересует пункт (b). Ну и смотрите. Частоту часов АЦП знаете? А частоту контроллера? Вы обновляете не после, а во время первого тика. В итоге ADMUX не меняется и Вы читаете всё время с одного и того же пина.
Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Ну частота контроллера 16 МГц, а частота АЦП зависит от частоты МК и предделителя, насколько знаю. Получается, нужен таймер перед следующим считыванием для задержки по времени и все? 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Я сделал задержку по времени, но ничего не меняется..( 

ISR(ADC_vect){
    result = ADCH;
    switch (analogPin)
    {
      case A0:
      porog1 = result;
      analogPin |= (0 & 0x08);    // Выбираем порт PC0 для преобразования
      case A1:
      if (millis() - timing > 1000){ 
      timing = millis();}
      porog2 = result; 
       analogPin |= (0 & 0x09);    // Выбираем порт PC1 для преобразования
      case A2:
      porog3 = result; 
      analogPin |= (0 & 0x07);    // Выбираем порт PC2 для преобразования
     
 
}
ADCSRA |= 1<<ADSC;
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Snova_Sumerki пишет:

Я сделал задержку по времени, но ничего не меняется..( 

А с какого бодуна ему меняться?

https://www.youtube.com/watch?v=ZSXimQHCjKo - Вы не сделали никакой задержки от слова совсем.

Во-первых, для задержки нужно не if (millis() - timing > 1000), а while (millis() - timing > 1000);. А во-вторых, если Вы так сделаете, то то это будет задержка навечно - программа намертво повиснет, т.к. millis внутри обработчика прерывания не изменяется и всегда возвращает одно и тоже.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Snova_Sumerki пишет:

частота АЦП зависит от частоты МК и предделителя, насколько знаю. 

Неправильно знаете. Вы её настраиваете сами и должны знать её точно. Для полного разрешения АЦП частота должна быть от 50 до 200 килогерц.

-NMi-
Offline
Зарегистрирован: 20.08.2018

Эмммм...

Эт щас такой студент пошёл, шо фприрывании милс считает?  Шо с нами будет... Ужос...

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Та я уже не знаю, где что посчитать, голова не работает. http://www.cyberforum.ru/avr/thread2085603.html здесь пишут, что считать вообще не нужно ничего, каналы можно сразу переключать. Я вроде все правильно делаю, пины переключаю: 

ISR(ADC_vect){
    
    result = ADCH;
    analogPin +=1;
    if (analogPin > A5) {
    analogPin = A0;
}
  ADCSRA |= (1 << ADSC);  // Запускаем преобразование
   
}

Результат в case вывожу в loop(), этот АЦП в упор не хочет видеть другие пины кроме A0. Где еще что поставить,

я уже не знаю. По-моему, это невыполнимая задача какая-то.

 

Все верно ведь по логике... 

1) Настройка АЦП, запуск преобразования

2) Обработка прерываний от АЦП, переключение пина, новый запуск преобразования

3) Завершение преобразования, обработка прерываний

4) Переключение пина, новый запуск и т.д.

 

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Зачем нужны 6, 8, 12-канальные АЦП, если их невозможно нормально настроить?..

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Snova_Sumerki пишет:

Зачем нужны 6, 8, 12-канальные АЦП, если их невозможно нормально настроить?..

Почему невозможно? "Рыба есть, ловить надо уметь"

Snova_Sumerki пишет:
здесь пишут

Ну, не знаю, Вы на каждом заборе читаете, что пишут? Читайте даташит. там пишут всё правильно.

Snova_Sumerki пишет:
По-моему, это невыполнимая задача какая-то.

Ну, почему, я же Вам уже всё сказал. Просто назначайте новый пин после того, как прошёл первый тик преобразования (можно парочку тиков пропустить для надёжности). Делов-то.

Snova_Sumerki пишет:

4) Переключение пина, новый запуск и т.д.

Стоп! Давайте определимся, чего Вы хотите. Уж либо "фри-раннинг", либо "новый запуск". Вы что-то выберите и в одну кучу не валите.

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Спасибо за ссылку, завтра ознакомлюсь с даташитом.

Ну фри-раннинг должен подразумевать непрерывную обработку всех каналов, правильно? Результаты этой обработки моментально присваиваются в loop() соответствующим переменным porog1, porog2, porog3 и т.д., правильно? Т.е. loop() и ISR работают, не мешая друг другу. 

Задержку я пробовал делать через выключение/включение АЦП перед переключением пинов. Вот так это в коде выглядит: 

ISR(ADC_vect){
    
    result = ADCH;
    ADCSRA &= ~(1<<ADEN);
    analogPin +=1;
    if (analogPin > A5) {
    analogPin = A0;
}
  ADCSRA |= (1 << ADEN);  // Запускаем АЦП
  ADCSRA |= (1 << ADSC);  // Запускаем преобразование
   
}
loop() {

 switch (analogPin)
{
  case A0:
  porog1 = result;
  case A1: 
  porog2 = result;
  case A2: 
  porog3 = result;
}

}

Также я попробовал поставить Serial.begin после каждого case и обнаружил, что в монитор порта выводится значение PC0, то есть 14, получается, что переключения просто-напросто не происходит, насколько я понял.

С другой стороны, я установил Serial.begin после 

analogPin +=1;

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

 

sadman41
Offline
Зарегистрирован: 19.10.2016

ЕвгенийП пишет:

Ну, почему, я же Вам уже всё сказал. Просто назначайте новый пин после того, как прошёл первый тик преобразования (можно парочку тиков пропустить для надёжности). Делов-то.

Там, вроде, даже первый результат чтения надо в утиль спускать после смены канала. Или это не про то?

rkit
Offline
Зарегистрирован: 23.11.2016

Если переключать канал в прерывании, в режиме автозапуска, то это происходит уже после старта нового захвата, и новый канал станет активен только после следующего прерывания. Учесть это не сложно.

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Извините, а как это учесть? Где и что прописать, в loop, setup, ISR или в функции, отвечающей за настройку ADC? Подозреваю, что вы имеете ввиду какую-то проверку на определение нового входа, но как ее реализовать, если не через switch(analogPin)

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Snova_Sumerki пишет:

Ну фри-раннинг должен подразумевать непрерывную обработку всех каналов, правильно? 

У атмеги всего один АЦП и аналоговый коммутатор с помощью которого можно подключать этот один АЦП к разным ножкам по очереди. Фри ранинг означает, что следующее измерение автоматически запускается сразу же после окончания предыдущего. Причем по тому же самому каналу. При этом срабатывает прерывание, но к тому времени как обработчик начинает его обрабатывать АЦП уже во всю оцифровывает следующую выборку.

Фри ранинг используется когда нам надо получать выборки по одному каналу с минимальными паузами. Если нам надо скакать между каналами, то такой режим использовать смысла нет. Тогда для максимально быстрого опроса нужен  режим одиночных измерений и обработка и переключение каналов по прерыванию. Но для вашего случая (датчика MQ-2) экономить микросекунды смысла нет. Как тут уже неоднократно упоминали - используйте analogRead без всяких прерываний и будет вам счастье. Ну получите вы сигнал о задымлении на одну десятитысячную секунды позже, что это изменит?

Кстати если вы используете код приведенный в сообщении #9 то у вас в 19 строке ошибка, тильду пропустили. Хотя в данном случае это ни на что особо не влияет.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sadman41 пишет:

Там, вроде, даже первый результат чтения надо в утиль спускать после смены канала. Или это не про то?

Нет, это после смены "Voltage Reference"

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Snova_Sumerki пишет:

Извините, а как это учесть? Где и что прописать, в loop, setup, ISR или в функции, отвечающей за настройку ADC? Подозреваю, что вы имеете ввиду какую-то проверку на определение нового входа, но как ее реализовать, если не через switch(analogPin)

Блин, ну Вы голову-то включите. Ну, запустили Вы преобразование в самом начале. Запоминайте время. Проверяйте в лупе, не прошло ли два , скажем тика ADC (время тика Вы обязаны знать!). Как прошло, перезаписывайте ADMUX. Случилось прерывание, запоминайте время, хватайте результат и убирайтесь из обработчика прерывания. И снова "проверяйте в лупе ..." и так далее.

Snova_Sumerki
Offline
Зарегистрирован: 04.01.2020

Ничего не получается. Наверно, буду делать через analogRead(); Я уже попробовал одиночное преобразование по-разному делать, и с задержкой, и с переключением пинов в обработчике прерывания, с проверкой обработки прерывания и последующим переключением пинов, этот АЦП не сдается. А мне сдается, что мультиплексор вообще не умеет работать по неизвестным мне причинам с другими портами кроме PC0, может с ардуинкой что-то не то, может с АЦП. Я написал чистую программу для работы с несколькими каналами, ничерта не работает. 

void setup() {

  Serial.begin(9600);
  ADC_INIT();

  

}

volatile int p1,p2,p3;
volatile int res;


void ADC_INIT() 
{
  
  
  ADCSRA = 0;
  ADCSRB = 0;
  
  ADMUX = (1<<REFS0);
  ADMUX |= (1<<ADLAR);

  ADMUX |= (0 & 0x07);

  ADCSRA |= (1 << ADPS2);                     
  ADCSRA &= ~ ((1 << ADPS1) | (1 << ADPS0));  

  ADCSRA &=~(1<<ADATE);
  ADCSRA |= (1 << ADIE);
  ADCSRA |= (1<<ADEN);
  ADCSRA |= (1<<ADSC);
}

void loop() { 

if (ADIF == 1) {
switch (ADMUX)
  {
    case 0 & 0x07:
    p1 = res;  
    ADMUX |= 0 & 0x08; 
    break;

    p2 = res;
    ADMUX |= 0 & 0x07;
    break;
    default:
    break;
    }
}
  Serial.println(p1);
  Serial.println(p2);
  

}


ISR(ADC_vect) {
  res = ADCH;
  ADCSRA |= (1<<ADSC);
}

И задержку делал на 2 такта, как указано в даташите и как посоветовал Евгений. Что не так? Режим Single conversion mode, преобразование завершилось, обработчик прерываний включился, далее после присваивания результата переменной res я вновь запускаю АЦП, а в loop меняю пины для переключения. Я делал и с задержкой, не помогает вообще. А еще я заметил, что если вот тут 

ADC_INIT () {
}

вместо 

ADMUX |= (0 & 0x07);

указать

ADMUX |= (0 & 0x08);

убрать к черту свитч и просто пытаться вывести результат на A1 пине, то что получается? Правильно, ничего. Ничего не меняется, АЦП не хочет работать ни с каким пином кроме A0.