Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] ACS712-5A AC Current Reading - How to?

Status
Not open for further replies.
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
 
@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
    }
}

 

Attachments

  • SPMM-Test-Rev-1.4.rar
    133 KB · Views: 79
  • SS-1.png
    SS-1.png
    160.5 KB · Views: 108
Last edited:

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
 
@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 values is 0 what ever I do. I also disabled min 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 and min. 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 and max

Method 0 takes just 15ms max to read all sensors and get min and maxvalues.

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
    }
}

 

Attachments

  • SS-2-Method-1-Good-1.png
    SS-2-Method-1-Good-1.png
    173.6 KB · Views: 98
  • SS-2-Method-0-Bad-1.png
    SS-2-Method-0-Bad-1.png
    173.8 KB · Views: 100
  • SS-2-Method-0-Good-3.png
    SS-2-Method-0-Good-3.png
    174 KB · Views: 94
Last edited:

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
    }
}

 

Attachments

  • SS-5.png
    SS-5.png
    177.1 KB · Views: 96
Last edited:

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.
 
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:

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?
 

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 ...
 
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
        }
    }
}

 

Attachments

  • Correct-With-Wrong-Casting.png
    Correct-With-Wrong-Casting.png
    248.8 KB · Views: 93
  • Correct-Rotated-With-Correct-Casting.png
    Correct-Rotated-With-Correct-Casting.png
    251.9 KB · Views: 94
  • SPMM-RMS-2.0.0.rar
    181.5 KB · Views: 73
  • SPMM-RMS.PDF
    76.8 KB · Views: 82
Last edited:

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
 
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
        }
    }
}
 

Attachments

  • Perfect Values.png
    Perfect Values.png
    254.7 KB · Views: 95
  • SPMM-RMS-2.0.2.rar
    158.8 KB · Views: 64
Last edited:

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])) [COLOR="#008000"]* 0.0059017841[/COLOR];

Klaus
 
Hi,



No. This is what I mean:
Code:
:
Irms[k] = sqrt((double)(meanValuesSaved[k])) [COLOR="#008000"]* 0.0059017841[/COLOR];

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.
 

Attachments

  • Very Perfect.png
    Very Perfect.png
    261.3 KB · Views: 91
  • SPMM-RMS-2.0.3.rar
    158.3 KB · Views: 70
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top