solar module
lemigsaw
Posts: 5
Hello, I need to measure both the voltage and current from a solar model with a Voc 21V and Isc 2A. I made a circuits based on the ADC0831 8-bit A/D using a potential divider to give me a max 5V using a 150k and 47k resistors ( so I could use a regulated 5V supply as the reference). The voltmeter works but when I measure the voltage from a controlled supply i noticed the measured voltage goes up in steps of 4 not inc ( 0V, 4V, 8V, 12V, 16V, then maxing at 21V) which must be because my program isn't rounding as it should (the 4 volts is due to, 5 = 21(47/(150+47); v_measured/v_supply = (150+47)/47 = 4.2, ie 5(measured) = 5*4.2= 21v(supply)). Could you guys please tell me what I have done wrong in the code below?
' {$STAMP BS2}
' {$PBASIC 2.5}
' Declarations
v_unit VAR Byte
v_tenth VAR Byte
v_hundredth VAR Byte
adcBits VAR Byte
v_r VAR Byte
v_dec VAR Byte
v_u VAR Byte
v VAR Byte
r VAR Byte
v2 VAR Byte
v3 VAR Byte
' Initialation
CS PIN 0
CLK PIN 1
DataOutput PIN 2
DEBUG CLS
' Main Routine
DO
GOSUB ADC_Data
GOSUB Calc_Volts
GOSUB Display
LOOP
' Sends control Signals
ADC_Data:
HIGH CS 'Sets the clock select high to start a conversion
LOW CS 'Sets the clock select low, Active. CS remains low for the conversion
LOW CLK 'for clock low-high-low
PULSOUT CLK, 210 'sends a pulsed clock to the CLK input, starts ADC converting on the next pulse
SHIFTIN DataOutput, CLK, MSBPOST, [noparse][[/noparse]adcBits\8] 'sends serial data on clk
RETURN
Calc_Volts:
v_unit = 4
v_tenth = 9
v_hundredth = 6
v = v_hundredth*adcBits/255 ' Calculates integer Voltage
r = v_hundredth*adcBits//255 ' Calculates the integer remainder
v2 = 100*r/255
v3 = 100*r // 255 ' Remainder from v2
v3 = 10*v3 / 255 ' long devision
IF (v3 >= 5) THEN v2 = v2+1 'Adds 1 to v2 when the thousandth's place is more than 5
IF (v2 >=100) THEN ' if v2 is eqaul to 100 at 1
v = v+1
v2 = v2 - 100
ENDIF
v_r = v2
v_dec = v
v_u = 0
v = v_tenth*adcBits/255 ' Calculates integer Voltage
r = v_tenth*adcBits//255 ' Calculates the integer remainder
v2 = 100*r/255
v3 = 100*r//255 ' Remainder from v2
v3 = 10*v3/255 ' long devision
IF (v3 >= 5) THEN v2 = v2+1 'Adds 1 to v2 when the thousandth's place is more than 5
IF (v2 >=100) THEN ' if v2 is eqaul to 100 at 1
v = v+1
v2 = v2 - 100
ENDIF
v_r = v_r + 10*(v2//10)
IF (v_r >= 50) THEN
v_dec = v_dec + 1
v_r = 0
ENDIF
v_dec = v_dec + (10*v) + (v2/10)
IF (v_dec >= 100) THEN
v_u = v_u + 1
v_dec = v_dec - 100
ENDIF
v = v_unit*adcBits/255 ' Calculates integer Voltage
r = v_unit*adcBits//255 ' Calculates the integer remainder
v2 = 100*r/255
v3 = 100*r//255 ' Remainder from v2
v3 = 10*v3/255 ' long devision
IF (v3 >= 5) THEN v2 = v2+1 'Adds 1 to v2 when the thousandth's place is more than 5
IF (v2 >=100) THEN ' if v2 is eqaul to 100 at 1
v = v+1
v2 = v2 - 100
ENDIF
v_dec = v_dec+ v2
IF (v_dec >= 100) THEN
v_u = v_u+1
v_dec = v_dec - 100
ENDIF
v_u = v_u + v
v_u = v_u*413
v2 = v_dec + (v_u//100)
v_u = v_u/100
v_dec = v_dec*413
IF (v_dec >= 10000) THEN
v_u = v_u + (v_dec/10000)
v_dec = v_dec//10000
ENDIF
RETURN
Display:
DEBUG HOME
DEBUG "8-bit binary value: ", BIN8 adcBits
DEBUG CR, CR, "Decimal value: ", DEC3 adcBits
DEBUG CR, CR, "DVM Reading: "
DEBUG DEC2 v_u, ".", DEC2 v_dec, " Volts"
RETURN
Additionally I am using a shunt resistor (0.1 ohms) and measuring the voltage across to find the current (I = v/0.1=v*10). I'm using a pot to give the ADC a 0.5V referece voltage, however the output jumps about way too much to be of useful. I really don't know what to do, I was thinking about amplifying the voltage across the resistor to 5V? Can anyone see errors in my code:
' {$STAMP BS2}
' {$PBASIC 2.5}
' Declarations
adcBits VAR Byte
v VAR Byte
r VAR Byte
v2 VAR Byte
v3 VAR Byte
v_temp VAR Byte
I VAR Byte
I2 VAR Byte
I3 VAR Byte
' Initialation
CS PIN 0
CLK PIN 1
DataOutput PIN 2
DEBUG CLS
' Main Routine
DO
GOSUB ADC_Data
GOSUB Calc_Volts
GOSUB Display
LOOP
' Sends control Signals
ADC_Data:
HIGH CS 'Sets the clock select high to start a conversion
LOW CS 'Sets the clock select low, Active. CS remains low for the conversion
LOW CLK 'for clock low-high-low
PULSOUT CLK, 210 'sends a pulsed clock to the CLK input, starts ADC converting on the next pulse
SHIFTIN DataOutput, CLK, MSBPOST, [noparse][[/noparse]adcBits\8] 'sends serial data on clk
RETURN
Calc_Volts:
v = 5*adcBits/255 ' Calculates integer Voltage
r = 5*adcBits//255 ' Calculates the integer remainder
v2 = 100*r/255
v3 = 100*r // 255 ' Remainder from v2
v3 = 10*v3 /255 ' long devision
IF (v3 >= 5) THEN v2 = v2+1 'Adds 1 to v2 when the thousandth's place is more than 5
IF (v2 >=100) THEN ' if v2 is eqaul to 100 at 1
v = v+1
v2 = 0
ENDIF
v = (v*100)+ v2
I = v*10
'I3 = I//10
'I2 = (I//100)/10
'I = I/100
'IF (I3 >=5) THEN
'I2 = I2+1
'ENDIF
'IF (I2 >=10) THEN
'I = I+1
'ENDIF
PAUSE 1000
RETURN
Display:
DEBUG HOME
DEBUG "8-bit binary value: ", BIN8 adcBits
DEBUG CR, CR, "Decimal value: ", DEC adcBits
DEBUG CR, CR, "DVM Reading: "
DEBUG DEC5 v, " mV"
DEBUG CR, CR, "Ameter Reading: "
DEBUG DEC5 I, " A"
RETURN
I will be truly very greatful for your help,
Regards,
Ross
' {$STAMP BS2}
' {$PBASIC 2.5}
' Declarations
v_unit VAR Byte
v_tenth VAR Byte
v_hundredth VAR Byte
adcBits VAR Byte
v_r VAR Byte
v_dec VAR Byte
v_u VAR Byte
v VAR Byte
r VAR Byte
v2 VAR Byte
v3 VAR Byte
' Initialation
CS PIN 0
CLK PIN 1
DataOutput PIN 2
DEBUG CLS
' Main Routine
DO
GOSUB ADC_Data
GOSUB Calc_Volts
GOSUB Display
LOOP
' Sends control Signals
ADC_Data:
HIGH CS 'Sets the clock select high to start a conversion
LOW CS 'Sets the clock select low, Active. CS remains low for the conversion
LOW CLK 'for clock low-high-low
PULSOUT CLK, 210 'sends a pulsed clock to the CLK input, starts ADC converting on the next pulse
SHIFTIN DataOutput, CLK, MSBPOST, [noparse][[/noparse]adcBits\8] 'sends serial data on clk
RETURN
Calc_Volts:
v_unit = 4
v_tenth = 9
v_hundredth = 6
v = v_hundredth*adcBits/255 ' Calculates integer Voltage
r = v_hundredth*adcBits//255 ' Calculates the integer remainder
v2 = 100*r/255
v3 = 100*r // 255 ' Remainder from v2
v3 = 10*v3 / 255 ' long devision
IF (v3 >= 5) THEN v2 = v2+1 'Adds 1 to v2 when the thousandth's place is more than 5
IF (v2 >=100) THEN ' if v2 is eqaul to 100 at 1
v = v+1
v2 = v2 - 100
ENDIF
v_r = v2
v_dec = v
v_u = 0
v = v_tenth*adcBits/255 ' Calculates integer Voltage
r = v_tenth*adcBits//255 ' Calculates the integer remainder
v2 = 100*r/255
v3 = 100*r//255 ' Remainder from v2
v3 = 10*v3/255 ' long devision
IF (v3 >= 5) THEN v2 = v2+1 'Adds 1 to v2 when the thousandth's place is more than 5
IF (v2 >=100) THEN ' if v2 is eqaul to 100 at 1
v = v+1
v2 = v2 - 100
ENDIF
v_r = v_r + 10*(v2//10)
IF (v_r >= 50) THEN
v_dec = v_dec + 1
v_r = 0
ENDIF
v_dec = v_dec + (10*v) + (v2/10)
IF (v_dec >= 100) THEN
v_u = v_u + 1
v_dec = v_dec - 100
ENDIF
v = v_unit*adcBits/255 ' Calculates integer Voltage
r = v_unit*adcBits//255 ' Calculates the integer remainder
v2 = 100*r/255
v3 = 100*r//255 ' Remainder from v2
v3 = 10*v3/255 ' long devision
IF (v3 >= 5) THEN v2 = v2+1 'Adds 1 to v2 when the thousandth's place is more than 5
IF (v2 >=100) THEN ' if v2 is eqaul to 100 at 1
v = v+1
v2 = v2 - 100
ENDIF
v_dec = v_dec+ v2
IF (v_dec >= 100) THEN
v_u = v_u+1
v_dec = v_dec - 100
ENDIF
v_u = v_u + v
v_u = v_u*413
v2 = v_dec + (v_u//100)
v_u = v_u/100
v_dec = v_dec*413
IF (v_dec >= 10000) THEN
v_u = v_u + (v_dec/10000)
v_dec = v_dec//10000
ENDIF
RETURN
Display:
DEBUG HOME
DEBUG "8-bit binary value: ", BIN8 adcBits
DEBUG CR, CR, "Decimal value: ", DEC3 adcBits
DEBUG CR, CR, "DVM Reading: "
DEBUG DEC2 v_u, ".", DEC2 v_dec, " Volts"
RETURN
Additionally I am using a shunt resistor (0.1 ohms) and measuring the voltage across to find the current (I = v/0.1=v*10). I'm using a pot to give the ADC a 0.5V referece voltage, however the output jumps about way too much to be of useful. I really don't know what to do, I was thinking about amplifying the voltage across the resistor to 5V? Can anyone see errors in my code:
' {$STAMP BS2}
' {$PBASIC 2.5}
' Declarations
adcBits VAR Byte
v VAR Byte
r VAR Byte
v2 VAR Byte
v3 VAR Byte
v_temp VAR Byte
I VAR Byte
I2 VAR Byte
I3 VAR Byte
' Initialation
CS PIN 0
CLK PIN 1
DataOutput PIN 2
DEBUG CLS
' Main Routine
DO
GOSUB ADC_Data
GOSUB Calc_Volts
GOSUB Display
LOOP
' Sends control Signals
ADC_Data:
HIGH CS 'Sets the clock select high to start a conversion
LOW CS 'Sets the clock select low, Active. CS remains low for the conversion
LOW CLK 'for clock low-high-low
PULSOUT CLK, 210 'sends a pulsed clock to the CLK input, starts ADC converting on the next pulse
SHIFTIN DataOutput, CLK, MSBPOST, [noparse][[/noparse]adcBits\8] 'sends serial data on clk
RETURN
Calc_Volts:
v = 5*adcBits/255 ' Calculates integer Voltage
r = 5*adcBits//255 ' Calculates the integer remainder
v2 = 100*r/255
v3 = 100*r // 255 ' Remainder from v2
v3 = 10*v3 /255 ' long devision
IF (v3 >= 5) THEN v2 = v2+1 'Adds 1 to v2 when the thousandth's place is more than 5
IF (v2 >=100) THEN ' if v2 is eqaul to 100 at 1
v = v+1
v2 = 0
ENDIF
v = (v*100)+ v2
I = v*10
'I3 = I//10
'I2 = (I//100)/10
'I = I/100
'IF (I3 >=5) THEN
'I2 = I2+1
'ENDIF
'IF (I2 >=10) THEN
'I = I+1
'ENDIF
PAUSE 1000
RETURN
Display:
DEBUG HOME
DEBUG "8-bit binary value: ", BIN8 adcBits
DEBUG CR, CR, "Decimal value: ", DEC adcBits
DEBUG CR, CR, "DVM Reading: "
DEBUG DEC5 v, " mV"
DEBUG CR, CR, "Ameter Reading: "
DEBUG DEC5 I, " A"
RETURN
I will be truly very greatful for your help,
Regards,
Ross
Comments
The calcualtor formula to get from the raw count from the ADC (0-255), to the input voltage (0 to 21) is
' volts = ADCbits * 0.082353 (0.082353 = 21/255).
In the Stamp, that would be
The factor after the ** comes from 0.082353 * 65536 * 10 = 53971. The ** operator causes the Stamp to multiply internally by 53971 (32 bit result) and also internally it divides by 65536. Note that 53971/65536 is a very close approximation to 0.82353 = 210/255.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com
Post Edited (Tracy Allen) : 2/29/2008 5:05:18 PM GMT
Your other two duplicate messages cross-posted in other forums have been removed. Please post messages only once and in the appropriate forum for the subject of the message.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support
Sorry about posting on other forums, I have just got so frustraighted with the program not working!!!
' {$STAMP BS2}
' {$PBASIC 2.5}
' Declarations
adcBits VAR Word
volts VAR Word
' Initialation
CS PIN 0
CLK PIN 1
DataOutput PIN 2
DEBUG CLS
' Main Routine
DO
GOSUB ADC_Data
GOSUB Calc_Volts
GOSUB Display
LOOP
' Sends control Signals
ADC_Data:
HIGH CS 'Sets the clock select high to start a conversion
LOW CS 'Sets the clock select low, Active. CS remains low for the conversion
LOW CLK 'for clock low-high-low
PULSOUT CLK, 210 'sends a pulsed clock to the CLK input, starts ADC converting on the next pulse
SHIFTIN DataOutput, CLK, MSBPOST, [noparse][[/noparse]adcBits\8] 'sends serial data on clk
RETURN
Calc_Volts:
volts = adcbits ** 53971 ' in units of 0.1 volt
RETURN
Display:
DEBUG HOME
DEBUG "8-bit binary value: ", BIN8 adcBits
DEBUG CR, CR, "Decimal value: ", DEC3 adcBits
DEBUG CR, CR, "DVM Reading: "
DEBUG TAB, DEC volts/10, ".", DEC1 volts ' e.g. 11.3 volts
RETURN
However I don't fully understand how ** works. I understand how the ** operator causes the Stamp to multiply internally by 53971 (32 bit result) but I don't understand how the stamp is instructed to divides by 6553?
I send you a PM
This will help you Understand how you·use the·" * "
I hope that this helps
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
··Thanks for any··that you may have and all of your time finding them
·
·
·
·
Sam
Another way to do it is with the PBASIC operator */, as follows:
Calc_Volts:
volts = adcbits */ 211 ' in units of 0.1 volt
RETURN
That works in a manner similar to the ** 53971. However, instead of an implied divisor of 65536, here it is 256. The Stamp internally multiplies adcbits times 211, and then divides by 256. You do not have to instruct it to divide by 256; that is part of the */ operator and is suggested by the "*/" symbol.
In this case there will not be much preference for using either */ or **. The ** is often preferred when higher accuracy is desired, for example, when working with a 12 or 16 bit ADC instead of an 8 bit ADC. The ** operator also comes into play in double precision arithmetic as the high word of a double precision multiply.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com
Thank You for Explaining what this is and how it is used·" ** " and ·" */ "
I learned something today
........to divide by 256; that is part of the */ operator and is suggested by the "*/" symbol............
In this case there will not be much preference for using either */ or **. The ** is often preferred when higher accuracy is desired, for example, when working with a 12 or 16 bit ADC instead of an 8 bit ADC. The ** operator also comes into play in double precision arithmetic as the high word of a double precision multiply.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
··Thanks for any··that you may have and all of your time finding them
·
·
·
·
Sam
Post Edited (sam_sam_sam) : 3/1/2008 5:53:58 AM GMT
I am working on a project that has a similar set of requirements, its a weather station with a solar powered external sensor array. I wanted to monitor the output of the three solar panels and the battery bus feeding the system. In order to process all the sensors, I was getting somewhat confused with the integer math techniques available on the basic stamp. I added the Floating Point Coprocessor (Parallax Item code 604-00030) and the development became much simpler and the code much easier to debug. I also am pushing the limits on the programming memory of the BS2, so the ability to store the routines as functions in the FPU has given me the head room needed for the project. The code for the voltage readings is as follows.
In the external sensor array:
'Set VoltSelect to one of the following based on requested data
'Constants for the 4 channel Power Monitor (ADC0834)
SolarV1·· CON %1100 ' A/D MUX IDs for Ch 0..3
SolarV2·· CON %1110 ' Bit 3 = 1, start bit
SolarV3·· CON %1101 ' Bit 2 = 1, single (1)/diff (0)
BattBus·· CON %1111 ' Bit 1 odd / sign, Bit 0 select
...
DataValue· VAR Word····· 'Value to send to Internal Unit
...
ReadVoltages:
· HIGH PM_V_CS· 'Deactivate the ADC0831 Voltage Monitor
· LOW PM_Clk
· LOW PM_Din
· DataValue = 0
· 'A2D_Start_Conversion
· LOW PM_V_CS
· SHIFTOUT PM_Din,PM_Clk,MSBFIRST,[noparse][[/noparse]VoltSelect\4]
· PULSOUT PM_Clk,10·· '20 uSec for data conversion
· SHIFTIN PM_Dout,PM_Clk,MSBPRE,[noparse][[/noparse]DataValue.LOWBYTE]
· HIGH PM_V_CS
RETURN
Code in the Internal Unit:
'
uM-FPU V2 Register Definitions
BaroReadingHg·· CON···· 1·············· ' uM-FPU register 1
BaroReading···· CON···· 2·············· ' uM-FPU register 2
VoltsIN········ CON···· 2·············· ' uM-FPU register 2
Voltage········ CON···· 1·············· ' uM-FPU register 1
DSTemp········· CON···· 2·············· ' uM-FPU register 2
ElectTemp······ CON···· 1·············· ' uM-FPU register 1
soT············ CON···· 2·············· ' uM-FPU register 2
Temperature···· CON···· 1·············· ' uM-FPU register 1
soH············ CON···· 2·············· ' uM-FPU register 2
RH············· CON···· 1·············· ' uM-FPU register 1
'
uM-FPU V2 Function Definitions
GetBaro········ CON···· 1·············· ' uM-FPU user function 1
GetVoltage····· CON···· 2·············· ' uM-FPU user function 2
GetElectTemp··· CON···· 3·············· ' uM-FPU user function 3
GetTemperature· CON···· 4·············· ' uM-FPU user function 4
GetHumidity···· CON···· 5·············· ' uM-FPU user function 5
ProcessVoltage:
· GOSUB Get_Data 'Communications routine to the external unit
· SELECT Instrument
··· CASE "S"
····· PINK_Register=21 'The variable in the Netburner to publish the data on a web page
··· CASE "U"
····· PINK_Register=22
··· CASE "N"
····· PINK_Register=23
··· CASE "B"
····· PINK_Register=24
· ENDSELECT
· SHIFTOUT FpuOut, FpuClk, MSBFIRST, [noparse][[/noparse]VoltsIN,
·········· LOADWORD, IncomingData.HIGHBYTE, IncomingData.LOWBYTE, FSET]
· SHIFTOUT FpuOut, FpuClk, MSBFIRST, [noparse][[/noparse]XOP, FUNCTION+GetVoltage]
· format = 53
· GOSUB Print_FloatFormat 'A function of the FPU to output formatted floating point
The code in the FPU:
IncomingData VAR Word
DataIN· equ F2
DataOut equ F1
'
Voltage Conversion
#FUNCTION 2 GetVoltage
DataOut= DataIN * 0.0195 * 2
#End
DataIN = IncomingData
@GetVoltage
Although this was slightly overkill for the voltages, the rain/snow sensor I built has a much more complex routine:
InchRain = -2E-12(DataIN)^3 + 3E-08(DataIN)^2 + 0.0002(DataIN) + 0.0035
I gave up trying to program this with just PBasic.
Post Edited (MSDTech) : 3/2/2008 2:35:29 PM GMT
Can you Please post the hole code
I would like to use part of your code·
If you do not mind
Thanks for any help that you can give
I want to use a ADC 0834 in an up coming project that·I have in mind
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
··Thanks for any··that you may have and all of your time finding them
·
·
·
·
Sam
' {$STAMP BS2}
' {$PBASIC 2.5}
' Declarations
adcBits VAR Word
volts VAR Word
' Initialation
CS PIN 0
CLK PIN 1
DataOutput PIN 2
DEBUG CLS
' Main Routine
DO
GOSUB ADC_Data
GOSUB Calc_Volts
GOSUB Display
LOOP
' Sends control Signals
ADC_Data:
HIGH CS 'Sets the clock select high to start a conversion
LOW CS 'Sets the clock select low, Active. CS remains low for the conversion
LOW CLK 'for clock low-high-low
PULSOUT CLK, 210 'sends a pulsed clock to the CLK input, starts ADC converting on the next pulse
SHIFTIN DataOutput, CLK, MSBPOST, [noparse][[/noparse]adcBits\8] 'sends serial data on clk
RETURN
Calc_Volts:
volts = adcbits ** 53971 ' in units of 0.1 volt
RETURN
Display:
DEBUG HOME
DEBUG "8-bit binary value: ", BIN8 adcBits
DEBUG CR, CR, "Decimal value: ", DEC3 adcBits
DEBUG CR, CR, "DVM Reading: "
DEBUG TAB, DEC volts/10, ".", DEC1 volts ' e.g. 11.3 volts
RETURN
Thanks all, I will post how the ammeter worked tomorrow! If anyone wants to see the excel data please ask
Ross
The Code for the Internal Processor, the External Processor and the code for the FPU.
Keep in mind, I am still programming the system. I've got all the sensors working correctly, including the rain gage (a weight based unit that will also measure snow equivalent). I still need to up the storage routines. I have a 32K EEPROM in the system that can store about 60 days of hourly data.
For each instrument, the reading code is in the External Unit and the data is processed by the Internal Unit.
Most of the code is modified from the samples provided on the Parallax site.
For the shunt resistor measurements you might want to use something like the Analog Devices AD7705. This is what I'm using on the rain gage to read the signal off the strain gage in the scale. It combines an amplifier with the ADC into a single package. The code for it is in the External unit.
Post Edited (MSDTech) : 3/9/2008 5:19:29 AM GMT