|
Частотомер на Atmega8 (CVAVR) |
|
|
|
Jun 9 2010, 17:23
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Делаю (пытаюсь сделать) частотомер по методу предложеному =GM= тут: http://electronix.ru/forum/index.php?showtopic=29796. Но вот что то не получается. Верней получается но не совсем. Во первых если я меняю задержку между началом и концом измерения то получаю существенно разные варианты. Но в то же время, если задержка ровно 1 сек (delay_ms(1000)  то результат выводится либо равный расчетному либо чуть больше. Причем как будто бы не хватает одного переполнения таймера 1 т.е. Perepol_Timer1++; и число N1 получается на 65536 меньше. Из за чего результат чуть больше. Но куда оно может пропасть? код вообще то взят в основном отсюда http://pro-radio.ru/controllers/5978/(с комментариями) но там не работает регистрация поэтому спрашиваю тут. Код char gate; static float Fx; unsigned long int N, N0, M, M0, N1, M1; unsigned int Perepol_Timer0=0, Perepol_Timer1=0, count_T1, count_T0,Perepol_Timer1_real;
//Прерывание по переполнению Timer/Counter 0 interrupt [TIM0_OVF] void timer0_ovf_isr(void){ Perepol_Timer0++;//Увеличение переменной на 1 }
//Прерывание по переполнению Timer/Counter 1 interrupt [TIM1_OVF] void timer1_ovf_isr(void){ if (gate){ Perepol_Timer1++;//Увеличение переменной на 1 } }
//Прерывание по захвату Timer/Counter 1 interrupt [TIM1_CAPT] void timer1_capt_isr(void){ count_T1=ICR1;//Значение регистра ICR1 переписывается в переменную count_T0=TCNT0;//Значение регистра TCNT0 переписывается в переменную TIMSK&=0xDF;//Запрет прерывания по захвату if (TIFR&0b00000100==1){ Perepol_Timer1++; TIFR&=0b00000100; } }
while (1){//Бесконечный цикл #asm("cli") gate=0; Perepol_Timer1=0;//Обнуление переменной Perepol_Timer0=0;//Обнуление переменной #asm("sei")//Разрешения прерываний TIMSK|=0x20;//Разрешили захват gate=1; while ((TIFR&0x20)==0x20){}//Ожидание прерывания по захвату Perepol_Timer1_real = Perepol_Timer1; N0=(((unsigned long int)(Perepol_Timer1_real))<<16)+count_T1; //Расчет общего количества тиков системной частоты M0=(((unsigned long int)(Perepol_Timer0))<<8)+count_T0;//Расчет общего количества тиков входной частоты //sprintf(lcd_buffer, "PT1=%u;CT1=%u;PT0=%u;CT0=%u;\r", Perepol_Timer1_real, count_T1, Perepol_Timer0, count_T0); //puts(lcd_buffer); delay_ms(1000);//Задержка на 1 с TIMSK|=0x20;//Разрешили захват gate=0; while ((TIFR&0x20)==0x20){}//Ожидание прерывания по захвату Perepol_Timer1_real = Perepol_Timer1; N1=(((unsigned long int)(Perepol_Timer1_real))<<16)+count_T1; //Расчет общего количества тиков системной частоты M1=(((unsigned long int)(Perepol_Timer0))<<8)+count_T0;//Расчет общего количества тиков входной частоты sprintf(lcd_buffer, "PT1=%u;CT1=%u;PT0=%u;CT0=%u;\r", Perepol_Timer1_real, count_T1, Perepol_Timer0, count_T0); puts(lcd_buffer); N=(N1-N0);//Расчет количества тиков системной частоты за время измерения M=(M1-M0);//Расчет количества тиков входной частоты за время измерения
Fx=12000000.0*(float)M/(float)N;//Вычисление частоты входного сигнала putchar('c'); sprintf(lcd_buffer, "F=%0.6fHz", Fx); lcd_clear(); lcd_puts(lcd_buffer); puts(lcd_buffer); putchar(13); } }
|
|
|
|
|
 |
Ответов
(1 - 53)
|
Jun 10 2010, 09:01
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Цитата(Сергей Борщ @ Jun 10 2010, 10:02)  Вы учитываете остаток в регистре таймера на момент окончания измерения, но не учитываете начальное значение таймера. а как же Код N0=(((unsigned long int)(Perepol_Timer1_real))<<16)+count_T1; вроде учитываю сount_T1...
|
|
|
|
|
Jun 10 2010, 21:36
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
У вас ошибка: второе прерывание TOV1 никогда не даст инкремента, поскольку GATE=0. Число N1 естественно будет меньше на 2^16.
Далее, счётчик T0 у вас 8-битный, а переменная count_T0 у вас int, ну и добавляете вы ее, как int, а надо только 8 бит. Для вашего компилятора может и пройдёт, но лучше по-честному добавлять 8-битное число.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 11 2010, 08:54
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Цитата(=GM= @ Jun 11 2010, 01:36)  У вас ошибка: второе прерывание TOV1 никогда не даст инкремента, поскольку GATE=0. Число N1 естественно будет меньше на 2^16. Таким образом пишем gate=0; после while ((TIFR&0x20)==0x20){}? Цитата(=GM= @ Jun 11 2010, 01:36)  Далее, счётчик T0 у вас 8-битный, а переменная count_T0 у вас int, ну и добавляете вы ее, как int, а надо только 8 бит. Для вашего компилятора может и пройдёт, но лучше по-честному добавлять 8-битное число. а здесь пишем count_T0=(int)TCNT0; с приведением типа. (хотя компилятор сам это делает, не делает а пишет варнинги если написать char*2, например, то он ругнется на переполнение чара.) В общем результат тот же.  И число N1 то меньше на 65536 то ровно столько сколько надо. От чего это зависит не понимаю. 3 измерения так - 3 так.
|
|
|
|
|
Jun 11 2010, 21:28
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Структура вашей программы в некотором смысле эклектична.
1) Вроде бы работаете по прерываниям, но и ждёте флаг прерывания ICF1 в фоне, и явно это будет другое прерывание, поскольку по завершению прерывания флаг ICF1 сбрасывается в самом прерывании. Зачем тогда его ждёте?
2) В начале цикла измерения вы разрешаете прерывания по захвату, но не учитываете, что физически захват как молотил со скоростью входной частоты, так и молотит. Следовательно, после разрешения прерывания TOIE1=1 надо бы сбросить флаг ICF1, также и в конце измерения.
Кстати, каков диапазон частот вы хотите измерять, какой проц и тактовая?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 12 2010, 11:43
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Цитата(=GM= @ Jun 12 2010, 01:28)  Структура вашей программы в некотором смысле эклектична. Кстати, каков диапазон частот вы хотите измерять, какой проц и тактовая? Да, программа такова, ибо сначала я пытался измерять методом ворот, но удачи не достиг  Вот код моего варианта: Код float result; char buff[16], tim, numizm=2, state=0;
// Timer 1 overflow interrupt service routine interrupt [TIM1_OVF] void timer1_ovf_isr(void) { tim++; // увеличиваем счетчик переполнений. }
// Timer 1 input capture interrupt service routine interrupt [TIM1_CAPT] void timer1_capt_isr(void) { if (state==0){ // первый фронт сигнала tim=0; // обнуляем переменные и таймер TCNT1=0; } state++; // прибавляем счетчик if (state == numizm){ // если счетчик и кол-во измерений равны, то вычисляем частоту result = 12000000 / ((float)tim*65535+ICR1); // вычисляем "частоту" result *= (int)numizm; // и умножаем на кол-во измерений, получая действительную частоту
numizm = 255; //выставляем число измерений if (numizm < result){ // если оно меньше полученной частоты то ставим ее равной частоте ( т.о. измерение будет длиться меньше секунды) numizm = result; } sprintf(buff,"F = %0.3f Гц",result); // выводим на экран и в UART puts(buff); putchar(13); lcd_clear(); lcd_puts(buff); state = 0; // Обнуляем состояние } } На мой взгляд совершенно логичный, но не работающий. Потом мне объяснили что таким способом, разрешающая способность будет не велика. Поэтому я решил пойти по пути Вашего метода. Ну и взял 2 варианта кода и их объединил  Ну а частоты которые мне нужно измерять - 2 кГц -- 10 кГц. Насколько я понимаю, Вашим методом можно достичь очень хорошей точности, что для струнного датчика (линейный размер -> частота) было бы очень неплохо  МК Atmega8 частота не принципиальна, но вот сейчас под рукой кварц на 12 мГц.
|
|
|
|
|
Jun 12 2010, 21:51
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Цитата(=GM= @ Jun 12 2010, 16:51)  Как вы струну возбуждаете? Для этого используется автогенератор. На выходе его 300 мВ 2 -10 кГц прямоугольные импульсы. Но вообще эти старые железки хочется переделать и встроить в свое устройство. Кстати говоря, вы своим вопросом породили во мне другой вопрос: можно ли использовать в Вашем алгоритме компаратор встроенный в мегу8 для захвата и будет ли его достаточно для детектирования столь низкого по амплитуде сигнала?
|
|
|
|
|
Jun 13 2010, 22:22
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(ps1x @ Jun 12 2010, 20:51)  можно ли использовать в Вашем алгоритме компаратор встроенный в мегу8 для захвата и будет ли его достаточно для детектирования столь низкого по амплитуде сигнала? В принципе, думаю можно, хотя оффсет у компаратора достаточно большой, посмотрите на рис. 167-168 док. 2486. Думаю, что для ваших целей подойдёт более простой код для измерения частоты, это модификация вашего варианта, я только немного упорядочил и заменил названия "непроизносимых" переменных. Есть правда один нюанс, но об этом позже. Компилятор WinAVR-20100110 CODE static float volatile Fx; uint32_t volatile N,N1,N2,M,M1,M2; uint16_t volatile mtick1,mtick2,mover=0; uint16_t volatile ntick1,ntick2,nover=0; ISR (TIMER0_OVF_vect) //переполнение счётчика0 входных тиков { mover++; //учтём в mover } ISR (TIMER1_OVF_vect) //переполнение таймера1 системных тиков { nover++; //учтём в nover } int main(void) { TIMSK=(1<<TOIE1)|(1<<TOIE0); //разрешим TOV1 и TOV0 asm volatile("sei\n\t":  ; //разрешим прерывания while(1) //цикл непрерывного измерения частоты { TIFR=(1<<ICF1); //сбросим флаг захвата while((TIFR&0x20)==0x20); //ждём начала измерения ntick1=ICR1; //запомним ICR1 и TCNT0 mtick1=TCNT0; //в начале измерения ntick2=nover; mtick2=mover&0x00FF; N1=((uint32_t)(ntick2)<<16)+(uint32_t) ntick1; //системные тики M1=((uint32_t)(mtick2)<<8) +(uint32_t) mtick1; //входные тики delay_ms(1000); //задержка на 1 с TIFR=(1<<ICF1); //сбросим флаг захвата while((TIFR&0x20)==0x20); //ждём конца измерения ntick1=ICR1; //запомним ICR1 и TCNT0 mtick1=TCNT0; //в конце измерения ntick2=nover; mtick2=mover&0x00FF; N2=((uint32_t)(ntick2)<<16)+(uint32_t) ntick1; //системные тики M2=((uint32_t)(mtick2)<<8) +(uint32_t) mtick1; //входные тики N=N2-N1; //системные тики за время измерения M=M2-M1; //входные тики за время измерения Fx=12000000.0*(float)M/(float)N; //вычисление частоты входного сигнала // <<здесь должен быть код вывода на индикатор>> } } Обращаю внимание СИСАДМИНА: при редактировании тег [ / codebox ] самопроизвольно меняется на тег < / div >, возникает ошибка.
Сообщение отредактировал rezident - Jun 14 2010, 22:29
Причина редактирования: Редактирование тэгов цитаты исходника.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 14 2010, 18:46
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Цитата(=GM= @ Jun 14 2010, 02:22)  В принципе, думаю можно, хотя оффсет у компаратора достаточно большой, посмотрите на рис. 167-168 док. 2486. Но офсет ведь не влияет? Мы же начинаем измерение фронтом и заканчиваем, и теоретически, задержка прихода фронта не должна влиять. Естественно если она одна и та же для начала и окончания. Спасибо за пример, единственно, надо будет разобраться с регистрами всяких настроек таймеров, прерываний и т.п. В CVAVR таких удобных обращений нет  p.s. Правильны ли эти дефайны: Код #define TOIE0 0x01 #define TOIE1 0x04 #define ICF1 0x20 Судя по всему нет, ибо МК перезагружается на первой же строчке: TIMSK=(1<<TOIE1)|(1<<TOIE0);
|
|
|
|
|
Jun 15 2010, 09:11
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
1) Оффсет влияет на начало фронта, многое зависит от ваших требований к изделию, пробуйте, потом расскажете. Если оффсет не изменяется за время измерения, то задержки обоих фронтов будут одинаковые. 2) Дифайны неправильные, надо так Код #define TOIE0 0 #define TOIE1 2 #define ICF1 5 Но самому делать ничего не надо, всё сделано до нас, определения находятся в одном из io*.h, для атмеги8 в частности в файле WinAVR-20100110\avr\include\avr\iom8.h. Цитата(=GM= @ Jun 13 2010, 21:22)  Обращаю внимание СИСАДМИНА: при редактировании тег [ / codebox ] самопроизвольно меняется на тег < / div >, возникает ошибка Уважаемый rezident, спасибо за исправление, я тоже вначале так делал, но при этом искажается код программы, кроме того, вы разрушили моё красивое форматирование комментов, мне так не нравится. Обратите внимание, в исправленном вами коде вместо : : ) появилась заставка рожицы  . Это уже не дело, а ведь могут быть искажения и посерьёзнее, особенно там, где присутствуют угловые скобки < или >. Тогда уж не надо было вводить в практику и тег [ code ]. ЕЩЁ РАЗ ОБРАЩАЮ ВНИМАНИЕ: при редактировании сообщения тег [ / codebox ] самопроизвольно меняется на тег < / div >, приходится вручную забивать div и допечатывать codebox. При первом вводе сообщения такой замены не происходит. Похоже это баг системы, пожалуйста, разберитесь и по возможности исправьте.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 15 2010, 09:38
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
CODE #include <mega8.h> //Подключение #include <stdio.h> // внешнх #include <stdlib.h> #include <delay.h> // библиотек #include <16x2.h>//
#define TOIE0 0 #define TOIE1 2 #define ICF1 5
//Объвление переменных static float volatile Fx; unsigned long volatile N,N1,N2,M,M1,M2; unsigned int volatile mtick1,mtick2,mover=0; unsigned int volatile ntick1,ntick2,nover=0;
//Прерывание по переполнению Timer/Counter 0 interrupt [TIM0_OVF] void timer0_ovf_isr(void){ mover++; }
//Прерывание по переполнению Timer/Counter 1 interrupt [TIM1_OVF] void timer1_ovf_isr(void){ nover++; }
//Тело основной программы void main(void){
unsigned char lcd_buffer[46];//Обявление локальной строковой переменной
PORTC=0x00; DDRC=0xFF;
//Инициализация Timer/Counter 0 TCCR0=0x07;
//Инициализация Timer/Counter 1
TCCR1B=0x01;
UCSRA=0x00; UCSRB=0x08; UCSRC=0x86; UBRRH=0x00; UBRRL=0x4D; putsf("reset\r"); lcd_init();//Инициализация LCD HD44780
#asm("sei")
TIMSK=(1<<TOIE1)|(1<<TOIE0); //разрешим TOV1 и TOV0 putchar('a');
while (1){//Бесконечный цикл
TIFR=(1<<ICF1); //сбросим флаг захвата putchar('b'); while((TIFR&0x20)==0x20); //ждём начала измерения putchar('c'); ntick1=ICR1; //запомним ICR1 и TCNT0 mtick1=TCNT0; //в начале измерения ntick2=nover; mtick2=mover&0x00FF; N1=((long)(ntick2)<<16)+(long) ntick1; //системные тики M1=((long)(mtick2)<<8) +(long) mtick1; //входные тики putchar('d'); delay_ms(1000); //задержка на 1 с TIFR=(1<<ICF1); //сбросим флаг захвата while((TIFR&0x20)==0x20); //ждём конца измерения ntick1=ICR1; //запомним ICR1 и TCNT0 mtick1=TCNT0; //в конце измерения ntick2=nover; mtick2=mover&0x00FF; N2=((long)(ntick2)<<16)+(long) ntick1; //системные тики M2=((long)(mtick2)<<8) +(long) mtick1; //входные тики N=N2-N1; //системные тики за время измерения M=M2-M1; //входные тики за время измерения Fx=12000000.0*(float)M/(float)N; //вычисление частоты входного сигнала putchar('c'); sprintf(lcd_buffer, "F=%0.6fHz", Fx); lcd_clear(); lcd_puts(lcd_buffer); puts(lcd_buffer); putchar(13); } } Это код который я гружу в контроллер. CODE bcdcF=1016.036315Hz
bcdcF=1017.031433Hz
bcdcF=1016.036315Hz
bcdcF=1021.588439Hz
bcdcF=1021.588439Hz
bcdcF=1021.588439Hz
bcdcF=1021.588439Hz
bcdcF=1016.036315Hz
bcdcF=1017.031433Hz
bcdcF=1016.036315Hz
bcdcF=1021.588439Hz
bcdcF=1021.588439Hz
bcdcF=1021.588439Hz
bcdcF=1021.588439Hz
bcdcF=1016.036315Hz
bcdcF=1017.031433Hz
bcdcF=1016.036315Hz
bcdcF=1016.036315Hz
bcdcF=1021.588439Hz
bcdcF=1021.588439Hz
bcdcF=1021.588439Hz
bcdcF=1016.036315Hz
bcdcF=1017.031433Hz
bcdcF=1016.036315Hz
bcdcF=1016.036315Hz
bcdcF=1021.588439Hz
bcdcF=1022.588989Hz
bcdcF=1021.588439Hz
bcdcF=1016.036315Hz
bcdcF=1016.036315Hz
bcdcF=1016.036315Hz
bcdcF=1016.036315Hz
А это то что на выходе в терминале.
|
|
|
|
|
Jun 15 2010, 10:34
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
1) Для начала неплохо. Каков был номинал входной частоты?
2) Поставьте putchar('b'); до сброса флага захвата TIFR=(1<<ICF1); Вы должны понимать, что сбрасываете предыдущее состояние, которое возникло неизвестно когда, и ожидаете свежего захвата, после которого немедленно запоминаете свежие значения TCNT0 и ICR1, пока они не поменялись снова.
3) Из тех же соображений уберите вывод putchar('c'); сразу после захвата, это достаточно длительная функция.
4) Неплохо бы для отладки выводить в цикле не только частоту, но и значения N1, N2, M1, M2.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 15 2010, 11:36
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Входная частота 1019.02173 Гц. Расчетная. По осцилографу тоже очень похоже (С117 с метками). CODE reset N1=0 M1=97 N2=0 M2=1130 cF=1016.924499Hz
N1=0 M1=1168 N2=0 M2=2204 cF=1014.423889Hz
N1=0 M1=2242 N2=0 M2=3277 cF=1018.893310Hz
N1=0 M1=3315 N2=0 M2=4350 cF=1018.893310Hz
N1=0 M1=4388 N2=0 M2=5423 cF=1018.893310Hz
N1=0 M1=5461 N2=0 M2=6496 cF=1018.893310Hz
N1=0 M1=6534 N2=0 M2=7569 cF=1018.893310Hz
N1=0 M1=7607 N2=0 M2=8642 cF=1018.893310Hz
N1=0 M1=8680 N2=0 M2=9715 cF=1013.444702Hz
N1=0 M1=9753 N2=0 M2=10788 cF=1018.893310Hz
N1=0 M1=10827 N2=0 M2=11863 cF=1014.423889Hz
N1=0 M1=11902 N2=0 M2=12939 cF=1020.862243Hz
N1=0 M1=12978 N2=0 M2=14014 cF=1019.877746Hz
N1=0 M1=14053 N2=0 M2=15089 cF=1019.877746Hz
N1=0 M1=15128 N2=0 M2=16164 cF=1014.423889Hz
N1=0 M1=16203 N2=0 M2=17240 cF=1020.862243Hz
Такое ощущение, что нужно обнулять nover и mover. Но что то еще не так. Смущает так же, что N1 и N2 = 0. Если обнулять nover и mover то измерения такие: CODE reset N1=0 M1=98 N2=0 M2=1131 F=1016.924499Hz
N1=0 M1=144 N2=0 M2=1178 F=1017.908935Hz
N1=0 M1=191 N2=0 M2=1225 F=1017.908935Hz
N1=0 M1=238 N2=0 M2=1272 F=1017.908935Hz
N1=0 M1=29 N2=0 M2=1062 F=1022.421386Hz
N1=0 M1=75 N2=0 M2=1108 F=1016.924499Hz
N1=0 M1=121 N2=0 M2=1155 F=1017.908935Hz
N1=0 M1=168 N2=0 M2=1202 F=1017.908935Hz
N1=0 M1=215 N2=0 M2=1249 F=1017.908935Hz
N1=0 M1=6 N2=0 M2=1038 F=1021.431579Hz
N1=0 M1=51 N2=0 M2=1084 F=1016.924499Hz
N1=0 M1=97 N2=0 M2=1130 F=1016.924499Hz
N1=0 M1=143 N2=0 M2=1177 F=1023.411132Hz
N1=0 M1=190 N2=0 M2=1224 F=1017.908935Hz
N1=0 M1=237 N2=0 M2=1272 F=1024.400878Hz
N1=0 M1=29 N2=0 M2=1062 F=1016.924499Hz
N1=0 M1=75 N2=0 M2=1108 F=1016.924499Hz
N1=0 M1=121 N2=0 M2=1155 F=1017.908935Hz
N1=0 M1=168 N2=0 M2=1202 F=1017.908935Hz
N1=0 M1=215 N2=0 M2=1249 F=1017.908935Hz
N1=0 M1=6 N2=0 M2=1038 F=1015.940002Hz
N1=0 M1=51 N2=0 M2=1084 F=1016.924499Hz
N1=0 M1=97 N2=0 M2=1130 F=1022.421386Hz
N1=0 M1=143 N2=0 M2=1177 F=1017.908935Hz
N1=0 M1=190 N2=0 M2=1224 F=1017.908935Hz
А вот и сам код: CODE while (1){//Бесконечный цикл
TIFR=(1<<ICF1); //сбросим флаг захвата while((TIFR&0x20)==0x20); //ждём начала измерения ntick1=ICR1; //запомним ICR1 и TCNT0 mtick1=TCNT0; //в начале измерения ntick2=nover; mtick2=mover&0x00FF; N1=((long)(ntick2)<<16)+(long) ntick1; //системные тики M1=((long)(mtick2)<<8) +(long) mtick1; //входные тики sprintf(lcd_buffer, "N1=%i M1=%i\r", N1,M1); puts(lcd_buffer); delay_ms(1000); //задержка на 1 с TIFR=(1<<ICF1); //сбросим флаг захвата while((TIFR&0x20)==0x20); //ждём конца измерения ntick1=ICR1; //запомним ICR1 и TCNT0 mtick1=TCNT0; //в конце измерения ntick2=nover; mtick2=mover&0x00FF; N2=((long)(ntick2)<<16)+(long) ntick1; //системные тики M2=((long)(mtick2)<<8) +(long) mtick1; //входные тики sprintf(lcd_buffer, "N2=%i M2=%i\r", N2,M2); puts(lcd_buffer); N=N2-N1; //системные тики за время измерения M=M2-M1; //входные тики за время измерения Fx=12000000.0*(float)M/(float)N; //вычисление частоты входного сигнала
sprintf(lcd_buffer, "F=%0.6fHz", Fx); lcd_clear(); lcd_puts(lcd_buffer); puts(lcd_buffer); putchar(13); nover=0; mover=0; } }
|
|
|
|
|
Jun 15 2010, 12:03
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Разница М2-М1 всё время где-то 1033-1034, это приемлемо, по крайней мере согласуется с количеством импульсов входной частоты за 1 сек. А вот разница N2-N1=0, как это может быть? И как можно получить конечную частоту, деля на 0?
Скорее всего, неверный формат вывода. N1, N2, М1, М2 - целые числа формата long, значит формат вывода должен быть %li, а не %i.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 15 2010, 12:50
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Код reset aN1=65536 M1=98 ntick1=0 ntick2=1 N2=12582912 M2=1158 ntick1=0 ntick2=192 F=1016.187438Hz
N1=0 M1=205 ntick1=0 ntick2=0 N2=12451840 M2=1262 ntick1=0 ntick2=190 F=1018.644653Hz
N1=0 M1=52 ntick1=0 ntick2=0 N2=12451840 M2=1109 ntick1=0 ntick2=190 F=1018.644653Hz
N1=0 M1=155 ntick1=0 ntick2=0 N2=12517376 M2=1213 ntick1=0 ntick2=191 F=1014.270141Hz
N1=0 M1=3 ntick1=0 ntick2=0 N2=12451840 M2=1058 ntick1=0 ntick2=190 F=1016.717163Hz
N1=0 M1=105 ntick1=0 ntick2=0 N2=12517376 M2=1162 ntick1=0 ntick2=191 F=1013.311462Hz
N1=0 M1=208 ntick1=0 ntick2=0 N2=12451840 M2=1266 ntick1=0 ntick2=190 F=1019.608398Hz
N1=0 M1=56 ntick1=0 ntick2=0 N2=12451840 M2=1113 ntick1=0 ntick2=190 F=1018.644653Hz
N1=0 M1=159 ntick1=0 ntick2=0 N2=12451840 M2=1216 ntick1=0 ntick2=190 F=1018.644653Hz Действительно, только %li
|
|
|
|
|
Jun 15 2010, 14:05
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Теперь мне не нравится, что ntick1 всё время равен 0, так не должно быть. Хотя N2=ntick2<<16.
И почему такая разница во времени между циклами измерения? Для 12 МГц клока составит 65536*83нс=5,461 мс.
Признавайтесь, куда у вас подключена нога захвата :-)?
И ещё, попробуйте поставить все операторы sprintf после вычисления Fx, возможно они вносят неоднородную задержку в цикл измерения. Не забудьте ввести доп.переменные ntick3, 4... чтобы не затирать начало
А потом перейдём к решению "нюанса".
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 15 2010, 14:58
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Цитата(=GM= @ Jun 15 2010, 18:05)  Признавайтесь, куда у вас подключена нога захвата :-)? Входной меандр подключен к Т0. ICP висит в воздухе...
|
|
|
|
|
Jun 15 2010, 15:35
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(ps1x @ Jun 15 2010, 13:58)  Входной меандр подключен к Т0. ICP висит в воздухе... Ну вот, приплыли :-). Не обижайтесь, шутю я, у всех бывает. У вас в ICR1 стоял 0х0000 по умолчанию, вот вы его и считывали. Нога должна быть физически подключена к генератору и Т0. Иначе захват не будет работать. Далее, таймер0 и захват должны быть настроены на срабатывание от одного фронта, скажем 1-0.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 15 2010, 19:22
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Появилась стабильность  Значения 1018.8184 - 1018.8183 около того. Наверное, можно списать на погрешность кварца генератора и частотомера, хотя один из вариантов прошлого (  ) периодически показывал значения очень близкие к расчетному +0.00030 или около того. Однако периодически происходят выбросы 1024.125... К сожалению перешел на другое рабочее место, где самодельный переходник USB-USART не определяется, посему не могу предоставить никакой отладочной информации, сам считываю с дисплейчика.
|
|
|
|
|
Jun 15 2010, 19:36
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Ну, я рад за вас. Выбросы происходят из-за того самого "нюанса", который теперь стоит обсудить. Дело в том, что между считыванием ICR1 и считыванием nover есть временной зазор, если прерывание TOV1 попадёт на него, то nover изменится на 1, хотя не должно. Вот такой нюанс. Подумайте сами, как его можно разрешить, завтра обсудим. Кстати, нельзя ли взглянуть на схему генератора струны?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 15 2010, 20:21
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Автогенератор в институте, и схемы от него нет, даже боюсь его развинчивать, но постараюсь что нибудь добыть когда там буду. Может быть запретить прерывания перед считыванием ICR1?  up: выбросы бывают и в меньшую сторону, около 1013 Гц.
|
|
|
|
|
Jun 16 2010, 10:10
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(ps1x @ Jun 15 2010, 19:21)  Может быть запретить прерывания перед считыванием ICR1?  Всё равно между захватом и запретом можем пропустить переполнение tov1 или tov0, хотя и реже. Расскажу, как работает код Код 1 TIFR=(1<<ICF1); //сбросим флаг захвата 2 while((TIFR&0x20)==0x20); //ждём начала измерения 3 ntick1=ICR1; //запомним ICR1 и TCNT0 4 mtick1=TCNT0; //в начале измерения 5 ntick2=nover; 6 mtick2=mover&0x00FF; 1. Сбросили флаг захвата, это понятно, чтобы будущее содержимое ICR1 и TCNT0 было синхронизировано. 2. Ждём захвата, чтобы текущее содержимое системного времени в TCNT1 защёлкнулось в ICR1 и чтобы содержимое TCNT0 соответствовало защёлкнутому времени. 3-4. Сохраняем содержимое ICR1 и TCNT0 в памяти для дальнейшего использования. 5. Сохраняем старшую часть 32-битного счётчика nover в памяти для дальнейшего использования. Заметьте, я специально оттянул время запоминания nover подальше от захвата п.2, чтобы дать время сработать возможному прерыванию и скорректировать nover. 6. Сохраняем старшую часть 32-битного счётчика mover в памяти для дальнейшего использования. Тут статика, никаких особенностей. Тут можно посмотреть варианты решения http://electronix.ru/forum/index.php?showtopic=16900
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 25 2010, 10:27
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Работает прекрасно  +/- 0.0001 мкС Большущее спасибо!
|
|
|
|
|
Jun 25 2010, 11:19
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
На здоровье.
Но 0,0001 мкс - это 0,1 нс, вы не ошиблись?
Меня ваш проект заинтересовал постольку, поскольку он написан на си (который я местами недолюбливаю :-), а на форуме было много вопросов, как реализовать мой алгоритм именно на си, но что-то все кодеры пропадали, не дойдя до конечного результата. Теперь одна из реализаций налицо, буду на неё ссылаться при случае :-).
Ещё, интересно было бы выяснить, какую максимальную частоту вы сможете измерить без переделки программы? С небольшими изменениями вы можете мерить до половины тактовой, в вашем случае до 6 МГц.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 25 2010, 12:00
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(=GM= @ Jun 25 2010, 15:19)  На здоровье. Простите, что вклиниваюсь, но возникает у меня вопросик. А что будет с прибором, когда частота очень низкая или её нет вовсе? Может я что не понял, но в коде есть "бесконечные" циклы, ожидающие события от периферии...
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jun 25 2010, 13:06
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(demiurg_spb @ Jun 25 2010, 11:00)  Простите, что вклиниваюсь, но возникает у меня вопросик. А что будет с прибором, когда частота очень низкая или её нет вовсе? Может я что не понял, но в коде есть "бесконечные" циклы, ожидающие события от периферии... Я уж испугался, что будет вопросик про Балеру или, того хуже, про прачечную :-). Это у вас с переездом связано, что ли? 1) У автора стоит автогенератор, вырабатывающий частоты в диапазоне 2-10 кГц, так что частота должна быть. 2) С другой стороны, если нет частоты, то вроде бы нечего отображать. 3) Однако, вы абсолютно правы в том, что данная программа имеет некоторые ограничения (как и всё в этом мире, впрочем). В программе нет модуля оценки входной частоты, просто в данном топике задача была не представить полностью коммерческий продукт, а немного другая, именно - написать программу на си для измерения частоты с минимальной погрешностью. Код программы открыт, так что, кому надо могут модифицировать его под себя. Задача в основном достигнута, 1000 Гц измеряются с СЕМЬЮ верными цифрами. Кстати, методом ворот можно достичь только ТРИ значащие цифры.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 26 2010, 09:13
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Цитата(=GM= @ Jun 25 2010, 15:19)  Но 0,0001 мкс - это 0,1 нс, вы не ошиблись? Наверное ошибся. +/-0.0001 Гц было точно при частоте ~1018 гц Цитата(=GM= @ Jun 25 2010, 15:19)  Ещё, интересно было бы выяснить, какую максимальную частоту вы сможете измерить без переделки программы? С небольшими изменениями вы можете мерить до половины тактовой, в вашем случае до 6 МГц. Завтра попробую.
|
|
|
|
|
Jun 27 2010, 19:19
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(=GM= @ Jun 25 2010, 17:06)  Я уж испугался, что будет вопросик про Балеру или, того хуже, про прачечную :-). Это у вас с переездом связано, что ли? Да нет:-) Разработчики пока на старом месте останутся. Цитата 1) У автора стоит автогенератор, вырабатывающий частоты в диапазоне 2-10 кГц, так что частота должна быть. 2) С другой стороны, если нет частоты, то вроде бы нечего отображать. 3) Однако, вы абсолютно правы в том, что данная программа имеет некоторые ограничения (как и всё в этом мире, впрочем). В программе нет модуля оценки входной частоты, просто в данном топике задача была не представить полностью коммерческий продукт, а немного другая, именно - написать программу на си для измерения частоты с минимальной погрешностью. Код программы открыт, так что, кому надо могут модифицировать его под себя.
Задача в основном достигнута, 1000 Гц измеряются с СЕМЬЮ верными цифрами. Кстати, методом ворот можно достичь только ТРИ значащие цифры. Понятно. Но я вижу лёгкое неудобство в том что надо детектировать наличие частоты. Я в своём тахометре работаю по двум алгоритмам и когда надо перехожу с одного на другой. Но как всегда есть одно но. Хочется повысить быстродействие измерительного канала и при этом не потерять в точности, вот я и приглядываюсь к Вашему методу. Пока лишь смотрю, т.к. сразу не вижу простого и красивого способа его применить.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jun 28 2010, 11:34
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
1) В чём конкретно вы видите лёгкое неудобство от детектирования?
2) Так всё таинственно, ну расскажите, что за алгоритмы...
3) Не знаю, что вы понимаете под красиво и легко, но посмотрел вполглаза на паспорт вашего тахометра, и увидел, что ваша "детская" погрешность в 1 Гц для 1000 Гц моим методом может быть легко превышена за время измерения 0,001 с (с погрешностью не более +-0,1 Гц).
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jun 28 2010, 17:34
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(=GM= @ Jun 28 2010, 15:34)  1) В чём конкретно вы видите лёгкое неудобство от детектирования? Теряется единообразие для быстрых и медленных частот (у меня же от 0,001Гц индикация работает). Да и со свободными таймерами могут быть напряги. Надо попробовать т.к это лишь предположения:-) Цитата 2) Так всё таинственно, ну расскажите, что за алгоритмы... Считаю либо кол-во импульсов за секунду, либо интервалы между импульсами, а переключаюсь по условию наименьшей погрешности измерения. Цитата 3) Не знаю, что вы понимаете под красиво и легко, но посмотрел вполглаза на паспорт вашего тахометра, и увидел, что ваша "детская" погрешность в 1 Гц для 1000 Гц моим методом может быть легко превышена за время измерения 0,001 с (с погрешностью не более +-0,1 Гц). При этом имеем динамическую индикацию и клавиатуру, modbus до 921.6КБод, DAC, счётчик импульсов и счётчик времени наработки, внешние логические входы-выходы и ещё всякого разного функционала немало наберётся, да и бутлоадер отъедает часть флеша. Я не спорю, что можно лучше, я даже уверен в этом. Но ресурсов контроллера уже особо не хватает на сильный импрувмент:-( Приборчик то старенький уже, сейчас бы на кортексе делал а не на 16 (162)-ой меге. Вот я и примеряюсь, обдумываю неспешно, т.к. текущий проект много сил требует... Как вспомню, сколько нервов истратил на его сертификацию в Морском регистре, уууу.... то дисплей им с регулировкой яркости подавай, то корпус горючий, то питание =24В с нехилым гистерезисом и все эти требования постепенно выдают ведь собаки такие:-)
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Jun 28 2010, 21:56
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(demiurg_spb @ Jun 28 2010, 16:34)  Теряется единообразие для быстрых и медленных частот (у меня же от 0,001Гц индикация работает) Ну, это вы ещё не прочувствовали мой алгоритм, в этом плане он универсальный. Можно или задаться числом периодов M=1, когда измеряете период длинного импульса, близкого к интервалу наблюдения, или целое число периодов М>1, также близкого к интервалу наблюдения, когда измеряете более короткие импульсы. Вся прелесть метода в том, что погрешность измерения минимальна всегда, невзирая на номинал входной частоты, поэтому не надо переключаться с одного алгоритма на другой, полное "единообразие" по-вашему.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 3 2010, 16:19
|
Частый гость
 
Группа: Свой
Сообщений: 127
Регистрация: 4-04-07
Из: Ижевск
Пользователь №: 26 773

|
В mega8 есть аналоговый компаратор, имеющий доступ к модулю CAPT таймера1 и непосредственно вход ICP1. Переключаясь программно между двумя режимами работы таймера, можно измерить обе частоты. Цитата(=GM= @ Jun 29 2010, 01:56)  ...Можно или задаться числом периодов M=1, когда измеряете период длинного импульса, близкого к интервалу наблюдения, или целое число периодов М>1, также близкого к интервалу наблюдения, когда измеряете более короткие импульсы. Вся прелесть метода в том, что ... Задаваться числом М можно, но ведь заранее неизвестно, какой сигнал придет, а вот подсчитать целые числа M и N за выбранный примерно интервал измерения - запросто.
|
|
|
|
|
Nov 3 2010, 18:15
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Цитата(akl @ Nov 3 2010, 20:19)  В mega8 есть аналоговый компаратор, имеющий доступ к модулю CAPT таймера1 и непосредственно вход ICP1. Переключаясь программно между двумя режимами работы таймера, можно измерить обе частоты. Мне тут умные люди подсказали что при измерении двух струн собственно измерения должны проводиться одновременно. В таком случае может использовать T0 и T1 входы таймеров а подключать их программно через транзистор? без ICP... А на входе поставить внешний компаратор, например lm339n. ps. А вот и GM!
|
|
|
|
|
Nov 3 2010, 18:39
|
Частый гость
 
Группа: Свой
Сообщений: 127
Регистрация: 4-04-07
Из: Ижевск
Пользователь №: 26 773

|
Цитата(ps1x @ Nov 3 2010, 15:50)  Судя по всему нужно подключать датчики и считать по очереди. Я исходил из этого. По новой вводной можно сказать -если две струны это составляющие одного преобразователя -если они возбуждаются индивидуальными автогенераторами, причем исключена возможность их взаимосинхронизации -если будут учтены различия в работе Т0 и Т1, то, наверно, можно. ИМХО, я бы, в таком случае, поставил две ATtiny2313 с тактированием от одного кварцевого генератора.
|
|
|
|
|
Nov 3 2010, 20:40
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Если измерять частоты надо одновременно, то вот вам пара путей реализации.
1) Взять два МК, те же тайни, в них - одна и та же уже готовая программа с единственным отличием - один МК получает измеренную частоту из второго, скажем, по spi или уарт, не суть важно.
2) Взять один МК с двумя схемами захвата, программа будет посложнее, но тоже реализуема в обозримое время.
Какой вариант реализации выбрать - зависит от вашей лености.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 3 2010, 20:50
|
Местный
  
Группа: Свой
Сообщений: 300
Регистрация: 15-03-06
Из: Москва
Пользователь №: 15 284

|
Но ведь вроде T0 и T1 асинхронные, и считают независимо от исполнения других комманд? Сейчас автогенератор работает в режиме перевозбуждения (что не есть гуд и приводит к нелинейности), вообще планируется выходной сигнал через прецезионный выпрямитель пустить на АЦП и таким образом завести ООС, чтобы датчик был с линейной характеристикой. Поскольку частоты не велики, нет ну правда, всего-то два сигнала 10кГц каждый, думается можно вполне все успевать. Цитата(=GM= @ Nov 4 2010, 00:40)  2) Взять один МК с двумя схемами захвата, программа будет посложнее, но тоже реализуема в обозримое Т.е. все таки без двух захватов не обойтись? А если программно отключать входы? Мне сверх высокая точность не нужна, достаточно двух знаков после запятой, дальше все равно уже шумы, вибрации, и т.п.
|
|
|
|
|
Nov 3 2010, 22:55
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Ну, вот вам ещё вариант: берёте МК с тремя таймерами и одним захватом. Входные сигналы на таймер0 и таймер2, и их же подаёте через коммутатор на схему захвата. Дальше, думаю, не надо объяснять.
Вообще, для оценки частоты с двумя знаками после запятой, вам достаточно взять время измерения 10 мс. Предположим, что время интеграции вашей системы будет больше, т.е. вы измеряете постоянную величину. Исходя из этого, вот вам ещё вариант - измеряете частоты последовательно: F1, F2, F1, F2, F1,... Измерения затем можно статистически обработать. Стандартная девиация - очень важный параметр для оценки качества, не пренебрегайте.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 7 2010, 13:54
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 18-06-10
Пользователь №: 58 001

|
=GM= Заинтересовался Вашим способом, давно хотел сделать частотомер на работу, но как то не получалось.. Скомпоновал исходник из вашего поста 32 и поста 13 ps1x. Пробовал в протеусе и vmlab 315, показания пляшут. Из темы понял что это окончательный вариант алгоритма и все должно работать. Переменную Fx не выводил, смотрел в окне watch (я пока не знаю как вывести float, не используя fprint и т.п.). Ну и вот тут у меня не понятки Код TIMSK &=~_BV(TOIE1); //запретим прерывания TOV1 do { // } while((TIFR&_BV(TOV1))==0); //ждём начала измерения ntick1=ICR1; ntick2=nover; //запомним ICR1 и старшую часть if(TIFR &_BV(TOV1))// <----------------? { nover++; TIFR =_BV(TOV1); //сбросим TOV1 if(ntick1<0x8000) ntick2=nover; } Зачем нужен if, ведь после while((TIFR&_BV(TOV1))==0); флаг TOV1 будет поднят, а прерывания запрещены? И к стыду не понял это if(ntick1<0x8000) ntick2=nover; Прикрепил архив с проектом для протеуса и vmlab, алгоритм разбил на две функции, иначе в vmlab нельзя было поставить точки останова и увидеть N и M.
Сообщение отредактировал horoc - Nov 7 2010, 15:12
Прикрепленные файлы
f.zip ( 85.91 килобайт )
Кол-во скачиваний: 87
|
|
|
|
|
Nov 7 2010, 18:52
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Ну, трудно обьяснить, попробую. Цикл do ... while((TIFR&_BV(TOV1))==0) достаточно длинный и может так случиться, что возник TOV1, сделана проверка и выход, хотя переменная nover не была должным образом модифицирована. Случается это редко, но случается, ps1x как раз с этим и столкнулся. Вот для этого такие навороты. Реализаций программы может быть множество, возможно именно эта - не самая лучшая.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 7 2010, 19:16
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 18-06-10
Пользователь №: 58 001

|
Я поэкспериментировал немного, сделал вот так. Код void freg1(void){ TCCR1B=(0<<ICES1)|(0<<CS10);//stop TCNT1=0; TIFR =(1<<TOV1); TIMSK &=~_BV(TOIE1); nover=0; mover=0; TCCR1B=(0<<ICES1)|(1<<CS10);//start TIFR=(1<<ICF1); while((TIFR&_BV(ICF1))==0); if(TIFR &_BV(TOV1)) { nover++; TIFR =_BV(TOV1); } ntick2=nover; ntick1=ICR1; TIMSK |=_BV(TOIE1); mtick1=TCNT0; mtick2=mover; N1=((uint32_t)(ntick2)<<16)+(uint32_t) ntick1; //системные тики M1=((uint32_t)(mtick2)<<8) +(uint32_t) mtick1; //входные тики }
void freg2(void){ while(TCNT1<65525); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); TIFR=(1<<ICF1); while((TIFR&_BV(ICF1))==0); ntick2=nover; ntick1=ICR1; mtick1=TCNT0; mtick2=mover; N2=((uint32_t)(ntick2)<<16)+(uint32_t) ntick1; M2=((uint32_t)(mtick2)<<8) +(uint32_t) mtick1; N=N2-N1; M=M2-M1; Fx=12000000.0*(float)M/(float)N; } Может коряво  но прыгать перестало, но особо не тестировал еще. Только вот сейчас смотрю, почему при входном 1Мег результат 999996. Еще охота избавится от флоат, но не знаю как.
Сообщение отредактировал horoc - Nov 7 2010, 19:17
|
|
|
|
|
Nov 7 2010, 21:06
|
Участник

Группа: Участник
Сообщений: 41
Регистрация: 18-06-10
Пользователь №: 58 001

|
Вот еще на танцевал с бубном =GM= благодарю!  я на такой результат и не рассчитывал. Для моих сугубо радиолюбительских целей лучше не надо. -------------------------- немного изменил код
Сообщение отредактировал horoc - Nov 8 2010, 19:37
Прикрепленные файлы
2.zip ( 23.44 килобайт )
Кол-во скачиваний: 200
|
|
|
|
|
Jun 19 2011, 11:32
|
Группа: Новичок
Сообщений: 4
Регистрация: 17-04-11
Пользователь №: 64 424

|
Приветствую. Я плохо разбираюсь пока что в микроконтроллерах, но вот надо сделать частотомер, хотя там на самом деле толщиномер пойдет, но принцип на измерении частоты. Подскажите пожалуйста пойдет ли последняя схема при измерении частоты до 1 МГц и так же в какой форме там выходной сигнал (я так понял там какой то счетчик на выходе стоит) и как его вывести на LCD или что то подобное. Благодарю заранее. Заранее извиняюсь что такие простые вопросы спрашиваю, просто разобраться надо быстро, в процессе буду изучать.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|