Таймеры.....
- Войдите на сайт для отправки комментариев
Ср, 18/05/2016 - 13:08
Люди! Помогите...
Есть такая задача: вычислить частоту сигнала на ноге (100Гц...5кГц), умножить на коэффициент (скажем, к=1.78) и отправить вычисленную частоту на другую ногу. Всё с максимальной возможной точностью.
Реально это на одной Ардуине Нано?.....
Все примеры, что я нашёл, делают это отдельно на T1. А единовременно?..........
Была похожая тема
Была похожая тема
Да! Практически моя задача. Спасибо большое! "Пошёл" вникать в детали......
Глубоко вникнуть не удалось - у моей наны, похоже, попросту нет таймера 3. Я прав?
a_sel, нету, да. Я не помню почему я написал тот скетч под ардуину-микро, видимо два 16-битных таймера было удобно применить в целях упрощения кода. В принципе ничто не мешает переписать под другой контроллер и таймер, но у меня спортивного интереса к этой теме больше нет :(
На 5кГц можно и библами обойтись, как мне кажется, чё там с таймерами выёживаться. Возьмите фреквенси коунтер готовый, помножте на 1.78 и скормите Тоне().
http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-frequency-counter-library/
https://www.arduino.cc/en/Reference/Tone
Добрый день всем!
Вроде бы разобрался я с этик кодом. Спасибо dimax за отличную идею. Переписал я под 2-й таймер, хоть и восьмибитный...
const int pini = 8; const int pino = 11; #define _DEBUG 1 volatile unsigned int icr_tic; volatile unsigned int int_tic; volatile unsigned long tic; unsigned int _ostat = 0; unsigned int _totover = 0; unsigned int _over = 0; unsigned long _tim = 50000; void setup(){ Serial.begin(57600); pinMode (pino,OUTPUT); // выход сигнала pinMode (pini,INPUT); // вход сигнала //настройка 16 бит таймера-счётчика 1 TCCR1B = 0; TCCR1A = 0; TCNT1 = 0; TIMSK1 = (1<<ICIE1)|(1<<TOIE1); //создавать прерывание от сигнала на пине ICP1 TCCR1B = (1<<ICNC1)|(1<<ICES1)|(1<<CS10);//div 1 //настройка таймера-генератора 2 TCCR2A=0; TCCR2B=(1<<WGM22)|(1<<CS20); //div1 CTC TIMSK2=1<<OCIE2A; //прерывание по переполнению OCR2A delay(100); } /// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ISR (TIMER1_CAPT_vect) { //прерывание захвата сигнала на входе ICP1 TCNT1 = 0; icr_tic=ICR1; tic = ((uint32_t)int_tic<<16) | icr_tic; //подсчёт тиков int_tic=0; } /// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ISR (TIMER1_OVF_vect) { int_tic++; } //прерывания счёта по переполнению uint /// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ISR (TIMER2_COMPA_vect) { //прерывание счёта тактов и управления выходом static volatile unsigned long temp_ocr; if (temp_ocr <= 255) { OCR2A = temp_ocr; PORTB ^= 0x10; // D12 ===> D8 #if _DEBUG _ostat = temp_ocr; _totover = _over; _over=0; temp_ocr = _tim ; #else temp_ocr = tic; #endif return; } if (temp_ocr > 255) { OCR2A = 255; temp_ocr=temp_ocr - 255; _over++; } } /// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void loop(){ static int cntl=44; for ( ; cntl > 0; cntl--) { Serial.print(" tic = "); Serial.print(tic,DEC); Serial.print(" _ticT2 "); Serial.println(_totover * 255 + _ostat,DEC); } }Правда, стала набегать погрешность из-за постоянных прерываний, наверное. Чуть поясню... Я "зарядил" timer2 на формирование меандра на d11 (50000 тиков), а 1-м таймером его (меандр) ловлю на d4 и вычисляю. Это для отладки. Потом все будет наоборот. И вот что показывает Serial:
tic = 100780 _ticT2 50000
tic = 100780 _ticT2 50000
tic = 100780 _ticT2 50000
tic = 100773 _ticT2 50000
tic = 100778 _ticT2 50000
tic = 100778 _ticT2 50000
tic = 100778 _ticT2 50000
tic = 100778 _ticT2 50000
tic = 100777 _ticT2 50000
tic = 100777 _ticT2 50000
tic = 100777 _ticT2 50000
tic = 100778 _ticT2 50000
tic = 100883 _ticT2 50000
tic = 100671 _ticT2 50000
tic = 100779 _ticT2 50000
tic = 100779 _ticT2 50000
................................................
Почти 800 лишних тиков набежало... Не подскажите - каким образом можно скомпенсировать эту погрешность? Хотя бы натолкните на путь истинный...
a_sel, ну коли вы решили в качестве теста посвистеть тамером в 12 пин, то хорошо бы его (пин) сделать как Output, а то у вашего генератора выходное сопротивление под 100 МОм получилось :)
dimax, сорри. Согласен, спасибо. На работе совершенно не возможно работать, будь она не ладна...
А по существу вопроса есть какие нибудь мысли?
a_sel, это и было по существу. Могло глючить ещё сильнее.
Да, я конечно же тут же поправил этот ляп. Увы, как мёртвому припарка. Ни на тик не изменилась картинка.
a_sel, я сам не особо заморачивался с погрешностями. Может это и норма. Методика захвата через ICP для не очень высоких частот, если перевести это в герцы -то погрешность уйдёт "за запятую" и особо волновать не будет. Даже подсчитал сейчас -в вашем случае это дельта 158,9 ... 158,5 Герц. Если есть боевой настрой, то могу посоветовать покапаться внутрях популярной библы FreqMeasure там по идее тот-же принцип, можно вытащить переменную, аналогичную моей tic и посмотреть, сильно ли её мандражит...
Не, фигня какая то.... Нет тут никакой связи с обилием прерываний.... Тут другая собака порылась. Без "поллитры" или осцилоскопа не разберёшься.
tic = 1956 _over 3 _ostat 235 _ticT2 1000
tic = 1956 _over 3 _ostat 235 _ticT2 1000
tic = 1956 _over 3 _ostat 235 _ticT2 1000
tic = 1956 _over 3 _ostat 235 _ticT2 1000
tic = 1955 _over 3 _ostat 235 _ticT2 1000
tic = 4004 _over 7 _ostat 215 _ticT2 2000
tic = 4004 _over 7 _ostat 215 _ticT2 2000
tic = 4003 _over 7 _ostat 215 _ticT2 2000
tic = 4005 _over 7 _ostat 215 _ticT2 2000
tic = 4004 _over 7 _ostat 215 _ticT2 2000
tic = 5782 _over 11 _ostat 195 _ticT2 3000
tic = 5794 _over 11 _ostat 195 _ticT2 3000
tic = 5539 _over 11 _ostat 195 _ticT2 3000
tic = 5795 _over 11 _ostat 195 _ticT2 3000
tic = 5541 _over 11 _ostat 195 _ticT2 3000
tic = 7587 _over 15 _ostat 175 _ticT2 4000
tic = 7588 _over 15 _ostat 175 _ticT2 4000
tic = 7844 _over 15 _ostat 175 _ticT2 4000
tic = 7844 _over 15 _ostat 175 _ticT2 4000
tic = 7844 _over 15 _ostat 175 _ticT2 4000
tic = 9886 _over 19 _ostat 155 _ticT2 5000
tic = 9891 _over 19 _ostat 155 _ticT2 5000
tic = 9635 _over 19 _ostat 155 _ticT2 5000
tic = 9635 _over 19 _ostat 155 _ticT2 5000
tic = 9891 _over 19 _ostat 155 _ticT2 5000
tic = 11939 _over 23 _ostat 135 _ticT2 6000
tic = 11938 _over 23 _ostat 135 _ticT2 6000
tic = 11684 _over 23 _ostat 135 _ticT2 6000
tic = 11683 _over 23 _ostat 135 _ticT2 6000
tic = 11683 _over 23 _ostat 135 _ticT2 6000
tic = 13732 _over 27 _ostat 115 _ticT2 7000
tic = 13986 _over 27 _ostat 115 _ticT2 7000
tic = 14075 _over 27 _ostat 115 _ticT2 7000
tic = 13732 _over 27 _ostat 115 _ticT2 7000
tic = 13987 _over 27 _ostat 115 _ticT2 7000
tic = 15689 _over 31 _ostat 95 _ticT2 8000
tic = 15673 _over 31 _ostat 95 _ticT2 8000
tic = 15688 _over 31 _ostat 95 _ticT2 8000
tic = 15690 _over 31 _ostat 95 _ticT2 8000
tic = 15689 _over 31 _ostat 95 _ticT2 8000
tic = 17737 _over 35 _ostat 75 _ticT2 9000
tic = 17738 _over 35 _ostat 75 _ticT2 9000
tic = 17736 _over 35 _ostat 75 _ticT2 9000
tic = 17738 _over 35 _ostat 75 _ticT2 9000
tic = 17738 _over 35 _ostat 75 _ticT2 9000
tic = 19796 _over 39 _ostat 55 _ticT2 10000
tic = 20123 _over 39 _ostat 55 _ticT2 10000
tic = 20043 _over 39 _ostat 55 _ticT2 10000
tic = 19785 _over 39 _ostat 55 _ticT2 10000
tic = 19784 _over 39 _ostat 55 _ticT2 10000
tic = 22431 _over 43 _ostat 35 _ticT2 11000
tic = 22435 _over 43 _ostat 35 _ticT2 11000
tic = 22435 _over 43 _ostat 35 _ticT2 11000
tic = 22436 _over 43 _ostat 35 _ticT2 11000
tic = 22435 _over 43 _ostat 35 _ticT2 11000
Спасибо. Попробую завтра на работе осцилографом глянуть, как это выглядит визуально.
Посмотрел. Ну дрожит немного задний фронт, это если растянуть в "период на экран". Да и фиг с ним. В целом очень красивая картинка. Подал эталонный килогерц - получилось 15 983 +- 2 тика. Ну,.. вот такой китайский кварц. Для моей задачи это абсолютно некритично. Хоть в попугаях, поскольку выходной сигнал формируется тем же кварцем.
В общем, спасибо всем большое!
Ни чё не работает, ни на 11, ни на Д4.
MagicianT, вот прога прямо с работающего макета. D12 и D8 - перемычка.
const int pini = 8; const int pino = 12; volatile unsigned int icr_tic; volatile unsigned int int_tic; unsigned long tic; unsigned int _ostat = 0; unsigned long _totover = 0; unsigned long _over = 0; unsigned long _tim = 5000; void setup(){ Serial.begin(9600); pinMode (pino,OUTPUT); pinMode (pini,INPUT); digitalWrite(pini, HIGH); //настройка 16 бит таймера-счётчика 1 TCCR1B = 0; TCCR1A = 0; TCNT1 = 0; TIMSK1 = (1<<ICIE1)|(1<<TOIE1); //создавать прерывание от сигнала на пине ICP1 TCCR1B = (1<<ICNC1)|(1<<ICES1)|(1<<CS10);//div 1 //настройка таймера-генератора 2 TCCR2A=0; TCCR2B=(1<<WGM22)|(1<<CS20); //div1 CTC TIMSK2=1<<OCIE2A; //прерывание по переполнению OCR2A delay(100); } /// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ISR (TIMER1_CAPT_vect) { //прерывание захвата сигнала на входе ICP1 TCNT1 = 0; icr_tic=ICR1; tic = ((uint32_t)int_tic<<16) | icr_tic; //подсчёт тиков int_tic=0; } /// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ISR (TIMER1_OVF_vect) { int_tic++; } //прерывания счёта по переполнению uint /// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ISR (TIMER2_COMPA_vect) { //прерывание счёта тактов и управления выходом static volatile unsigned long temp_ocr = 1000; if (temp_ocr <= 255) { OCR2A = temp_ocr; PORTB ^= 0x10; // PortB.4 == 12 ноге!!! pino _ostat = temp_ocr; _totover = _over; _over=0; temp_ocr = _tim ; return; } else { OCR2A = 255; temp_ocr -= 255; _over++; } } /// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void loop(){ int n; Serial.print(" tic = "); Serial.print(tic,DEC); // тиков на входе pini tic = 1; // если не будет прерываний.... Serial.print(" _ticT2 "); Serial.println(_totover * 255 + _ostat,DEC); // тиков в выходнлм полупериоде delay(300); n = Serial.available(); if (n) { n = Serial.read(); if (n == 32) { // " " --> пауза while (!Serial.available() ); // ждём любой символ по rs232 Serial.read(); // удаляем этот символ из буфера } else { _tim += 1000; // увеличиваем полупериод на 1000 тиков delay(100); Serial.println(); } } }В терминале -
tic = 9881 _ticT2 5000
tic = 9879 _ticT2 5000
tic = 9875 _ticT2 5000
tic = 9877 _ticT2 5000
tic = 9876 _ticT2 5000
tic = 9893 _ticT2 5000
tic = 9880 _ticT2 5000 и т.д.
А что Ваш терминал выдаёт?
Без "поллитры" или осцилоскопа не разберёшься.
Посмотрел. Ну дрожит немного задний фронт ...
...
Да и фиг с ним
Рано сдаваться! Вы ведь только осциллограф попробовали. Может поллитра лучший результат даст? Отпишитесь, как проверите.
Евгений, "поллитра" - это крайняя мера. Тем более в будний день... Не! Не наш метод!
MagicianT, интересно бы узнать ещё хотя бы один способ 8-битным таймером генерить герцовые импульсы с точностью 62.5 наносек... Поделитесь, плиииз.....
Я не понимаю о какой точности 62.5 вы говорите, у вас пин дрыгается в прерывании, а прерывание +-3 микросекунды, это в лучшем случае, если другое прерывание не пришло и не сдвинуло. Генерить правильно через хардваре, пин 3 или 11, но согласен что 8-битный таймер до 62 кГц только хорош, потом преселектор надо заюзать, а тогда хоть частотно-временое разрешение и ухудшится пропорционально, и станет как сейчас, но по крайней мере фаза прыгать-дёргаться не будет.
const byte interruptPin = 2; volatile unsigned long mikrosekynd = 0; volatile unsigned long mikros_last = 0; float multiplier = 1.78; int update_rate = 100; // 100 millisekynd. unsigned long millis_last = 0; void setup(){ // Serial.begin(9600); pinMode(interruptPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(interruptPin), blink, RISING); tone(3, 1); } void loop() { unsigned long millisekynd = millis(); if((millisekynd - millis_last) > update_rate) { tone(3, ( multiplier *1000000.0/((float) mikrosekynd))); millis_last = millisekynd; } } void blink() { unsigned long temp = micros(); unsigned long filter = temp - mikros_last; mikros_last = temp; mikrosekynd = (255 * mikrosekynd + filter)/ 256; if(mikrosekynd < 200) mikrosekynd = 200; // if(mikrosekynd > 10000) mikrosekynd = 10000; // tone(3, ( 1000000.0/((float) mikrosekynd))); }на выходе джиттер всё равно есть, когда обновляется тоне(). Программа работает, но если свербит и хочется совершенства, то таймер-1 свободен, примерно до 122 герц в фейз-корект ПВМ, что несколько выше тех. задания. Если ниже надо, то с прескалером на 8 разрешение по частоте падает до 13 Гц (гранулярность?) на 5000 кГц. Всего 0.25%