АЦП через регистры

AS31979
Offline
Зарегистрирован: 22.12.2015

Задумка сделать что то вроде быстрого вольтметра, использование analogRead не устраивает - сожрет слишком много быстродействия на ожидание ответа АЦП. Накарябал код с управлением АЦП через регистры. Опыта с регистрами АЦП ноль - пожайлуста гляньте на предмет явных косяков.

// Version 0.0
// Попытка опрашивать 5 каналов АЦП на прерываниях
// Идея такая - цепляемся к таймеру Timer0 его все равно уже используется millis()
// обрабатываем промежуточную переменную, програмируем АЦП на измерение следующего канала
// АЦП измеряет, генерирует прерывание, подпрограмма читает данные и присваивает их промежуточной
// переменной. И так по кругу...
// Весь этот цирк для того чтобы микроконтролер не простаивал дожидаясь данных с АЦП
// По идее 976 в секунду / на 5 каналов = 200 на канал
// Если фильтровать по 16 значениям получается 12 измерений в секунду на каждый канал


// Масив данных для програмирования входа мультиплексора АЦП
unsigned char pin_AD [5] = {0x47,0x46,0x45,0x44,0x43}; 
// Если не лоханулся каналы 7, 6, 5, 4, 3


void setup()
{
   //Нпастройка прерывания, используется Timer0 чтобы потом не накосячить с генерацией ШИП
 OCR0A = 0xAF; // Timer0 уже используется millis() - прерываемся где-то
 TIMSK0 |= _BV(OCIE0A); // посередине и вызываем ниже функцию "Compare A"

  Serial.begin(9600); // Настройка последовательного порта для отправки данных на компьютер

  // Програмирование АЦП
 DIDR0 = 0x3F;   // отключаем цифровые входы, по идее только для порта А
 ADCSRA = 0xAF;  // включаем АЦП, разрешаем прерывания, делитель = 128
 ADCSRB = 0x40;  // Включаем каналы MUX АЦП, режим постоянной выборки
 sei();          // устанавливаем флаг разрешающий прерывания

/////////////////////////////////////////////////////////////
 byte i=0;        // Переменная для чтения масива, заодно и для разнесения данных с одного АЦП
                  // на 5 переменных
int analogValue = 0; // значение аналогового сигнала АЦП
}

///////////////////////////////////////////////////////////////
SIGNAL(TIMER0_COMPA_vect) // Прерывание вызывается 976.5625 в секунду
{
 // действия при прерываниях от таймера
// Тут будет присваивание данных переменной конкретного канала
for (int i=0;i<5;i++) {ADMUX=pin_AD[i];} // Если не накосячил то работает так:
// Берется байт с масива и пишется в регистр - задаем какой канал АЦП читать
bitWrite(ADCSRA, 6, 1);// Запускаем преобразование установкой бита 6 (=ADSC) в ADCSRA
}

/*** Процедура обработки прерывания АЦП ***//////////////////////
ISR(ADC_vect) 
{
 analogValue = ADCL; // сохраняем младший байт результата АЦП
 analogValue += ADCH << 8; // сохраняем старший байт АЦП
 bitWrite(ADCSRA, 6, 0); 
 // Останавливаем АЦП, высокая частота чтения не нужна, запустим от таймера
}


void loop()
{
  //Тут буду обрабатывать
}

Использованны статьи, лучшее из найденного по теме:

http://robotosha.ru/arduino/analog-measurements-arduino.html

http://www.junradio.com/index/analogovye_vkhody_arduino/0-284

axill
Offline
Зарегистрирован: 05.09.2011

есть два комментария

1. для повышения точности и стабильности измерений рекомендую делать серию измерений и потом усреднять. Так как АЦП 10 бит, то можно делать от 2 до 64 измерений в 16-ти битный аккумулятор и потом усреднять.

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

MagicianT
Offline
Зарегистрирован: 03.10.2015

Бред какой-то. Вы зачем крутите вчодной MUX?

for (int i=0;i<5;i++) {ADMUX=pin_AD[i];} // Если не накосячил то работает так:
Цикл просто пробегает, а старт конверсион нету.
Еще лучше сконфигурировать старт конверсион от таймера, ADATE, тогда нужно будет только одно прерывание чтоб забрать результат. От таймера или от АЦП - конверсион комплит.
ISR(TIMER1_COMPB_vect)
{ 
static int16_t counter = 0;
static int32_t accumul = 0;

    int32_t temp  = ADCL;  
            temp += (ADCH << 8);  
            temp -= adc_Offst;

  temp = temp * temp;
  accumul += temp;

  if(++counter > 1000) { // 20 Hz, 20 frame/sec.
    ppm_Level = accumul;
    counter = 0;
    accumul = 0;
    flag    = 1;
    }
}

void adc_init()
{ 
  ADMUX    = 0xC5;        // PIN 5 Analog. REF Internal. 
  ADCSRA = ((1<< ADEN)|   // 1 = ADC Enable
      (0<< ADSC)| // ADC Start Conversion 
      (1<<ADATE)| // 1 = ADC Auto Trigger Enable
      (0<< ADIF)| // ADC Interrupt Flag
      (0<< ADIE)| // ADC Interrupt Enable
      (1<<ADPS2)|
      (0<<ADPS1)| // ADC Prescaler : 1 MHz.
      (0<<ADPS0));  
  ADCSRB = ((1<<ADTS2)|   // Sets Auto Trigger source - Timer/Counter1 Compare Match B
      (0<<ADTS1)|
      (1<<ADTS0));
  /* Set up TIMER 1 - ADC sampler */
  TIMSK0 = 0x00;
  TIMSK1 = 0x00;
  TIMSK2 = 0x00; 

  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1C = 0;

  TCCR1A =  ((1<<WGM11) | (1<<WGM10));       // Mode 15, Fast PWM
  TCCR1B =  ((1<<WGM13) | (1<<WGM12));       // Mode 15, Fast PWM

  TCCR1B |=  (1<<CS10);                      // clk/1 prescaling.
  OCR1A  = SMP_TMR1;
  OCR1B  = SMP_TMR1;

  TCNT1  = 0;
  TIFR1   |= (1<<OCF1B); 
  TIMSK1  |= (1<<OCIE1B);
}

 

А на форуме нельзя файл приатачить? У меня есть проверенный код с таймером 1

https://drive.google.com/file/d/0Bw4tXXvyWtFVUGw5T280QnZlb1U/view?usp=sharing

 

 

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

AS31979 Вы сравнивали, ваш метод быстрее библиотеки CyberLib.h?

 

axill
Offline
Зарегистрирован: 05.09.2011

MagicianT в даташите явно сказано, что при использовании тригеров для запуска преобразования или free running изменение admux без остановки преобразования приведет к ситуации когда атмел не гарантирует какой канал был преобразован - в ADMUX может быть одно значение, а преобразование совершено с другим

поэтому если нужно делать преобразование по разным каналам перед исзменением ADMUX нужно останавливать преобразование

MagicianT
Offline
Зарегистрирован: 03.10.2015

axill пишет:
поэтому если нужно делать преобразование по разным каналам перед исзменением ADMUX нужно останавливать преобразование

Не обязательно. Вы всегда можете проверить с какого входа приходят самплы. Не останавливая АЦП скорость преобразования 14 тактов, а с остановкой 25. Почти вдвое. В примере когда АЦП clock 1 МГц, частота до 76 кГц. Там бывает что MUX не успевает переключиться и отстанет на один такт, но если скорост самплирования не менять на лету, выставив один раз и проверив с какого входа идут измерения, потом можно быть увереным что это не изменится

Primer:

ISR(TIMER1_COMPB_vect)
{ 
 int16_t adc_value = ADC - adc_Offst;
 static int16_t last_smpl = 0;
 
 if ( smpl_Nmbr < SAMPL_P )
 {
   if( smpl_Nmbr & 0x01 )
   {
    ADMUX = 0xC5;                     // Voltage, pin AN5  
    v_s[smpl_Nmbr >>1] = (last_smpl + adc_value) / 2; //Linear Interpolation
    last_smpl = adc_value; 
   }
   else
   { 
    ADMUX = 0xC4;                     // Current, pin AN4
    c_s[smpl_Nmbr >>1] = adc_value;  
   }
 }
 smpl_Nmbr++;
}

 

axill
Offline
Зарегистрирован: 05.09.2011

Цитата:
The
user is thus advised not to write new channel or reference selection values to ADMUX until one ADC clock cycle
after ADSC is written.

MagicianT
Offline
Зарегистрирован: 03.10.2015

Правильно, 1 clock , в примере:

1 МГц ADC clock 
1 cycle = 1 microsec.;    14 clock full conversion.
Не менять MUX в течении 1 microsec. поскольку ADSC запущено таймером одновременно с вызовом в ISR(),
к тому времени пока ардуино доидет до строки MUX пройдет 1.5 - 3 microsec. - проверено, это время перехода в ISR()
axill
Offline
Зарегистрирован: 05.09.2011

Да, но при частоте АЦП выше 250кгц атмел не рекомендует использовать 10бит преобразования, а только 8

для 10бит частота должна быть менее 250кгц

MagicianT
Offline
Зарегистрирован: 03.10.2015

Не могу найти, в сети был график снижения точности АЦП от частоты, наверное удалили. Не всё там так резко, и тот-же дата шит говорит что исходная точность на 200 кГц  +- 2LSB.

Если это принципиально, то АЦП можно оставить на 125 - дефолт, а время  OCR1B выставить меньше на 8 микросек.
AS31979
Offline
Зарегистрирован: 22.12.2015

Дааа..., я вроде на пояснения в скече не поскупился.

Строка 7, 8, 9 там и про фильтрацию, и про частоту преобразования. Задача выдавить из АЦП максимум не стоит - результаты измерений будет обрабатывать сам микроконтролер, куча данных которые микроконтролер не успеет обработать мне даром не нужна, 10-12 измерений по 5 каналам хватит.

AS31979
Offline
Зарегистрирован: 22.12.2015

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

Из всего написанного мне оказались полезны ответы:

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

axill - "в даташите явно сказано, что..." никуда не спешу, лучше пару лишних команд всталю чем потом косяк словлю.

 

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

Данные по снижению точности АЦП от частоты преобразования можно найти в первой ссылке, там в конце описанно понятнее чем в даташите.

MagicianT
Offline
Зарегистрирован: 03.10.2015

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

Перевод имел бы смысл если даташит был бы на русском. А так не целесообразно. Дата шит скачали? Первое время постоянно приходится сверяться в каком регистре какой бит находится/прописать. 

AS31979
Offline
Зарегистрирован: 22.12.2015

В общем первый блин как и ожидалось - комом, оптимизировал/отрихтовал.

За последующую обработку не беспокоюсь, всегда можно на монитор COM порта послать переменную для отладки. Сильно беспокоит програмирование АЦП - есть соображения где я облажался?

// Version 0.01
// Попытка опрашивать 5 каналов АЦП на прерываниях
// Идея такая - цепляемся к таймеру Timer0 его все равно уже используется millis()
// задаем какой следующий канал будем измерять, забираем результаты предыдущего измерения, запускаем АЦП
// обрабатываем забраную промежуточную переменную, и так по кругу...
// Весь этот цирк для того чтобы микроконтролер не простаивал дожидаясь данных с АЦП
// По идее 976 раз в секунду / на 5 каналов = 200 на канал
// Если фильтровать по 16 значениям получается 12 измерений в секунду на каждый канал


// Масив данных для програмирования входа мультиплексора АЦП
unsigned char pin_AD [5] = {B11000111,B11000110,B11000101,B11000100,B11000011};
  // Если не лоханулся каналы 7, 6, 5, 4, 3
  // Разшифровка слева - направо
  // 11 - REFS1.0 внутрений источник опорного напряжения 1,1В
  // 0 - ADLAR выравнивание результата преобразования, как я понял указание АЦП
  //     в какой регистр ложить старший байт, а в какой младший. По умолчанию вроде ноль.
  // xxxxx - номер канала мультиплексора, каналов всего 8, так что 2 старших бита всегда нули.


void setup()
{
   //Нпастройка прерывания, используется Timer0 чтобы потом не накосячить с генерацией ШИП
 OCR0A = 0xAF;         // Timer0 уже используется millis() - прерываемся где-то
 TIMSK0 |= _BV(OCIE0A);// посередине и вызываем ниже функцию "Compare A"

  Serial.begin(9600); // Настройка последовательного порта для отправки данных на компьютер

  // Програмирование АЦП
 DIDR0 = 0x3F;        // отключаем цифровые входы, по идее только для порта А
 ADCSRA = B10000111;   
 // Разшифровка слева - направо
 // 1 - ADEN - включаю АЦП
 // 0 - ADSC - запускать преобразование буду отдельно про прерываниям таймера
 // 0 - ADATE - разовое преобразование
 // 0 - ADIF - не знаю зачем он вообще, но мне точно не нужен, АЦП по любому 
 //            сделает замер раньше чем наступит следующее прерывание
 // 0 - ADIE - прерывание от компаратора не нужно
 // 111 - ADPS2.0 - устанавливается делитель тактирования АЦП на 128

///////////////////////////////////////////////////////////////////////
 byte i=0; // Переменная для чтения масива, заодно и для разнесения данных
           // с одного АЦП на 5 переменных
 int analogValue = 0;    // значение аналогового сигнала АЦП
}

////////////////////////////////////////////////////////////////////////
SIGNAL(TIMER0_COMPA_vect)  // Прерывание вызывается 976.5625 в секунду
{
  // действия при прерываниях от таймера
for (int i=0;i<5;i++) {ADMUX=pin_AD[i];} 
  // Берется байт с масива и пишется в регистр - задаю какой канал АЦП читать,
  // задаю еще до чтения данных из регистров АЦП для того чтобы компаратор
  // пока читаются данные  успел переключится.
                                          
analogValue = ADCL;  // сохраняем младший байт результата АЦП
analogValue += ADCH << 8; // сохраняем старший байт АЦП
                                          
(0<<ADATE);  // Запуск преобразования установкой бита ADATE в 0
// Позже в этом же прерывании наверное буду крутить оверсемплинг
}

void loop()
{
  //Тут буду обрабатывать
}

 

 

MagicianT
Offline
Зарегистрирован: 03.10.2015

Там всё неправильно. Перечислять косяки нет смысла, Вы вообще ответы, что выше, читали?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

AS31979, я не сразу понял что вы пытались изобразить. Этот режим называется  Auto trigged mode using Timer в принципе штатный режим АЦП, вот так он будет по-человечески выглядеть:

#include <avr/delay.h>
volatile int aread0,aread1,aread2;
void setup() {
Serial.begin(9600);
OCR0A=0xAF;
TIMSK0|=1<<OCIE0A;
ADMUX=1<<REFS0; // AVCC with external capacitor at AREF pin
ADCSRA=(1<<ADEN)|(1<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
ADCSRB=(1<<ADTS1)|(1<<ADTS0); // Timer/Counter0 Compare Match A
}

ISR(TIMER0_COMPA_vect) { 
static uint8_t n=0;
ADMUX = ADMUX & 0b11111000 | n;
switch(n){
    case 0: aread2 = ADC; n=1;  break;
     case 1: aread0 = ADC; n=2;  break;
      case 2: aread1 = ADC; n=0;  break;
       }
}
void loop() {
Serial.print("A0="); Serial.print(aread0);
Serial.print(" A1="); Serial.print(aread1);
Serial.print(" A2="); Serial.println(aread2);
_delay_ms(100);
}

 

AS31979
Offline
Зарегистрирован: 22.12.2015

MagicianT - "Там все неправильно..." и т.д. это конечно ОЧЕНЬ проясняет ситуацию, но новичку вроде меня проще перичитать даташит с нуля чем извлечь пользу с вашего ответа.

dimax - спасибо, ваш пример подходит идеально.

К сожалению с коментариями в примере не густо, прошу глянуть правильно ли я разшифровал действия. Есть подозрение что 14 строка примера изменяет нустройки опорного напряжения сделанные в 7 строке!?

Непонятно зачем использовалась нестандартная библиотека формирования задержек, в коде вроде нет ничего что бы нарушало работу millis, у меня заработало с стандартной задержкой.

Фактически тот же скечь только с моими коментариями:

volatile int aread0,aread1,aread2; //Переменные для данных с 3-х входов

void setup()
{
Serial.begin(9600); //задание скорости последовательного порта
OCR0A=0xAF;         //значения таймера при котором
TIMSK0|=1<<OCIE0A;  //разрешить прерывание при совпадении
ADMUX=(1<<REFS0|1<<REFS1); //у вас опорным было напряжение питания
                           //я ставлю внутрений 1,1В
ADCSRA=(1<<ADEN)|(1<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
//включение АЦП
//режим преобразования задается битами ADTS2:0
//тактовая частота АЦП 1/128 от тактовой частоты микроконтролера
ADCSRB=(1<<ADTS1)|(1<<ADTS0); // запуск прерывания от Timer0
}

ISR(TIMER0_COMPA_vect) { //действия при прерывании от Timer0
                        
static uint8_t n=0;      //локальная переменная которая видна
                         //только обработчику прерывания
                         
ADMUX = ADMUX & 0b11111000 | n; //наложение n, вибирается № входа 
//А вот тут не понял, не соответствует настройкам из вашего примера
//вы задали ADMUX 01хууууу, 2 старших бита опорное напряжение AVCC, 
//а сейчас ставите опорным внутренее!?!?!?
//х(ADLAR) - по идее равен нолю(тут не уверен), значение 4 и 5 бита
//не имеют значения - входов всего 8(хватает 3-х бит)

switch(n){
//тут просто непрерывный цикл с заменной n которая одновременно и
//переменная в цикле и данные для ноложения &, хитрый способ
case 0: aread2 = ADC; n=1;  break;
 case 1: aread0 = ADC; n=2;  break;
  case 2: aread1 = ADC; n=0;  break;
//не по порядку  потому что не ждем ответа АЦП, програмируем какой  
//канал АЦП измеряем  - забираем данные предыдущего измерения - 
//изменяем n. При таком большом коэфициенте делителя АЦП без проблем.
  }
}

//Дальше уже ничего интересного, чем не устроил стандартный delay
//непонятно, но в данном случае непринципиально.
void loop() {
Serial.print("A0="); Serial.print(aread0);
Serial.print(" A1="); Serial.print(aread1);
Serial.print(" A2="); Serial.println(aread2);
delay(1000);
}

Если кто будет повторять:

Входы выбираются в строках 34-36, но в отличии от analogRead пины выбираются довольно извращенным образом, сначала выбрали канал, при следующем прерывании дали задание АЦП мерять этот канал и только при третьем прерывании забрали результат.

Лично у меня при delay(100) COM порт лег менее чем за минуту.

Без конденсаторов на входах АЦП и AREF даные будут дико прыгать, на маленьких напряжениях контакты макетной платы могут внести такую погрешность что показания покажутся бредом!!!

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

AS31979,

- внешняя библа delay.h была взята на всякий случай, если я в процессе эксперементов собью настроки таймера0. Не потребовалась.

- в 8 строке корректнее написать так ADMUX=(1<<REFS0)|(1<<REFS1);

- в 22 строке старшие 5 бит регистра ADMUX остаются неизменны, точно как были заданы в сетапе. Обнуляются три младших бита, затем складываются с переменной n.

 

 

 

Pyotr
Offline
Зарегистрирован: 12.03.2014

MagicianT пишет:

Не могу найти, в сети был график снижения точности АЦП от частоты, наверное удалили. Не всё там так резко, и тот-же дата шит говорит что исходная точность на 200 кГц  +- 2LSB.

Если это принципиально, то АЦП можно оставить на 125 - дефолт, а время  OCR1B выставить меньше на 8 микросек.

Не график, но для сравнения  http://www.gammon.com.au/adc

AS31979
Offline
Зарегистрирован: 22.12.2015

dimax - 7 и 14 строку я имел в виду из вашего скеча, они у вас по идее конфликтуют. В своей версии я это учел, кроме того есть подозрение что 22 строка моего скеча делеет необязательной 8 строку.

Pyotr - по точности АЦП есть ссылка в самом первом сообщении.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

AS31979 пишет:

dimax - 7 и 14 строку я имел в виду из вашего скеча, они у вас по идее конфликтуют. В своей версии я это учел, кроме того есть подозрение что 22 строка моего скеча делеет необязательной 8 строку.

Я же вам написал про это. Повторю ещё раз в команда  ADMUX = ADMUX & 0b11111000 обнуляет только три младших бита. Старшие  какие были такие и остаются.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Пытаюсь измерять ток, что-то как-то не заладилось...

Библиотека отсюда
 

// PINOUT
// L_EN -> 7
// R_EN -> 8
// L_PWM -> 5
// R_PWM -> 6
// R_IS ->A0
// L_IS ->A1
// A3 -> not connected


#include <util/delay.h>
#include "BTS7960.h"

const uint8_t L_EN = 7;
const uint8_t R_EN = 8;
const uint8_t L_PWM = 5;
const uint8_t R_PWM = 6;

BTS7960 motorController(L_EN, R_EN, L_PWM, R_PWM);

volatile int aread0, aread1, aread2;

void setup()
{
  Serial.begin(115200);
  OCR0A = 0xAF;
  TIMSK0 |= 1 << OCIE0A;
  ADMUX = 1 << REFS0; // AVCC with external capacitor at AREF pin
  ADCSRA = (1 << ADEN) | (1 << ADATE) | (1 << ADPS1) | (1 << ADPS0);
  ADCSRB = (1 << ADTS1) | (1 << ADTS0); // Timer/Counter0 Compare Match A
}

ISR(TIMER0_COMPA_vect) {
  static uint8_t n = 0;
  ADMUX = ADMUX & 0b11111000 | n;
  switch (n) {
    case 0: aread1 = ADC; n = 1;  break;
    case 1: aread0 = ADC; n = 0;  break;
  }
}


void loop()
{
  motorController.Enable();
  for (int speed = 0 ; speed < 255; speed += 5)
  {
    motorController.TurnLeft(speed);
    delay(100);
    Serial.print("A0="); Serial.print(map(aread0, 0, 1023, 0, 43000));
    Serial.print(" A1="); Serial.println(map(aread1, 0, 1023, 0, 43000));
  }
  motorController.Stop();
  for (int speed = 255 ; speed > 0; speed -= 5)
  {
    motorController.TurnLeft(speed);
    delay(100);
    Serial.print("A0="); Serial.print(aread0);
    Serial.print(" A1="); Serial.println(aread1);

  }
  motorController.Stop();
  for (int speed = 0 ; speed < 255; speed += 5)
  {
    motorController.TurnRight(speed);
    delay(100);
    Serial.print("A0="); Serial.print(aread0);
    Serial.print(" A1="); Serial.println(aread1);
  }
  motorController.Stop();
  for (int speed = 255 ; speed > 0; speed -= 5)
  {
    motorController.TurnRight(speed);
    delay(100);
    Serial.print("A0="); Serial.print(aread0);
    Serial.print(" A1="); Serial.println(aread1);
  }
  motorController.Stop();
  motorController.Disable();
  delay(5000);

}

 

AS31979
Offline
Зарегистрирован: 22.12.2015

ua6em - вы так "подробно и емко" описали проблему, что единственный ответ который я могу вам дать:

"Пытаюсь помочь, что-то как-то с помощью не заладилось..."

И думаю НИКТО НЕ СМОЖЕТ!!!!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

AS31979 пишет:

ua6em - вы так "подробно и емко" описали проблему, что единственный ответ который я могу вам дать:

"Пытаюсь помочь, что-то как-то с помощью не заладилось..."

И думаю НИКТО НЕ СМОЖЕТ!!!!

думаю никто не поможет, с долей вероятности близкой к 100% чипы поддельные

PS надеялся, что в коде есть косяки, сделал скетч с чтением через analogRead(), ничего не изменилось...

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

Пины-то нагрузил? У них выход токовый

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

rkit пишет:

Пины-то нагрузил? У них выход токовый

1 ком там стандартная нагрузка

Дим-мычъ
Offline
Зарегистрирован: 20.03.2021

Может надо вынести из обработчика   static uint8_t n = 0;? 

А то case 1 никогда не происходит

P.S. Возможно это сделано специально, для проверки...догадался Штирлиц))

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

Ну тогда остается немыслимое - измерить мультиметром.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

AS31979 пишет:

ua6em - вы так "подробно и емко" описали проблему, что единственный ответ который я могу вам дать:

"Пытаюсь помочь, что-то как-то с помощью не заладилось..."

И думаю НИКТО НЕ СМОЖЕТ!!!!

а как перенести измерение на пины A6  и A7?

AS31979
Offline
Зарегистрирован: 22.12.2015

Входы  задаются этой строкой

case 0: aread2 = ADC; n=1;  break;

Только произвольно в моем примере их изменять нельзя - переменная n одновременно переменная цикла.

Хорошо описана адресация входов АЦП тут: http://www.junradio.com/index/analogovye_vkhody_arduino/0-284

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

так? Если измеряем A5 A6 A7
 

ISR(TIMER0_COMPA_vect) { 
static uint8_t n=5;
ADMUX = ADMUX & 0b11111000 | n;
switch(n){
    case 5: aread7 = ADC; n=6;  break;
     case 6: aread5 = ADC; n=7;  break;
      case 7: aread6 = ADC; n=5;  break;
       }
}