Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

Проблем на честотомер с Атмега32
http://mcu-bg.com/mcu_site/viewtopic.php?f=3&t=8739
Страница 1 от 2

Автор:  the_bull [ Чет Мар 24, 2011 6:39 pm ]
Заглавие:  Проблем на честотомер с Атмега32

Здравейте, от известно време се мъча с направата на честотомер елемнтарен, който да мери честота в диапазона до 10 кHz. Използвам Атмега32 на 4 MHz. Измерването го правя като броя входните импулси с таймер/брояч 1 който пък нулирам през определен период с таймер 2. Теоритично би трябвало да измерва честота до 65 kHz като калибрирам системата и като знам, че брояа ми е 16 битов. Работя с микро С за АВР на микроелектроника. Но имам много гаден проблем и не мога да хвана къде греша. Това ми е сорса държа да подчертая че съм доста начинаещ и може би това не е най добрия метод за направа на честотомер. Ето това ми е сорса:
Код:
                /*// LCD module connections
sbit LCD_RS at PORTA5_bit;
sbit LCD_EN at PORTA4_bit;
sbit LCD_D4 at PORTA3_bit;
sbit LCD_D5 at PORTA2_bit;
sbit LCD_D6 at PORTA1_bit;
sbit LCD_D7 at PORTA0_bit;

sbit LCD_RS_Direction at DDA5_bit;
sbit LCD_EN_Direction at DDA4_bit;
sbit LCD_D4_Direction at DDA3_bit;
sbit LCD_D5_Direction at DDA2_bit;
sbit LCD_D6_Direction at DDA1_bit;
sbit LCD_D7_Direction at DDA0_bit;
// End LCD module connections*/

// LCD module connections
sbit LCD_RS at PORTD2_bit;
sbit LCD_EN at PORTD3_bit;
sbit LCD_D4 at PORTD4_bit;
sbit LCD_D5 at PORTD5_bit;
sbit LCD_D6 at PORTD6_bit;
sbit LCD_D7 at PORTD7_bit;

sbit LCD_RS_Direction at DDD2_bit;
sbit LCD_EN_Direction at DDD3_bit;
sbit LCD_D4_Direction at DDD4_bit;
sbit LCD_D5_Direction at DDD5_bit;
sbit LCD_D6_Direction at DDD6_bit;
sbit LCD_D7_Direction at DDD7_bit;
// End LCD module connections


unsigned  int count,oldCount,count1,Rh;
char txt[8],txt2[8];
const char _THRESHOLD = 16;
char counter,flag;

void Timer2Overflow_ISR() org IVT_ADDR_TIMER2_OVF {

  if (counter >= _THRESHOLD) {
     count1 = ((TCNT1H<<8)+TCNT1L);
     //count=count1;//-(count1*0.044);
     oldCount = count1;
     //Rh=565.3-(oldCount*0.07675);
     count1 = 0;
     counter = 0;
     TCNT1H=0;
     TCNT1L=0;

  }
  else
    counter++;                    // increment counter
}
void main() {
     SREG_I_bit = 1;                   // Interrupt enable
     TOIE2_bit  = 1;                  // Timer2 overflow interrupt enable
     TCCR2  = 0x07;                   // Start timer with 1024 prescaler
     TCCR1A = 0x00;                   //Setup TC1 to count PB1
     TCCR1B = 0x07;
  Lcd_Init();                                   // Initialize LCD
  Lcd_Cmd(_LCD_CLEAR);                          // Clear LCD
  Lcd_Cmd(_LCD_CURSOR_OFF);                     // Turn cursor off
  Lcd_Out(1, 1, "Frecuncy:");
  Lcd_Out(2,15,"Hz");
  while (1) {
  count = ((TCNT1H<<8)+TCNT1L);
  //Rh=565.3-(oldCount*0.07675);
  WordToStr(count, txt2);
  Lcd_Out(1, 10, txt2);
  WordToStr(oldCount, txt);
  Lcd_Out(2,1,txt);

  }
}

Проблема ми е следния. Това нещо работи и измерва, но примерно аз му подавам 6600 Hz то през голяма част от времето показва тази стойност, но на моменти показва примерно 6900 Hz. Прави го напълно произволно и най лошото е че не съм сигурен софтуерен ли е проблема или в хардуера ми. Склонен съм да мисля че е софтуерен защото на няколко пъти го бях укротил да си показва честотата колкото е. И само като добавя 1 сметка която трябва да имам започваха сривовете. Някой ако може да помогне със съвети или покаже къде греша в подхода. Да подчертая също че проблема не е в генератора от който подавам сигнал, прави го при 2 различни генератора. Също така генераторите ги контролирам с честотомер и няма подобен проблем. Всичко идва от моето устройство.

Сорса е сглобяван с фрагменти от example на микро С така, че голяма част от него е ползван като готов такъв. Ако може някой да ми обясни и как точно функционират прекъсванията. Аз знам доста за това какво представляват и как да ги използвам но не разбирам защо микро С то не ми позволява да ги влагам във функции и може би греша нещо спрямо тях.

Автор:  marcuka68 [ Вто Апр 05, 2011 10:35 pm ]
Заглавие: 

Пробвай да видиш какъв резултат дава (а << 8), когато а е от тип char. Честота не съм мерил, но изразът, с който взимаш стойността на двата регистъра на таймера, ми изглежда грешен. А не можеш ли да я вземеш наведнъж: а = TCNT1; ?

Автор:  the_bull [ Вто Апр 05, 2011 10:51 pm ]
Заглавие: 

Здравей и благодаря за съветите. Проблема мисля се отстрани като направих някой корекции в сорса. Също така преди това бях се заблудил нещо и вместо да работи с външен кварц работеше на вътрешен осцилатор. Сега се е укротило след като всичко му е сетнато както трябва. В случая използвам микроС и в него няма дефиниран този регистър TCNT1 като 16 битов а е разделен на 2 регистъра по 8 бита. Преобразуването си е добре и е коректно. Проблем до някъде е, че права много неща в прекъсването, по принцип не е хубаво ама работи перфектно така. Като се опитам да изнеса някой сметки извън прекъсване стават гафове затова засега смятам в прекъсването. Днес дори мигрирах на 16MHz, че преди това работих на 4. Сега остава да навържа още няколко модула към системата без да се скапе нещо.

Автор:  marcuka68 [ Сря Апр 06, 2011 8:35 am ]
Заглавие: 

Странно, аз съм имал проблеми с такъв израз, но щом върви, добре е :)

Автор:  radiko [ Пет Мар 23, 2012 1:52 pm ]
Заглавие:  Re: Проблем на честотомер с Атмега32

Колега радвам се че си пуснал тази тема. Това е нещо което ме интересува живо. Мислех и аз да се захващам с експерименти но за щастие се сетих първо да потърся в нета.
накратко трябват ми повечко такива честотомери за автоматизиране на едни измервания. Бих се радвал ако ти или някой друг който чете тази тема и се се интересува. Се свърже с ме. за да поработим съвместно по въпроса може би ще се наложи да отворя и нова тема но сега очаквам отзиви тук

Автор:  bkulev [ Нед Апр 01, 2012 10:15 am ]
Заглавие:  Re: Проблем на честотомер с Атмега32

Помисли в/у този израз: "count = ((TCNT1H<<8)+TCNT1L);"
Както и да го напишеш на 'C', ако процесора ти е 8 битов реално регистрите ще се прочетат в различно време. И какво ще се случи с крайния резултат, ако точно в момента настъпи пренос от 'L' към 'H'?
Приципът е: Операцията по четенето на променлива, която се изменя в прекъсване или от някакъв външен процес, трябва да бъде АТОМИЧНА.

Автор:  ps66 [ Нед Апр 01, 2012 11:20 am ]
Заглавие:  Re: Проблем на честотомер с Атмега32

bkulev написа:
този израз: "count = ((TCNT1H<<8)+TCNT1L);"
...

на човешки помпилатор, най-вероятно винаги ще е count = TCNT1L;
(ако някой се чуди ... що? - нека се сети че става въпрос за 8-битова аритметика)

Автор:  tgi [ Нед Апр 01, 2012 1:24 pm ]
Заглавие:  Re: Проблем на честотомер с Атмега32

bkulev написа:
Помисли в/у този израз: "count = ((TCNT1H<<8)+TCNT1L);"
Както и да го напишеш на 'C', ако процесора ти е 8 битов реално регистрите ще се прочетат в различно време. И какво ще се случи с крайния резултат, ако точно в момента настъпи пренос от 'L' към 'H'?
Приципът е: Операцията по четенето на променлива, която се изменя в прекъсване или от някакъв външен процес, трябва да бъде АТОМИЧНА.


А, защо, не непременно. Стандарнтият начин е:
-прочита се старшия
-прочита се младшия
-прочита се старшия
-ако двете прочетени стойности на старшия се различават, повтаря се цялата последователност.

Автор:  perlsite [ Нед Апр 01, 2012 10:57 pm ]
Заглавие:  Re: Проблем на честотомер с Атмега32

Не съм убеден, че това е надежден подход, тъй като между двете четения на старшият байт могат да настъпят промени, при което старшият байт при второто четене отново да е с началната си стойност, но младшия байт вече да е променен...?!

Автор:  itso.t [ Нед Апр 01, 2012 11:03 pm ]
Заглавие:  Re: Проблем на честотомер с Атмега32

...старшият байт винаги е с различна стойност = while(1) ? :D

Автор:  perlsite [ Пон Апр 02, 2012 1:53 am ]
Заглавие:  Re: Проблем на честотомер с Атмега32

Код:
0b11010 11110100 -> 6900
0b11001 11001000 -> 6600
    0b1 00101100 -> 300


Прави ми впечатление, че старшият байт се увеличава точно с едно...

Автор:  tgi [ Пон Апр 02, 2012 2:25 am ]
Заглавие:  Re: Проблем на честотомер с Атмега32

itso.t написа:
...старшият байт винаги е с различна стойност = while(1) ? :D


Ти се майтапиш ама май те взеха насериозно :D :D :D

Автор:  the_bull [ Пон Апр 02, 2012 10:36 pm ]
Заглавие:  Re: Проблем на честотомер с Атмега32

Наистина не е най-добрия вариант за направа на честотомер, но на мен ми свърши работа.
Проблема с отскоците не съм много сигурен, но мисля че беше от кофти кварц, и не добре сетнати fuse битове. Когато имаше проблемите работеше на вътрешен осцилатор а мислех, че работи на кварц, и някъде оттам ми се струва че беше този бъг.
Това преобразуване, което коментирате при други компилатори не би се наложило.В datasheeta има примерен сорс за 16-битовия таймер и там си има посочен 16-битов регистър от който може да се чете директно стойността. AVR Studioto си го познава, но на микро С то не беше добавян този регистър и затова си реших на бързо проблема по този начин.

Автор:  bkulev [ Вто Апр 03, 2012 4:28 pm ]
Заглавие:  Re: Проблем на честотомер с Атмега32

Ако няма друг надежден и бърз начин, то най - сигурният е:
Disable Interrupt;
count = ((TCNT1H<<8)+TCNT1L);
Enable Interrupt;

Защото, колега сега може и да не се виждат някакви "отскоци", "несъответствия" или каквото там му викаш, но бъди сигурен ЩЕ ИМА. Друг е въпросът дали ти ще ги забележиш. :)
Така че както е казал нашия мъдър народ: "Вържи попа, та да е мирно селото"

Автор:  tgi [ Вто Апр 03, 2012 5:07 pm ]
Заглавие:  Re: Проблем на честотомер с Атмега32

Е ако са две 8 бита четения (т.е. два отделни цикъла) маскирането на прекъсванията
няма да върже попа :) .

Страница 1 от 2 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/