ширина импульса с использованием флага прерывания

Я хотел бы измерить ширину импульса с помощью pic 18f4550 CCP в режиме захвата. Идея такова: когда модель CCP получает нарастающий фронт, запускается timer1, и после каждого прерывания Timer 1, x который является константой с начальным значением 0 увеличивается на 1, когда модель CCP получает задний фронт timer1 останавливается, и увеличение x также должно прекратиться, чтобы его значение можно было использовать при расчете пульса. проблема, которую я обнаружил, заключается в том, что увеличение x не останавливается, а код работает как счетчик, и, поскольку я новичок в программировании изображений, я не мог найти ошибку. если кто может помочь буду признателен. код, который я использую, приведен ниже. Благодарность!

#include <stdio.h>
#include <stdlib.h>

#include "osc_config.h"
#include "LCD_8bit_file.h"
#include <string.h>

int x=0;

void main()
{
    unsigned long comtage;
    unsigned long DEPHASAGE[20];
    float Deph_tempo;
    
    TRISCbits.TRISC2=1;
    
    IRCF0=1;     
    IRCF1=1;
    IRCF2=1;  
    
    LCD_Init();
    
    LCD_String_xy(0,0,"pulse"); 
 
    PIE1bits.CCP1IE=1;
    PIR1bits.CCP1IF=0; 
    
    CCP1CON=0b00000101; 
    CCPR1=0;        
    
    T1CONbits.RD16=0;
    T1CKPS0=0;
    T1CKPS1=0;
    TMR1CS=0;
    
    while(1)        
    {    
        CCP1CON         = 0b00000101;
        PIR1bits.CCP1IF = 0;
        TMR1ON          = 0; 
        TMR1            = 0;

        while (!PIR1bits.CCP1IF)
            ;

        TMR1ON          = 1; 
        CCP1CON         = 0b00000100;
        PIR1bits.CCP1IF = 0;
    
        if (TMR1IF==1)
        {
            x++;
            TMR1IF=0;
        }
    
        while (!PIR1bits.CCP1IF)
            ; 

        comtage = x; 
    
        Deph_tempo = ((float)comtage /7843.13 ); 
        sprintf(DEPHASAGE,"%.5f  ",Deph_tempo); 

        LCD_String_xy(2,0,DEPHASAGE);
    }
    x = 0;
}                              

``

person mad na    schedule 18.03.2021    source источник
comment
Я немного исправил отступы. Есть причина, по которой важно поддерживать порядок в коде. Вы Состояние x = 0; находится за пределами вашего бесконечного цикла и, следовательно, недостижимо. Вы должны переместить этот оператор внутрь цикла while. Желательно ближе к началу цикла, рядом с оператором TMR1 = 0;, это упростит чтение кода и его осмысление.   -  person Michaël Roy    schedule 19.03.2021
comment
спасибо, я уже проверил этот выбор, но мой ЖК-дисплей отображает постоянное значение, даже если я изменяю ширину импульса.   -  person mad na    schedule 19.03.2021
comment
В этом коде есть и другие ошибки... например, x всегда равен 0. Что ты пытаешься сделать? Каковы ваши параметры? Я имею в виду, какой диапазон импульсов вы пытаетесь прочитать? Очень сложно дать ответ без предыстории.   -  person Michaël Roy    schedule 19.03.2021
comment
Я вижу, что исказил свою проблему, поэтому приношу свои извинения за то, что не предоставил вам необходимую информацию. Как и у всех новичков, у меня было много ошибок в этом коде. Теперь я хотел бы измерить пульс между 10uS и 1S. Проблема в том, что мой код не может измерять импульсы выше 0,03 с без использования прерываний, а когда я их использую, я не могу написать правильный код. Спасибо   -  person mad na    schedule 20.03.2021
comment
Какова скорость вашего осциллятора? И требуемая точность? Это тоже важно. Для математики.   -  person Michaël Roy    schedule 20.03.2021
comment
Я использую внутренний генератор на 8 МГц, для точности, которую я хотел бы получить как можно выше, используя внутренний генератор.   -  person mad na    schedule 20.03.2021
comment
Есть один способ добиться того, что вы хотите сделать... Это немного сложно, так как вам нужен таймер шириной более 16 бит. Можно использовать как TMR1, так и TMR3 для работы с CCPCON, и получить 19-битный таймер, при Fosc = 8 МГц, ваш тактовый вход в таймеры составляет 2 МГц, что означает, что этот 24-битный таймер будет сбрасываться через 2^19 * 0,5 мкс = 264 мкс секунд или около того... Это все еще немного.   -  person Michaël Roy    schedule 20.03.2021
comment
Чтобы расширить диапазон ваших аппаратных счетчиков, вы можете либо разделить тактовую частоту вашего генератора на 4 и запустить на частоте 2 МГц = 500 тыс. инструкций в секунду, либо использовать TMR2 для генерации ШИМ, который вы подключите внешне электрически к T13CKI/RC0 и будете использовать как часы. Я бы так и сделал.   -  person Michaël Roy    schedule 20.03.2021
comment
Идея состоит в том, чтобы использовать TMR1 без предделителя и TMR3 с предделителем 1:8, использовать триггер специального события CCP (описанный в техническом описании в разделе 12.5) для одновременного сброса обоих таймеров. Затем переключите модуль КПК в режим захвата и дождитесь захвата. Не нужно прерываний. Я опубликую ответ позже сегодня ... Я также занят в другом месте.   -  person Michaël Roy    schedule 20.03.2021
comment
Это даст вам результат 2 мкс и максимальный импульс 1,048 с. Конечно, идеальным решением был бы MCU с 32-битным таймером, что-то вроде PIC24.   -  person Michaël Roy    schedule 20.03.2021


Ответы (1)


Есть один способ добиться того, что вы хотите сделать... Это немного сложно, так как вам нужен таймер шириной более 16 бит. Можно использовать как TMR1, так и TMR3 для работы с CCPCON, и получить 19-битный таймер, при Fosc = 8 МГц, ваш тактовый вход в таймеры составляет 2 МГц, что означает, что этот 19-битный таймер будет сбрасываться через 2^19 * 0,5 мкс = 264 мкс секунд или около того... Мы могли бы использовать TMR3IF для обнаружения опрокидывания и сделать его 20-битным, но это все еще немного мало.

Существует также возможность использования TMR0, который имеет предварительный делитель 1:256, но вам нужно будет питать TMR0 от внешнего тактового генератора. Вы можете использовать TMR3 и генератор PWM для генерации тактового сигнала 500 кГц на CCP2/RC1 и направить его на TK0CKI/RA4. Это эффективно создаст 26-битный счетчик с разрешением 4/Fosc = 0,5 мкс и диапазоном 33,55 секунды. Вы можете увеличить разрешение, используя PLL для увеличения частоты генератора. Это также имеет то преимущество, что оно будет довольно точным. Повторяемость зависит от петель. Использование ISR для перехвата прерываний немного улучшит повторяемость.

#include <stdio.h>
#include <stdlib.h>

#include "osc_config.h"
#include "LCD_8bit_file.h"
#include <string.h>

void main()
{
    unsigned long count = 0;

    // Setting up TMR0 for extarnal clock on T0CKI/RA4

    LATAbits.LATA4    = 0;
    TRISAbits.TRISA0  = 1;     // RC0 as input
    T0CON             = 0x27   // Prescaler 1:256, 0->1 transition, T0CKI input 
    TMR0IE            = 0;     // mask interrupts.

    // Setting up TMR1/CCP1CON for capture on RC2/CCP1

    TRISCbits.TRISC2  = 1;     // CCP2/RC2 as input
    LATCbits.LATC2    = 0;
    T1CON             = 0x80   // internal clock oscillator off, 1:1 pre, 16 bits reads
    TMR1              = 0;
    CCP1CON           = 0x05   // set capture mode on rising edge
    CCP2IE            = 0;     // mask interrupts
    TMR1IE            = 0;

    // Setting up TMR2/CCP2CON for generating the clock on CCP2/RC1

    LATCbits.LATC1    = 0;     // clear RC1 latch
    TRISCbits.TRICSC1 = 0;     // RC1 as output
    T2CON             = 0;     // timer2 off, prescaler 1:1, post scaler 1:1
    PR2               = 3;     // PWM frequency = (Fosc / 4) / 4
    TMR2              = 0;
    CCPR2             = 0;
    CCP2CON           = 0x1C;  // CCP2M = PWM mode, DCB2<0> = 1 (LSB for duty cycle compare) 
    CCP2IE            = 0;     // mask interrupts
    TMR2IE            = 0;

    while (1)
    {
        // get ready to capture.
        TMR2ON          = 0;      // stop our timing clock.
        TMR0ON          = 0;      // this reset TMR0 prescaler
        TMR0            = 0;      // clear timers.
        TMR1            = 0;
        TMR2            = 0;
        TMR0ON          = 1;      // Timer 0 is ready to count.
        CCP1CON         = 0x05;   // set capture mode on rising edge
        PIR1bits.CCP1IF = 0;

        while (!PIR1bits.CCP1IF)  // wait for event
            ;

        PIR1bits.CCP1IF = 0;
        CCP1CON         = 0x04;   // set capture mode on falling edge

        TMR1ON          = 1;
        TMR2ON          = 1;

        while (!PIR1bits.CCP1IF)  // wait for event
            ;
        
        // here we have to make sure to keep the same latency as after 
        // rising edge, so we are precise. 
        PIR1bits.CCP1IF = 0;
        CCP1CON         = 0x04;   // set capture mode on rising edge

        TMR1ON          = 0;
        TMR2ON          = 0;      // also stops TMR0 

        // TMR0's clock is is divided by 2²2 * 2^8 = 2^10
        // its lower 6 bits should be equal to the upper 6 bits
        // of TMR1.   
        count = ((TMR0 & 0xFFC0 << 10) + TMR1;

        // convert to us
        count >>= 1;

        // display...
    }
}

Это самое близкое, что я могу сделать без реального устройства и прицела передо мной. Дайте мне знать, если у вас есть какие-либо вопросы или возникнут какие-либо проблемы.

person Michaël Roy    schedule 20.03.2021
comment
спасибо, я протестирую этот код и все варианты, которые вы дали. еще раз спасибо - person mad na; 21.03.2021
comment
В расчете count произошла ошибка. Прости за это. - person Michaël Roy; 22.03.2021
comment
все дело в идеях, небольшие ошибки можно исправить. - person mad na; 22.03.2021