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

Регистриран на: Вто Дек 20, 2016 6:39 pm
Мнения: 32
Местоположение: Русе
Мнение Re: Измерване на период с PIC16F
Използвам PIC16F628a, както разполагам и с 16F84a, и 12F675 от малките PIC-ове. По принцип първоначалната идея беше програмата да е приложима за серията 12F, и по-нататък и за 16F заради повечето IO пинове, и съответно устройството ще е по-функционално. Предпочетох да подкарам нещата първо на 16F, защото има повече информация в интернет. Ще съм ти изключително благодарен ако ме ориентираш в структурата на програмата :)
Поздрави!

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


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

Регистриран на: Вто Дек 14, 2004 9:02 am
Мнения: 325
Мнение Re: Измерване на период с PIC16F
Някъде 1990г. и по-рано.
http://www.njr.com/semicon/PDF/NJM2611_E.pdf
https://www.voti.nl/docs/M51660L.pdf
http://twlwtwo.appspot.com/shema-standa ... hinki.html
Да не си помислиш че те съветвам да го правиш така, въпреки че би имало някаква полза.


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

Регистриран на: Вто Дек 20, 2016 6:39 pm
Мнения: 32
Местоположение: Русе
Мнение Re: Измерване на период с PIC16F
Незнам дали е коректно така да повдигам свои стари теми, но по-добре така, отколкото да отварям нова.
Справих се със задачката, използвайки CCP1 модула. Използвам вътрешния осцилатор на PIC16F628A (4MHz) и прескалер 1:1 на таймер 1. Доволен съм от резултата, точността е отлична.
И тук идва проблемът - реших, че искам да чета 3 такива сигнала, а пикчето разполага само със 1 CCP модул, работещ само на един от пиновете (RB3).
Възможно решение, което намерих в интернет: Таймер 0 (8 битов) прави периодично прекъсване, а таймер 1 (16 битов) върви свободно (буквален превод). При всяко прекъсване на таймер 0 се чете състоянието на дадения порт и се сравнява резултатът с предишния. Ако не съвпадат последните и логическото ниво е високо на даден пин на порта, се чете 16 битовият таймер, а ако е ниско се изважда предишната записана стойност от текущата на таймер 1.
Това е кодът, който сътворих и използвам в момента за 1 сигнал:
Код:
unsigned long t;
short flag = 0;
char txt[10];

void interrupt(void) {
if(flag == 0) {          //if rising edge detected
  CCP1CON = 0x04;  //wait for falling edge
  TMR1L = 0;            //clear TMR1L & TMR1H
  TMR1H = 0;
  PIR1.B2 = 0;
  flag = 1;
  }
else if(flag == 1) {    //if falling edge detected
  CCP1CON = 0x05;   //wait for rising edge
  t = TMR1H;            //read TMR1L & TMR1H
  t = t << 8;
  t = t | TMR1L;
  PIR1.B2 = 0;
  flag = 0;
  }
}

void main() {
UART1_Init(9600);
Delay_ms(100);
T1CON = 0x01;
CCP1CON = 0x05;
INTCON = 0xC0;
PIE1 = 0x04;
TRISB3_bit = 1;

while(1) {
  LongToStr(t, txt);
  UART1_Write_Text(txt);
  UART1_Write(10);
  UART1_Write(13);
  delay_ms(50);
  }
}

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

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


Съб Дек 09, 2017 6:42 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Чет Фев 03, 2005 1:21 am
Мнения: 10611
Местоположение: София
Мнение Re: Измерване на период с PIC16F
Nyakоi написа:
Незнам дали е коректно така да повдигам свои стари теми, но по-добре така, отколкото да отварям нова.
Справих се със задачката, използвайки CCP1 модула. Използвам вътрешния осцилатор на PIC16F628A (4MHz) и прескалер 1:1 на таймер 1. Доволен съм от резултата, точността е отлична.
И тук идва проблемът - реших, че искам да чета 3 такива сигнала, а пикчето разполага само със 1 CCP модул, работещ само на един от пиновете (RB3).
Възможно решение, което намерих в интернет: Таймер 0 (8 битов) прави периодично прекъсване, а таймер 1 (16 битов) върви свободно (буквален превод). При всяко прекъсване на таймер 0 се чете състоянието на дадения порт и се сравнява резултатът с предишния. Ако не съвпадат последните и логическото ниво е високо на даден пин на порта, се чете 16 битовият таймер, а ако е ниско се изважда предишната записана стойност от текущата на таймер 1...

Не е ясно какъв е очаквания период на сигналите и на таймер 0.
Ако сигналът смени състоянието си от 0 в 1 и пак в 0 преди да се е извъртял таймер 0? Или таймер 0 се ползва за дебоунс на сигналите?


Съб Дек 09, 2017 7:30 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Дек 20, 2016 6:39 pm
Мнения: 32
Местоположение: Русе
Мнение Re: Измерване на период с PIC16F
Според моите разбирания периодът трябва да е възможно най-малък, съответно честотата на проверяване най-висока. Беше спомената 32KHz честота на прекъсване, но не беше написано със сигурност. Като цяло не се гони голяма точност, а по-скоро добре работещо решение. В първия пост на темата бях споменал, че съм намислил 1) спийд контролер, при който ще използвам CCP модула заради голямата точност на декодиране (измерване) на сигнала, и 2) контролер за светлини, за който е по-важно да чете 3 такива канала коректно и с прилична скорост, а точността не е критична, защото ме интересува единствено кога дължината на импулса е в зададен интервал.

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


Съб Дек 09, 2017 7:41 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Дек 20, 2016 6:39 pm
Мнения: 32
Местоположение: Русе
Мнение Re: Измерване на период с PIC16F
Поиграх си с описания метод и взе, че тръгна, но дава известна грешка. С наклонени черти съм отбелязал частта от кода, която ми създава проблеми. Така, както са написани условията (!s1flag и s1flag) в проверката кода няма причина да работи правилно, тъй като това не е bool променлива, но премахвайки това второ условие кода се побърква тотално.
Интересното е, че в момента дава между 5 и 8 последователни верни измервания (генериран импулс с дължина 1500 микросекунди се измерва като 1502 микросекунди), а следващите 2 или 3 измервания ми ги дава с голяма грешка (с точно 256 микросекунди нагоре или надолу, тоест 1756 или 1244).
Променяйки кода от !s1flag и s1flag на s1flag == 0 и съответно s1flag == 1, както трябва да бъде, води до резултат 1487 или 1534, като двете стойности се редуват периодично през 2-3 измервания.
Играх си с прескалера, но резултат никакъв. TMR0 е 255 за да може да се препълни веднага и да генерира по-често прекъсване, в което да проверява състоянието на портовете. И с него си играх, става по-лошо. Подозирам гадната функция LongToStr() като виновна за забавяне в проверката, но към момента ми е единствената обратна връзка :(. Също така за сега тествам с 1 канал, незнам какво ще се случи като добавя още два.
Ако някой забележи нещо ще се радвам да го сподели. Благодаря!
Код:
unsigned long t1rise, t1fall, result = 0;
char txt[10];
short s1flag;

void Interrupt(){
  if (TMR0IF_bit){
    TMR0IF_bit = 0;
    TMR0 = 255;
    if(RB4_bit && !s1flag){       //
     t1rise = TMR1H;
     t1rise = t1rise << 8;
     t1rise = t1rise | TMR1L;
     s1flag = 1;
     }
     if(!RB4_bit && s1flag){      //
      t1fall = TMR1H;
      t1fall = t1fall << 8;
      t1fall = t1fall | TMR1L;
      result = t1fall - t1rise;
      LongToStr(result, txt);
      UART1_Write_Text(txt);
      UART1_Write(13);
      s1flag = 0;
    }
  }
  if (TMR1IF_bit){
    TMR1IF_bit = 0;
    TMR1H = 0x00;
    TMR1L = 0x00;
  }
}

void main() {
  TRISB4_bit = 1;
  OPTION_REG = 0b10001000; //Bits 0:2 prescaller rate select
  INTCON = 0b11100000;
  T1CON = 0x01;
  TMR1IE_bit = 1;
  UART1_Init(9600);
  while(1);
}


Нед Дек 10, 2017 9:26 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 1:01 pm
Мнения: 1952
Местоположение: Варна
Мнение Re: Измерване на период с PIC16F
Код:
#define TX_BUF_SIZE     (8)
#define T1_RISE             (0)
#define T1_FALL             (1)

unsigned short tx_buf[TX_BUF_SIZE][2];
volatile unsigned char tx_buf_head;
volatile unsigned char tx_buf_tail;

volatile unsigned char s1flag;



void Interrupt(){

  unsigned short t1val;

  if (TMR0IF_bit){
    TMR0IF_bit = 0;
    TMR0 = 255;
    if(RB4_bit && !s1flag){       //
        t1val = TMR1H;
        t1val = t1val << 8;
        t1val = t1val | TMR1L;

        tx_buf[tx_buf_head % TX_BUF_SIZE][T1_RISE] = t1val;

        s1flag = 1;
     }
     if(!RB4_bit && s1flag){      //
         t1val = TMR1H;
         t1val = t1val << 8;
         t1val = t1val | TMR1L;

          tx_buf[tx_buf_head % TX_BUF_SIZE][T1_FALL] = t1val;
          tx_buf_head++;

          s1flag = 0;
    }
  }
  if (TMR1IF_bit){
    TMR1IF_bit = 0;
    TMR1H = 0x00;
    TMR1L = 0x00;
  }
}

void main() {
    unsigned long width;
    unsigned short t1fall, t1rise;
    char txt[10];

    tx_buf_head = 0;
    tx_buf_tail = 0;

    TRISB4_bit = 1;
    OPTION_REG = 0b10001000; //Bits 0:2 prescaller rate select
    INTCON = 0b11100000;
    T1CON = 0x01;
    TMR1IE_bit = 1;
    UART1_Init(19200);

    while(1) {
        if(tx_buf_head != tx_buf_tail) {

            t1fall = tx_buf[tx_buf_tail % TX_BUF_SIZE][T1_FALL];
            t1rise = tx_buf[tx_buf_tail % TX_BUF_SIZE][T1_RISE];
            tx_buf_tail++;

            if(t1fall >= t1rise) {
                width = t1fall - t1rise;
            }
            else {
                width = (unsigned short)0 - (t1rise - t1fall);
            }

            LongToStr(width, txt);

            UART1_Write_Text(txt);
            UART1_Write(13);
        }
    }
}

Това го писах гледайки само кода, който си написал. Не съм го компилирал и опитвал върху MCU. Погледни го като идея, как да изкараш времеотнемащите функции от обработчика на прекъсването и да ги преместиш в основния цикъл.
Ползването на freerun таймер изисква "кръгова аритметика" за тайм-щампите взети от него.
Защо нулираш Timer1? Не превърта ли свободно при препълване(не съм гледал описанието му).

Не е зле ако можеш да вдигнеш малко скоростта на UART-а.

_________________
Най-опасният враг на истината и свободата е мнозинството.


Нед Дек 10, 2017 11:29 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Дек 20, 2016 6:39 pm
Мнения: 32
Местоположение: Русе
Мнение Re: Измерване на период с PIC16F
Довърших програмата за 3 канала като промених някои неща, основното от които е нулирането на таймер 1 при ниско към високо логическо ниво (не казвам фронт защото не се случва точно на тогъла на състоянието). По този начин си спестих колебанията в измерванията (спряха да играят нагоре-надолу), а точността не се подобри съществено. Слагайки едно volatile пред променливите, които държат времената подобри значително точността (не мога да си обясня защо). Също така не мога да си обясня защо като използвам (TMR1H <<8) | TMR1L вместо същите операции, извършени отделно една от друга точността се понижава. Очаквах нещата да се случват по-бързо, но не е така. Вдигнах baud-рейта от 9600 на 19200, повече явно не му понася на MCUто, защото почва да ми говори на маймунски :D .
В този си вид програмата чете 3 канала, като при 1000us дължина на импулса измерва 974us, при 1500us - 1517, a 2000us ги чете като 2003 или 2007. Грешката намалява с нарастване на измерваното време. Най-доброто, което ми идва на ума е да закръглям резултатите до хилядна, тоест 974 като 1000, 1517 като 1500. Целта е да постигна стъпка 100uS.

Код:
volatile unsigned long t1, t2, t3;
char txt[12];
short tflag;

void Interrupt(){
  if (TMR0IF_bit){
    TMR0IF_bit = 0;
    TMR0 = 255;
    if(RB4_bit && tflag == 0){
      TMR1H         = 0x00;
      TMR1L         = 0x00;
      tflag = 1;
     }
     
     if(!RB4_bit && tflag == 1){
      t1 = TMR1H;
      t1 = t1 << 8;
      t1 = t1 | TMR1L;
      //t1 =  (TMR1H << 8) | TMR1L;
      tflag = 2;
    }
   
    if(!RB5_bit && tflag == 2) tflag = 3;
     
    if(RB5_bit && tflag == 3){
      TMR1H         = 0x00;
      TMR1L         = 0x00;
      tflag = 4;
     }
     
     if(!RB5_bit && tflag == 4){
      t2 = TMR1H;
      t2 = t2 << 8;
      t2 = t2 | TMR1L;
      tflag = 5;
    }
   
    if(!RB6_bit && tflag == 5) tflag = 6;
   
    if(RB6_bit && tflag == 6){
      TMR1H         = 0x00;
      TMR1L         = 0x00;
      tflag = 7;
     }

     if(!RB6_bit && tflag == 7){
      t3 = TMR1H;
      t3 = t3 << 8;
      t3 = t3 | TMR1L;
      LongToStr(t1, txt);
      UART1_Write_Text(txt);
      LongToStr(t2, txt);
      UART1_Write_Text(txt);
      LongToStr(t3, txt);
      UART1_Write_Text(txt);
      UART1_Write(13);
      tflag = 8;
    }
   
    if(!RB4_bit && tflag == 8) tflag = 0;
    }
}

void main() {
  OPTION_REG = 0b10001000;
  INTCON = 0b11100000;
  T1CON = 0b00000001;
  TMR1IE_bit = 1;
  UART1_Init(19200);
  Delay_ms(100);
  while(1);
}


Съб Дек 16, 2017 6:15 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 1:01 pm
Мнения: 1952
Местоположение: Варна
Мнение Re: Измерване на период с PIC16F
Дебела глава си :D

Здравко Димитров
45 години

PS: В израза: t1 = (TMR1H <<8) | TMR1L;
(TMR1H <<8) най-вероятно винаги ти дава нула. Възможно е дори при оптимизацията, компилатора да го премахва от кода. Причината ще се досетиш.

_________________
Най-опасният враг на истината и свободата е мнозинството.


Съб Дек 16, 2017 8:55 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Апр 27, 2005 11:48 am
Мнения: 4715
Мнение Re: Измерване на период с PIC16F
имаш таймер с GATE контрол

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


Нед Дек 17, 2017 11:04 am
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 8:21 pm
Мнения: 27996
Местоположение: София
Мнение Re: Измерване на период с PIC16F
Зависи от компилатора, трябва да ги каства, но ссs би изгенерирал нещо различно от 0 май.


Пон Дек 18, 2017 4:12 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Яну 26, 2005 1:01 pm
Мнения: 1952
Местоположение: Варна
Мнение Re: Измерване на период с PIC16F
Да, трябва да се справи компилатора с implicit type promotion. Но съм почти напълно сигурен, по спомен от опита ми с Микрочипски компилатори, че в случая това е поведението му.

_________________
Най-опасният враг на истината и свободата е мнозинството.


Пон Дек 18, 2017 9:14 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Апр 20, 2005 11:02 am
Мнения: 8891
Местоположение: Разград
Мнение Re: Измерване на период с PIC16F
Абе чета тука от известно време и се чудя защо аджеба се занимавате с някви сложни софтуерни гимнастики като има пик дето това нещо го има като хардуер - е верно че е само с два модула, ама да кажем третия може да се остави софтуерен и значително да се разтовари програмата и да не се чудим що подяволите става така...


Пон Дек 18, 2017 1:58 pm
Профил ICQ
Ранг: Почетен член
Ранг: Почетен член

Регистриран на: Съб Окт 30, 2004 10:19 pm
Мнения: 605
Мнение Re: Измерване на период с PIC16F
Ако все пак решиш да ползваш хардуерни CCP модули, новите 16-ки(катоPIC16F18324) са с по 4 модула.
А като екстри/ценово/корпуси и пинове с PPS, са далеч по-добри от ф84/ф628


Пон Дек 18, 2017 3:04 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Сря Апр 20, 2005 11:02 am
Мнения: 8891
Местоположение: Разград
Мнение Re: Измерване на период с PIC16F
Въобще не говоря за CCP модули а за 24 битови Signal Measurement Timers - това е в 16F1519 - с тая въшка такава гимнастика с хардуер и софтуер имам правена че чак ум да ти зайде. 1/4 от кода е настройка на хардуера и 1/4 е фактическата програма - другото разни таблици. Почти всичко го прави хардуера, като CLC, SMT, CCP и не знам още какво са навързани като черва помежду си - като резултат почти всичко става хардуерно. В тая програма имам няколко страници коментари, а за някой редове имам изписан цял ферман да мога да си спомня някой ден каква еквилибристика се е случила...


Пон Дек 18, 2017 8:04 pm
Профил ICQ
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 33 мнения ]  Отиди на страница Предишна  1, 2, 3  Следваща

Кой е на линия

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


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

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