Компаратор LGT8F328 (Arduino IDE)

Компаратор — устройство, сравнивающее величины аналоговых сигналов.

Когда на входы компаратора подают два аналоговых сигнала, то на выходе появляется сигнал высокого уровня, если сигнал на неинвертирующем входе («+») больше, чем на инвертирующем (инверсном) входе («−»), и сигнал низкого уровня, если сигнал на неинвертирующем входе меньше, чем на инверсном входе. Значение выходного сигнала компаратора при равенстве входных напряжений, в общем случае не определено. Обычно в логических схемах сигналу высокого уровня приписывается значение логической 1, а низкому — логического 0.

В микроконтроллере LGT8F328 два компаратора, которые содержат определенный функционал зависящий от состояния регистров управления режимами работы компаратора. В этой статье будет рассмотрен ряд примеров работы компаратора AC0.

Как использовать плату в среде программирования Arduino IDE рассказано в — http://rcl-radio.ru/?p=129966

Перед использованием примеров описанных в этой статье необходимо собрать простую тестовую схему:

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

Для не инверсного входа выбор входного источника сигнала определяет состояние бита C0BG в регистре состояния управления C0SR и бита C0PS0 в регистре C0XR.

Для инверсного входа выбор входного источника сигнала определяет состояние битов CME01 CME00 регистра ADCSRB.

Для примера, пусть входным источником сигнала для не инверсного входа будет AC0P

Источник сигнала для инверсного входа будет ADMUX. ADMUX это регистр управляющий работой ADC. В ADMUX можно выбрать любой аналоговый вход. Для примера выберем аналоговый вход PC0 (А0).

Состояние выхода компаратора можно считывать непосредственно через регистры, а запросы прерывания также могут быть сгенерированы для обеспечения более эффективного захвата событий в реальном времени.
Выход компаратора также может выводиться непосредственно на внешний порт ввода-вывода, для компаратора AC0 это вывод PD2 (D2). Для его активации необходимо указать 1 в бите C0OE регистра C0XR.

Для чтения состояния компаратора используется бит C0O регистра C0SR.

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

Не инверсный вход AC0P который мы выбрали ранее это вход D6, инверсный вход ADMUX в котором выбран вход PC0, это А0. Теперь на вход D6 подадим напряжение 3,3 В с платы контроллера, это будет опорное напряжение с которым будем сравнивать напряжение поданное на вход А0. К выходу D2 подключен светодиод, если напряжение на входе A0 будет меньше чем на входе D6, то светодиод не будет гореть, но как только напряжение на А0 станет больше чем на входе D6, светодиод загорится.

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

Ниже показан пример запуска компаратора:

void setup() {
  Serial.begin(9600);
  C0SR = 0;C0XR=0;
  C0XR |=(1<<C0OE); // C0OE[7] = 1, выход компаратора AC0 для внешнего порта PD2

  // ВЫБОР ИНВЕРСНОГО ВХОДА
  ADCSRB = 0b01000000;// ADMUX
  /*
  CME01[7] CME00[6] Источник входного сигнала AC0
  0        0        ACXN
  0        1        ADMUX
  1        0        DFFO
  */
 
  ADMUX = 0b00000000; // CHMUX[3:0] = 0000 Источник входного сигнала PC0 (A0)

  // ВЫБОР НЕИНВЕРСНОГО ВХОДА
  C0SR &=~(1<<C0BG);C0XR &=~(1<<C0PS0);
  /*
  C0BG C0PS0 Источник входного сигнала AC0
  0    0     AC0P
  0    1     ACXP
  1    0     DAO
  */
}

void loop() {
 Serial.println((C0SR >> 5) & 1, BIN);
 delay(1000);
}

Монитор порта, вывод состояния компаратора.

Ниже показаны биты управления выбором источника входного сигнала АЦП

Как ранее отмечалось, изменение состояния компаратора могут вызывать прерывания, для активации прерывания необходимо установить 1 в бит C0IE регистра C0SR.

Так же в скетч необходимо добавить обработчик прерывания:

ISR(ANALOG_COMP_0_vect){}

Режимы запуска прерывания зависят от битов C0IS1 C0IS0 регистра C0SR:

Ниже показан пример работы прерывания, при изменении состояния компаратора при нарастающем фронте, происходит прерывание (для примера в момент прерывания в монитор порта выводятся надпись «YYYY»).

void setup() {
  Serial.begin(9600);
  C0SR = 0;C0XR=0;
  C0XR |=(1<<C0OE); // C0OE[7] = 1, выход компаратора AC0 для внешнего порта PD2

  // ВЫБОР ИНВЕРСНОГО ВХОДА
  ADCSRB = 0b01000000;// ADMUX
  /*
  CME01[7] CME00[6] Источник входного сигнала AC0
  0        0        ACXN
  0        1        ADMUX
  1        0        DFFO
  */
 
  ADMUX = 0b00000000; // CHMUX[3:0] = 0000 Источник входного сигнала PC0 (A0)

  // ВЫБОР НЕИНВЕРСНОГО ВХОДА
  C0SR &=~(1<<C0BG);C0XR &=~(1<<C0PS0);
  /*
  C0BG C0PS0 Источник входного сигнала AC0
  0    0     AC0P
  0    1     ACXP
  1    0     DAO
  */

  C0SR |= (1<<C0IE); // РАЗРЕШИТЬ ПРЕРЫВАНИЯ
  C0SR |= (1<<C0IS1)|(1<<C0IS0); // Режим прерывания - Нарастающий фронт

  C0XR |= (1<<C0FEN)|0B11;
  // Разрешить управление цифровым фильтром компаратора
  // Установка ширины цифрового фильтра компаратора 11 = 96us
  
}

void loop() {
 Serial.println((C0SR >> 5) & 1);
 delay(1000);
}

ISR(ANALOG_COMP_0_vect){
  Serial.println("YYYY");
  }

 

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

Для активации фильтра необходимо установить 1 в бите C0FEN регистра C0XR, а так же выбрать период работы цифрового фильтра:

Далее рассмотрим два практических примера использования компаратора.

Измерение периода сигнала

Для этого примера необходимо собрать простую схему:

На вход ACOP (D6) подается опорное напряжение 3,3 В, а на вход ADMUX (A0) TTL сигнал. Данный пример позволяет измерять период сигнала с большой длительностью.

Для примера на вход А0 будет подаваться меандр с периодом следования сигнала в 5 мс. Для измерения помимо компаратора в примере будет использован таймер_1 для подсчета времени периода следования сигнала.

volatile int x;
float f;
bool w;


void setup() {
  Serial.begin(9600);
  TCNT1 = 0;
  TCCR1A = 0;
  TCCR1C = 0;
  TCCR1B = 1;
  TIMSK1 |= (1 << TOIE1);
  
  C0SR = 0;C0XR=0;
  C0XR |=(1<<C0OE); // C0OE[7] = 1, выход компаратора AC0 для внешнего порта PD2

  // ВЫБОР ИНВЕРСНОГО ВХОДА
  ADCSRB = 0b01000000;// ADMUX
  /*
  CME01[7] CME00[6] Источник входного сигнала AC0
  0        0        ACXN
  0        1        ADMUX
  1        0        DFFO
  */
  
  ADMUX = 0b00000000; // CHMUX[3:0] = 0000 Источник входного сигнала PC0 (A0)

  // ВЫБОР НЕИНВЕРСНОГО ВХОДА
  C0SR &=~(1<<C0BG);C0XR &=~(1<<C0PS0);
  /*
  C0BG C0PS0 Источник входного сигнала AC0
  0    0     AC0P
  0    1     ACXP
  1    0     DAO
  */

   C0SR |= (1<<C0IE); // РАЗРЕШИТЬ ПРЕРЫВАНИЯ
   C0SR |= (1<<C0IS1)|(1<<C0IS0); // Режим прерывания - Нарастающий фронт
}

void loop() {
   Serial.print(f/32,0); 
   Serial.println(" uS");
   delay(1000);
}

ISR(ANALOG_COMP_0_vect){f = x * 65535 + TCNT1;x=0;TCNT1=0;}
ISR(TIMER1_OVF_vect){x++;}

Таймер_1 вызывает прерывание при переполнении счетного регистра TCNT1. Таймер_1 работает всегда, отсчитывая такты микроконтроллера, прерывания компаратора происходят при возрастающем фронте сигнала, в этот момент фиксируется показания таймера_1 и вывод этих показаний в монитор порта. После каждого прерывания компаратора счетный регистр таймер TCNT1 обнуляется.

Измерение емкости

Для измерения емкостей до 1 мкФ необходимо собрать простую схему:

Измерение емкости основано на времени заряда, напряжение на конденсатор подается с выхода D7 через резистор с сопротивлением 1 МОм.

Измерение емкости происходит циклично, сначала емкость полностью разряжается, для этого на конденсатор подается логический 0 (напряжение близкое к GND) с вывода D7, а после завершения разряда на конденсатор подается логическая 1 (напряжение близкое к VCC).

На вход ACOP (D6) подается опорное напряжение 3,3 В, а на вход ADMUX (A0) поступает изменяющееся напряжение заряда конденсатора. Таймер_1 работает постоянно, как только напряжение заряда конденсатора достигнет 3,3 В, произойдет прерывание компаратора, в этот же момент так же произойдет подсчет прерываний таймера_1 и счетного регистра TCNT1. Показания таймера_1 после простых вычислений станут показаниями емкости измеряемого конденсатора.

#define CALL   58.00
#define CALL_0 26.50

volatile int x;
long f;

void setup() {
  Serial.begin(9600);
  DDRD |= (1<<PD7);
  
  TCNT1 = 0;
  TCCR1A = 0;
  TCCR1C = 0;
  TCCR1B = 1;
  TIMSK1 |= (1 << TOIE1);
  
  C0SR = 0;C0XR=0;
  C0XR |=(1<<C0OE); // C0OE[7] = 1, выход компаратора AC0 для внешнего порта PD2

  // ВЫБОР ИНВЕРСНОГО ВХОДА
  ADCSRB = 0b01000000;// ADMUX
  /*
  CME01[7] CME00[6] Источник входного сигнала AC0
  0        0        ACXN
  0        1        ADMUX
  1        0        DFFO
  */
  
  ADMUX = 0b00000000; // CHMUX[3:0] = 0000 Источник входного сигнала PC0 (A0)

  // ВЫБОР НЕИНВЕРСНОГО ВХОДА
  C0SR &=~(1<<C0BG);C0XR &=~(1<<C0PS0);
  /*
  C0BG C0PS0 Источник входного сигнала AC0
  0    0     AC0P
  0    1     ACXP
  1    0     DAO
  */
  ADMUX |= 1 << REFS0;
  ADCSRA |= 1 << ADEN | 1 << ADSC | 1 << ADATE | 0b111;
}

void loop() {
  PORTD &=~ (1<<PD7);
  while((ADCSRA & (1 << ADIF)) == 0);
  while((ADCL|ADCH << 8)>10);
   
  PORTD |= (1<<PD7); TCNT1=0;x=0;
  
  while(((C0SR >> 5) & 1)==1){f = x * 65535 + TCNT1;}
  Serial.print(f/CALL-CALL_0,1);Serial.println(" pF");
  delay(1000);
}

ISR(TIMER1_OVF_vect){x++;}

Форум — http://forum.rcl-radio.ru/viewtopic.php?id=624

Добавить комментарий

Войти с помощью: