Чтение ШИМ 5 кГц

Morze
Offline
Зарегистрирован: 05.08.2013

Здравствуйте. Подскажите пожалуйста, способна ли Ардуино прочитать ШИМ с частотой 5 кГц? Заполнение 0 - 100%. Мне необходим вывод значения в процентах. Так же интересует насколько корректно будут читаться показания на этой скорости.

Извиняюсь заранее, если кому - то покажется этот вопрос очень глупым...

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

1.Может.

2.Точность предельная 0.03 %. (62.5 нс)

3.Корректность зависит от тебя.

4.Да, вопрос глупый.

Morze
Offline
Зарегистрирован: 05.08.2013

Спасибо большое. Значит начинаю собирать макетку и ставить эксперименты.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Ардуина может, её я знаю.

Тебя - совсем не знаю, сможешь ты или нет - не могу сказать.

Morze
Offline
Зарегистрирован: 05.08.2013

А вот тут я уже вопроса не задавал ;-)

freeman86
Offline
Зарегистрирован: 07.09.2016

Чтобы темы не плодить, спрошу тут.
Мне нужен был считыватель импульсов в секунду, и чтобы далеко не ходить, сделал генератор из своего же шима на nano. Когда я запустил сие на значении шима analogWrite(a, 1), количество импульсов показало ~900, в другой раз 787. На максимальных 255, показывает ~ 189300 импульсов. Получается, он не увеличивает длительность импульса в периоде, а увеличивает количество импульсов в том же самом периоде?

b707
Offline
Зарегистрирован: 26.05.2017

freeman86 пишет:
На максимальных 255, показывает ~ 189300 импульсов.

этот результат говорит только о том, что измеряете вы полную чепуху. При ШИМ 255 не должно быть импульсов вовсе, потому что 255 - это просто постоянное включение пина на HIGH

freeman86
Offline
Зарегистрирован: 07.09.2016

На сколько мне известно, в компьютерной техники нет постоянных токов, а только импульсные. Но спорить не буду, так как не уверен. Можете сами попробовать повторить эксперимент

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

Чем измерял импульсы?

b707
Offline
Зарегистрирован: 26.05.2017

freeman86 пишет:
На сколько мне известно, в компьютерной техники нет постоянных токов, а только импульсные. Но спорить не буду, так как не уверен.

утверждение неверное.

В любом случае сотни тысяч импульсов на стандартном ШИМе это бред. Если бы вы правильно измеряли - при значениях ШИМ от 1 до 254 должны были получить частоту ШИМ - 490 или 980 Гц(в зависимости от пина), а на значениях 0 и 255 - постоянку.

 

freeman86
Offline
Зарегистрирован: 07.09.2016

Входом digitalRead(), количество импульсов добавлялось в счётчик в течении секунды, потом счётчик обнуляется и все заново.

b707
Offline
Зарегистрирован: 26.05.2017

freeman86 пишет:
Входом digitalRead(), количество импульсов добавлялось в счётчик в течении секунды, потом счётчик обнуляется и все заново.

код выложите?

freeman86
Offline
Зарегистрирован: 07.09.2016

Со смартфона, поэтому без форматирования выкладываю, уж простите:

byte buttonPin = 12;
byte PWM = 3;
unsigned long Time = 0;
unsigned long sum = 0;

void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT);
pinMode(PWM, OUTPUT);
}

void loop() {

analogWrite(PWM, 1);

Time = millis();
while (millis() - Time < 1000){
if (digitalRead(buttonPin) == HIGH) {
sum ++;
}
}

Serial.println(sum);
sum = 0;
Time = 0;
}

b707
Offline
Зарегистрирован: 26.05.2017

шикарный код :)

А где в нем детектор импульсов ? Вы понимаете, что для того чтобы детектировать импульс - нужно поймать момент перехода между LOW и HIGH - или наоборот.

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

Более того, этот код будет неверно считать импульсы и при тех значениях ШИМ, где импульсы все-таки есть

В общем, как я и писал вначале - измеряете чепуху

freeman86
Offline
Зарегистрирован: 07.09.2016

Похоже вы правы, надо ловить переход.
А количество чего он насчитывает в данном случае?

b707
Offline
Зарегистрирован: 26.05.2017

freeman86 пишет:
Похоже вы правы, надо ловить переход. А количество чего он насчитывает в данном случае?

для ШИМ 255 - число "оборотов" цикла while() в секунду. Для других ШИМ будет меньше

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

Немного не в тему, но думаю пригодится.
Стояла задача сделать BLINK на ШИМе, её можно приспособить и под ваши цели

1. Шимим пин ардуино связанный с прерыванием, использовал ПИН 3 прерывание INT1
2. В процедуре прерывания увеличиваем счетчик
Осталось только дать точку отсчета запомнив значение millis()
и через отрезок в 1000 миллисекунд, останавливаем прерывания и считываем значение счётчика

Как-то так...
Я правда не настоящий сталевар, делаю по крестьянски, ГУРУ наверное подскажут как правильно

ЗЫ кстати это analogWrite(PWM, 1); изменить на это analogWrite(PWM, 0х80); будет правильней (дути 50%)

freeman86
Offline
Зарегистрирован: 07.09.2016

Хм, а как количество оборотов while связано с шим? Разве скорость прохождения цикла не привязано к скорости процессора?

b707
Offline
Зарегистрирован: 26.05.2017

freeman86 пишет:
Хм, а как количество оборотов while связано с шим?

никак

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

freeman86 пишет:
На сколько мне известно, в компьютерной техники нет постоянных токов, а только импульсные. Но спорить не буду, так как не уверен. Можете сами попробовать повторить эксперимент

1. Вряд ли у кого возникнет желание "повторять эксперимент", результат которого известен заранее.

2. Чем выдвигать необоснованные предположения и предлагать кому-то их проверить, лучше бы взяли, да сами посмотрели осциллографом. Глядишь, и появились бы какие-то зачатки понимания, какие "токи" бывают в компьютерной технике.

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

Дело было вечером, делать было нечего:

Набросок и вывод порта:

ЗЫ на самом деле о точности в 0,2% на рассыпухе раньше можно было только мечтать )))
 

#define pinINT1 3
#define PIN_LED 13
volatile unsigned long old_millis = 0;
volatile unsigned long sch = 0;

void start_Sch(){
     digitalWrite(PIN_LED,HIGH);
     attachInterrupt(1, Sch, RISING );
     analogWrite(pinINT1,0x80);
     old_millis = millis();
 }

void end_Sch(){
     detachInterrupt(1);
     digitalWrite(PIN_LED,LOW);
      }

void Sch(void){
  sch++;
  }

  
void setup() {
  Serial.begin(115200);
  pinMode(PIN_LED,OUTPUT);
  start_Sch();
}

void loop() {
  if(millis() - old_millis >=1000){
    end_Sch();
    Serial.print("Счетчик = ");
     Serial.println(sch);
     // Serial.println();
      delay(1000);
       sch=0;
        start_Sch();
  }
}
Счетчик = 490
Счетчик = 491
Счетчик = 491
Счетчик = 490
Счетчик = 491
Счетчик = 491
Счетчик = 491
Счетчик = 490
Счетчик = 490
Счетчик = 491
Счетчик = 491
Счетчик = 491
Счетчик = 491
Счетчик = 491
Счетчик = 490
Счетчик = 491
Счетчик = 491
Счетчик = 491
Счетчик = 491
Счетчик = 491

 

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

и еще один набросок, генератор сделан на таймере, частота 5 Кгц, смотрим разброс показаний:
0,0014 = 0,14% )))
 

TCCR2B = 0x00 | timerBits2 = 2
OCR2A = timerTicks2 : = 200

Счетчик = 4975
Счетчик = 4969
Счетчик = 4968
Счетчик = 4974
Счетчик = 4974
Счетчик = 4973
Счетчик = 4974
Счетчик = 4973
Счетчик = 4969
Счетчик = 4968
Счетчик = 4969
Счетчик = 4974
Счетчик = 4973
Счетчик = 4974
Счетчик = 4973

 

Код:
 

#ifndef CONSTANTS
  #include "ConstTimers.h"
  // Параметры для работы таймера/счётчика №2 на частоте 5kГц
  //
  constexpr uint8_t timerBits2 = getPrescalerBits(2, 10000);
  constexpr uint8_t timerTicks2 = getTimerTicks(2, 10000);
  //
#endif

#define pinINT1 3
#define PIN_LED 13
volatile unsigned long old_millis = 0;
volatile unsigned long sch = 0;

void start_Sch(){
     digitalWrite(PIN_LED,HIGH);
     attachInterrupt(1, Sch, RISING );
    // analogWrite(pinINT1,0x80);
     old_millis = millis();
 }

void end_Sch(){
     detachInterrupt(1);
     digitalWrite(PIN_LED,LOW);
      }

void Sch(void){
  sch++;
  }

  
void setup() {
  Serial.begin(115200);
  pinMode(PIN_LED,OUTPUT);
   pinMode(11, OUTPUT);
   TCCR2A = 0x42;                  // Инвертирование пина 11 по сравнению и режим CTC то OCR2A
   TCCR2B = 0x00 | timerBits2;     // Установить СТС режим и делитель частоты
   OCR2A = timerTicks2;            // установить TOP равным topValue
   Serial.print("TCCR2B = 0x00 | timerBits2 = ");
   Serial.println(timerBits2);
   Serial.print("OCR2A = timerTicks2 : = ");
   Serial.println(timerTicks2);
   Serial.println();
 
  start_Sch();
}

void loop() {
  if(millis() - old_millis >=1000){
    end_Sch();
    Serial.print("Счетчик = ");
     Serial.println(sch);
     // Serial.println();
      delay(1000);
       sch=0;
        start_Sch();
  }
}

 

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

да в строках 5 и 6 можно и ручками установить делители

 constexpr uint8_t timerBits2 = 2; //getPrescalerBits(2, 10000);
  constexpr uint8_t timerTicks2 =199; // getTimerTicks(2, 10000);

Попробовал, а насколько точно измеряет на частоте 100кГц

TCCR2B = 0x00 | timerBits2 = 1
OCR2A = timerTicks2 : = 80

Счетчик = 98747
Счетчик = 98611
Счетчик = 98612
Счетчик = 98712
Счетчик = 98712
Счетчик = 98712
Счетчик = 98712
Счетчик = 98713
Счетчик = 98611
Счетчик = 98611
Счетчик = 98611

И на пределе этой технологии )))

TCCR2B = 0x00 | timerBits2 = 1
OCR2A = timerTicks2 : = 53

Счетчик = 147903
Счетчик = 147864
Счетчик = 147868
Счетчик = 147847
Счетчик = 148019
Счетчик = 148037
Счетчик = 148015
Счетчик = 148026
Счетчик = 148003
Счетчик = 147884
Счетчик = 147859

 

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

"А девкой был бы краше" )))
 

volatile unsigned int int_tic=0; 
volatile unsigned long tic; 
static byte flag = 0;
void setup() {
  Serial.begin(115200);
TCCR1A=0; TIMSK1 = 1<<TOIE1; //прерывание по переполнению
analogWrite(11,0x80);
}

ISR (TIMER1_OVF_vect){ int_tic++; }

void loop() {
pinMode (5,INPUT); // вход сигнала T1 (only для atmega328)
TCCR1B = (1<<CS10)|(1<<CS11)|(1<<CS12);//тактировани от входа Т1
delay(1000);
TCCR1B=0;
tic= ((uint32_t)int_tic<<16) | TCNT1; //сложить что натикало
int_tic=0; TCNT1 = 0; 
if(flag >= 1){
Serial.print(tic);
Serial.println(" Hz  ");
}
flag++;
}

И вывод:
 

490 Hz  
490 Hz  
490 Hz  
490 Hz  
490 Hz  
491 Hz  
490 Hz  
490 Hz  
491 Hz  
490 Hz  
490 Hz  
490 Hz  
490 Hz  
490 Hz  
490 Hz  
491 Hz  
490 Hz  
490 Hz  
491 Hz  
490 Hz 

 

b707
Offline
Зарегистрирован: 26.05.2017

ua6em пишет:

и еще один набросок, генератор сделан на таймере, частота 5 Кгц, смотрим разброс показаний:
0,0014 = 0,14% )))

 

разброс был бы неплох, если бы среднее значение совпало с теоретическим. А оно занижено на 30 гц - ошибка вчетверо выше "разброса", что полностью обесценивает эту "кучность" :) Где-то в счетчике систематическая ошибка?

По подключению - правильно я понял, выход 11 физически подключен на вход прерывания пин 3?

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

b707 пишет:

По подключению - правильно я понял, выход 11 физически подключен на вход прерывания пин 3?

если верхние скетчи, то да, на крайнем на 5 ногу

а если коээфициенты ввести в соответствии с калькулятором, то:
 

TCCR2B = 0x00 | timerBits2 = 2
OCR2A = timerTicks2 : = 199

Счетчик = 5000
Счетчик = 4993
Счетчик = 4994
Счетчик = 4998
Счетчик = 4998
Счетчик = 4999
Счетчик = 4998
Счетчик = 4998
Счетчик = 4994
Счетчик = 4993
Счетчик = 4993
Счетчик = 4999
Счетчик = 4999
Счетчик = 4998
Счетчик = 4999
Счетчик = 4994
Счетчик = 4993
Счетчик = 4993
Счетчик = 4999
Счетчик = 4998
Счетчик = 4998
Счетчик = 4999
Счетчик = 4993

 

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

Интересно, какой теоретический предел в частоте вызова функции прерывания для ардуино нано, у меня получается 150 килогерц ...

Гриша
Offline
Зарегистрирован: 27.04.2014

ЗЫ... тема поменялась на частотомер и первый пост не соответсвует...

Morze пишет:

 способна ли Ардуино прочитать ШИМ с частотой 5 кГц? Заполнение 0 - 100%. Мне необходим вывод значения в процентах. 

в процентах чего от чего? / это Скважность на частоте 5 кГц измерить? указав частоту и скважность...?  

чатотомер это хорошо, но неколько не соответсвует ТЗ первого поста...

 

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

Гриша пишет:

ЗЫ... тема поменялась на частотомер и первый пост не соответсвует...

Morze пишет:

 способна ли Ардуино прочитать ШИМ с частотой 5 кГц? Заполнение 0 - 100%. Мне необходим вывод значения в процентах. 

в процентах чего от чего? / это Скважность на частоте 5 кГц измерить? указав частоту и скважность...?  

чатотомер это хорошо, но неколько не соответсвует ТЗ первого поста...

Для измерения скважности я пользовался библиотекой от ЕвгенийП правда для частоты 100 герц, позволяет измерять с точностью 0.1 микросекунды, ТС это устроит?

Гриша
Offline
Зарегистрирован: 27.04.2014

ua6em пишет:

скважности я пользовался библиотекой от ЕвгенийП правда для частоты 100 герц, позволяет измерять с точностью 0.1 микросекунды, ТС это устроит?

это был вопрос к ТС...  просто несколько раз перечитывал первый пост, так и не понял о каких процентах идет речь...

да и топик был открыт 2 месяца назад, а недавно поменял проф ариентацию на простой частотомер 

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

Гриша пишет:

ua6em пишет:

скважности я пользовался библиотекой от ЕвгенийП правда для частоты 100 герц, позволяет измерять с точностью 0.1 микросекунды, ТС это устроит?

это был вопрос к ТС...  просто несколько раз перечитывал первый пост, так и не понял о каких процентах идет речь...

да и топик был открыт 2 месяца назад, а недавно поменял проф ариентацию на простой частотомер 

я так понимаю о DUTY а хотел видимо этого )))

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

ua6em пишет:

Интересно, какой теоретический предел в частоте вызова функции прерывания для ардуино нано, у меня получается 150 килогерц ...

Где-то так.

В проекте http://arduino.ru/forum/proekty/floppy-hdd-music я разгонял прерывания до 110 кГц. Правда, при единственном голосе. И еще ставил условие, чтобы для фонового процесса оставалось не менее некоторого процента времени. Если мне не изменяет память, это было 50%.

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

выше 150кгц у меня миллис падает, тикает в 4 раза медленней

Onkel
Offline
Зарегистрирован: 22.02.2016

Время выполнения millis() 4-6 мкс.

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

Onkel пишет:
Время выполнения millis() 4-6 мкс.

на 150 кгц расчетное время между вызовами прерывания где-то 3,3 мкс, ещё отрабатывает, а стоит счетчик грузить значением 52 вместо 53 и всё - затык...
 Значит нормально будет порядка 10 килогерц, время и на другие операции останется

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Все куда проще.
Частоту можно узнать таймером считывая и обнуляя TCNT по прерыванию.
А зная частоту посчитать скважность замерив длинну лог1, функцией pulseIn();

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

Больше того pulseIn можно померить HIGH и LOW, их отношение скважность, а единица деленная на сумму частота.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Так точность будет ниже.
В идеале HIGH тоже лучше таймером мерять, но там уже код усложняется.

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

Обоснуйте. С измерением частоты да, со сважностью на этой частоте и выводом в процентах какая будет ошибка? Зато трудозатраты несоимеримо меньше.

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

Kakmyc пишет:
Все куда проще. Частоту можно узнать таймером считывая и обнуляя TCNT по прерыванию. А зная частоту посчитать скважность замерив длинну лог1, функцией pulseIn();

Об этом, еще в посте #30 озвучено, я даже скетчик, поправив для ардуины нано скидал, правда не проверял:

// Использование таймера в режиме захвата. Измерение ширины,
// скважности импульса и частоты сигнала
// Сигнал частотой до 100кгц подавать на вход ICP(1) пин D8 для Atmega328
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
unsigned char OVF_counter, zamer_1, zamer_T, zamer_t, duty;
unsigned long t, T, f;
unsigned int rising_1, rising_2, falling;

// Прерывание по переполнению Таймера/счетчика 1
ISR(TIMER1_OVF_vect)
{
OVF_counter++; // Увеличиваем счетчик переполнений
}
// Прерывание по захвату Таймера/счетчика 1
ISR(TIMER1_CAPT_vect)
{
switch(zamer_1)
  {
    case 0: // Вычисляем ширину импульса
      switch(zamer_t)
      {
      case 0:
      rising_1 = ICR1; // Запоминаем значениие счётчика
      TCCR1B &= ~(1 << ICES1); // Устанавливаем прерывание по спадающему фронту импульса
      OVF_counter = 0; // Обнуляем количество переполнений счётчика
      zamer_t = 1; // Переходим к следующему вычислению
      break;
       
      case 1:    
      falling = ICR1;           // Запоминаем значение счётчика
      TCCR1B |= (1 << ICES1);   // Устанавливаем прерывание по нарастающему фронту импульса
// Приводим все переменные к одному типу и вычисляем длительность импульса
      t = (unsigned long)falling - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536);
      zamer_t = 0;
      zamer_1 = 1; // Переходим к следующему вычислению
      break;     
      }
    break;
    case 1: // Вычисляем период импульса
      switch(zamer_T) 
      {
      case 0:
      rising_1 = ICR1; // Запоминаем значение счётчика
      OVF_counter = 0; // Обнуляем количество переполнений счётчика
      zamer_T = 1; // Переходим к следующему вычислению
      break;
   
      case 1:
      rising_2 = ICR1; // Запоминаем значение счётчика
// Приводим все переменные к одному типу и вычисляем период импульса
      T = (unsigned long)rising_2 - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536);
      zamer_T = 0;
      zamer_1 = 2; // Переходим к следующему вычислению
      break;
      }
    break;
  case 2:                  
  f = 1000000/T; // Вычисляем частоту сигнала в Гц
  duty = (t*100)/T; // Вычисляем скважность импульса в процентах
  zamer_1 = 0; // Переходим к следующему вычислению
  break;
  }
}

void setup() {
  Serial.begin(115200);
  TCCR1B |= (1 << ICNC1)|(1 << CS11); // Активируем входной подавитель шума, предделитель на 8
  TIMSK1 |= (1 << ICIE1)|(1 << TOIE1); // Разрешаем прерывание по захвату и переполнению
}

void loop() {
Serial.print("Частота = ");
Serial.println(f);
Serial.print("Скважность = ");
Serial.println(duty);
delay(1000);
}

 

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

Проверил, измеряет как бык по дороге прошёл )))
 

Скважность = 238
 - 
Частота = 24390
Скважность = 0
 - 
Частота = 24390
Скважность = 48
 - 
Частота = 0
Скважность = 0
 - 
Частота = 24390
Скважность = 0
 - 
Частота = 0
Скважность = 48
 - 
Частота = 0
Скважность = 0
 - 
Частота = 24390
Скважность = 48
 - 
Частота = 0
Скважность = 0
 - 
Частота = 24390
Скважность = 80
 - 
Частота = 0
Скважность = 48
 - 
Частота = 0
Скважность = 0
 - 
Частота = 15
Скважность = 26
 - 
Частота = 0
Скважность = 0
 - 
Частота = 24390
Скважность = 48
 - 
Частота = 0
Скважность = 0
 - 
Частота = 24390
Скважность = 0
 - 
Частота = 0
Скважность = 0
 - 
Частота = 24390
Скважность = 0

Всё не просто плохо, а очень плохо, что по нижним частотам, что по верхним, видимо алгорим подсчёта не совсем удачный

// Использование таймера в режиме захвата. Измерение ширины,
// скважности импульса и частоты сигнала
// Сигнал частотой до 100кгц подавать на вход ICP

#include "ConstTimers.h"
#define  TIMER 2
#define FREQUENCY 50000

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
unsigned char OVF_counter, zamer_1, zamer_T, zamer_t, duty;
unsigned long t, T, f;
unsigned int rising_1, rising_2, falling;

// Прерывание по переполнению Таймера/счетчика 1
ISR(TIMER1_OVF_vect)
{
OVF_counter++; // Увеличиваем счетчик переполнений
}
// Прерывание по захвату Таймера/счетчика 1
ISR(TIMER1_CAPT_vect)
{
switch(zamer_1)
  {
    case 0: // Вычисляем ширину импульса
      switch(zamer_t)
      {
      case 0:
      rising_1 = ICR1; // Запоминаем значениие счётчика
      TCCR1B &= ~(1 << ICES1); // Устанавливаем прерывание по спадающему фронту импульса
      OVF_counter = 0; // Обнуляем количество переполнений счётчика
      zamer_t = 1; // Переходим к следующему вычислению
      break;
       
      case 1:    
      falling = ICR1;           // Запоминаем значение счётчика
      TCCR1B |= (1 << ICES1);   // Устанавливаем прерывание по нарастающему фронту импульса
// Приводим все переменные к одному типу и вычисляем длительность импульса
      t = (unsigned long)falling - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536);
      zamer_t = 0;
      zamer_1 = 1; // Переходим к следующему вычислению
      break;     
      }
    break;
    case 1: // Вычисляем период импульса
      switch(zamer_T) 
      {
      case 0:
      rising_1 = ICR1; // Запоминаем значение счётчика
      OVF_counter = 0; // Обнуляем количество переполнений счётчика
      zamer_T = 1; // Переходим к следующему вычислению
      break;
   
      case 1:
      rising_2 = ICR1; // Запоминаем значение счётчика
// Приводим все переменные к одному типу и вычисляем период импульса
      T = (unsigned long)rising_2 - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536);
      zamer_T = 0;
      zamer_1 = 2; // Переходим к следующему вычислению
      break;
      }
    break;
  case 2:                  
  f = 1000000/T; // Вычисляем частоту сигнала в Гц
  duty = (t*100)/T; // Вычисляем скважность импульса в процентах
  zamer_1 = 0; // Переходим к следующему вычислению
  break;
  }
}

void setup() {
  Serial.begin(115200);
  TCCR1B |= (1 << ICNC1)|(1 << CS11); // Активируем входной подавитель шума, предделитель на 8
  TIMSK1 |= (1 << ICIE1)|(1 << TOIE1); // Разрешаем прерывание по захвату и переполнению

// и запустим проверочный таймер
  constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY);
  constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY);
  
  pinMode(11,OUTPUT);
    pinMode(3,OUTPUT);
 // DDRB|=(1<<DDB3)|(1<<DDB2);
  TCCR2A=(1<<COM2A0)|(1<<COM2B0)|(1<<WGM21); 
  TCCR2B=1<<CS20 | prescalerBits;
  OCR2A=timerTicks; //b3,b2 - тикаем с уст.частотой ПИН D11 и D3
}

void loop() {
Serial.print("Частота = ");
Serial.println(f);
Serial.print("Скважность = ");
Serial.println(duty);
Serial.println(" - ");
delay(1000);
}

На WAVGAT всё выглядит аналогично плохо, в оригинале процессор был atmega8 может косяки адаптирования?
 

// Скетч для платы на чипе WAVGAT
// Использование таймера в режиме захвата. Измерение ширины,
// скважности импульса и частоты сигнала
// Сигнал частотой до 100кгц подавать на вход ICP(1) пин D8 для Atmega328
 
#include "ConstTimers.h"
#include "lgtx8p.h"

#define  TIMER 2
#define FREQUENCY 52000
#define DELTA 5

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
unsigned char OVF_counter, zamer_1, zamer_T, zamer_t, duty;
unsigned long t, T, f;
unsigned int rising_1, rising_2, falling;

// Прерывание по переполнению Таймера/счетчика 1
ISR(TIMER1_OVF_vect)
{
OVF_counter++; // Увеличиваем счетчик переполнений
}
// Прерывание по захвату Таймера/счетчика 1
ISR(TIMER1_CAPT_vect)
{
switch(zamer_1)
  {
    case 0: // Вычисляем ширину импульса
      switch(zamer_t)
      {
      case 0:
      rising_1 = ICR1; // Запоминаем значениие счётчика
      TCCR1B &= ~(1 << ICES1); // Устанавливаем прерывание по спадающему фронту импульса
      OVF_counter = 0; // Обнуляем количество переполнений счётчика
      zamer_t = 1; // Переходим к следующему вычислению
      break;
       
      case 1:    
      falling = ICR1;           // Запоминаем значение счётчика
      TCCR1B |= (1 << ICES1);   // Устанавливаем прерывание по нарастающему фронту импульса
// Приводим все переменные к одному типу и вычисляем длительность импульса
      t = (unsigned long)falling - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536);
      zamer_t = 0;
      zamer_1 = 1; // Переходим к следующему вычислению
      break;     
      }
    break;
    case 1: // Вычисляем период импульса
      switch(zamer_T) 
      {
      case 0:
      rising_1 = ICR1; // Запоминаем значение счётчика
      OVF_counter = 0; // Обнуляем количество переполнений счётчика
      zamer_T = 1; // Переходим к следующему вычислению
      break;
   
      case 1:
      rising_2 = ICR1; // Запоминаем значение счётчика
// Приводим все переменные к одному типу и вычисляем период импульса
      T = (unsigned long)rising_2 - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536);
      zamer_T = 0;
      zamer_1 = 2; // Переходим к следующему вычислению
      break;
      }
    break;
  case 2:                  
  f = 1000000/T; // Вычисляем частоту сигнала в Гц
  duty = (t*100)/T; // Вычисляем скважность импульса в процентах
  zamer_1 = 0; // Переходим к следующему вычислению
  break;
  }
}

void setup() {
  Serial.begin(115200);
  TCCR1B |= (1 << ICNC1)|(1 << CS11); // Активируем входной подавитель шума, предделитель на 8
  TIMSK1 |= (1 << ICIE1)|(1 << TOIE1); // Разрешаем прерывание по захвату и переполнению

// и запустим проверочный таймер
  constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY);
  constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY,DELTA);
  
  pinMode(11,OUTPUT);
  //  pinMode(3,OUTPUT);
 // DDRB|=(1<<DDB3)|(1<<DDB2);
  TCCR2A=(1<<COM2A0)|(1<<WGM21); //|(1<<COM2B0)|(1<<WGM21); 
  TCCR2B=1<<CS20 | prescalerBits;
  OCR2A=timerTicks; //b3,b2 - тикаем с уст.частотой ПИН D11 и D3
}

void loop() {
Serial.print("Частота = ");
Serial.println(f);
Serial.print("Скважность = ");
Serial.println(duty);
Serial.println(" - ");
delay(250);
}

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018
int volatile LL,HL;
int FRQ,DUTY;
void log1(){
    LL=TCNT1;
    TCNT1=0;
    attachInterrupt(0,log0,FALLING);
}

void log0(){
    HL=TCNT1;
    TCNT1=0;
    attachInterrupt(0,log1,RISING);
}

void setup(){
Serial.begin(9600);
attachInterrupt(0,log1,RISING);
TCCR1A=0;TCCR1B=0;TCNT1=0;
TCCR1B =(1<<CS00)|(1<<CS01);//тик таймера 4мкс
}

void loop(){
    int _HL=HL,_LL=LL;
 FRQ=250000/(_HL+_LL);
DUTY=((_HL+_LL)/_HL)*100;
    Serial.println(FRQ);
    Serial.println(DUTY);
delay(1000);
}

Написал, хотел проверить, но сдернули работать

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

Kakmyc пишет:

int volatile LL,HL;
int FRQ,DUTY;
void log1(){
    LL=TCNT1;
    TCNT1=0;
    attachInterrupt(0,log0,FALLING);
}

void log0(){
    HL=TCNT1;
    TCNT1=0;
    attachInterrupt(0,log1,RISING);
}

void setup(){
Serial.begin(9600);
attachInterrupt(0,log1,RISING);
TCCR1A=0;TCCR1B=0;TCNT1=0;
TCCR1B =(1<<CS00)|(1<<CS01);//тик таймера 4мкс
}

void loop(){
    int _HL=HL,_LL=LL;
 FRQ=250000/(_HL+_LL);
DUTY=((_HL+_LL)/_HL)*100;
    Serial.println(FRQ);
    Serial.println(DUTY);
delay(1000);
}

Написал, хотел проверить, но сдернули работать

Проверил на WAVGAT, как то так: (соединял 11 и 8 пины)
 

-1
-100
-1
-100
-1
-100
-1
-100
-1
-100
-1
-100
-1
-100

Код:
 

// Скетч для платы на чипе WAVGAT
// Использование таймера в режиме захвата. Измерение ширины,
// скважности импульса и частоты сигнала
// Сигнал частотой до 100кгц подавать на вход ICP(1) пин D8 для Atmega328
 
#include "ConstTimers.h"
#include "lgtx8p.h"

#define  TIMER 2
#define FREQUENCY 52000
#define DELTA 5

int volatile LL,HL;
int FRQ,DUTY;
void log1(){
    LL=TCNT1;
    TCNT1=0;
    attachInterrupt(0,log0,FALLING);
}

void log0(){
    HL=TCNT1;
    TCNT1=0;
    attachInterrupt(0,log1,RISING);
}

void setup(){
Serial.begin(9600);
attachInterrupt(0,log1,RISING);
TCCR1A=0;TCCR1B=0;TCNT1=0;
TCCR1B =(1<<CS00)|(1<<CS01);//тик таймера 4мкс

// и запустим проверочный таймер
  constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY);
  constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY,DELTA);
  
  pinMode(11,OUTPUT);
  //  pinMode(3,OUTPUT);
 // DDRB|=(1<<DDB3)|(1<<DDB2);
  TCCR2A=(1<<COM2A0)|(1<<WGM21); //|(1<<COM2B0)|(1<<WGM21); 
  TCCR2B=1<<CS20 | prescalerBits;
  OCR2A=timerTicks; //b3,b2 - тикаем с уст.частотой ПИН D11 и D3
}

void loop(){
    int _HL=HL,_LL=LL;
 FRQ=250000/(_HL+_LL);
DUTY=((_HL+_LL)/_HL)*100;
    Serial.println(FRQ);
    Serial.println(DUTY);
delay(1000);
}

Если соединяю пин 2 и пин 11 (на 11 меандр частоты 25кгц обязан быть)
 

-1
-100
6250
200
6250
200
6250
200
6250
200
6250
200

 

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

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

// Скетч для платы на чипе WAVGAT
// Использование таймера в режиме захвата. Измерение ширины,
// скважности импульса и частоты сигнала
// Сигнал частотой до 100кгц подавать на вход ICP(1) пин D8 для Atmega328
 
#include "ConstTimers.h"
#include "lgtx8p.h"

#define  TIMER 2
#define FREQUENCY 52000
#define DELTA 5

int volatile LL,HL;
int FRQ,DUTY;
void log1(){
    LL=TCNT1;
    TCNT1=0;
    attachInterrupt(0,log0,FALLING);
}

void log0(){
    HL=TCNT1;
    TCNT1=0;
    attachInterrupt(0,log1,RISING);
}

void setup(){
Serial.begin(9600);
attachInterrupt(0,log1,RISING);
TCCR1A=0;TCCR1B=0;TCNT1=0;
TCCR1B =(1<<CS00)|(1<<CS01);//тик таймера 4мкс

// и запустим проверочный таймер
  constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY);
  constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY,DELTA);
  
  pinMode(11,OUTPUT);
  //  pinMode(3,OUTPUT);
 // DDRB|=(1<<DDB3)|(1<<DDB2);
  TCCR2A=(1<<COM2A0)|(1<<WGM21); //|(1<<COM2B0)|(1<<WGM21); 
  TCCR2B=1<<CS20 | prescalerBits;
  OCR2A=timerTicks; //b3,b2 - тикаем с уст.частотой ПИН D11 и D3
}

void loop(){
    int _HL=HL,_LL=LL;
 FRQ=250000/(_HL+_LL)*4;
DUTY=((_HL+_LL)/_HL)*100;
    Serial.println(FRQ);
    Serial.println(DUTY);
delay(1000);
}

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Неправильно так
FRQ=250000/(_HL+_LL)*4;

Не нужно умножать правую часть на 4, я уже левую поделил на 4.

Иначе было бы так:
FRQ=1000000/((_HL+LL)*4);

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

иначе частота вычисляется неверно

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Ну по логике: 1 тик =4мкс,

Потому как множитель 64/16000000(частота CPU)=0,000004

В секунде 1е6 мкс.

FRQ=1000000/((_HL+LL)*4);

А это вроде как то же самое, что и 

FRQ=250000/(_HL+_LL);

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Завтра, если время будет проверю на стенде, где генерировать частоту/скважность ШИМ буду генератором

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Только int надо заменить на word или unsigned int для HL LL и скважность перевернуть HL/(HL+LL)*100

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Ну можно и множители менять на ходу. Но тут не разработка конечного продукта а просто некая концепция

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Концепция работает.

Не ясно пока почему в протеусе при 50/50 высокий уровень импульса всегда длинее низкого...

Для TC - на 16 МГц чипе без предделителя (таймер на частоте кварца) диапазон измерений будет 4-94 процента. (по методу перехвата прерывания по входу)