Sunday, February 19, 2012

Shortcut protection for power supply



This i the automatic shortcut protection circuit in my dual  rail power supply with 2 x lm338



Schemtaic for the shortcut protection circuit,. This is scheematic for the single rail powersupply, you can just add more  optocouplers in series for dual rail, or even more rails.

Wednesday, February 15, 2012

Saturday, February 11, 2012

Arduino as voltmeter

I made a solardatalogger for few years ago (will publish code latter to this solardatalogger).

In my solardatalogger i used arduino with a ethershield to mesure battery bank voltage with analog input.

The analog input at the arduino board are not protected, and will burn if 20 volt is connected. So i made a overvoltage protecting circuit with a few 1% resistors and a 5 volt zener.

The codesnip below is used to integrate in you own arduino sketch, enjoy ;)
Arduino as Voltmeter


The routine showed in the codesnip collect data from analog pin 5, at 5 volts contains whole 1023, the divide by 2 and converted into 4 digits. The 4 digits plus a decimal point is stored in a string of char with excitement: 05.00 ready to send serial with usb or via ethernet.

A better way to scale the analog input is with the MAP command:

map(value, fromLow, fromHigh, toLow, toHigh)

This command is very flexible. value is converted from 0 to 1023 to 0 to 20000

Then we have a good solid scale, and need only to divide by 1000 to place the decimal point.

In my own solardatalogger project data is sent to a mysql database and it is easy to handle calculations in php instead of the Arduino.


In my EVduino-MS project the voltage value will be converted into  graphic bars on the LCD touch display

Friday, February 10, 2012

Automatic switch between offgrid and ingrid

Just installed the automatic swich box for my television corner.

The schematic is already published in a earlier post.

It works well, test if batteri voltage is high enough to drive television watching, light and dvbt antenna. If voltage is ok, then turns on the 12 - 230 volt inverter.

If voltage get below a preadjusted level, it turns to gridtie electricity, and turn off inverter.


The inverter placed in the cellar. Connected to the offgrid 12 volt interconnection board.


The controller circuit, yes i know, it don't look beautiful, but it works as expected ;)


Adjustment off the minimum offgrid voltage accepted, before automatic switching to grid-tie.


Gridtie connection

Monday, February 6, 2012

Dallas ds18b20 temperature sensor and arduino

Code piece for arduino integrated with dallas ds18b20 temperature sensor

** Remark that the code piece must be integrated into your own application to work properly, it is a draft !
Dallas Ds18b20

How To connect the dallas ds18b20 to arduino digital pin (this is not one wire connecting)



This picture show a DFRduino (Arduino Mega 1280 compatibel) with 2,8" LCD touch display. This unit is intend to be used in the project: EVduino-MS. EVduino-MS is a Electric Vehicle Monitoring and datalogger System will be used in my kewet 2 EV.

Dallas ds18b20 Links and ressources:
caminoi
avrfreaks
c code package ds18b20

Arduino Test software 9 february 2012,  Demo video
In this test version, dallas ds18b20 works well


Grab the demo Code pieces / schetch below demo movie









// EVduino-MS-08b first playground version
//
// Project start date: 22 January 2012
// Version of the EVduino-MS: 0,8beta
// Author: Michael Pedersen
// Project Home: http://mynerdstuff.blogspot.com/2012/01/arduino-based-electric-vehicle.html
//
// This 0,8 beta Version is intend to bed used in a KEWET 2 electric vehicle with 4 lead Acid batteries
// Link to 0.8beta home: http://mynerdstuff.blogspot.com/2012/02/evduino-ms-08beta-code.html

#include <f12x12.h>
#include <TFT_Font.h>
#include <TFT_Graphics.h>
#include <Touchpanel.h>
#include <util/delay.h>
#include <stdlib.h>
#include "f15x22.h"
#include <string.h>


//Dallas ds18b20temperature sensor define
#define TEMP_PIN  11 //pwm11 , pwm 13 did not work in my DFRduino, don't know why, might work on other megaduino boards
#define RED_LED_PIN  12 //pwm12
void getCurrentTemp(char *temp);
void enginetemperature();

#define TP_STABLE_COUNT 1
Graphics tft;

TFT_Font font;
touchpanel tp;

void colormap();
void fontmap();
void bitmap();
uint8_t mount_sd();
uint8_t open_root_dir();
uint8_t show_bitmap();
void calibrate();
void tp_calibrate();
//void batteriesvoltage(float *voltage);

typedef struct menu_item{
  uint16_t sx;
  uint16_t sy;
  uint16_t ex;
  uint16_t ey;
  char *str;
  void (*func)(void);
}
MENUITEM;

//This is the main menu placement
#define MENU_START_X 40
#define MENU_START_Y 60
#define MENU_WIDTH 120
#define MENU_HEIGHT 40
#define MENU_GAP 20

// This is the main menu buttons, black with white text. Turns green when pressed
#define MENU_FONT_COLOR WHITE
#define MENU_NORMAL_COLOR BLACK
#define MENU_HIGHLIGHT_COLOR GREEN

MENUITEM menu[4];
int current_menu_no = -1;
float volt1;

void setup()
{

  //initialize DS18B20 datapin
  digitalWrite(TEMP_PIN, LOW);
  pinMode(TEMP_PIN, INPUT);

  pinMode(RED_LED_PIN, OUTPUT);
  digitalWrite(RED_LED_PIN, HIGH);

  //digitalWrite(11, LOW);
  //pinMode(11, INPUT);


  volt1 = 12,34;
  tft.initialize(LCD_HORIZONTAL);
  tft.ClearScreen(WHITE);
  font.set_Font(f12x12);
  tp.init();
  tp.get_matrix();

  //setup menu
  menu[0].sx = MENU_START_X;
  menu[0].sy = MENU_START_Y;
  menu[0].ex = MENU_START_X + MENU_WIDTH;
  menu[0].ey = MENU_START_Y + MENU_HEIGHT;
  menu[0].str = PSTR("Engine Current");
  menu[0].func = enginecurrent;

  menu[1].sx = MENU_START_X;
  menu[1].sy = MENU_START_Y + MENU_HEIGHT + MENU_GAP;
  menu[1].ex = MENU_START_X + MENU_WIDTH;
  menu[1].ey = MENU_START_Y + 2*MENU_HEIGHT + MENU_GAP;
  menu[1].str = PSTR("Batteries");
  menu[1].func = batteriesvoltage;

  menu[2].sx = MENU_START_X + MENU_WIDTH +MENU_GAP;
  menu[2].sy = MENU_START_Y;
  menu[2].ex = MENU_START_X + 2*MENU_WIDTH+MENU_GAP;
  menu[2].ey = MENU_START_Y + MENU_HEIGHT;
  menu[2].str = PSTR("Engine Temp");
  menu[2].func = enginetemperature;

  menu[3].sx = MENU_START_X + MENU_WIDTH +MENU_GAP;
  menu[3].sy = MENU_START_Y + MENU_HEIGHT + MENU_GAP;
  menu[3].ex = MENU_START_X + 2*MENU_WIDTH+MENU_GAP;
  menu[3].ey = MENU_START_Y + 2*MENU_HEIGHT + MENU_GAP;
  menu[3].str = PSTR("TP CALIBRATION");
  menu[3].func = calibrate;


}

void text_box_P(uint16_t x1,uint16_t y1, uint16_t x2, uint16_t y2, uint16_t radius, char* str_P)
{
  tft.DrawRoundRect(x1,y1,x2,y2, radius, font.BK_color, 1);
  font.set_Cursor( (x1+x2-font.str_Width_P(str_P))>>1, (y1+y2-font.Font_Height)>>1 );
  font.putstr_P(str_P);
}

void init_menu()
{
  int i;
  font.set_Color(MENU_FONT_COLOR, MENU_NORMAL_COLOR,1);
  for(i=0; i<4; i++)
    text_box_P( menu[i].sx, menu[i].sy, menu[i].ex, menu[i].ey, 8, menu[i].str);

  current_menu_no = -1 ;
}




void text_box(uint16_t x1,uint16_t y1, uint16_t x2, uint16_t y2, uint16_t radius, char* str)
{
  tft.DrawRoundRect(x1,y1,x2,y2, radius, font.BK_color, 1);
  font.set_Cursor( (x1+x2-font.str_Width(str))>>1, (y1+y2-font.Font_Height)>>1 );
  font.putstr(str);
}


uint8_t get_stable_tp(POINT* tp)
{
  static POINT previous_tp;
  static uint8_t count=0;


  if(tp->x == 0 || tp->y == 0)
    return 0;

  if(tp->x == previous_tp.x && tp->y == previous_tp.y)
    count++;
  else{
    count = 0;
    previous_tp.x = tp->x;
    previous_tp.y = tp->y;
  }

  if(count>= TP_STABLE_COUNT){
    count = 0;
    return 1;
  }

  return 0;
}


char tp_inside_menu(POINT *tp)
{
  int i;
  for(i=0; i<4; i++){
    if( tp->x>= menu[i].sx && tp->y>= menu[i].sy &&
      tp->x <= menu[i].ex && tp->y <= menu[i].ey )

      return i;
  }
  return -1; // not inside any menu item

}


void loop()
{
  POINT *tp_dat;

  init_menu();
  while(1)
  {
    char cord[5];
    tp_dat = tp.read_lcd_point();

    if(get_stable_tp(tp_dat) )  // got a stable tp point
    {
      current_menu_no = tp_inside_menu(tp_dat);

      if(current_menu_no >=0 && current_menu_no<=4){
        font.set_Color(MENU_FONT_COLOR, MENU_HIGHLIGHT_COLOR,1); // draw current menu in highlight color
        text_box_P( menu[current_menu_no].sx, menu[current_menu_no].sy, menu[current_menu_no].ex, menu[current_menu_no].ey, 8, menu[current_menu_no].str);
        _delay_ms(50);
        (*(menu[current_menu_no].func))();

        init_menu();
      }
    }

    _delay_ms(5);
  }
}

void wait_for_OK()
{
  POINT *tp_dat;

  font.set_Color(MENU_FONT_COLOR, MENU_NORMAL_COLOR,1);

  text_box_P( 120, 20, 200, 50, 5, PSTR("OK"));

  while(1)
  {
    tp_dat = tp.read_lcd_point();

    if(get_stable_tp(tp_dat) )
    {
      if(tp_dat->x>=120 && tp_dat->y >=20&& tp_dat->x <=200 && tp_dat->y<=50)
      {
        tft.ClearScreen(WHITE);
        return;
      }
    }
    _delay_ms(5);
  }
}

uint8_t wait_for_input()
{
  POINT *tp_dat;

  font.set_Color(MENU_FONT_COLOR, MENU_NORMAL_COLOR,1);

  text_box_P( 120, 20, 180, 50, 5, PSTR("OK"));
  text_box_P( 200, 20, 280, 50, 5, PSTR("NEXT"));

  while(1)
  {
    tp_dat = tp.read_lcd_point();

    if(get_stable_tp(tp_dat) )
    {
      if(tp_dat->x>=120 && tp_dat->y >=20&& tp_dat->x <=180 && tp_dat->y<=50) return 1;
      else if (tp_dat->x>=200 && tp_dat->y >=20&& tp_dat->x <=280 && tp_dat->y<=50) return 0;
    }
    _delay_ms(5);
  }
}


void colormap()
{
  uint8_t i,j,k;
  // draw a clolormap
  uint16_t color;
  tft.ClearScreen(WHITE);

  // draw 512 (10x15) boxes with incremantal color
  for(i=0; i<8; i++){
    for(j=0; j<8; j++){
      for(k=0;k<8;k++){
        color = _RGB565(i<<5, j<<5, k<<5);
        tft.DrawRoundRect(i*40+(j/2)*10, k*15+ (j&0x1)*120,i*40+(j/2)*10 +9, k*15+ (j&0x1)*120 +14, 0, color,1);
      }
    }
  }
  wait_for_OK();
}


void fontmap()
{
  char i;
  uint8_t row=0;

  // draw font
  tft.ClearScreen(WHITE);

  tft.DrawRoundRect( 40, 70, 280, 230,  10, MENU_HIGHLIGHT_COLOR,1);

  font.set_Font(f15x22);
  font.set_Color(MENU_FONT_COLOR, MENU_NORMAL_COLOR,1);

  font.set_Cursor( 50, 80);

  for(i=font.Font_FirstChar; i<= font.Font_LastChar; i++)
  {
    if(font.CharWidth(i) !=0)
    {
      if( (font.CursorX + font.CharWidth(i)) > 270)
      {
        row++;
        font.set_Cursor(50, 80+ (row* font.Font_Height + 2));
      }

      font.putChar(i);
    }
  }
  font.set_Font(f12x12);
  wait_for_OK();
}


void bitmap()
{
  uint8_t res;
  char temp[10];
  tft.ClearScreen(WHITE);
#if defined(__AVR_ATmega328P__)||defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  res = mount_sd();
  if(res) {
    text_box_P( 80, 50, 250, 200, 15, PSTR("Cannot mount SDcard"));
 
 
    wait_for_OK();
  }
  else
  {
    if(open_root_dir()) return;
    while(1){
   
      res= show_bitmap();
      if(!res){
        if(wait_for_input()==1) {
          tft.ClearScreen(WHITE);
          break;  // ok button is pressed, break the loop
        }
      }
      else if(res==0x10)  // reopen root dir
      {
        if(open_root_dir()) return;
      }
    }
  }


#else
  text_box_P(80, 60, 250, 200, 15, PSTR("N/A in ATMEGA168"));
  wait_for_OK();
#endif

}

void enginetemperature()
{
  digitalWrite(RED_LED_PIN, LOW);

  //exampel place qwerty in the drawn RoundRect
  String sensorTypeTxt;
  String test;
  char i = 42;
  char sensorData[20] = "12,34 Volt";    

 // dallas ds18b20 variables test
  uint16_t plen, dat_p;
        char temp_string[10] = "1234";
     
       getCurrentTemp(sensorData); //go get dallas ds18b20 temperature
     
     

  sensorTypeTxt = "Engine Temp. is: ";
//sensorTypeTxt.concat(millis());
  sensorTypeTxt.concat(sensorData);
  uint8_t row=0;

  // draw font
  tft.ClearScreen(WHITE);

  tft.DrawRoundRect( 40, 70, 280, 130,  10, MENU_HIGHLIGHT_COLOR,1);

  font.set_Font(f15x22);
  font.set_Color(MENU_FONT_COLOR, MENU_NORMAL_COLOR,1);

  font.set_Cursor( 50, 80); //Place cursor at low/left of LCD

  for(i=0; i<43;i++) //loop until al chrs in sensorData is placed on the LCD display
  {
    font.putChar(sensorTypeTxt[i]); //place the sensorData variable, sensorData come from a sensor as voltage sensor, current sensor, temperature sensor

    if(font.CharWidth(i) !=0)
    {
      if( (font.CursorX + font.CharWidth(i)) > 270)
      {
        row++;
        font.set_Cursor(50, 80+ (row* font.Font_Height + 2));
      }    
    }
  }

  font.set_Font(f12x12); // set font to menu size
  wait_for_OK();
}


void enginecurrent()
{
  text_box_P( 80, 50, 250, 200, 15, PSTR("300A messhunt data:"));
   digitalWrite(RED_LED_PIN, LOW);
  wait_for_OK();
}


void batteriesvoltage()
{
  digitalWrite(RED_LED_PIN, HIGH);

  //exampel place qwerty in the drawn RoundRect
  String sensorTypeTxt;
  String test;
  char i = 42;
  char sensorData[20] = "12,34 Volt";    

 // dallas ds18b20 variables test
  uint16_t plen, dat_p;
        char temp_string[10] = "1234";
     
       getCurrentTemp(sensorData); //go get dallas ds18b20 temperature
     
     

  sensorTypeTxt = "Battery one: ";
//sensorTypeTxt.concat(millis());
  sensorTypeTxt.concat(sensorData);
  uint8_t row=0;

  // draw font
  tft.ClearScreen(WHITE);

  tft.DrawRoundRect( 40, 70, 280, 130,  10, MENU_HIGHLIGHT_COLOR,1);

  font.set_Font(f15x22);
  font.set_Color(MENU_FONT_COLOR, MENU_NORMAL_COLOR,1);

  font.set_Cursor( 50, 80); //Place cursor at low/left of LCD

  for(i=0; i<43;i++) //loop until al chrs in sensorData is placed on the LCD display
  {
    font.putChar(sensorTypeTxt[i]); //place the sensorData variable, sensorData come from a sensor as voltage sensor, current sensor, temperature sensor

    if(font.CharWidth(i) !=0)
    {
      if( (font.CursorX + font.CharWidth(i)) > 270)
      {
        row++;
        font.set_Cursor(50, 80+ (row* font.Font_Height + 2));
      }    
    }
  }

  font.set_Font(f12x12); // set font to menu size
  wait_for_OK();

}


void calibrate()
{
  tft.ClearScreen(BLACK);
  tp_calibrate();
  wait_for_OK();
}

//*********************************
// onewire and dallas ds18b20 code
//*********************************

void OneWireReset(int Pin) // reset.  Should improve to act as a presence pulse
{
     digitalWrite(Pin, LOW);
     pinMode(Pin, OUTPUT); // bring low for 500 us
     delayMicroseconds(500);
     pinMode(Pin, INPUT);
     delayMicroseconds(500);
}

void OneWireOutByte(int Pin, byte d) // output byte d (least sig bit first).
{
   byte n;

   for(n=8; n!=0; n--)
   {
      if ((d & 0x01) == 1)  // test least sig bit
      {
         digitalWrite(Pin, LOW);
         pinMode(Pin, OUTPUT);
         delayMicroseconds(5);
         pinMode(Pin, INPUT);
         delayMicroseconds(60);
      }
      else
      {
         digitalWrite(Pin, LOW);
         pinMode(Pin, OUTPUT);
         delayMicroseconds(60);
         pinMode(Pin, INPUT);
      }

      d=d>>1; // now the next bit is in the least sig bit position.
   }
 
}

byte OneWireInByte(int Pin) // read byte, least sig byte first
{
    byte d, n, b;

    for (n=0; n<8; n++)
    {
        digitalWrite(Pin, LOW);
        pinMode(Pin, OUTPUT);
        delayMicroseconds(5);
        pinMode(Pin, INPUT);
        delayMicroseconds(5);
        b = digitalRead(Pin);
        delayMicroseconds(50);
        d = (d >> 1) | (b<<7); // shift d to right and insert b in most sig bit position
    }
    return(d);
}

void getCurrentTemp(char *temp)
{
  int HighByte, LowByte, TReading, Tc_100, sign, whole, fract;

  OneWireReset(TEMP_PIN);
  OneWireOutByte(TEMP_PIN, 0xcc);
  OneWireOutByte(TEMP_PIN, 0x44); // perform temperature conversion, strong pullup for one sec

  OneWireReset(TEMP_PIN);
  OneWireOutByte(TEMP_PIN, 0xcc);
  OneWireOutByte(TEMP_PIN, 0xbe);

  LowByte = OneWireInByte(TEMP_PIN);
  HighByte = OneWireInByte(TEMP_PIN);
  TReading = (HighByte << 8) + LowByte;
  sign = TReading & 0x8000;  // test most sig bit
  if (sign) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25

  whole = Tc_100 / 100;  // separate off the whole and fractional portions
  fract = Tc_100 % 100;

if(sign) temp[0]='-';
else temp[0]='+';

temp[1]= (whole-(whole/100)*100)/10 +'0';
//u temp[1]= 'a' ;
temp[2]= whole-(whole/10)*10 +'0';

temp[3]='.';
temp[4]=fract/10 +'0';
temp[5]=fract-(fract/10)*10 +'0';

temp[6] = '\0';
}

Sunday, February 5, 2012

Laboratory Power supply lm317 1.2 - 36 volt and current limiter 0 - 5 amps



The schematic for the lm317 based powersupply includes two PNP transistors to increase the power performance.

There is a fault on this schematic, the bd140 current limiter is connected wrong, i will make a new schematic latter.

You can make a shortcut protection circuit for this power supply also follow link




Saturday, February 4, 2012

EVduino-MS-08beta-Code

Version EVduino-MS08 beta will include: 

  • 4 pcs. Voltage sensors for 4 x 12 volt 
  • 1 pcs. Low current sensor 30 amps, measure car energy consumption, headlights, instrument lights and so. NOT electric heater and The DC engine 
  • 1 pcs. High current sensor 300-400 amps for engine consumption and electric heater 
  • Temperature sensor for the DC engines coil temperature, code piece for dallas ds18b20

Startup coding the EVduino-MS-08beta

Starup with the code using the 2,8" LCD example from nuelectronic, and modify this to fit my application.


I used a hole week trying to place mesured data in one of the black text boxes shown on above picture.

Well, i don't think i can be done with text_box_p. Text_box_p is used to place static strings as the 'Batteries' on the screen.

I found that another lib must be used to place variables, the font lib.

Command used:

font.putChar('y')

Example: 



The code:

void batteriesvoltage()
{
       //exampel place qwerty in the drawn RoundRect
        char i = 22;
        char sensorData[20] = "qwertyuiopasdfghjkl";
     
uint8_t row=0;

// draw font
tft.ClearScreen(WHITE);

tft.DrawRoundRect( 40, 70, 280, 230,  10, MENU_HIGHLIGHT_COLOR,1);

font.set_Font(f15x22);
font.set_Color(MENU_FONT_COLOR, MENU_NORMAL_COLOR,1);

font.set_Cursor( 50, 80);

for(i=0; i<23;i++) //loop until al chrs in sensorData is placed on the LCD display
          {
            font.putChar(sensorData[i]); //place the sensorData variable, sensorData come from a sensor as voltage sensor, current sensor, temperature sensor
         
if(font.CharWidth(i) !=0)
{
if( (font.CursorX + font.CharWidth(i)) > 270)
{
row++;
font.set_Cursor(50, 80+ (row* font.Font_Height + 2));
}    
}
 }

font.set_Font(f12x12); // set font to menu size
wait_for_OK();

}