Wednesday, June 6, 2012

avr solar counter

To log the harvested energy from your solar cells, you need a counter device. Here is my low cost counter (10$) with AVR micro controller, LCD and SD card for small solar cells upto 25W.
This is an ongoing project. Therefore more features and improvements will follow.

Features (so far):
-current upto 2A
-display of actual current
-display of harvested mA hours since begin of logging
-easy firmware update of the device through com port 

features not implemented yet:
-logging of hourly harvested energy to SD card
-upload of SD card data through serial connection (com port)



Time is displayed in the upper left,  iv = instant value for current - here 12mA in the evening of a rainy day, second line shows the total harvested Energy in mAh.





Current from the solar cell to the rechargeable battery is measured over R2. Resistor 2 is about 0.1 Ohm which is suitable for measurements upto 2A. If you wish to measure currents over 2A a smaller Resistor is needed otherwise the resistor will get too hot and will waste your energy. Calculate the power wasted by the resistor by the formula:
P= I² *R  At 2 Amperes and 0.1Ohm  this gives 0.4 Watt over the resistor.
The LM358 (2 op amps in a 8 pin package) amplifies the voltage of R2 and feeds the ADC of Atmels Atmega8. Note that Atmega 48, 88, 168 are pin compatible replacements.
Compiled hex file and source code in bascom are on the bottom of this page.

UPDATE:
new feature: SD card logging

The eeprom logging feature will not been implemented as the memory capacity of the standard 2 wire eeproms 24Cxx is insufficient.
Therefore logging to SD card will be the only choice. SD cards give a virtually unlimited storage space for this purpose. Data can be written directly to sectors and read out via the serial connection of the logger.
Electrically the card should be connected as shown in the schematic. Pin 1 to 7 are connected. When soldering the wires directly to the card, take care not to connect pin 7 and 8.

SD cards are specified for a voltage upto 3.6V. MMC cards are pin compatible and might work from 1.8V to 3.6V.
Source code and more description will follow.













Source code versions

version 1
 basic version, no logging feature, time, instant current value and collected energy will be displayed on LCD until next reset of the logger


 *********************** start of version 1 *************************

   $regfile = "m8def.dat"
$crystal = 4096000
$hwstack = 100
$swstack = 100
$framesize = 100




'******************* LCD-  ************************

 Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portd.7 , Db6 = Portb.0 , _
   Db7 = Portb.1 , E = Portd.4 , Rs = Portd.3
Config Lcd = 16 * 2
Cursor Off




Dim Displayflag As Bit                                      'update display 1s set flag in timer1 isr

Dim Adcflag As Bit                                          'adc flag will be set to 0 by timer 1s
Dim A As Byte                                               ' count variable for ADCmeasure

Dim Second As Byte
Dim Minute As Byte
Dim Hour As Byte
Dim Day As Byte
Dim Hourvalue As Word                                       'value per hour
Dim Instvalue As Word                                       ' value of adc measurement

Dim Sumvalue As Long                                        'sum of all adc measurements

Dim Totalseconds As Long                                    'seconds since start of measurement
Dim Totalcharge As Long                                     'totalcharge since beginning of measurement
  ' - - - - - - - - Timer1 - - - - - - - - - - - - - - - -
Config Timer1 = Timer , Prescale = 256                      'config Timer1
Enable Timer1                                               'turn on t1
On Timer1 Isr_von_timer1                                    'verzweige bei Timer1 überlauf zu   Isr_von_Timer1
Enable Interrupts
Timer1 = 49535                                              'timer value to get 1s-- 65535´-16000 = 49535
 Second = 0

  ' - - - - - - - - int0 - - - - - - - - - - set clock


 On Int0 Int0isr                                            'on interrupt0 goto  INT0ISR
 Config Int0 = Falling
  Enable Int0
 Enable Interrupts                                          'Interrupts enabled


Config Pind.2 = Input                                       'int0 pin

Portd.2 = 1                                                 'enable pullup for Interrupt0 pin



  '------------adc-----------------


  Config Adc = Single , Prescaler = Auto , Reference = Avcc ' AVCC = 3V - for SD card






'------------main-------------------
    Do

  '- lcd values 1x /s

  If Displayflag = 1 Then
Totalcharge = Sumvalue / 3600                               'total charge until now
Locate 1 , 1
 Cls
Lcd Hour ; "H" ; Minute ; " iv " ; Instvalue ; "mA"         'display 00H00_iv_xxxxmA  displays minute, hours, instant value,
 Locate 2 , 1

 Lcd Totalcharge ; "mAh Total"                              '1024_T2048mAh
                                                            'will be updated next second again, timer1 resets flag
  Displayflag = 0




  End If

  '- count minutes up

 If Second = 60 Then

 Second = 0
 Incr Minute


End If

  '-  count hours up and calculate values
If Minute = 60 Then
Incr Hour
Minute = 0



End If

 '-count days up

If Hour = 24 Then
Hour = 0
Incr Day
End If


 '- measure adc once per second
If Adcflag = 0 Then Gosub Adcmeasure













 Loop





   '----------timer1  -------------

 Isr_von_timer1:                                            '
Timer1 = 49535                                              'Timer1 counts from 34285 to get 1second
Adcflag = 0                                                 'to read ADC value in main programm after timer interrupt
Incr Second
Incr Totalseconds

Displayflag = 1                                             'update lcd once per second in main program
Return

  '----------set clock  -------------
Int0isr:                                                    'to set clock

Incr Minute

Return

 '----------measure current -----------------
 Adcmeasure:
  Instvalue = 0                                             ' reset instvalue for next getadc

   For A = 1 To 2
Instvalue = Instvalue + Getadc(0)                           ' instvalue = mA
     Next A
                                  'instvalue is reset to 0 in timer1 isr

  Sumvalue = Sumvalue + Instvalue                           'adc sum of seconds since start of device

   Adcflag = 1                                              ' prevent main programm to do measurement again in this second



  Return


*********************** end of version 1 *************************

Wednesday, May 30, 2012

AVR 9V battery charger





Several devices use the 9V batteries and the rechargeable NiMh version is a good option. 
There are only a few commercial chargers for this type of 9V block available, and most of them are either expensive or of low quality and will damage your rechargeable battery.
Here comes my version of charger with the following features:
- input voltage from 12 to 42V
-constant current charge 
-micro-controller verifies the charge and switches charging off when a certain voltage of the battery is reached
- battery voltage displayed on LCD during charge
-low cost - about 10$ in total




Details:

The AVR micro controller measures the voltage of the battery over R4 and R3. Before measurement is taken, the charging voltage is switched off by the micro controller via Q1.
Q1 can be any P-channel FET, in my case I use an smd version in a SOT8 package which contains 1 N-channel and 1 P-channel FET. 
IC6 is just a 5V linear voltage regulator. In my case a LM1117 smd but any other 5V regulator would do the job. You can also use LF50, 7805, LP2950 etc.
The LCD is a standard HD47780 compatible LCD, in my case with 8x2. R7 for the LCD contrast, can be replaced by a fixed resistor connected to ground. Try values from 600 Ohm to 6k .
Charging current is limited to a maximum of 25mA by the resistor and LM117 combination at the output.


http://www.gutenberg.org


Here comes the bascom source code:

 $regfile = "attiny44.dat"
$crystal = 978149                                           '1001625                                                   500 in 8min56s = 536s /128x = 65536x timer =
$hwstack = 20
$swstack = 20
$framesize = 20


Dim A As Byte                                               'counter for 10x get ADC

Dim Voltage As Word                                         'calculated voltage from ADCwert
Dim Adcwert As Word                                         'For Battery Voltage
Dim Timecount As Word
Dim Displayvolt As String * 3                               'convert number to string for decimal point value
Dim Voltstring As String * 4
 Config Portb.0 = Output                                    'switches charging mosfet to 0
 Config Porta.6 = Input                                     ' set tri-state adcpin to prevent voltage


'----------timer1 for voltage check time--------------

  Config Timer1 = Timer , Prescale = 64                     'configure timer for 2 seconds
Enable Timer1                                               'enable timer
On Timer1 Isr_timer1                                        'after 2 seconds iterrupt routine is executed  Isr_von_Timer1
Enable Interrupts
 'Timer1 = 1337


 'lcd ----------------------------------------------
Config Lcdpin = Pin , Db4 = Porta.3 , Db5 = Porta.2 , Db6 = Porta.1 , _
   Db7 = Porta.0 , E = Porta.4 , Rs = Porta.5
Config Lcd = 16 * 2



't---------------------config ADC----------------------

   Config Adc = Single , Prescaler = Auto , Reference = Avcc
   Start Adc



'(

 if voltage =  0 then Lcd Insert Battery
 if voltage < 10v then start charge via Pb.0 = 0
if voltage > 10v then display "battery full" and finish



')



'----------main loop----------------------------
  Do


  Wait 2



  Loop







  Isr_timer1:



   '----------Measure battery voltage------------

    Portb.0 = 0
    Config Portb.0 = Input                                  'measuring of voltage every 2 seconds while not charging ,switch mosfet off, no charge
  Waitms 5


    Adcwert = 0
   For A = 1 To 10
    Adcwert = Adcwert + Getadc(6)                           'pin7
    Next A


  '---------display state ---------------
     If Adcwert > 3700 Then
    Cls
                                      'when voltage is over 370= 10V, battery full, end charge


    Lcd "full"
    End If

  If Adcwert = 0 Then
  Cls

 Locate 1 , 1
 Lcd "insert"
 Locate 2 , 1
 Lcd "battery"
 End If


 If Adcwert < 3701 And Adcwert > 0 Then                     '3701 =10V

  Config Portb.0 = Output
    Portb.0 = 1                                             'Switch Mosfet On , Charge
 Cls

  Voltage = Adcwert / 37
      Displayvolt = Str(voltage)
            Voltstring = Format(displayvolt , " 0.0")

            Locate 1 , 1
            Lcd "charging"
            Locate 2 , 1
    Lcd Voltstring ; " V"


    End If


    Return



    Finish:


   Portb.0 = 0                                              'switch mosfet off, no charge


    Cls

    Lcd "full"
    Wait 2

    Return