+ Post New Thread
Page 2 of 2 FirstFirst 1 2
Results 21 to 36 of 36
  1. #21
    Super Moderator
    Points: 79,089, Level: 68
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,051
    Helped
    3635 / 3635
    Points
    79,089
    Level
    68

    Re: ACS712-5A AC Current Reading - How to?

    Hi,

    This way the reading + processing should not exceed 20ms + 10ms (64 MHz Oscillator) and I will be able to trip the faulty load line within 30ms of fault.
    When using ADC interrupt, why not immediately process the incoming data? You have plenty of time doing this inbetween two samples.
    For the minimal solution it's just (pseudo code)
    * read ADC value
    * setup MUX
    * setup ADC that conversion can be triggered by timer
    * compare stored_ADC value with trip_max
    * if bigger: trip SSR
    * compare stored_ADC value with trip_min
    * if lower: trip SSR
    * leave ISR

    ****
    If the ISR stores the ADC values in an array that may be read in main loop: you may transmit the values (maybe every 100ms) to the PC for monitoring. You are free to do what you like in the main loop..it won't harm the "overcurrent detection" as long as you don't disable interrupts.

    Klaus
    Please donīt contact me via PM, because there is no time to respond to them. No friend requests. Thank you.


    1 members found this post helpful.

  2. #22
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    @Klaus

    As now I prefer RMS value finding for current how can I do these without processing the raw data?

    Is there a way to do it?

    Code:
    compare stored_ADC value with trip_max
    * if bigger: trip SSR
    * compare stored_ADC value with trip_min
    * if lower: trip SSR
    What should be the timer ISR interrupt period?

    Code:
    * setup ADC that conversion can be triggered by timer
    I am taking into consideration 45Hz to 70Hz for mains frequency as I am trying to implement for both 110C 60Hz and 220V 50Hz systems.

    I have to minitor both over current and under current for each channel.

    - - - Updated - - -

    I implemented a new method that should read all 8 channels within 20ms and then process it and display it to UART but something is wrong which I could not find out and which is printing wrong current values on UART.

    Where is the bug?

    The piece of code which is giving wrong value is #else method

    Code C - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    
    #define Method 0
     
    sbit Chip_Select           at LATC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
     
    unsigned int adcVal = 0;
    unsigned int max[8] = {0};
    unsigned int min[8] = {0};
    unsigned char maxFlag = 0;
    unsigned char minFlag = 0;
    double volt = 0.0;
    double current = 0.0;
    unsigned int i = 0;
    char txt[67];
     
    void Select_ADG731_Channel(unsigned char data_) {
         Chip_Select = 0;
         SPI1_Write(data_);
         Chip_Select = 1;
    }
     
    void Clear_Arrays() {
        memset(max, 0, sizeof(max));
        memset(min, 0, sizeof(min));
        maxFlag = 0;
        minFlag = 0;
    }
     
    void main() {
        OSCCON = 0x73;
        OSCCON2 - 0x03;
        OSCTUNE = 0x00;
        
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
     
        SLRCON = 0x00;
     
        ADCON0 = 0x00;
        ADCON1 = 0x00;
        ADCON2 = 0b10110101;
     
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
     
        TRISA = 0xC1;
        TRISB = 0x00;
        TRISC = 0xC0;
        TRISD = 0x00;
        TRISE = 0x00;
     
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
        PORTE = 0x00;
     
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;
        LATD = 0x00;
        LATE = 0x00;
     
        UART1_Init(9600);
     
        Chip_Select = 1;
        Chip_Select_Direction = 0;
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV16, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
        Delay_ms(100);
        
        UART1_Write_Text("Taking readings...\r\n\r\n");
        Clear_Arrays();
     
        LATD5_bit = 1;
        
        while(1) {
               #if Method
                   i = 0;
                   while(i < 8) {
                       Select_ADG731_Channel(i);
                       Delay_us(1);
     
                       max[i] = 0;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(20);
                            if(max[i] < adcVal)max[i] = adcVal;
                            else break;
                       }
     
                       min[i] = 1024;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(20);
                            if(min[i] > adcVal)min[i] = adcVal;
                            else break;
                       }
     
                       i++;
                   }
               #else
                   memset(max, 0, sizeof(max));
                   while(maxFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          Delay_us(1);
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(20);
                          if(max[i] < adcVal)max[i] = adcVal;
                          else maxFlag |= (1 << i);
     
                          i++;
                       }
                   }
     
                   memset(min, 0, sizeof(min));
                   while(minFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          Delay_us(1);
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(20);
                          if(min[i] > adcVal)min[i] = adcVal;
                          else minFlag |= (1 << i);
     
                          i++;
                       }
                   }
               #endif
               
               LATD6_bit = 1;
               
               for(i = 0; i < 8; i++) {
                   volt = (double)(max[i] - min[i]) * 5.0 / 1023.0;
                   volt = (volt / 2.0) * 0.707;
                   current = volt * 1000.0 / 185.0;
                   sprintf(txt, "Channel [%u] = %5.2f Amps\r\n", i, current);
                   UART1_Write_Text(txt);
               }
     
               UART1_Write_Text("\r\n");
               Clear_Arrays();
               LATD7_bit = 1;
     
               asm reset
        }
    }
    Last edited by baileychic; 22nd November 2019 at 09:00.



  3. #23
    Super Moderator
    Points: 79,089, Level: 68
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,051
    Helped
    3635 / 3635
    Points
    79,089
    Level
    68

    Re: ACS712-5A AC Current Reading - How to?

    Hi,

    what do you mean with:
    without processing the raw data
    *************
    What should be the timer ISR interrupt period?
    * timer triggers ADC_conversion
    * ADConversion_finished triggers ADC_ISR

    As far as I understood your requirement:
    You want to process 8 channels with 10 samples within 10ms each --> 1 conversion per channel in 1ms.

    one channel 1ms --> 1kHz
    8 channels 1ms each --> 8kHz

    8kHz --> 125us
    ****************
    I am taking into consideration 45Hz to 70Hz for mains frequency as I am trying to implement for both 110C 60Hz and 220V 50Hz systems.
    When I want to process 50Hz as well as 60Hz I use a running average over 100ms. (5 full waves of 50Hz / 6 fullwaves of 60Hz)
    (Mathematically you need to calculate the greatest common divisor of 50Hz and 60Hz --> 10Hz. 10Hz --> 100ms)

    If this is too slow for you you have two options:
    * or use a (software) select: either 50Hz or 60Hz. ... and still use running average (over the desired numbers of samples)
    * using a biquad instead of running average (to reduce 100Hz ripple /120Hz ripple)

    Klaus
    Please donīt contact me via PM, because there is no time to respond to them. No friend requests. Thank you.


    1 members found this post helpful.

    •   AltAdvertisement

        
       

  4. #24
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    @Klaus

    I will follow and implement your recommendations while I will implement the ISR method tonight.

    For now I am still trying to get my new method of reading and processing in main loop to work perfectly.

    This is the latest code.

    Code C - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    
    #define Method 1
     
    sbit Chip_Select           at LATC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
     
    unsigned int adcVal = 0;
    unsigned int max[8] = {0};
    unsigned int min[8] = {0};
    unsigned char maxFlag = 0;
    unsigned char minFlag = 0;
    double volt = 0.0;
    double current = 0.0;
    unsigned int i = 0;
    char txt[87];
     
    void Select_ADG731_Channel(unsigned char data_) {
         Chip_Select = 0;
         SPI1_Write(data_);
         Chip_Select = 1;
    }
     
    void Clear_Arrays() {
        memset(max, 0, sizeof(max));
        memset(min, 0, sizeof(min));
        maxFlag = 0;
        minFlag = 0;
    }
     
    void main() {
        OSCCON = 0x73;
        OSCCON2 - 0x03;
        OSCTUNE = 0x40;
        
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
     
        SLRCON = 0x00;
     
        ADCON0 = 0x00;
        ADCON1 = 0x00;
        ADCON2 = 0b10110101;
     
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
     
        TRISA = 0xC1;
        TRISB = 0x00;
        TRISC = 0xC0;
        TRISD = 0x00;
        TRISE = 0x00;
     
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
        PORTE = 0x00;
     
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;
        LATD = 0x00;
        LATE = 0x00;
     
        UART1_Init(9600);
     
        Chip_Select = 1;
        Chip_Select_Direction = 0;
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
        Delay_ms(100);
        
        UART1_Write_Text("Taking readings...\r\n\r\n");
        Clear_Arrays();
     
        LATD5_bit = 1;
        
        while(1) {
               #if Method
                   i = 0;
                   while(i < 8) {
                       Select_ADG731_Channel(i);
                       Delay_us(1);
     
                       max[i] = 0;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(20);
                            if(max[i] <= adcVal)max[i] = adcVal;
                            else break;
                       }
     
                       min[i] = 1024;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(20);
                            if(min[i] >= adcVal)min[i] = adcVal;
                            else break;
                       }
     
                       i++;
                   }
               #else
                   memset(max, 0, sizeof(max));
                   while(maxFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          Delay_us(1);
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(20);
                          if(adcVal >= max[i])max[i] = adcVal;
                          else maxFlag |= (1 << i);
     
                          i++;
                       }
                   }
     
                   memset(min, 1024, sizeof(min));
                   while(minFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          Delay_us(1);
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(20);
                          if(adcVal <= min[i])min[i] = adcVal;
                          else minFlag |= (1 << i);
     
                          i++;
                       }
                   }
               #endif
               
               LATD6_bit = 1;
               
               //if((maxFlag == 0xFF) && (minFlag == 0xFF)) {
                   for(i = 0; i < 8; i++) {
                       volt = (double)(max[i] - min[i]) * 5.0 / 1023.0;
                       sprintf(txt, "max[%u] = %u,   min[%u] = %u,  max[%u] - min[%u] = %u\r\n", i, max[i], i, min[i], i, i, max[i] - min[i]);
                       UART1_Write_Text(txt);
                       volt = (volt / 2.0) * 0.707;
                       current = volt * 1000.0 / 185.0;
                       sprintf(txt, "Channel [%u] = %5.2f Amps\r\n", i, current);
                       UART1_Write_Text(txt);
                   }
     
                   UART1_Write_Text("\r\n");
                   Clear_Arrays();
                   LATD7_bit = 1;
               //}
     
               //asm reset
        }
    }

    In this

    the result for

    Code:
    #define Method 1
    is very good as you can see in the screenshot.

    but for

    Code:
    #define Method 0
    all min[i] values is 0 what ever I do. I also disabled min[i] reading code and used memset() to set min[] values to 1024 and print it but they still is 0.

    So, I suspect compiler bug.

    What do you say?


    Yes, it was actually a compiler bug. I used it using for() loop to reset the min[] array to 1024 and now it works perfectly.

    So, mikroC PRO PIC's memset() function has some issue.

    Here is the new code which works perfectly.

    Code C - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    
    #define Method 0
     
    sbit Chip_Select           at LATC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
     
    unsigned int adcVal = 0;
    unsigned int max[8] = {0};
    unsigned int min[8] = {0};
    unsigned char maxFlag = 0;
    unsigned char minFlag = 0;
    double volt = 0.0;
    double current = 0.0;
    unsigned int i = 0;
    char txt[87];
     
    void Select_ADG731_Channel(unsigned char data_) {
         Chip_Select = 0;
         SPI1_Write(data_);
         Chip_Select = 1;
    }
     
    void Clear_Arrays() {
        //memset(max, 0, sizeof(max));
        //memset(min, 1024, sizeof(min));
        maxFlag = 0;
        minFlag = 0;
    }
     
    void main() {
        OSCCON = 0x73;
        OSCCON2 - 0x03;
        OSCTUNE = 0x40;
        
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
     
        SLRCON = 0x00;
     
        ADCON0 = 0x00;
        ADCON1 = 0x00;
        ADCON2 = 0b10110101;
     
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
     
        TRISA = 0xC1;
        TRISB = 0x00;
        TRISC = 0xC0;
        TRISD = 0x00;
        TRISE = 0x00;
     
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
        PORTE = 0x00;
     
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;
        LATD = 0x00;
        LATE = 0x00;
     
        UART1_Init(9600);
     
        Chip_Select = 1;
        Chip_Select_Direction = 0;
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
        Delay_ms(100);
        
        UART1_Write_Text("Taking readings...\r\n\r\n");
        Clear_Arrays();
     
        LATD5_bit = 1;
        
        while(1) {
               #if Method
                   i = 0;
                   while(i < 8) {
                       Select_ADG731_Channel(i);
                       Delay_us(1);
     
                       max[i] = 0;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(20);
                            if(max[i] <= adcVal)max[i] = adcVal;
                            else break;
                       }
     
                       min[i] = 1024;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(20);
                            if(min[i] >= adcVal)min[i] = adcVal;
                            else break;
                       }
     
                       i++;
                   }
               #else
                   memset(max, 0, sizeof(max));
                   while(maxFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          Delay_us(1);
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(20);
                          if(adcVal >= max[i])max[i] = adcVal;
                          else maxFlag |= (1 << i);
     
                          i++;
                       }
                   }
     
                   //memset(min, 1024, sizeof(min));
                   for(i = 0; i < 8; i++) {
                       min[i] = 1024;
                   }
                   while(minFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          Delay_us(1);
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(20);
                          if(adcVal <= min[i])min[i] = adcVal;
                          else minFlag |= (1 << i);
     
                          i++;
                       }
                   }
               #endif
               
               LATD6_bit = 1;
               
               //if((maxFlag == 0xFF) && (minFlag == 0xFF)) {
                   for(i = 0; i < 8; i++) {
                       volt = (double)(max[i] - min[i]) * 5.0 / 1023.0;
                       sprintf(txt, "max[%u] = %u,   min[%u] = %u,  max[%u] - min[%u] = %u\r\n", i, max[i], i, min[i], i, i, max[i] - min[i]);
                       UART1_Write_Text(txt);
                       volt = (volt / 2.0) * 0.707;
                       current = volt * 1000.0 / 185.0;
                       sprintf(txt, "Channel [%u] = %5.2f Amps\r\n", i, current);
                       UART1_Write_Text(txt);
                   }
     
                   UART1_Write_Text("\r\n");
                   Clear_Arrays();
                   LATD7_bit = 1;
               //}
     
               //asm reset
        }
    }

    The result is also attached. It is better than the Method 1.

    In Method 1 I get channel 0 reading wrong. I Have to ix it. Maybe it is another compiler bug?

    The first image is for Method 0 that is new method working perfectly with 2nd code.

    The 2nd image is Method 0 which was not working with code 1 that is with

    Code:
    memset(min, 1024, sizeof(min));
    The third image is for Method 1 which slightly doesn't work fine that is wrong value for channel 0.

    - - - Updated - - -

    As I had expected with my new code it takes exact 14.202ms to read the 8x channels and get max[i] and min[i]. I had excpected 15ms max. I checked this in Proteus using RTD breadpoint at different stages.

    - - - Updated - - -

    Adding a 10ms delay (Delay_ms(10)) to Method 1 solved its issue of wrong max[0] value.

    The Method 1 takes 151.x ms to read all sensors and get min[i] and max[i]

    Method 0 takes just 15ms max to read all sensors and get min[i] and max[i]values.

    Now I will work on implementing Method 0 using interrupts.

    Code C - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    
    #define Method 1
     
    sbit Chip_Select           at LATC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
     
    unsigned int adcVal = 0;
    unsigned int max[8] = {0};
    unsigned int min[8] = {0};
    unsigned char maxFlag = 0;
    unsigned char minFlag = 0;
    double volt = 0.0;
    double current = 0.0;
    unsigned int i = 0;
    char txt[87];
     
    void Select_ADG731_Channel(unsigned char data_) {
         Chip_Select = 0;
         SPI1_Write(data_);
         Chip_Select = 1;
    }
     
    void Clear_Flags() {
        maxFlag = 0;
        minFlag = 0;
    }
     
    void main() {
        OSCCON = 0x73;
        OSCCON2 - 0x03;
        OSCTUNE = 0x40;
        
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
     
        SLRCON = 0x00;
     
        ADCON0 = 0x00;
        ADCON1 = 0x00;
        ADCON2 = 0b10110101;
     
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
     
        TRISA = 0xC1;
        TRISB = 0x00;
        TRISC = 0xC0;
        TRISD = 0x00;
        TRISE = 0x00;
     
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
        PORTE = 0x00;
     
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;
        LATD = 0x00;
        LATE = 0x00;
     
        UART1_Init(9600);
     
        Chip_Select = 1;
        Chip_Select_Direction = 0;
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
        Delay_ms(100);
        
        UART1_Write_Text("Taking readings...\r\n\r\n");
        LATD5_bit = 1;
        
        while(1) {
               Clear_Flags();
               #if Method
                   i = 0;
                   Delay_ms(10);  //Don't modify this delay, it is required to get correct value for max[0]
                   while(i < 8) {
                       Select_ADG731_Channel(i);
                       Delay_us(1);
     
                       max[i] = 0;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(10);
                            if(max[i] <= adcVal)max[i] = adcVal;
                            else break;
                       }
     
                       min[i] = 1024;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(10);
                            if(min[i] >= adcVal)min[i] = adcVal;
                            else break;
                       }
     
                       i++;
                   }
               #else
                   memset(max, 0, sizeof(max));
                   while(maxFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          Delay_us(1);
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(10);
                          if(adcVal >= max[i])max[i] = adcVal;
                          else maxFlag |= (1 << i);
     
                          i++;
                       }
                   }
     
                   //memset(min, 1024, sizeof(min));
                   for(i = 0; i < 8; i++) {    //New patch up code as above memset() code was not working, compiler bug!?
                       min[i] = 1024;
                   }
                   while(minFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          Delay_us(1);
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(10);
                          if(adcVal <= min[i])min[i] = adcVal;
                          else minFlag |= (1 << i);
     
                          i++;
                       }
                   }
               #endif
               
               LATD6_bit = 1;
               
               //if((maxFlag == 0xFF) && (minFlag == 0xFF)) {
                   for(i = 0; i < 8; i++) {
                       volt = (double)(max[i] - min[i]) * 5.0 / 1023.0;
                       sprintf(txt, "max[%u] = %u,   min[%u] = %u,  max[%u] - min[%u] = %u\r\n", i, max[i], i, min[i], i, i, max[i] - min[i]);
                       UART1_Write_Text(txt);
                       volt = (volt / 2.0) * 0.707;
                       current = volt * 1000.0 / 185.0;
                       sprintf(txt, "Channel [%u] = %5.2f Amps\r\n", i, current);
                       UART1_Write_Text(txt);
                   }
     
                   UART1_Write_Text("\r\n");
                   LATD7_bit = 1;
               //}
     
               //asm reset
        }
    }
    Last edited by baileychic; 22nd November 2019 at 11:10.



    •   AltAdvertisement

        
       

  5. #25
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    The pk-to-pk method using Isr has been implemented by me and it works perfectly in Proteus.

    Here is the code and the simulation result.

    Now I will implement RMS method using ISR.

    Code C - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    
    #define Method      0
    #define BreakPoints 0
     
    #define Isr1        1
     
    #ifndef Isr1
      #define Isr2  1
    #endif
     
    sbit Chip_Select           at LATC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
     
    unsigned int adcVal = 0;
    unsigned int max[8] = {0};
    unsigned int min[8] = {1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024};
    unsigned char maxFlag = 0;
    unsigned char minFlag = 0;
    double volt = 0.0;
    double current = 0.0;
    unsigned int i = 0;
    unsigned int j = 0;
    char txt[87];
     
    #define _MAX_CHANNELS 12
    #define _MAX_SAMPLES  20
     
    unsigned int _minRawAdcValue[_MAX_CHANNELS][_MAX_SAMPLES] = {0, 0};
    unsigned int _maxRawAdcValue[_MAX_CHANNELS][_MAX_SAMPLES] = {0, 0};
    unsigned int _rawCurrents[_MAX_CHANNELS][_MAX_SAMPLES] = {0, 0};
    unsigned int _rawCurrentsSquared[_MAX_CHANNELS][_MAX_SAMPLES] = {0, 0};
    unsigned int _rawCurrentsAverage[_MAX_CHANNELS][_MAX_SAMPLES] = {0, 0};
    unsigned int _rawCurrentsRms[_MAX_CHANNELS][_MAX_SAMPLES] = {0, 0};
    unsigned int _minFlag = 0;
    unsigned int _maxFlag = 0;
     
    unsigned int _min[_MAX_CHANNELS][_MAX_SAMPLES] = {0, 0};
    unsigned int _max[_MAX_CHANNELS][_MAX_SAMPLES] = {0, 0};
     
    unsigned char flagReg = 0;
     
    sbit skipFirstReadingFlag at flagReg.B0;
     
    //Timer4
    //Prescaler 1:4; Postscaler 1:8; TMR4 Preload = 250; Actual Interrupt Time : 500.5 us
    void InitTimer4() {
        T4CON = 0x3D;
        TMR4IE_bit = 1;
        PR4 = 250;
    }
     
    void Select_ADG731_Channel(unsigned char data_) {
         Chip_Select = 0;
         SPI1_Write(data_);
         Chip_Select = 1;
    }
     
    void interrupt() {
        #if Isr1
        if((ADIE_bit) && (ADIF_bit)) {
            ADIF_bit = 0;
            adcVal = 0;
            
            if(skipFirstReadingFlag == 1) {
                skipFirstReadingFlag = 0;
                i = 0;
                Select_ADG731_Channel(i);
                asm nop
                GO_DONE_bit = 1;
            }
            else {
                adcVal = (unsigned int)((unsigned int)(ADRESH << 8) + ADRESL);
     
                if(maxFlag != 0xFF) {
                    if(adcVal >= max[i])max[i] = adcVal;
                    else maxFlag |= (1 << i);
                }
     
                if((maxFlag == 0xFF) && (minFlag != 0xFF)) {
                    if(adcVal <= min[i])min[i] = adcVal;
                    else minFlag |= (1 << i);
                }
                
                if(++i >= 8)i = 0;
                Select_ADG731_Channel(i);
                asm nop
     
                if(!((maxFlag == 0xFF) && (minFlag == 0xFF)))GO_DONE_bit = 1;
            }
        }
        #endif
            if((TMR4IE_bit) && (TMR4IF_bit)) {
                TMR4IF_bit = 0;
            
            }
            
            if((ADIE_bit) && (ADIF_bit)) {
                ADIF_bit = 0;
                adcVal = 0;
            
            }
        #if Isr2
        
        #endif
    }
     
    void Clear_Flags() {
        maxFlag = 0;
        minFlag = 0;
    }
     
    void main() {
        OSCCON = 0x73;
        OSCCON2 - 0x03;
        OSCTUNE = 0x40;
     
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
     
        SLRCON = 0x00;
     
        ADCON0 = 0x00;
        ADCON1 = 0x00;
        //ADCON2 = 0b10110101;
        ADCON2 = 0b10111110;
     
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
     
        TRISA = 0xC1;
        TRISB = 0x00;
        TRISC = 0xC0;
        TRISD = 0x00;
        TRISE = 0x00;
     
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
        PORTE = 0x00;
     
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;
        LATD = 0x00;
        LATE = 0x00;
     
        UART1_Init(9600);
     
        Chip_Select = 1;
        Chip_Select_Direction = 0;
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
        UART1_Write_Text("Taking readings...\r\n\r\n");
     
        ADC_Init_Advanced(_ADC_INTERNAL_REF);
        ADIE_bit = 1;
        INTCON |= 0xC0;
     
        #if Isr2
            InitTimer4();
        #endif
        
        skipFirstReadingFlag = 1;
        Delay_ms(100);
        GO_DONE_bit = 1;
        
        #if BreakPoints
            LATD5_bit = 1;
        #endif
        
        while(1) {
            #if Isr1
                if((maxFlag == 0xFF) && (minFlag == 0xFF)) {
                    //UART1_Write_Text("Isr1 Method...\r\n\r\n");  //this line makes readings funky that is alternte burst readings differ
                    
                    for(i = 0; i < 8; i++) {
                       sprintf(txt, "max[%u] = %u,   min[%u] = %u,  max[%u] - min[%u] = %u\r\n", i, max[i], i, min[i], i, i, max[i] - min[i]);
                       UART1_Write_Text(txt);
                       volt = (double)(max[i] - min[i]) * 5.0 / 1023.0;
                       volt = (volt / 2.0) * 0.707;
                       current = volt * 1000.0 / 185.0;
                       sprintf(txt, "Channel [%u] = %5.2f Amps\r\n", i, current);
                       UART1_Write_Text(txt);
                    }
     
                    memset(max, 0, sizeof(max));
                    for(i = 0; i < 8; i++) {
                       min[i] = 1024;
                    }
                    maxFlag = 0;
                    minFlag = 0;
     
                    UART1_Write_Text("\r\n");
                    #if BreakPoints
                        LATD7_bit = 1;
                    #endif
                  
                  GO_DONE_bit = 1;
                }
            #elif Isr2
            
            #else
                Clear_Flags();
                #if Method
                   i = 0;
                   Delay_ms(10);  //Don't modify this delay, it is required to get correct value for max[0]
                   while(i < 8) {
                       Select_ADG731_Channel(i);
                       //Delay_us(1);
                       asm nop
     
                       max[i] = 0;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(10);
                            if(max[i] <= adcVal)max[i] = adcVal;
                            else break;
                       }
     
                       min[i] = 1024;
                       adcVal = 0;
                       while(1) {
                            adcVal = ADC_Read(0);
                            Delay_us(10);
                            if(min[i] >= adcVal)min[i] = adcVal;
                            else break;
                       }
     
                       i++;
                   }
                #else
                   memset(max, 0, sizeof(max));
                   while(maxFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          //Delay_us(1);
                          asm nop
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(10);
                          if(adcVal >= max[i])max[i] = adcVal;
                          else maxFlag |= (1 << i);
     
                          i++;
                       }
                   }
     
                   //memset(min, 1024, sizeof(min));
                   for(i = 0; i < 8; i++) {    //New patch up code as above memset() code was not working, compiler bug!?
                       min[i] = 1024;
                   }
                   while(minFlag != 0xFF) {
                       i = 0;
     
                       while(i < 8) {
                          Select_ADG731_Channel(i);
                          //Delay_us(1);
                          asm nop
     
                          adcVal = 0;
                          adcVal = ADC_Read(0);
                          Delay_us(10);
                          if(adcVal <= min[i])min[i] = adcVal;
                          else minFlag |= (1 << i);
     
                          i++;
                       }
                   }
                #endif
     
                #if BreakPoints
                    LATD6_bit = 1;
                #endif
     
                //if((maxFlag == 0xFF) && (minFlag == 0xFF)) {
                   for(i = 0; i < 8; i++) {
                       volt = (double)(max[i] - min[i]) * 5.0 / 1023.0;
                       sprintf(txt, "max[%u] = %u,   min[%u] = %u,  max[%u] - min[%u] = %u\r\n", i, max[i], i, min[i], i, i, max[i] - min[i]);
                       UART1_Write_Text(txt);
                       volt = (volt / 2.0) * 0.707;
                       current = volt * 1000.0 / 185.0;
                       sprintf(txt, "Channel [%u] = %5.2f Amps\r\n", i, current);
                       UART1_Write_Text(txt);
                   }
     
                   UART1_Write_Text("\r\n");
                   #if BreakPoints
                      LATD7_bit = 1;
                   #endif
                //}
     
                //asm reset
            #endif
        }
    }
    Last edited by baileychic; 22nd November 2019 at 15:21.



  6. #26
    Advanced Member level 5
    Points: 15,106, Level: 29
    schmitt trigger's Avatar
    Join Date
    Apr 2013
    Posts
    2,508
    Helped
    810 / 810
    Points
    15,106
    Level
    29

    Re: ACS712-5A AC Current Reading - How to?

    Something that you have not mentioned is the load type.

    All practical loads will have some sort of inrush current behavior.

    Some may last a couple of cycles, like the capacitor charging in electronic circuits or the initial magnetizing current in a transformer. Whereas electrical motors may last several seconds depending on the inertia.

    If you are going to design an overcurrent sensor, the code must take into account this fact.
    My batteries are recharged by "Helpful Post" ratings.
    If you feel that I've helped you, please indicate it as a Helpful Post


    1 members found this post helpful.

    •   AltAdvertisement

        
       

  7. #27
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    Yes, I will take care of this.

    There will be a piece of code that monitors if the fault exists for a set period of time and if yes then it will trip the load and also there will be an option for the auto-reclose faulty channel after the fault subsides.

    - - - Updated - - -

    Loads are standars known loads like pumps, motors, domestic power supply.

    Actually it is used as a circuit breaked for a house.

    A house may have different floors and or differentr setions like Living room, dining + kitchen, bathroom, etc,... The main ACS7xx sensor used for supply side is 200A or 100A type and other CAS sensors or 20A, 30A, 50A types. The main supply to the house after fuse bax goes through 100 or 200 Amps sensor and that sensor will trip the supply side SSR 100A or 200A Fotek SSR which will trip the full power supply to the house. The load side sensors will trip the individual sections of the house or supply to different floors of the house.

    I also have plans to make a 3-Phase Mains/Load Monitor after this single phase one completes successfully.

    It is a circuit breaker which doesn't cut-off power to whole house or building when small load side fault occurs. Also, one ACS7xx channel of 30A type is used to monitor earthing current. If there is a leakage into earthing then it is treated as earth fault similar to ELCB (Earth Leakage Circuit Breaker). It will trip the main supply if there is a earth or any other severe fault.


    What is the duration that the inrush current lasts? 100ms?
    Last edited by baileychic; 22nd November 2019 at 16:21.



  8. #28
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    Now I want to code the ISR method which gets the RMS value for the 8 channels.

    So, what is the best method to take readings using ISR which handles noise in the ACS712 sensor outputs?



  9. #29
    Advanced Member level 5
    Points: 11,930, Level: 26

    Join Date
    Aug 2015
    Location
    Melbourne
    Posts
    1,951
    Helped
    713 / 713
    Points
    11,930
    Level
    26

    Re: ACS712-5A AC Current Reading - How to?

    you are using a PIC uP? they are notorious for susceptibility to RFI - i.e. large relays / reclosers closing & opening - I hope the hardware will be suitably shielded / protected ...


    1 members found this post helpful.

  10. #30
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    I will be using Fotek SSRs.



  11. #31
    Advanced Member level 5
    Points: 11,930, Level: 26

    Join Date
    Aug 2015
    Location
    Melbourne
    Posts
    1,951
    Helped
    713 / 713
    Points
    11,930
    Level
    26

    Re: ACS712-5A AC Current Reading - How to?

    I kinda meant all the low level hardware will need to be shielded / protected ...


    1 members found this post helpful.

  12. #32
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    I implemented a rough code for the True RMS method using interrupts and it works fine somewhat. There is one issue though that is in ADC ISR if I do incorrect casting then the result is fine and stable but if I cast correctly then I get array index rotated once correct value which slightly varies sometimes.

    I referred this document to implement the true-rms method.

    It is currently taking 20ms to get the readings (meanValues[]) in the ISR and then 5ms to find out Irms[] in the main loop. I guess this timing is sufficient to trip the load in case of fault.

    https://www.pge.com/includes/docs/pdfs/mybusiness/customerservice/energystatus/powerquality/nonsinusoid
    al_power.pdf


    Page 3.

    What might be the issue? Is it a mikroC PRO PIC Compiler bug?


    The current code only works for 50Hz mains frequency. Once the issue with casting is solved I will implement code which gives true-rms readings for varying mains frequency between 40Hz to 80Hz.

    Code C - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    
    #define _BREAKPOINTS_PROTEUS    1
    #define _RESET                  0
    #define _DEBUG1                 0
    #define _PRINT_MEAN_VALUES      0
     
    #define _MAX_CHANNELS           8
    #define _MAX_SAMPLES            20
     
    sbit Chip_Select           at LATC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
     
    sbit INT0_FREQ     at LATD0_bit;
    sbit TMR4_FREQ     at LATD1_bit;
    sbit ZC_RESET_FREQ at LATD2_bit;
    sbit ADC_ISR_FREQ  at LATD3_bit;
    sbit i_RESET_FREQ  at LATD4_bit;
    sbit j_RESET_FREQ  at LATD5_bit;
     
    sbit BP1           at LATD7_bit;
     
    unsigned int i = 0;
    unsigned int j = 0;
    unsigned int k = 0;
    unsigned int t = 0;
     
    char txt[23];
     
    unsigned int adcValue = 0;
    long sample = 0;
    unsigned long squareValue = 0;
    unsigned long meanValues[_MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
    unsigned long meanValuesSaved[_MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
    double Irms[_MAX_CHANNELS] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
     
    unsigned char flagReg = 0;
    sbit processDataFlag at flagReg.B0;
     
    //Timer4
    //Prescaler 1:1; Postscaler 1:8; TMR4 Preload = 249; Actual Interrupt Time : 125 us
    void InitTimer4() {
        T4CON = 0x38;
        TMR4IE_bit = 1;
        PR4 = 249;
    }
     
    void Select_ADG731_Channel(unsigned char data_) {
         Chip_Select = 0;
         SPI1_Write(data_);
         Chip_Select = 1;
    }
     
    void Start_ADC_Conversion() {
        GO_DONE_bit = 1;
    }
     
    void interrupt() {
        if((TMR4IE_bit) && (TMR4IF_bit)) {
            TMR4IF_bit = 0;
            TMR4_FREQ = ~TMR4_FREQ;
            Start_ADC_Conversion();
        }
     
        if((INT0IE_bit) && (INT0IF_bit)) {
            INT0IF_bit = 0;
            INTEDG0_bit = ~INTEDG0_bit;
            INT0_FREQ = ~INT0_FREQ;
            ZC_RESET_FREQ = ~ZC_RESET_FREQ;
     
            if(!TMR4ON_bit) {
                i = 0;
                j = 0;
                Select_ADG731_Channel(i);
                TMR4ON_bit = 1;
            }
            
            Start_ADC_Conversion();
        }
        
        if((ADIE_bit) && (ADIF_bit)) {
            ADIF_bit = 0;
            ADC_ISR_FREQ = ~ADC_ISR_FREQ;
            
            #if DEBUG1
            #else
              adcValue = 0;
              sample = 0;
              squareValue = 0;
            #endif
     
            adcValue = ((unsigned int)(ADRESH << 8) + ADRESL);
            sample = (signed long)adcValue - 512;
            
            squareValue = (unsigned int)(sample * sample);    //casting is wrong but gives correct values
            //squareValue = (unsigned long)(sample * sample); //casting is correct but gives rotated once correct values
            
            meanValues[i] += (squareValue / 20);
     
            if(++i >= 8) {
                i_RESET_FREQ = ~i_RESET_FREQ;
                i = 0;
                if(++j >= 20) {
                    j_RESET_FREQ = ~j_RESET_FREQ;
                    j = 0;
                    if(!processDataFlag) {
                        for(t = 0; t < 8; t++)meanValuesSaved[t] = meanValues[t];
                    }
                    processDataFlag = 1;
                    memset(meanValues, 0, sizeof(meanValues));
                }
            }
     
            Select_ADG731_Channel(i);
        }
    }
     
    void main() {
        OSCCON = 0x70;
        OSCCON2 = 0x03;
        OSCTUNE = 0x40;
        
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
     
        SLRCON = 0x00;
     
        ADCON0 = 0x00;
        ADCON1 = 0x00;
        ADCON2 = 0b10111110;
     
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
     
        TRISA = 0xC1;
        TRISB = 0x01;
        TRISC = 0xC0;
        TRISD = 0x00;
        TRISE = 0x00;
     
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
        PORTE = 0x00;
     
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;
        LATD = 0x00;
        LATE = 0x00;
        
        UART1_Init(9600);
     
        Chip_Select = 1;
        Chip_Select_Direction = 0;
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
        UART1_Write_Text("Taking readings...\r\n\r\n");
     
        ADC_Init_Advanced(_ADC_INTERNAL_REF);
        ADIE_bit = 1;
        
        INTEDG0_bit = 0;
        INT0IF_bit = 0;
        INT0IE_bit = 1;
        
        InitTimer4();
        
        INT0_FREQ = 1;
        INTCON |= 0xC0;
        
        #if _BREAKPOINTS_PROTEUS
            BP1 = 1;
            BP1 = 0;
        #endif
        
        while(1) {
            #if _DEBUG1
                sprintf(txt, "adcValue = %u\r\n", adcValue);
                UART1_Write_Text(txt);
                sprintf(txt, "sample = %d\r\n", sample);
                UART1_Write_Text(txt);
            #endif
            
            if(processDataFlag) {
                for(k = 0; k < 8; k++) {
                    Irms[k] = sqrt((double)(meanValuesSaved[k])) * 0.026393581;
                    meanValuesSaved[k] = 0;
                }
                processDataFlag = 0;
                
                #if _BREAKPOINTS_PROTEUS
                    BP1 = 1;
                    BP1 = 0;
                #endif
                
                for(k = 0; k < 8; k++) {
                    #if _PRINT_MEAN_VALUES
                        sprintf(txt, "meanValues[%u] = %lu\r\n", k, meanValuesSaved[k]);
                        UART1_Write_Text(txt);
                    #endif
                    sprintf(txt, "Irms[%u] = %5.2fA\r\n", k, Irms[k]);
                    UART1_Write_Text(txt);
                }
     
                UART1_Write_Text("\r\n\r\n");
     
                #if _BREAKPOINTS_PROTEUS
                    BP1 = 1;
                    BP1 = 0;
                #endif
     
                #if _RESET
                    asm reset
                #endif
            }
        }
    }
    Last edited by baileychic; 25th November 2019 at 08:02.



  13. #33
    Super Moderator
    Points: 79,089, Level: 68
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,051
    Helped
    3635 / 3635
    Points
    79,089
    Level
    68

    Re: ACS712-5A AC Current Reading - How to?

    Hi,

    No idea about the "cast" problem, but...

    Code:
    meanValues[i] += (squareValue / 20);
    I'm not familiar with PIC, but I assume it has no hardware "divider"...thus a "divide" function takes long time.

    Better way is to "multiply with 0.05" if possible.
    Best is to omit it at all.

    If you omit it, there just is the 20fold value in your "mean value".
    Code:
    Irms[k] = sqrt((double)(meanValuesSaved[k])) * 0.026393581;
    Just replace "0.026393581" with "0.026393581 / sqrt(20)", which is "0.0059017841"

    ******
    If possible start the ADConversion purely hardware controlled.
    Currently you start it with software within the timer ISR.
    This causes frequency jitter in sampling rate --> more noisy ADCValues.

    Especially because there is an "IF" before the (two) "Start_ADC_Conversion()" there will be additional jitter.

    *****
    Also I see no benefit in using the "Start_ADC_Conversion()" function.
    I know this may be good programming style, but
    it causes additional processing power for
    * pushing return addres onto the stack
    * pushing variables onto the stack
    * jump
    * return

    For fast code within the ISR I'd avoid this. Just replace the function call with "GO_DONE_bit = 1;"

    Klaus
    Please donīt contact me via PM, because there is no time to respond to them. No friend requests. Thank you.


    1 members found this post helpful.

    •   AltAdvertisement

        
       

  14. #34
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    Quote Originally Posted by KlausST View Post
    Just replace "0.026393581" with "0.026393581 / sqrt(20)", which is "0.0059017841"
    Klaus
    You mean

    Code:
    Irms[k] = sqrt((double)(meanValuesSaved[k] / 20)) * 0.026393581;
    ???

    Code:
    if(!TMR4ON_bit) {
          i = 0;
          j = 0;
          Select_ADG731_Channel(i);
          TMR4ON_bit = 1;
    }
    The above only gets executed once only when device is restarted.

    I did like below and got perfect results and also removed the incorrect casting.

    Omce a while th epink signal that is TMR4 signal breaks for a while but results are stable. I know this is because of

    Code:
    if(!processDataFlag) {
         for(t = 0; t < 8; t++)meanValuesSaved[t] = meanValues[t] / 20;
    }
    Have to solve this issue.

    Code:
    #define _BREAKPOINTS_PROTEUS    1
    #define _RESET                  0
    #define _DEBUG1                 0
    #define _PRINT_MEAN_VALUES      1
    
    #define _MAX_CHANNELS           8
    #define _MAX_SAMPLES            20
    
    sbit Chip_Select           at LATC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
    
    sbit INT0_FREQ     at LATD0_bit;
    sbit TMR4_FREQ     at LATD1_bit;
    sbit ZC_RESET_FREQ at LATD2_bit;
    sbit ADC_ISR_FREQ  at LATD3_bit;
    sbit i_RESET_FREQ  at LATD4_bit;
    sbit j_RESET_FREQ  at LATD5_bit;
    
    sbit BP1           at LATD7_bit;
    
    unsigned int i = 0;
    unsigned int j = 0;
    unsigned int k = 0;
    unsigned int t = 0;
    
    char txt[23];
    
    unsigned int adcValue = 0;
    long sample = 0;
    unsigned long squareValue = 0;
    unsigned long meanValues[_MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
    unsigned long meanValuesSaved[_MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
    double Irms[_MAX_CHANNELS] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
    
    unsigned char flagReg = 0;
    sbit processDataFlag at flagReg.B0;
    
    //Timer4
    //Prescaler 1:1; Postscaler 1:8; TMR4 Preload = 249; Actual Interrupt Time : 125 us
    void InitTimer4() {
        T4CON = 0x38;
        TMR4IE_bit = 1;
        PR4 = 249;
    }
    
    void Select_ADG731_Channel(unsigned char data_) {
         Chip_Select = 0;
         SPI1_Write(data_);
         Chip_Select = 1;
    }
    
    void interrupt() {
        if((TMR4IE_bit) && (TMR4IF_bit)) {
            TMR4IF_bit = 0;
            TMR4_FREQ = ~TMR4_FREQ;
            GO_DONE_bit = 1;
        }
    
        if((INT0IE_bit) && (INT0IF_bit)) {
            INT0IF_bit = 0;
            INTEDG0_bit = ~INTEDG0_bit;
            INT0_FREQ = ~INT0_FREQ;
            ZC_RESET_FREQ = ~ZC_RESET_FREQ;
    
            if(!TMR4ON_bit) {
                i = 0;
                j = 0;
                Select_ADG731_Channel(i);
                TMR4ON_bit = 1;
            }
            
            GO_DONE_bit = 1;
        }
        
        if((ADIE_bit) && (ADIF_bit)) {
            ADIF_bit = 0;
            ADC_ISR_FREQ = ~ADC_ISR_FREQ;
            
            #if DEBUG1
            #else
              adcValue = 0;
              sample = 0;
              squareValue = 0;
            #endif
    
            adcValue = ((unsigned int)(ADRESH << 8) + ADRESL);
            sample = (signed long)adcValue - 512;
            squareValue = sample * sample;
            meanValues[i] += squareValue;
    
            if(++i >= 8) {
                i_RESET_FREQ = ~i_RESET_FREQ;
                i = 0;
                if(++j >= 20) {
                    j_RESET_FREQ = ~j_RESET_FREQ;
                    j = 0;
                    if(!processDataFlag) {
                        for(t = 0; t < 8; t++)meanValuesSaved[t] = meanValues[t] / 20;
                    }
                    processDataFlag = 1;
                    memset(meanValues, 0, sizeof(meanValues));
                }
            }
    
            Select_ADG731_Channel(i);
        }
    }
    
    void main() {
        OSCCON = 0x70;
        OSCCON2 = 0x03;
        OSCTUNE = 0x40;
        
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
    
        SLRCON = 0x00;
    
        ADCON0 = 0x00;
        ADCON1 = 0x00;
        ADCON2 = 0b10111110;
    
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
    
        TRISA = 0xC1;
        TRISB = 0x01;
        TRISC = 0xC0;
        TRISD = 0x00;
        TRISE = 0x00;
    
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
        PORTE = 0x00;
    
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;
        LATD = 0x00;
        LATE = 0x00;
        
        UART1_Init(9600);
    
        Chip_Select = 1;
        Chip_Select_Direction = 0;
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
        UART1_Write_Text("Taking readings...\r\n\r\n");
    
        ADC_Init_Advanced(_ADC_INTERNAL_REF);
        ADIE_bit = 1;
        
        INTEDG0_bit = 0;
        INT0IF_bit = 0;
        INT0IE_bit = 1;
        
        InitTimer4();
        
        INT0_FREQ = 1;
        INTCON |= 0xC0;
        
        #if _BREAKPOINTS_PROTEUS
            BP1 = 1;
            BP1 = 0;
        #endif
        
        while(1) {
            #if _DEBUG1
                sprintf(txt, "adcValue = %u\r\n", adcValue);
                UART1_Write_Text(txt);
                sprintf(txt, "sample = %d\r\n", sample);
                UART1_Write_Text(txt);
            #endif
            
            if(processDataFlag) {
                for(k = 0; k < 8; k++) {
                    Irms[k] = sqrt((double)(meanValuesSaved[k])) * 0.026393581;
                    #if _PRINT_MEAN_VALUES
                    #else
                        meanValuesSaved[k] = 0;
                    #endif
                }
                processDataFlag = 0;
                
                #if _BREAKPOINTS_PROTEUS
                    BP1 = 1;
                    BP1 = 0;
                #endif
                
                for(k = 0; k < 8; k++) {
                    #if _PRINT_MEAN_VALUES
                        sprintf(txt, "meanValuesSaved[%u] = %lu\r\n", k, meanValuesSaved[k]);
                        UART1_Write_Text(txt);
                    #endif
                    sprintf(txt, "Irms[%u] = %5.2fA\r\n", k, Irms[k]);
                    UART1_Write_Text(txt);
                }
    
                UART1_Write_Text("\r\n\r\n");
    
                #if _BREAKPOINTS_PROTEUS
                    BP1 = 1;
                    BP1 = 0;
                #endif
    
                #if _RESET
                    asm reset
                #endif
            }
        }
    }
    Last edited by baileychic; 25th November 2019 at 09:54.



  15. #35
    Super Moderator
    Points: 79,089, Level: 68
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,051
    Helped
    3635 / 3635
    Points
    79,089
    Level
    68

    Re: ACS712-5A AC Current Reading - How to?

    Hi,

    You mean

    Code:
    :
    Irms[k] = sqrt((double)(meanValuesSaved[k] / 20)) * 0.026393581;
    ???
    No. This is what I mean:
    Code:
    :
    Irms[k] = sqrt((double)(meanValuesSaved[k])) * 0.0059017841;
    Klaus
    Please donīt contact me via PM, because there is no time to respond to them. No friend requests. Thank you.


    1 members found this post helpful.

  16. #36
    Advanced Member level 2
    Points: 3,284, Level: 13
    baileychic's Avatar
    Join Date
    Aug 2017
    Posts
    651
    Helped
    50 / 50
    Points
    3,284
    Level
    13

    Re: ACS712-5A AC Current Reading - How to?

    Quote Originally Posted by KlausST View Post
    Hi,



    No. This is what I mean:
    Code:
    :
    Irms[k] = sqrt((double)(meanValuesSaved[k])) * 0.0059017841;
    Klaus
    Okay, your method gives very perfect and constant results. Thank you.

    Code:
    #define _BREAKPOINTS_PROTEUS    1
    #define _RESET                  0
    #define _DEBUG1                 0
    #define _PRINT_MEAN_VALUES      1
    
    #define _METHOD1               0
    #define _METHOD2               1
    
    #define _MAX_CHANNELS           8
    #define _MAX_SAMPLES            20
    
    sbit Chip_Select           at LATC0_bit;
    sbit Chip_Select_Direction at TRISC0_bit;
    
    sbit INT0_FREQ     at LATD0_bit;
    sbit TMR4_FREQ     at LATD1_bit;
    sbit ZC_RESET_FREQ at LATD2_bit;
    sbit ADC_ISR_FREQ  at LATD3_bit;
    sbit i_RESET_FREQ  at LATD4_bit;
    sbit j_RESET_FREQ  at LATD5_bit;
    
    sbit BP1           at LATD7_bit;
    
    unsigned int i = 0;
    unsigned int j = 0;
    unsigned int k = 0;
    unsigned int t = 0;
    
    char txt[23];
    
    unsigned int adcValue = 0;
    long sample = 0;
    unsigned long squareValue = 0;
    unsigned long meanValues[_MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
    unsigned long meanValuesSaved[_MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
    double Irms[_MAX_CHANNELS] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
    
    unsigned char flagReg = 0;
    sbit processDataFlag at flagReg.B0;
    
    //Timer4
    //Prescaler 1:1; Postscaler 1:8; TMR4 Preload = 249; Actual Interrupt Time : 125 us
    void InitTimer4() {
        T4CON = 0x38;
        TMR4IE_bit = 1;
        PR4 = 249;
    }
    
    void Select_ADG731_Channel(unsigned char data_) {
         Chip_Select = 0;
         SPI1_Write(data_);
         Chip_Select = 1;
    }
    
    void interrupt() {
        if((TMR4IE_bit) && (TMR4IF_bit)) {
            TMR4IF_bit = 0;
            TMR4_FREQ = ~TMR4_FREQ;
            GO_DONE_bit = 1;
        }
    
        if((INT0IE_bit) && (INT0IF_bit)) {
            INT0IF_bit = 0;
            INTEDG0_bit = ~INTEDG0_bit;
            INT0_FREQ = ~INT0_FREQ;
            ZC_RESET_FREQ = ~ZC_RESET_FREQ;
    
            if(!TMR4ON_bit) {
                i = 0;
                j = 0;
                Select_ADG731_Channel(i);
                TMR4ON_bit = 1;
            }
            
            GO_DONE_bit = 1;
        }
        
        if((ADIE_bit) && (ADIF_bit)) {
            ADIF_bit = 0;
            ADC_ISR_FREQ = ~ADC_ISR_FREQ;
            
            #if DEBUG1
            #else
              adcValue = 0;
              sample = 0;
              squareValue = 0;
            #endif
    
            adcValue = ((unsigned int)(ADRESH << 8) + ADRESL);
            sample = (signed long)adcValue - 512;
            squareValue = sample * sample;
            meanValues[i] += squareValue;
            
            if(++i >= 8) {
                i_RESET_FREQ = ~i_RESET_FREQ;
                i = 0;
                if(++j >= 20) {
                    j_RESET_FREQ = ~j_RESET_FREQ;
                    j = 0;
                    
                    if(!processDataFlag) {
                        #if _METHOD1
                            for(t = 0; t < 8; t++)meanValuesSaved[t] = meanValues[t] / 20;
                        #endif
    
                        #if _METHOD2
                            for(t = 0; t < 8; t++)meanValuesSaved[t] = meanValues[t];
                        #endif
                    
                        processDataFlag = 1;
                    }
                    memset(meanValues, 0, sizeof(meanValues));
                }
            }
    
            Select_ADG731_Channel(i);
        }
    }
    
    void main() {
        OSCCON = 0x70;
        OSCCON2 = 0x03;
        OSCTUNE = 0x40;
        
        CM1CON0 = 0x00;
        CM2CON0 = 0x00;
    
        SLRCON = 0x00;
    
        ADCON0 = 0x00;
        ADCON1 = 0x00;
        ADCON2 = 0b10111110;
    
        ANSELA = 0x01;
        ANSELB = 0x00;
        ANSELC = 0x00;
        ANSELD = 0x00;
        ANSELE = 0x00;
    
        TRISA = 0xC1;
        TRISB = 0x01;
        TRISC = 0xC0;
        TRISD = 0x00;
        TRISE = 0x00;
    
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
        PORTE = 0x00;
    
        LATA = 0x00;
        LATB = 0x00;
        LATC = 0x00;
        LATD = 0x00;
        LATE = 0x00;
        
        UART1_Init(9600);
    
        Chip_Select = 1;
        Chip_Select_Direction = 0;
        SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_HIGH_2_LOW);
        UART1_Write_Text("Taking readings...\r\n\r\n");
    
        ADC_Init_Advanced(_ADC_INTERNAL_REF);
        ADIE_bit = 1;
        
        INTEDG0_bit = 0;
        INT0IF_bit = 0;
        INT0IE_bit = 1;
        
        InitTimer4();
        
        INT0_FREQ = 1;
        INTCON |= 0xC0;
        
        #if _BREAKPOINTS_PROTEUS
            BP1 = 1;
            BP1 = 0;
        #endif
        
        while(1) {
            #if _DEBUG1
                sprintf(txt, "adcValue = %u\r\n", adcValue);
                UART1_Write_Text(txt);
                sprintf(txt, "sample = %d\r\n", sample);
                UART1_Write_Text(txt);
            #endif
            
            if(processDataFlag) {
                for(k = 0; k < 8; k++) {
                    #if _METHOD1
                        Irms[k] = sqrt((double)(meanValuesSaved[k])) * 0.026393581;
                    #endif
                    
                    #if _METHOD2
                        Irms[k] = sqrt((double)(meanValuesSaved[k])) * 0.0059017841;
                    #endif
                    
                    #if _PRINT_MEAN_VALUES
                    #else
                        meanValuesSaved[k] = 0;
                    #endif
                }
                processDataFlag = 0;
                
                #if _PRINT_MEAN_VALUES
                    #else
                memset(meanValuesSaved, 0, sizeof(meanValuesSaved));
                #endif
                
                #if _BREAKPOINTS_PROTEUS
                    BP1 = 1;
                    BP1 = 0;
                #endif
                
                for(k = 0; k < 8; k++) {
                    #if _PRINT_MEAN_VALUES
                        sprintf(txt, "meanValuesSaved[%u] = %lu\r\n", k, meanValuesSaved[k]);
                        UART1_Write_Text(txt);
                    #endif
                    
                    sprintf(txt, "Irms[%u] = %5.2fA\r\n", k, Irms[k]);
                    UART1_Write_Text(txt);
                }
    
                UART1_Write_Text("\r\n\r\n");
    
                #if _BREAKPOINTS_PROTEUS
                    BP1 = 1;
                    BP1 = 0;
                #endif
    
                #if _RESET
                    asm reset
                #endif
            }
        }
    }
    - - - Updated - - -

    Forgot to attach the project. Here it is.


    1 members found this post helpful.

--[[ ]]--