Отговори на тема  [ 33 мнения ]  Отиди на страница 1, 2, 3  Следваща
Измерване на период с PIC16F 
Автор Съобщение
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Дек 20, 2016 6:39 pm
Мнения: 32
Местоположение: Русе
Мнение Измерване на период с PIC16F
Здавейте! Идеята ми е да измеря периода на сигнал от приемник на радиоуправляем модел. Целта е да се направи спийд контролер за постояннотоков четков електромотор на същия модел кола, както и модул за дистанционно управление на светлините по модела.
Нещата стоят така: периодът е с дължина 20 милисекунди, като това, което ме интересува е колко точно е дължината на импулса (високо логическо ниво). Последния варира в границите 0,5 до 1,5 милисекунди:

Изображение
Това, което съм измислил и направил до момента е да стартирам таймер с време на прекъсване 1 микросекунда, и когато логическото ниво стане 0 да спра таймера. По този начин очаквам да получа стойности на брояча на таймера от 1500 до 2500 (с малък толеранс). Като резултат от софтуерните тестове забелязах, че толерансите не са чак толкова малки, от 1500us на сигналгенератор MCU измерва всеки път различно с около 200us нагоре или надолу. Въпросите ми са: 1) За толкова малко време на таймера достатъчна ли е тактова честота 4MHz на процесора и възможно ли е това да е причината за ниската резолюция на измерването? 2) Ще се получи ли по-точно със CCP модула на микроконтролера?
Това е кода, който съм "съчинил" до сега, твърде възможно е да изглежда недовършено:
Код:
int timer = 0, period = 0;

  void InitTimer0(){
  OPTION_REG    = 0x88;
  TMR0       = 255;
  INTCON    = 0xA0;
  }
 
  void Interrupt(){
    if (TMR0IF_bit){
    TMR0IF_bit    = 0;
    TMR0       = 255;
      if(RB0_bit) timer++;
      if(!RB0_bit){
       period = timer;
       timer = 0;
      }
    }
  }

void main() {
  TRISB = 0;
  TRISB0_bit = 1; //Read Pin
  PORTB = 0;
  InitTimer0();
 
  while(1){
  }
}


Ако някой има някакви идеи ще се радвам да ги сподели, защото явно трябва да сменя подхода.
Благодаря ви за отделеното време!

_________________
Никола Богданов
16 години


Нед Апр 09, 2017 7:58 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Ное 27, 2012 8:27 pm
Мнения: 2008
Мнение Re: Измерване на период с PIC16F
4 Мхз е добре но те съветвам направо да потърсиш специализиран чип, не са скъпи и са достъпни. Правих на времето подобни шуротийки но не помня чипа, а нямам достъп до харда понеже му затрих платката.


Нед Апр 09, 2017 9:13 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Яну 01, 2012 7:04 pm
Мнения: 2581
Местоположение: Велико Търново / София
Мнение Re: Измерване на период с PIC16F
Тея if-ве нещо не ми харесват. Когато на RB0 стане 1ца примерно влизаш в прекъсването. Нулираш брояча ( TMR0=0 ) чакаш RB0 да стане 0ла, записваш резултата на брояча RESULT = TMR0, и това е. По съвършен начин е брояча да се нулира от прекъсване по високо ниво наRB0, а резултата да се записва при прекъсване генерано от ниско ниво на RB0.

_________________
https://github.com/slav4ocom/


Нед Апр 09, 2017 9:34 pm
Профил
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Пет Фев 14, 2014 3:45 pm
Мнения: 420
Местоположение: Монтана
Мнение Re: Измерване на период с PIC16F
При 4 MHz на системния клок, без активен PLL - instruction clock ще бъде 1 MHz. Т.е. ако завържеш Timer 1 (16-бит) към instruction clock с prescaller 1:1 - таймера ще се увеличава с 1 на всяка микросекунда. Препълването (и съответно да предизвика прекъсване, ако си му включил Timer 1 interrupt) ще става на всеки 65536 микросекунди (малко над 65 милисекунди). Времена от порядъка на 1-20 милисекунди можеш да измерваш с него със сравнително добра точност, като нулираш таймера в подходящите моменти според логиката на програмата.

Или ако искаш да направиш така, че проца да изчака 20 милисекунди, и тогава да направи нещо - сетваш Timer 1 със стойност около 45536 (плюс още малко, за да компенсираш тактовете, необходими за самото изпълнение на инструкциите - обикновено се донастройва опитно след като схемата тръгне), и препълването ще трябва да се случи след точно определеното време.

Tmr0 = 255 е много, ама много лоша идея. Необходимо е процесорно време за всяка една инструкция, а това включва и самите преходи към и от Interrupt. С такава реализация отклоненията е съвсем нормално да са големи.


П.П. Не си писал какъв процесор ще използваш. Огледай дейташийта, да видиш дали въпросния пин има IOC (interrupt on change). Така промяната на входа му ще предизвиква прекъсване, и в процедурата просто ще "измерваш" стойността на Timer 1, и така ще знаеш колко милисекунди е траел импулса.

П.П.2. С външен кварц честотата на системния клок може да е точна, но ако си го спестил, и използваш вътрешния RC осцилатор - той си дава грешка по принцип.
Наздраве. :partyman:

_________________
Не карай по-бързо от своя ангел-пазител!


Нед Апр 09, 2017 11:05 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Май 29, 2007 1:23 pm
Мнения: 3545
Местоположение: Високо в планината
Мнение Re: Измерване на период с PIC16F
slav4o.com написа:
..По съвършен начин е брояча да се нулира от прекъсване по високо ниво наRB0, а резултата да се записва при прекъсване генерано от ниско ниво на RB0.

хм. Това пък защо. Така резултатът му ме зависи от коефиц. на запълване и нивата на сработване (различни при 1 и 0).
Иначе каква е идеята на това, което пишеш?

_________________
Хайде де!


Пон Апр 10, 2017 7:00 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Яну 01, 2012 7:04 pm
Мнения: 2581
Местоположение: Велико Търново / София
Мнение Re: Измерване на период с PIC16F
dan написа:
slav4o.com написа:
..По съвършен начин е брояча да се нулира от прекъсване по високо ниво наRB0, а резултата да се записва при прекъсване генерано от ниско ниво на RB0.

хм. Това пък защо. Така резултатът му ме зависи от коефиц. на запълване и нивата на сработване (различни при 1 и 0).
Иначе каква е идеята на това, което пишеш?

Ами да се види колко "бройки" е натрупал брояча докато нивото е високо. Т.е. да се измери дължината на импулса във високо ниво, то това го интерува уж. А и забравих нещо, може би брояча на таймера е 8 битов, та ако прескалера е 1:1 т.е. работи на 1MHz периода е 1us и ще брои до 255 us. Което не е достатъчно, ако периода е до 2 ms може да се сложи прескалера на 1:8 което ще е минимума, но пък точността ще е макс. добра - стъпка 8us.

_________________
https://github.com/slav4ocom/


Пон Апр 10, 2017 7:10 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Май 29, 2007 1:23 pm
Мнения: 3545
Местоположение: Високо в планината
Мнение Re: Измерване на период с PIC16F
Сега прочетох поста на момчето :) Той всъщност иска да мери продължителност на импулса, а не период... Ясно :)

_________________
Хайде де!


Пон Апр 10, 2017 7:17 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Яну 01, 2012 7:04 pm
Мнения: 2581
Местоположение: Велико Търново / София
Мнение Re: Измерване на период с PIC16F
То може и в двете прекъсвания да се мери и да се нулира брояча. После да си ги смята :)

_________________
https://github.com/slav4ocom/


Пон Апр 10, 2017 7:21 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 8:21 pm
Мнения: 27949
Местоположение: София
Мнение Re: Измерване на период с PIC16F
Точно същото нещо седискутира в друга тема, не е лошо да пусне един сърч.


Пон Апр 10, 2017 8:17 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Апр 27, 2005 11:48 am
Мнения: 4671
Мнение Re: Измерване на период с PIC16F
Алтернативата е да ползваш приемник по UART (виж Дрон) протокола може да го вземеш примерно от GitHub - betaflight, cleanflight....

_________________
main[-1u]={1};


Пон Апр 10, 2017 9:03 am
Профил ICQ
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Чет Май 10, 2007 2:49 pm
Мнения: 97
Мнение Re: Измерване на период с PIC16F
използвай CCP модул, в capture mode


Вто Апр 11, 2017 9:53 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Дек 20, 2016 6:39 pm
Мнения: 32
Местоположение: Русе
Мнение Re: Измерване на период с PIC16F
Здравейте отново! Бях позарязал темата, но сега ми се отвори малко време и реших да продължа проекта. Та накратко реших да послушам съветите на pechkov, дадени ми по-нагоре в тази тема.
Като за начало се позанимавах с Timer 1, и по-конкретно използвах онлайн калкулатор, като му зададох прескалер 1:1, тактова честота на процесора 4MHz, и TMR1 пресет 0. Според калкулатора периода на прекъсване се получи 65536 микросекунди. Реших да проверя дали наистина таймера ще се увеличава с 1 на всяка микросекунда, и за целта инициализирах UART, и му зададох на всеки 100us да изписва стойността на TMR1L. Това, което ме учуди е, че виртуалния терминал изписва числото 14, тоест малко преди да се ресетне TMR1L е бил 14, а не 65536 както очаквах. Това, което ми идва на ум е, че това не е моята променлива, която трябва да следя, и съответно според която да измерван дължината на импулса, което всъщност е целта :) . Това е кода:
Код:
char txt[7];
int time;

void InitTimer1(){
T1CON.T1CKPS1 = 0;   // bits 5-4  Prescaler Rate Select bits
T1CON.T1CKPS0 = 0;   // bit 4
T1CON.T1OSCEN = 1;   // bit 3 Timer1 Oscillator Enable Control bit 1 = on
T1CON.TMR1CS = 0;    // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
T1CON.TMR1ON = 1;    // bit 0 enables timer
TMR1H = 0;             // preset for timer1 MSB register
TMR1L = 0;             // preset for timer1 LSB register

  INTCON = 0;
  INTCON.TMR0IE = 0;
  PIR1.TMR1IF = 0;
  PIE1.TMR1IE  =   1;
  INTCON.TMR0IF = 0;
  INTCON.GIE = 1;
  INTCON.PEIE = 1;
  INTCON    = 0xC0;
}

void Interrupt(){
  if (TMR1IF_bit){
    TMR1IF_bit = 0;
    time = TMR1L;
    TMR1H    = 0;
    TMR1L    = 0;
  }
}

void main() {
  TRISB = 0;
  TRISB1_bit = 1;
  PORTB = 0;
  InitTimer1();
  UART1_Init(9600);

  while(1){
    IntToStr(time, txt);
    UART1_Write_Text(txt);
    delay_ms(100);
  }
}


Благодаря предварително!

_________________
Никола Богданов
16 години


Съб Май 20, 2017 12:48 pm
Профил
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Пет Фев 14, 2014 3:45 pm
Мнения: 420
Местоположение: Монтана
Мнение Re: Измерване на период с PIC16F
Nyakоi написа:


По-добре дефинирай още една променлива, и на всяко прекъсване от Timer1 я увеличавай с 1. Когато стойността на променливата достигне 100 - промени състоянието на някой изходен пин, и му закачи светодиод. Ако прекъсването на Timer1 се случва на всеки 0.065536 сек, то 100 прекъсвания ще трябва да се случат за 6.5536 сек… което е доста по-лесно да го измериш "на око" дори. Или ако имаш осцилоскоп - може и без такива еквилибристики, и просто на всяко препълване на таймера да правиш обръщане на състоянието на изходния пин.

П.П. Забавянето в main-а си го направил не 100 us, а 100 ms, което е доста по-различно. Освен това всяко превъртане на тези две функции в main отнема време, и не са синхронизирани с таймера, така че по този начин не може да се хване точно кога ще се препълни таймера.

Освен това TMR1L е само половината от стойността на таймера. Понеже това е 16-битов таймер - неговата стойност се записва в два байта - TMR1H и TMR1L. Прехвърлянето на стойността към time го правиш след като таймера се е препълнил, и вземаш само младшия му байт, което е нормално да ти връща такива стойности.

_________________
Не карай по-бързо от своя ангел-пазител!


Съб Май 20, 2017 1:11 pm
Профил ICQ
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Дек 20, 2016 6:39 pm
Мнения: 32
Местоположение: Русе
Мнение Re: Измерване на период с PIC16F
За delay функцията и времето, което съм написал - объркал съм се, точно 100ms (милисекунди) са, а не микросекунди. Ще внимавам малко повече :)
Пробвах с допълнителна променлива и увеличаването ѝ, докато стане 100. Според Proteus 8 на около 6,50 секунди flip-ва изход на микроконтролера, тоест - всичко с таймера е както трябва.

За TMR1L - незнам дали е половината точно, но според Virtual Terminal-а TMR1L беше 150, а TMR1H - 10 (изписани една след друга променливите). Може би не са равни, защото IntToStr() отнема много процесорно време. Отказах се да се занимавам с тези битове от регистъра :) .

Предполагам, следващото, което трябва да направя, е да използвам хардуерно прекъсване, за да стартирам таймера. Не мога да схвана обаче как трябва да "детектна" ниското ниво (след като вече е било засечено високо такова чрез специалния пин 0 на PIC-а) и съответно да спра таймера, за да имам записано в променлива времето, през което съм подавал единица на входа.

_________________
Никола Богданов
16 години


Съб Май 20, 2017 2:14 pm
Профил
Ранг: Напреднал
Ранг: Напреднал
Аватар

Регистриран на: Пет Фев 14, 2014 3:45 pm
Мнения: 420
Местоположение: Монтана
Мнение Re: Измерване на период с PIC16F
Nyakоi написа:
… как трябва да "детектна" ниското ниво …


Най-добре ако процесора има IOC (Interrupt On Change) на въпросния порт. На някои процесори дори може да се настройва в регистрите дали да се предизвиква прекъсване при преминаване от ниско към високо ниво, или от високо към ниско, или и в двата случая. Тогава се вдига флаг, подобен на TMR1IF, само че е наречен по друг начин, например IOCAF. Кажи какъв процесор си избрал, ще му огледам дейташийта, и ще мога да предложа нещо по-конкретно като структура на програмата.

_________________
Не карай по-бързо от своя ангел-пазител!


Съб Май 20, 2017 2:19 pm
Профил ICQ
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 33 мнения ]  Отиди на страница 1, 2, 3  Следваща

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 6 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни