Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Merenje efektivnog napona/struje 50 Hz microkontrolerom
#4
Ovaj kod sam pisao za jedan projekat sa PIC16F18855, fantastični malli mikrokontroler. Iz ranijeg iskustva, kao što je i Goran pisao, računanje kvadratnog korena je priličan "overkill" za ovakve mikrokontrolere, međutim na moje prijatno iznenađenje PIC16F18855 se odlično i junački držao. Pravljen je neki punjač akumulatora sa faznom regulacijom, pa je bilo potrebno da se struja meri kao efektivna vrednost, zbog faznog ugla nakon tiristora... Nisam previše ulazio u to kolika je preciznost i tačnost merenja, ali smo brzinskom proverom digitalnim TrueRMS unimerom ustanovili da je merenje veoma korektno za ovu namenu. Rađeno je jednom mom prijatelju, brzinski za jedno popodne, tako da je za ovu namenu prošao... za neke ozbiljnije i brže signale, ovo svakako ne bi moglo da se izvede sa majušnim PIC16Fxxx

Code:
#define ADC_REF_VOLTAGE 5.00
#define ADC_RESOLUTION  1023.00

// **** VARIABLES ****
bit Na10msFlag;
bit CalculateCurrentRMS;

float MeasuredCurrentmA;

volatile adc_result_t ADCCurrentRawVal = 0;
volatile adc_result_t ADCVoltageRawVal = 0;
 
uint32_t ADCCurrentRawForSquareRoot;

uint8_t SampleChannel = 0;

uint16_t ADCVoltageRawValFiltered = 0;

// FUNCTIONS
void TMR0_UserInterruptHandler(void)
{
  Na10msFlag = 1;
}

// ADC Interapt
// TMR5 je podesen da radi na 1ms i on radi triger semplovanja
void ADCC_UserInterruptHandler(void)
{
  static uint32_t ADCCurrentRawValSqAccu = 0;
  static uint8_t SamplesCountCurrent = 0;

  static unsigned long SampleAcuVolt = 0;

  if(SampleChannel == ADCCHStrujaPunjenja)
  {
    ADCCurrentRawVal = ADCC_GetConversionResult();
    SampleChannel = ADCCHNaponAkumulatora;
    // select the A/D channel
    ADPCH = ADCCHNaponAkumulatora;

    // Idemo u deo racunice za TrueRMS, ovde radimo sumu kvadrata semplova
    // Dole u main petlji kada se prepozna da vrednost ADCCurrentRawForSquareRoot
    // nije nula, on okida racunicu za Sqrt(ADCCurrentRawForSquareRoot) jer
    // je ADCCurrentRawForSquareRoot sadrzana suma kvadrata podeljena sa brojem
    // uzoraka! To je u nasem slucaiju 128 uzoraka
    ADCCurrentRawValSqAccu += ADCCurrentRawVal * ADCCurrentRawVal;
    if(++SamplesCountCurrent >= 128)
    {
      SamplesCountCurrent = 0;
      ADCCurrentRawValSqAccu = ADCCurrentRawValSqAccu / 128;
      ADCCurrentRawForSquareRoot = ADCCurrentRawValSqAccu;
      CalculateCurrentRMS = 1;
      ADCCurrentRawValSqAccu = 0;
    }
  }
}

/*
                         Main application
*/
void main(void)
{
    // initialize the device
    SYSTEM_Initialize();

    TMR0_SetInterruptHandler(TMR0_UserInterruptHandler);
    TMR2_SetInterruptHandler(TMR2_UserInterruptHandler);
    ADCC_SetADIInterruptHandler(ADCC_UserInterruptHandler);

    // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
    // Use the following macros to:

    // Enable the Global Interrupts
    INTERRUPT_GlobalInterruptEnable();

    // Enable the Peripheral Interrupts
    INTERRUPT_PeripheralInterruptEnable();

    // Disable the Global Interrupts
    //INTERRUPT_GlobalInterruptDisable();

    // Disable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptDisable();
   
    TMR6_StartTimer();
    SampleChannel = ADCCHStrujaPunjenja;
    ADCC_StartConversion(ADCCHStrujaPunjenja);

    TMR0_StartTimer();
   
    while (1)
    {
    
      // Add your application code
      if(Na10msFlag)
      {
        Na10msFlag = 0;
       
        if(CalculateCurrentRMS)
        {
          CalculateCurrentRMS = 0;
         
          float ADCCurrentRawValFinal = sqrt(ADCCurrentRawForSquareRoot);
          MeasuredCurrentmA = (float)1000.00 * (( (float)ADC_REF_VOLTAGE / (float)ADC_RESOLUTION) * (float)ADCCurrentRawValFinal) / (float)CURRENT_SENS_RESISTOR; // Rsens = 0.1
        }
  }
}
Reply


Messages In This Thread
RE: Merenje efektivnog napona/struje 50 Hz microkontrolerom - by npejcic - 10-19-2022, 12:42 PM

Forum Jump:


Users browsing this thread: 2 Guest(s)