Обсуждаем контроллеры компании Atmel.
Ответить

АЦП на attiny13

Пт окт 27, 2023 10:26:02

Здравствуйте, уважаемые форумчане.
Уже 2 дня бьюсь над проблемой, почему не работает правильно код на attiny13.
Суть в том, что тини берет значение напряжения с 3 входов ADC0, ADC1 и ADC2, преобразует их в ацп и в зависимости от того, какое наибольшее, включает соответствующий выход PB0, PB1 или PB3, а остальные выключает.
1) В прерывании ацп (каждые ~10 мкс) происходит запись в переменную и переключение пина ацп, т.е. ADMUX++, а так же запуск нового преобразования.
2) По прерыванию таймера Т0 с предделителем 1024 (около 27мс) происходит сравнивание значений с ацп, выключение всех выходов и включение соответствующего наибольшему напряжению с ацп, после чего все значения с ацп обнуляются и оно заново набирает их.
Беда в том, что оно то работает, то не работает. На скрине например на ADC0 4.6в, самое большое из 3, но почему-то работает выход PB3, а должен PB0. Но если подергать туда-сюда, то начинает работать. Потом опять клинит.
Живая микросхема работает так же, как в симуляторе. Значит ошибка где-то в коде.
Никак не могу найти ошибку, проблема еще в том, что нет толкового отладчика, atmel studio не поддерживает usbasp.
Вот код:
Спойлер
Код:
#include <avr/io.h>
#include <avr/interrupt.h>  //Для доступа к функции sei()
#include <avr/signal.h>     //Для доступа к макросу INTERRUPT

volatile uint8_t adcVal[3] = {0, 0, 0};
volatile uint8_t max = 0;
volatile uint8_t max1 = 0;

ISR(ADC_vect)
{
   uint8_t a = ADCH;
   if (a > adcVal[ADMUX - 32])                  //если значение с ацп больше записанного, то записываем это значение
   {
      adcVal[ADMUX - 32] = a;                  
   }
   
   if (ADMUX < 34)                           //переключаем пин ацп на следующий
   {
      ADMUX++;
   } else
   {
      ADMUX = 32;
   }   
   ADCSRA = ADCSRA | 0x40; //Устанавливаем разряд ADSC в регистре ADCSR, чтобы начать новое преобразование
}

ISR(TIM0_OVF_vect)
{   

   max = 0;
   if (adcVal[1]>adcVal[0]) max = 1;
   if (adcVal[2]>adcVal[1]) max = 2;            //Находим наибольшее напряжение
   
   if (max == max1)                        //если наиб. напряжение=предыдущему периоду, то устанавливаем выход
   {      
      switch (max)
      {
         case 0:
         PORTB = 1;
         break;
         case 1:
         PORTB = 2;
         break;
         case 2:
         PORTB = 8;
         break;
      }
   } else                                        //иначе отключаем все выходы
   {
      max1 = max;
      PORTB = 0;      
   }
   adcVal[0] = 0;                           //обнуляем ацп каждый период
   adcVal[1] = 0;
   adcVal[2] = 0;

}

int main(void)
{      
   TIMSK0 = 2;
   TCCR0A = 0;
   TCCR0B = 0b00000101;
   ADMUX = 32;
   ADCSRA = 0b11001000;
   DDRB = 0b00001011;
   sei();
    /* Replace with your application code */
    while (1)
    {      
    }
}

Изображение
Фьюзы:
CLKDIV8: 1
RSTDISBL: 0
CKSEL: 10
SUT: 10

Re: АЦП на attiny13

Пт окт 27, 2023 12:42:54

а нужны ли такие сложности? с массивами..
нужны 3 переменные: одна для хранения значения, вторая для хранения номера, ну, и номер текущего опрашиваемого входа.
пробегаем входы с 0 по 2 (ADMUX=in+ADC_VREF_TYPE)
в прерывании сравнивам ADCW (или его часть) с хранимым значением, если ADCW больше - обновляем переменные значения и номера входа.
когда все входы опрошены, по данным из номера конфигурируем выходы, затем обнуляем переменную значения (переменная номера сама обновится в следующем цикле)

Re: АЦП на attiny13

Пт окт 27, 2023 13:09:56

Не, без массива никак. Ведь по переполнению таймера должны сравниваться сразу все 3 значения.
Ацп опрашивается тысячи раз в секунду. А таймер только 36 раз в секунду.

Re: АЦП на attiny13

Пт окт 27, 2023 15:12:26

У них УВХ одно на всех. Надо или холостую выборку канала делать, а потом измерение, либо резко уменьшать выходное сопротивление измерительной цепи, либо увеличивать время выборки. Но не факт, что причина в этом.

Re: АЦП на attiny13

Сб окт 28, 2023 08:19:18

Код:
if ((adcVal[0] > adcVal[1]) & (adcVal[0] > adcVal[2]))
    max = 0;
  else if (adcVal[2] > adcVal[1])
    max = 2;
  else max = 1;


Изображение

Re: АЦП на attiny13

Сб окт 28, 2023 13:51:14

veso74 писал(а):&

&& :)

Re: АЦП на attiny13

Сб окт 28, 2023 15:09:31

... &&

Да, правильно. Спс. Утром рано, еще спим :P ...
А и с Bitwise AND работало на симуляцией ...

Re: АЦП на attiny13

Сб окт 28, 2023 15:19:51

А в данном случае неважно что побитовое И, что логическое. Просто как то неаккуратненько.)

Re: АЦП на attiny13

Сб окт 28, 2023 19:19:09

"пузырьки" с тремя (и более) значениями
:roll:
Ответить