Shop OBEX P1 Docs P2 Docs Learn Events
solar module — Parallax Forums

solar module

lemigsawlemigsaw Posts: 5
edited 2008-03-02 21:45 in Learn with BlocklyProp
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

Comments

  • Tracy AllenTracy Allen Posts: 6,664
    edited 2008-02-29 00:19
    Ross, there is an easier way to do the math, using the Stamp's ** operator.

    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
    volts = ADCbits ** 53971   ' in units of 0.1 volt
    DEBUG CR, BIN8 ADCbits
    DEBUG TAB, DEC volts/10, ".", DEC1 volts   ' e.g. 11.3 volts
    



    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
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2008-02-29 15:48
    Hello,

    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
  • lemigsawlemigsaw Posts: 5
    edited 2008-02-29 16:40
    Thanks Tracy, I will be giving that a try again tomorrow.

    Sorry about posting on other forums, I have just got so frustraighted with the program not working!!!
  • lemigsawlemigsaw Posts: 5
    edited 2008-02-29 23:40
    The program I am going to try is:

    ' {$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?
  • sam_sam_samsam_sam_sam Posts: 2,286
    edited 2008-03-01 00:33
    lemigsaw
    I send you a PM

    This will help you Understand how you·use the·" * "

    I hope that this helps

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ··Thanks for any·idea.gif·that you may have and all of your time finding them

    ·
    ·
    ·
    ·
    Sam
  • lemigsawlemigsaw Posts: 5
    edited 2008-03-01 00:40
    Thanks Sam, that really made using the '**' clear! I will post on this thread tomorrow to let you guys know how it worked!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2008-03-01 05:21
    Ross,

    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
  • sam_sam_samsam_sam_sam Posts: 2,286
    edited 2008-03-01 05:28
    Tracy Allen

    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·idea.gif·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
  • MSDTechMSDTech Posts: 342
    edited 2008-03-02 14:30
    lemigsaw,
    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
  • sam_sam_samsam_sam_sam Posts: 2,286
    edited 2008-03-02 19:37
    MSDTech
    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·idea.gif·that you may have and all of your time finding them

    ·
    ·
    ·
    ·
    Sam
  • lemigsawlemigsaw Posts: 5
    edited 2008-03-02 21:00
    The code worked really well! I'm going to build a little amp tomorrow to get the voltage from the shunt resistor to 5V max. The code that I used for the voltmeter was:

    ' {$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
  • MSDTechMSDTech Posts: 342
    edited 2008-03-02 21:45
    I've posted 3 files:

    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
Sign In or Register to comment.