Digital 2 channel 10 Amp Meter

 

History

 

This project is a 2 channels amp meter. Those channels are completely isolated up to 2000 volts.  I'm sure you don't need isolation like this but it could be very interesting to measure the charge current for 110V AC input or on the output of something like 12V DC.  That is, it provides auto detection for AC or DC current. The main part of this project is the current sensor ZMC10 a cool DIP 14, which supports up to 10 A. The current is measured inside by hall effect sensor.  I had used a graphic LCD to show very big numbers of the read current and max peek value, DC or AC

    Ok now, this was supposed to be simple, but I had to overcome a lot of problems doing this project. First the datasheet of the ZMC10 have a big 2 pages!
How an IC like that can have 2 pages documentation when LED datasheet have more than 15 pages?  Not having proper documentation was my biggest challenge. First the slope is non linear I had to make calibration at first to use it from 0 to 10 amps. The software calculates the slope from 0 to 1, 1 to 2, 2 to 3, with the formula Y2 - Y1 / X2 - X1  |   B = Y - M * X   |   X = Y - B / M   |  Y = M * X + B.  After I faced another problem, any metal pieces from 2 inches will completely false the reading. For example, if your charge is 5 A. Moving a screw driver at 2 inches of the ZMC10 you will give something like 1A or less. The other problem that I had faced is if the 2 sensors are closed to each other the current will interfere and will give you false reading.  I had to rebuild another PCB for that to separate each channel.  Also at 0 A the sensor will not give you zero, you must calculate the offset from one part to the other since the values are not the same.  In last all the values, slopes and offset are not the same if the current pass from A to B or B to A. I think this caused enough problems for a simple amp meter.

    The MCU has two jobs:  measure (calculate) the value from the analog board and display that value.  I drove the LCD in graphical mode. I had written the character generator for fonts 1x, 2x and 4x other function like draw line, square, clear screen and more. Also the MCU board has the power supply for itself and for the analog part.

 

Features

puce 2 Channel
puce From 0 to 10amp
puce Resolution of 0.1amp
puce Isolation between each channel of 2000 volt
puce Automatic AD/DC detection
puce Very big LCD and character

 

Pictures

Click to enlarge

Analog part 1 of 2

Graphic LCD with a SED1330

MCU board mounted on back of the LCD

Click to enlarge

Analog part 1 of 2

Final work in right position

Final work in slope position

 

Sources codes & Schematics

-Schematic of the Analog part

-Schematic of the Digital part

 

//*****************************************************************************
// AmpVoltMeter
// Version 10.0 Janv 2007
//
// 1.0 -> New code
//
// Sylvain Bissonnette
//*****************************************************************************
// Editor : UltraEdit32
//*****************************************************************************
//
//                    R E T U R N   S T A C K   6 4
//                          X T A L  16 MHZ
//                      BootLoader of 1024 word
//
//*****************************************************************************
//
//                F U S E   B I T
//
//( )7      ( )6     (X)BL12 (X)BL11  ( )BL02   ( )BL01    ( )Lock2   ( )Lock1
//( )7      ( )6     ( )     ( )      ( )       ( )M103C   ( )WDTON   ( )
//( )RSTDIS ( )WDON  (X)SPIEN(X)CKOPT (X)EESAVE ( )BOOTSZ1 (X)BOOTSZ0 (X)BOOTRST
//(X)BODLEV (X)BODEN ( )SUT1 ( )SUT0  ( )CKSEL3 ( )CKSEL2  ( )CKSEL1  ( )CKSEL0
//
//*****************************************************************************
//                        P I N   U S A G E
//
// PA0 -> Key Switch SW7
// PA1 -> Key Switch SW8
// PA2 -> Key Switch SW9
// PA3 -> Key Switch SW1
// PA4 -> Key Switch SW2
// PA5 -> Key Switch SW3
// PA6 -> Key Switch SW4
// PA7 -> Key Switch SW5
//
// PB0 -> n/c
// PB1 -> n/c
// PB2 -> n/c
// PB3 -> n/c
// PB4 -> n/c
// PB5 -> n/c
// PB6 -> LCD BackLight
// PB7 -> Piezo
//
// PC0 -> LCD Data bit 0
// PC1 -> LCD Data bit 1
// PC2 -> LCD Data bit 2
// PC3 -> LCD Data bit 3
// PC4 -> LCD Data bit 4
// PC5 -> LCD Data bit 5
// PC6 -> LCD Data bit 6
// PC7 -> LCD Data bit 7
//
// PD0 -> n/c
// PD1 -> n/c
// PD2 -> RS485 RX
// PD3 -> RS485 TX
// PD4 -> RS485 TXE
// PD5 -> LCD RESET
// PD6 -> LCD RD
// PD7 -> LCD WR
//
// PE0 -> n/c
// PE1 -> n/c
// PE2 -> n/c
// PE3 -> n/c
// PE4 -> n/c
// PE5 -> n/c
// PE6 -> n/c
// PE7 -> n/c
//
// PF0 -> n/c
// PF1 -> n/c
// PF2 -> n/c
// PF3 -> n/c
// PF4 -> n/c
// PF5 -> n/c
// PF6 -> Key Switch SW10
// PF7 -> Key Switch SW6
//
// PG0 -> LCD A0
// PG1 -> n/c
// PG2 -> n/c
// PG3 -> n/c
// PG4 -> n/c
//*****************************************************************************
//                        T I M E R   U S A G E
//
// Timer 0 is use by TaskManager
// Timer 1 is use for Sound generetor 1.265KHz
// Timer 2 not use
// Timer 3 not use
//
//*****************************************************************************

//*****************************************************************************
//                          I N C L U D E
//*****************************************************************************
#include <iom32v.h>
#include <shortnametype.h>
#include <macros.h>
#include <stdlib.h>
#include <STRING.H>
#include <stdio.h>
#include <eeprom.h>
#include "TaskManager.h"

//*****************************************************************************
//                              D E F I N E
//*****************************************************************************
#define VERSION             100
#define DEVICE              1280
#define XTAL                8000000

// ADC
#define ADC0                        (1<<REFS0) + 0
#define ADC1                        (1<<REFS0) + 1
#define ADC2                        (1<<REFS0) + 2
#define ADC3                        (1<<REFS0) + 3
#define ADC4                        (1<<REFS0) + 4
#define ADC5                        (1<<REFS0) + 5
#define ADC6                        (1<<REFS0) + 6
#define ADC7                        (1<<REFS0) + 7

// LCD
#define LCDDATA_DDR         DDRC
#define LCDDATA_PIN         PINC
#define LCDDATA_PORT        PORTC

#define LCDCTRL_DDR           DDRD
#define LCDCTRL_PIN           PIND
#define LCDCTRL_PORT          PORTD

#define LCD_A0              (1<<PD4)
#define LCD_WR              (1<<PD5)
#define LCD_RD              (1<<PD6)
#define LCD_RES             (1<<PD7)

#define LCD_X               256
#define LCD_Y               128
#define LCD_XTAL            6000000

#define FONT_1X                     1
#define FONT_2X                     2
#define FONT_4X                     4

// Switch
#define SWITCH_DDR               DDRB
#define SWITCH_PIN               PINB
#define SWITCH_PORT              PORTB

#define LEFT                        0x01
#define  RIGHT                      0x02
#define BOTH                        0x03

// Eprom
#define SLOPE1                   0    
#define SLOPE2                   50   
#define SLOPE3                   100  
#define SLOPE4                   150     

#define FOWARD                   0
#define REVERSE                     1

// Interrupt
#define INT_DDR                     DDRD
#define INT_PIN                     PIND
#define INT_PORT                 PORTD
#define INT_INPUT_0              0x04
#define INT_INPUT_1              0x08

// AC/DC
#define  AC                         TRUE
#define DC                          FALSE

//**************************************
//          P R O T O T LCD_Y P E
//**************************************
void InitCode(void);
void RedrawTick(void);
void Delay(ushort Del);
void IntInit(void);
void SplashScreen(void);
void DrawScreen(void);
void DrawDC1(void);
void DrawDC2(void);
void DrawAC1(void);
void DrawAC2(void);
void LoadSlope(ushort Polarity);
void CalculateMB(void);
void Calibration(void);
void PrintAmp1(int X, int Y, uint Value, int Size, ushort ACDC);
void PrintAmp2(int X, int Y, uint Value, int Size, ushort ACDC);

// Slope
float SlopeGetM (float X1, float Y1, float X2, float Y2);
float SlopeGetB (float X, float Y, float M);
float SlopeGetX (float Y, float B, float M);
float SlopeGetY (float X, float B, float M);

// LCD
void LCDInit(void);
void LCDWriteData(ushort byte);
void LCDWriteCmd(ushort byte);
ushort LCDReadData(void);
void LCDClrSCR(void);
void LCDGotoXY(ushort, ushort);
void LCDWriteString(char *ptr);
void LCDWriteConstString(const char *ptr);
void LCDCursor(ushort LCDCursor);
void LCDTextBox(int x, int y, int length,int stat);
void LCDDelay2ms(void);
void LCDDelay1us(void);

void LCDGraphClrSCR(void);
void LCDGraphGotoXY(ushort x, ushort y);
void LcdGraphString (ushort X, ushort Y, ushort Size, char *Ptr );
void LcdGraphConstString (ushort X, ushort Y, ushort Size, const char *Ptr );
void LcdGraphChr(ushort X, ushort Y, ushort Size, char Ch);
void LCDGraphSetRamPointer(int Address);
void LCDGraphPix(int x, int y, ushort stat);
void LCDGraphBox(int x1, int y1, int x2, int y2,int stat);
void LCDGraphLine(int x1, int y1, int x2, int y2);

// ADC
void ADInit(void);
void AD_interrupt(void);

// Switch
void SwitchInit(void);
void SwitchScan(void);

// AD/DC
void Int_0_AC(void);
void Int_1_AC(void);
void CheckAC(void);

//*****************************************************************************
//                         C O N S T A N T
//*****************************************************************************
static const ushort FontLookup [][7] =
{
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Space
    { 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04 }, // !
    { 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00 }, // "
    { 0x0A, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x0A }, // #
      { 0x04, 0x0F, 0x14, 0x0E, 0x05, 0x1E, 0x04 }, // $
      { 0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03 }, // %
      { 0x0C, 0x12, 0x14, 0x08, 0x15, 0x12, 0x0D }, // &
      { 0x0C, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00 }, // '
      { 0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02 }, // (

     { 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08 }, // )
    { 0x00, 0x04, 0x15, 0x0E, 0x15, 0x04, 0x00 }, // *
    { 0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00 }, // +
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x04 }, // ,
      { 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00 }, // -
      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C }, // .
      { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00 }, // /
      { 0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E }, // 0

      { 0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E }, // 1
    { 0x0E, 0x11, 0x02, 0x04, 0x08, 0x10, 0x1F }, // 2
    { 0x1F, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0E }, // 3
    { 0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02 }, // 4
      { 0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E }, // 5
      { 0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E }, // 6
      { 0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08 }, // 7
      { 0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E }, // 8

      { 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C }, // 9
    { 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00 }, // :
    { 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x04, 0x08 }, // ;
    { 0x01, 0x02, 0x04, 0x08, 0x04, 0x02, 0x01 }, // <
      { 0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00 }, // =
      { 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10 }, // >
      { 0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04 }, // ?
      { 0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0E }, // @

      { 0x0E, 0x11, 0x11, 0x11, 0x1F, 0x11, 0x11 }, // A
    { 0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E }, // B
    { 0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E }, // C
    { 0x1C, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1C }, // D
      { 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F }, // E
      { 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10 }, // F
      { 0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0F }, // G
      { 0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11 }, // H   

      { 0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E }, // I
    { 0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C }, // J
    { 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11 }, // K
    { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F }, // L
      { 0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11 }, // M
      { 0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11 }, // N
      { 0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E }, // O
      { 0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10 }, // P      

      { 0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D }, // Q
    { 0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11 }, // R
    { 0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E }, // S
    { 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }, // T
      { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E }, // U
      { 0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04 }, // V
      { 0x11, 0x11, 0x11, 0x11, 0x15, 0x15, 0x0A }, // W
      { 0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11 }, // X         

      { 0x11, 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04 }, // Y
    { 0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F }, // Z
    { 0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0E }, // [
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Space
      { 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E }, // ]
      { 0x04, 0x0A, 0x11, 0x00, 0x00, 0x00, 0x00 }, // ^
      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F }, // _
      { 0x06, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00 }, // `         

      { 0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F }, // a
    { 0x10, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x1E }, // b
    { 0x00, 0x00, 0x0F, 0x10, 0x10, 0x10, 0x0F }, // c
    { 0x01, 0x01, 0x0F, 0x11, 0x11, 0x11, 0x0F }, // d
      { 0x00, 0x00, 0x0E, 0x11, 0x1E, 0x10, 0x0E }, // f
      { 0x03, 0x04, 0x1F, 0x04, 0x04, 0x04, 0x04 }, // e
      { 0x00, 0x00, 0x0F, 0x11, 0x0F, 0x01, 0x0E }, // g
      { 0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x11 }, // h   

      { 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x0E }, // i
    { 0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0C }, // j
    { 0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12 }, // k
    { 0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E }, // l
      { 0x00, 0x00, 0x1E, 0x15, 0x15, 0x15, 0x15 }, // m
      { 0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11 }, // n
      { 0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E }, // o
      { 0x00, 0x00, 0x1E, 0x11, 0x1E, 0x10, 0x10 }, // p   

      { 0x00, 0x00, 0x0F, 0x11, 0x0F, 0x01, 0x01 }, // q
    { 0x00, 0x00, 0x16, 0x18, 0x10, 0x10, 0x10 }, // r
    { 0x00, 0x00, 0x0F, 0x10, 0x0E, 0x01, 0x1E }, // s
    { 0x04, 0x04, 0x1F, 0x04, 0x04, 0x04, 0x03 }, // t
      { 0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0D }, // u
      { 0x00, 0x00, 0x11, 0x11, 0x11, 0x0A, 0x04 }, // v
      { 0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A }, // w
      { 0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11 }, // x      

      { 0x00, 0x00, 0x11, 0x11, 0x0F, 0x01, 0x0E }, // y
    { 0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F }, // z
    { 0x06, 0x08, 0x08, 0x10, 0x08, 0x08, 0x06 }, // {
    { 0x04, 0x04, 0x04, 0x00, 0x04, 0x04, 0x04 }, // :
      { 0x0C, 0x02, 0x02, 0x01, 0x02, 0x02, 0x0C }, // }
      { 0x00, 0x04, 0x02, 0x1F, 0x02, 0x04, 0x00 }, // Right arrow
      { 0x00, 0x04, 0x08, 0x1F, 0x08, 0x04, 0x00 }, // Left arroe
      { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }  // Fill                
};

//*****************************************************************************
//                  G L O B A L   V A R I A B L E
//*****************************************************************************

// KeySwitch
ushort Switch;

// LCD
char Text[20];

// ADC
uint Amp1DC, Amp2DC;
uint Amp1AC,Amp2AC;
ushort Amp1ACDC, Amp2ACDC;
ushort Amp1DCSlope, Amp2DCSlope;
uint Amp1Max, Amp2Max;

// Correction Factor
float Sensor1Slope[11];
float Sensor1B[11];
float Sensor1Value[11];

float Sensor2Slope[11];
float Sensor2B[11];
float Sensor2Value[11];

// AD/DC
uint Sensor1ACCounter;
uint Sensor2ACCounter;

//*****************************************************************************
//                              M A I N
//*****************************************************************************
void main()
{
  TaskInit();
  LCDInit();
  ADInit();
  SwitchInit();
  IntInit();
  WDR();
  WDTCR = 0x0f;       // Watch Dog enable
  SEI();              //re-enable interrupts
  LCDClrSCR();
  LCDGraphClrSCR();

   SplashScreen();
   Delay(50);
  DrawScreen();

  TaskRegister(RedrawTick,T500MS,TRUE);
  TaskRegister(SwitchScan,T100MS,TRUE);

  while(1)
  {
    _StackCheck();

    if (Switch == (LEFT+RIGHT))
    {
      Switch = NULL;
      Calibration();
    }

    if (Switch == LEFT)
      {
         Switch = NULL;
         Amp1Max = 0;
      }

      if (Switch == RIGHT)
      {
         Switch = NULL;
         Amp2Max = 0;
      }
    WDR();
  }
}

/******************************************************************************

Name:         void _StackOverflowed(char c)

Description:  This function is automaticaly called if
              the stack crash.


Input:        none

Output:       none

Misc:
******************************************************************************/
void _StackOverflowed(char c)
{
  int i;

  LCDClrSCR();
  LCDGraphClrSCR();
  LCDGotoXY(5,12);
  LCDWriteConstString("S T A C K  O V E R F L O W !!!!!\0");
  LCDGotoXY(5,13);
  LCDWriteConstString("--------------------------------\0");
  for (i=0;i<1000;i++) LCDDelay2ms();
  CLI();
  while(1);
}

/******************************************************************************

Name:         void Delay(ushort Del)

Description:  This function make a delay

Input:        none

Output:       none

Misc:
******************************************************************************/
void Delay(ushort Del)
{
  int i,j;
  for (i=0;i<Del;i++) for (j=0;j<32000;j++) WDR();
}

/******************************************************************************

Name:         void LoadSlope(ushort Polarity)

Description:  This function

Input:        none

Output:       none

Misc:
******************************************************************************/
void LoadSlope(ushort Polarity)
{
   ushort i;

   for (i=0;i<11;i++)
   {
      EEPROMReadBytes(SLOPE1+(i*4)+(Polarity*100),&Sensor1Value[i],4);
      EEPROMReadBytes(SLOPE2+(i*4)+(Polarity*100),&Sensor2Value[i],4);
   }
   CalculateMB();
}

/******************************************************************************

Name:         void CalculateMB(void)

Description:  This function calculate M & B for all the 11 points

Input:        none

Output:       none

Misc:
******************************************************************************/
void CalculateMB(void)
{
   ushort i;

   for (i=0;i<10;i++)
   {
      Sensor1Slope[i] = SlopeGetM(i,Sensor1Value[i], i+1,Sensor1Value[i+1]);
      Sensor1B[i] = SlopeGetB(i, Sensor1Value[i], Sensor1Slope[i]);

      Sensor2Slope[i] = SlopeGetM(i,Sensor2Value[i], i+1,Sensor2Value[i+1]);
      Sensor2B[i] = SlopeGetB(i, Sensor2Value[i], Sensor2Slope[i]);
   }
}

/******************************************************************************

Name:         void Calibration(void)

Description:  This function is to equalibrate the non linear curve of the sensor

Input:        none

Output:       none

Misc:
******************************************************************************/
void Calibration(void)
{
   int i,j;

   TaskUnRegister(RedrawTick);

   Switch = NULL;

   LCDGraphClrSCR();
   LCDGraphBox(15, 14, 242, 113, 1);
   LCDGraphBox(1, 1, 256, 128, 1);
   LCDGraphBox(1, 1, 256, 128, 1);
   LcdGraphConstString (10, 4, FONT_1X, "Amp Meter V:1.0\0" );
   LcdGraphConstString (6, 20, FONT_2X, "Calibration\0" );
   LcdGraphConstString (4, 50, FONT_1X, "Set the current to :\0" );
   LcdGraphConstString (5, 60, FONT_1X, "IN THIS WAY ---------->>\0" );
   LcdGraphConstString (9, 70, FONT_1X, "and press any key\0" );
   LcdGraphConstString (6, 90, FONT_1X, "both amp meter must be\0" );
   LcdGraphConstString (8, 100, FONT_1X, "connected in series\0" );

   csprintf(&Text[0],"%d\0",i);
   LcdGraphConstString (24, 43, FONT_2X, "1");
   LcdGraphConstString (28, 50, FONT_1X, "Amp\0" );
   while(!Switch) WDR();
   Switch = NULL;

   for (i=0;i<11;i++)
   {
      csprintf(&Text[0],"%d\0",i);
      LcdGraphString (24, 43, FONT_2X, &Text[0]);
      LcdGraphConstString (28, 50, FONT_1X, "Amp\0" );
      while(!Switch) WDR();
      Switch = NULL;

      if ((INT_PIN & INT_INPUT_0)) j = 0;
      else j = 100;

      Sensor1Value[i] = Amp1DC;
      EEPROMWriteBytes(SLOPE1+(i*4)+j,&Sensor1Value[i],4);

      Sensor2Value[i] = Amp2DC;
      EEPROMWriteBytes(SLOPE2+(i*4)+j,&Sensor2Value[i],4);
   }

   LcdGraphConstString (5, 60, FONT_1X, "IN THIS WAY <<----------\0" );

   if (j == 0) j=100;
   else j = 0;

   for (i=0;i<11;i++)
   {
      csprintf(&Text[0],"%d \0",i);
      LcdGraphString (24, 43, FONT_2X, &Text[0]);
      LcdGraphConstString (28, 50, FONT_1X, "Amp\0" );
      while(!Switch) WDR();
      Switch = NULL;

      Sensor1Value[i] = Amp1DC;
      EEPROMWriteBytes(SLOPE1+(i*4)+j,&Sensor1Value[i],4);

      Sensor2Value[i] = Amp2DC;
      EEPROMWriteBytes(SLOPE2+(i*4)+j,&Sensor2Value[i],4);
   }
   DrawScreen();
   TaskRegister(RedrawTick,T500MS,TRUE);
}

/******************************************************************************

Name:         void SplashScreen(void)

Description:  This function draw splash Screen

Input:        none

Output:       none

Misc:
******************************************************************************/
void SplashScreen(void)
{
   LCDGraphClrSCR();
   LCDGraphBox(1, 1, 256, 128, 1);
   LcdGraphConstString (2, 20, FONT_2X, "Amp Meter V:1.0\0" );
   LcdGraphConstString (9, 50, FONT_2X, "Sylvain\0" );
   LcdGraphConstString (6, 70, FONT_2X, "Bissonnette\0" );
}

/******************************************************************************

Name:         void DrawScreen(void)

Description:  This function draw the main screen

Input:        none

Output:       none

Misc:
******************************************************************************/
void DrawScreen(void)
{
   LCDGraphClrSCR();
   LCDGraphBox(1, 1, 256, 128, 1);
   LcdGraphConstString (10, 4, FONT_1X, "Amp Meter V:1.0\0" );

   LCDGraphBox(4, 14, 125, 125, 1);
   LcdGraphConstString (3, 29, FONT_1X, "Max:\0" );
   LcdGraphConstString (13, 32, FONT_1X, "A\0" );
   LcdGraphConstString (6, 75, FONT_1X, "Current\0" );
   LcdGraphConstString (13, 103, FONT_2X, "A\0" );

   LCDGraphBox(131, 14, 252, 125, 1);
   LcdGraphConstString (19, 29, FONT_1X, "Max:\0" );
   LcdGraphConstString (29, 32, FONT_1X, "A\0" );
   LcdGraphConstString (22, 75, FONT_1X, "Current\0" );
   LcdGraphConstString (29, 103, FONT_2X, "A\0" );

   PrintAmp1(19, 90, Amp1DC, FONT_4X, DC);
   PrintAmp1(23, 25, Amp1Max, FONT_2X, DC);

   if (Amp1ACDC) LcdGraphConstString (6, 50, FONT_2X, "A/C");
   else LcdGraphConstString (6, 50, FONT_2X, "D/C");

   PrintAmp2(3, 90, Amp2DC, FONT_4X, DC);
   PrintAmp2(7, 25, Amp2Max, FONT_2X, DC);

   if (Amp2ACDC) LcdGraphConstString (22, 50, FONT_2X, "A/C");
   else LcdGraphConstString (22, 50, FONT_2X, "D/C");
}

/******************************************************************************

Name:         void IntInit(void)

Description:  This function initialize MCU for INT0 & INT1 to be enable

Input:        none

Output:       none

Misc:
******************************************************************************/
void IntInit(void)
{
   INT_DDR &= ~(INT_INPUT_0 + INT_INPUT_1);
   MCUCR |= (1<<ISC10) + (1<<ISC00);
   GICR |= (1<<INT0) + (1<<INT1);
}

/******************************************************************************

Name:         void Int_0_AC(void)

Description:  This function is call when the current change polarity

Input:        none

Output:       none

Misc:
******************************************************************************/
#pragma interrupt_handler Int_0_AC:2
void Int_0_AC(void)
{
   Sensor1ACCounter++;
}

/******************************************************************************

Name:         void Int_1_AC(void)

Description:  This function is call when the current change polarity

Input:        none

Output:       none

Misc:
******************************************************************************/
#pragma interrupt_handler Int_1_AC:3
void Int_1_AC(void)
{
   Sensor2ACCounter++;
}

/******************************************************************************

Name:         void CheckAC(void)

Description:  This function Check if the current is AC or DC

Input:        none

Output:       none

Misc:
******************************************************************************/
void CheckAC(void)
{
   if ((Sensor1ACCounter > 10) && (Sensor1ACCounter < 150)) Amp1ACDC = TRUE;
   else Amp1ACDC = FALSE;

   if ((Sensor2ACCounter > 10) && (Sensor2ACCounter < 150)) Amp2ACDC = TRUE;
   else Amp2ACDC = FALSE;

   Sensor1ACCounter = 0;
   Sensor2ACCounter = 0;
}

/******************************************************************************

Name:         void void RedrawTick(void)

Description:  This function print values on the LCD

Input:        none

Output:       none

Misc:
******************************************************************************/
void RedrawTick(void)
{
   CheckAC();

   if (Amp1ACDC == DC) DrawDC1();
   else DrawAC1();

   if (Amp2ACDC == DC) DrawDC2();
   else DrawAC2();
}

/******************************************************************************

Name:         void DrawDC1(void)

Description:  This function draw all the information on DC current

Input:        none

Output:       none

Misc:
******************************************************************************/
void DrawDC1(void)
{
   if (Amp1DCSlope) LoadSlope(FOWARD);
   else LoadSlope(REVERSE);

   LcdGraphConstString (6, 50, FONT_2X, "D/C");
   PrintAmp1(3, 90, Amp1DC, FONT_4X,DC);
   PrintAmp1(7, 25, Amp1Max, FONT_2X,DC);
}

/******************************************************************************

Name:         void DrawDC2(void)

Description:  This function draw all the information on DC current

Input:        none

Output:       none

Misc:
******************************************************************************/
void DrawDC2(void)
{
   if (Amp2DCSlope) LoadSlope(FOWARD);
   else LoadSlope(REVERSE);

   LcdGraphConstString (22, 50, FONT_2X, "D/C");
   PrintAmp2(19, 90, Amp2DC, FONT_4X,DC);
   PrintAmp2(23, 25, Amp2Max, FONT_2X,DC);
}

/******************************************************************************

Name:         void DrawAC1(void)

Description:  This function draw all the information on AC current

Input:        none

Output:       none

Misc:
******************************************************************************/
void DrawAC1(void)
{
   if (Amp1DCSlope) LoadSlope(FOWARD);
   else LoadSlope(REVERSE);

   LcdGraphConstString (6, 50, FONT_2X, "A/C");
   PrintAmp1(3, 90, Amp1AC, FONT_4X,AC);
   PrintAmp1(7, 25, Amp1Max, FONT_2X,AC);
   Amp1AC = 0;
}

/******************************************************************************

Name:         void DrawAC2(void)

Description:  This function draw all the information on AC current

Input:        none

Output:       none

Misc:
******************************************************************************/
void DrawAC2(void)
{
      if (Amp2DCSlope) LoadSlope(FOWARD);
      else LoadSlope(REVERSE);

      LcdGraphConstString (22, 50, FONT_2X, "A/C");
      PrintAmp2(19, 90, Amp2AC, FONT_4X,AC);
      PrintAmp2(23, 25, Amp2Max, FONT_2X,AC);
      Amp2AC = 0;
}

/******************************************************************************

Name:         void PrintAmp1(void)

Description:  This function print Amp value on the LCD

Input:        int x, int y, long value

Output:       none

Misc:
******************************************************************************/
void PrintAmp1(int X, int Y, uint Value, int Size,ushort ACDC)
{
   int i;
   float ValueFloat, x=0;

   ValueFloat = (float)Value;
   if (ValueFloat > (float)Sensor1Value[10]) ValueFloat = (float)Sensor1Value[10];
   if (ValueFloat < (float)Sensor1Value[0])  ValueFloat = (float)Sensor1Value[0];

   for (i=0;i<10;i++)
   {
      if ((ValueFloat > Sensor1Value[i]) && (ValueFloat <= Sensor1Value[i+1]))
      {
         x = SlopeGetX((float)ValueFloat,(float)Sensor1B[i],(float)Sensor1Slope[i]);
         break;
      }
   }

   if (ACDC == AC) x = x * 0.707106781;
   if (x < 0.0) x = 0.0;
   if (x > 9.9) x = 9.89999;
   csprintf(&Text[0],"%#3.1f\0",x);
   LcdGraphString (X, Y, Size, &Text[0]);
}

/******************************************************************************

Name:         void PrintAmp2(void)

Description:  This function print Amp value on the LCD

Input:        int x, int y, long value

Output:       none

Misc:
******************************************************************************/
void PrintAmp2(int X, int Y, uint Value, int Size, ushort ACDC)
{
   int i;
   float ValueFloat, x=0;

   ValueFloat = (float)Value;
   if (ValueFloat > (float)Sensor2Value[10]) ValueFloat = (float)Sensor2Value[10];
   if (ValueFloat < (float)Sensor2Value[0])  ValueFloat = (float)Sensor2Value[0];

   for (i=0;i<10;i++)
   {
      if ((ValueFloat > Sensor2Value[i]) && (ValueFloat <= Sensor2Value[i+1]))
      {
         x = SlopeGetX((float)ValueFloat,(float)Sensor2B[i],(float)Sensor2Slope[i]);
         break;
      }
   }

   if (ACDC == AC) x = x * 0.707106781;
   if (x < 0.0) x = 0.0;
   if (x > 9.9) x = 9.89999;
   csprintf(&Text[0],"%#3.1f\0",x);
   LcdGraphString (X, Y, Size, &Text[0]);
}

/******************************************************************************

Name:         ADCInit(void)

Description:  This function initialize the ADC

Input:        none

Output:       none

Misc:
******************************************************************************/
void ADInit(void)
{
   ADCSRA = (1<<ADEN) + (1<<ADIE) + (1<<ADPS2) + (1<<ADPS1) + (1<<ADPS0);
  ADMUX = ADC0;

  ADCSRA |= (1<<ADSC);      // Start AD convertion
}

/******************************************************************************

Name:         AD_interrupt(void)

Description:  This function is automaticaly called when the AD had finish
              is convertion

Input:        none

Output:       none

Misc:
******************************************************************************/
#pragma interrupt_handler AD_interrupt:17
void AD_interrupt(void)
{
   uint Amp1, Amp2;

   if (ADMUX == ADC0)
   {
      Amp1 = (uint)((int)ADCH << 8) + ADCL;

      Amp1DC = Amp1;

    if (Amp1 > Amp1AC) Amp1AC = Amp1;

    if (Amp1 > Amp1Max) Amp1Max = Amp1;

    Amp1DCSlope = INT_PIN & INT_INPUT_0;
      ADMUX = ADC1;
   }

   else if (ADMUX == ADC1)
   {
      Amp2 = (uint)((int)ADCH << 8) + ADCL;

    Amp2DC = Amp2;

    if (Amp2 > Amp2AC) Amp2AC = Amp2;

    if (Amp2 > Amp2Max) Amp2Max = Amp2;

    Amp2DCSlope = INT_PIN & INT_INPUT_1;
      ADMUX = ADC0;
   }
   ADCSRA |= (1<<ADSC);      // Start AD convertion
}

/******************************************************************************

Name:         float SlopeGetM (float X1, float Y1, float X2, float Y2)

Description:  This function Give the slope

Input:        float Y2, float Y1, float X2, float X1

Output:       float M

Misc:             (Y2 - Y1) / (X2 - X1)
******************************************************************************/
float SlopeGetM (float X1, float Y1, float X2, float Y2)
{
   float M;

   M = (Y2 - Y1) / (X2 - X1);
   return M;
}

/******************************************************************************

Name:         float SlopeGetB (float X, float Y, float B)

Description:  This function Give B offset of the slope

Input:        float M, float X, float M

Output:       float B

Misc:             B = Y - (M * X)
******************************************************************************/
float SlopeGetB (float X, float Y, float M)
{
   float B;

   B = Y - (M * X);
   return B;
}

/******************************************************************************

Name:         float SlopeGetX (float Y, float B, float M)

Description:  This function Give X the slope

Input:        float Y, float B, float M

Output:       float Y

Misc:             X = (Y - B) / M
******************************************************************************/
float SlopeGetX (float Y, float B, float M)
{
   float X;

   X = (Y - B) / M;
   return X;
}

/******************************************************************************

Name:         float SlopeGetY (float X, float B, float M)

Description:  This function Give Y the slope

Input:        float X, float B, float M

Output:       float Y

Misc:             Y = (M * X) + B
******************************************************************************/
float SlopeGetY (float X, float B, float M)
{
   float Y;

   Y = (M * X) + B;
   return Y;
}

//*****************************************************************************
//                         L C D    F U N C T I O N
//*****************************************************************************
/******************************************************************************

Name:         void LCDInit(void)

Description:  Initialize a graphic of  LCD_X & LCD_Y
SED1300

Input:        #define  LCD_X  ...
              #define  LCD_Y  ...

Output:       none

Misc:

******************************************************************************/
void LCDInit(void)
{
  int i,j;

  // LCD Data Bus
  LCDDATA_PORT = 0x00;
  LCDDATA_DDR = 0xff;

  // LCD control Bus
  LCDCTRL_DDR |= LCD_WR+LCD_RD+LCD_RES;
  LCDCTRL_DDR |= LCD_A0;

  LCDCTRL_PORT |= LCD_WR;        // LCD_WR -> 1
  LCDCTRL_PORT |= LCD_RD;        // LCD_RD -> 1

  LCDCTRL_PORT |= LCD_RES;
  LCDDelay2ms();
  LCDCTRL_PORT &= ~LCD_RES;      // Reset LCD
  LCDDelay2ms();
  LCDCTRL_PORT |= LCD_RES;
  for (i=0;i<200;i++)
  {
    LCDDelay2ms();
  }

  // SYSTEM SET COMMAND
  LCDWriteCmd(0x40);          // SYSTEM SET COMMAND
  LCDWriteData(0x30);         // P1   -> PRT=0, IV=1, W/S=0, M0-M2=0
  LCDWriteData(0x87);         // FX   -> WF=1, FX=7
  LCDWriteData(0x07);         // FY   -> FY=7
  LCDWriteData((LCD_X/8)-1);  // C/R  -> Char per line - 1
  LCDWriteData((LCD_XTAL / 70 / LCD_Y) / 9);  // TC/R -> (f_osc/f_frame/[L/F]-1)/9
  LCDWriteData(LCD_Y - 1);    // L/F  -> Line per graphic screen - 1 (127)
  LCDWriteData(LCD_X/8);      // APL  -> Virtual scr low byte (ch perline)
  LCDWriteData(00);           // APH  -> Virtual scr low byte

  // SCROLL COMMAND
  LCDWriteCmd(0x44);          // SCROLL COMMAND
  LCDWriteData(0x00);         // First Layer Low Byte  (0x0000)
  LCDWriteData(0x00);         // First Layer Hign Byte
  LCDWriteData(LCD_Y);        // 128 Line of scroll

  LCDWriteData(0x00);         // Second Layer Low Byte (0x1000)
  LCDWriteData(0x10);         // First Layer Hign Byte
  LCDWriteData(LCD_Y);        // 128 Line of scroll

  // HORIZONTAL SCROLL POSITION
  LCDWriteCmd(0x5a);          // HORIZONTAL SCROLL POSITION
  LCDWriteData(0x00);         // no scrool offset

  // OVERLAY COMMAND
  LCDWriteCmd(0x5b);          // OVERLAY COMMAND
  LCDWriteData(0x03);         // 2 layer (1-Text 2-Graphic)

  // DISPLAY ON/OFF COMMAND
  LCDWriteCmd(0x58);          // DISPLAY OFF COMMAND
  LCDWriteData(0x14);         // Layer 1 & 2 ON

  LCDClrSCR();
  LCDGraphClrSCR();

  // LCDCursor FORMAT COMMAND
  LCDWriteCmd(0x5d);          // LCDCursor FORMAT COMMAND
  LCDWriteData(0x07);         // LCDCursor width (7)
  LCDWriteData(0x87);         // LCDCursor Height(7) & Block type

  // DISPLAY ON/OFF COMMAND
  LCDWriteCmd(0x59);          // DISPLAY ON COMMAND
  LCDWriteData(0x14);         // Layer 1 & 2 ON

  // LCDCursor DIRECTION COMMAND
  LCDWriteCmd(0x4c);          // LCDCursor DIRECTION COMMAND (SHIFT RIGHT)

  // LCDCursor WRITE COMMAND
  LCDWriteCmd(0x46);          // LCDCursor WRITE COMMAND
  LCDWriteData(0x00);         // LCDCursor position low byte
  LCDWriteData(0x00);         // LCDCursor position high byte
}

/******************************************************************************

Name:         void LCDClrSCR(void)

Description:  Clear Text Screen layer 1

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDClrSCR(void)
{
  int i,j;

  LCDWriteCmd(0x46);      // LCDCursor WRITE COMMAND
  LCDWriteData(0x00);     // LCDCursor position low byte
  LCDWriteData(0x00);     // LCDCursor position high byte

  LCDWriteCmd(0x42);      // LCD WRITE MEMORY
  LCDDATA_PORT = ' ';
  LCDCTRL_PORT &= ~LCD_A0;   // LCD_A0 -> 0
  j = ((LCD_X/8)*(LCD_Y/8));
  for (i=0;i<j;i++)
  {
    LCDCTRL_PORT &=~LCD_WR;  // LCD_WR -> 0
    WDR();
    LCDCTRL_PORT |=LCD_WR;
  }

  LCDWriteCmd(0x46);      // LCDCursor WRITE COMMAND
  LCDWriteData(0x00);     // LCDCursor position low byte
  LCDWriteData(0x00);     // LCDCursor position high byte
}

/******************************************************************************

Name:         void LCDGotoXY(ushort x, ushort y)

Description:  Goto LCD_X LCD_Y coor

Input:        LCD_X,LCD_Y

Output:       none

Misc:

******************************************************************************/
void LCDGotoXY(ushort x, ushort y)
{
  int Address;
  ushort low;
  ushort high;

  x--;
  y--;
  Address = (y * (LCD_X/8)) + x;

  low = (ushort) (Address & 0x00ff);
  high = (ushort) ((Address & 0xff00) >> 8);

  LCDWriteCmd(0x46);        // LCDCursor WRITE COMMAND
  LCDWriteData(low);        // LCDCursor position low byte
  LCDWriteData(high);       // LCDCursor position high byte
}

/******************************************************************************

Name:         void LCDWriteString(char *prt)

Description:  Write a string to the LCD

Input:        String

Output:       none

Misc:         String must be ended by \0

******************************************************************************/
void LCDWriteString(char *ptr)
{
  int i;
  LCDWriteCmd(0x42);     // LCD WRITE MEMORY
  while(*ptr != 0x00) LCDWriteData(*ptr++);
}

void LCDWriteConstString(const char *ptr)
{
  int i;
  LCDWriteCmd(0x42);     // LCD WRITE MEMORY
  while(*ptr != 0x00) LCDWriteData(*ptr++);
}

/******************************************************************************

Name:         void LCDCursor(ushort)

Description:  0-> LCDCursor off
              1-> LCDCursor on

Input:        ON/OFF

Output:       none

Misc:

******************************************************************************/
void LCDCursor(ushort LCDCursor)
{
  LCDWriteCmd(0x59);      // DISPLAY ON COMMAND
  if (LCDCursor == 0) LCDWriteData(0x14);
  else LCDWriteData(0x16);
}

/******************************************************************************

Name:         void LCDGraphClrSCR(void)

Description:  Clear Graphic Screen layer 2

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDGraphClrSCR(void)
{
  int i,j;

  LCDWriteCmd(0x46);      // LCDCursor WRITE COMMAND
  LCDWriteData(0x00);     // LCDCursor position low byte
  LCDWriteData(0x10);     // LCDCursor position high byte

  LCDWriteCmd(0x42);      // LCD WRITE MEMORY COMMAND
  LCDDATA_PORT = 0x00;
  LCDCTRL_PORT &= ~LCD_A0;     // LCD_A0 -> 0
  j = ((LCD_X/8)*LCD_Y);
  for (i=0;i<j;i++)
  {
    LCDCTRL_PORT &=~LCD_WR;    // LCD_WR -> 0 & LCD_WR -> 1
    WDR();
    LCDCTRL_PORT |=LCD_WR;
  }

  LCDWriteCmd(0x46);      // LCDCursor WRITE COMMAND
  LCDWriteData(0x00);     // LCDCursor position low byte
  LCDWriteData(0x10);     // LCDCursor position high byte
}

/******************************************************************************

Name:         void LCDGraphGotoXY(ushort x, ushort y)

Description:  Goto LCD_X LCD_Y coor

Input:        LCD_X,LCD_Y

Output:       none

Misc:

******************************************************************************/
void LCDGraphGotoXY(ushort x, ushort y)
{
  int Address;
  ushort low;
  ushort high;

  x--;
  y--;
  Address = (y * (LCD_X/8)) + x;

  low = (ushort) (Address & 0x00ff);
   high = (ushort) (((Address & 0xff00) >> 8) + 0x10);

  LCDWriteCmd(0x46);        // LCDCursor WRITE COMMAND
  LCDWriteData(low);        // LCDCursor position low byte
  LCDWriteData(high);       // LCDCursor position high byte
}

/******************************************************************************

Name:         void LcdGraphString(ushort X, ushort Y, ushort Size, ushort *Ptr)

Description:  Displays a string at

Input:        size -> Font size.
              ch   -> Character to write.

Output:       none

Misc:

******************************************************************************/
void LcdGraphConstString (ushort X, ushort Y, ushort Size, const char *Ptr )
{
   while(*Ptr != 0x00)
   {
      LcdGraphChr(X,Y,Size,*Ptr++);
      if ( Size == FONT_1X ) X++;
      if ( Size == FONT_2X ) X+=2;
      if ( Size == FONT_4X ) X+=3;
   }
}

void LcdGraphString (ushort X, ushort Y, ushort Size, char *Ptr )
{
   while(*Ptr != 0x00)
   {
      LcdGraphChr(X,Y,Size,*Ptr++);
      if ( Size == FONT_1X ) X++;
      if ( Size == FONT_2X ) X+=2;
      if ( Size == FONT_4X ) X+=3;
   }
}

/******************************************************************************

Name:         void LcdGraphChr (ushort X, ushort Y, ushort Size, ushort Ch )

Description:  Displays a character at x,y  location

Input:        X    -> X axis position
                     Y    -> Y axis position
                     Size -> Font size.
              Ch   -> Character to write.

Output:       none

Misc:

******************************************************************************/
void LcdGraphChr (ushort X, ushort Y, ushort Size, ushort Ch )
{
   ushort i,j;
   uint Address;
   ushort low;
   ushort high;
   ushort b1,b2,b3,b4;
   ushort Font;

   Ch -=32;
   X--;
  Y--;
  Address = (Y * (LCD_X/8)) + X;
   LCDGraphSetRamPointer(Address);

   if ( Size == FONT_1X )
   {
      for (i=0;i<7;i++)
      {
         LCDWriteCmd(0x42);      // LCD WRITE MEMORY
         LCDWriteData( (ushort)(FontLookup[Ch][i]) << 2 );
         LCDGraphSetRamPointer(Address += LCD_X / 8);
      }
   }

   if ( Size == FONT_2X )
   {
   for ( i = 0; i < 7; i++ )
      {
         Font = FontLookup[Ch][i] << 2;

         b1 = 0;
         b2 = 0;

         if (Font & 0x01) b1 |= 0b00000011;
         if (Font & 0x02) b1 |= 0b00001100;
         if (Font & 0x04) b1 |= 0b00110000;
         if (Font & 0x08) b1 |= 0b11000000;
         if (Font & 0x10) b2 |= 0b00000011;
         if (Font & 0x20) b2 |= 0b00001100;
         if (Font & 0x40) b2 |= 0b00110000;
         if (Font & 0x80) b2 |= 0b11000000;

         for (j=0;j<2;j++)
         {
            LCDWriteCmd(0x42);      // LCD WRITE MEMORY
            LCDWriteData(b2);
            LCDWriteData(b1);
            LCDGraphSetRamPointer(Address += LCD_X / 8);
         }
      }
   }

   if ( Size == FONT_4X )
   {
      for ( i = 0; i < 7; i++ )
      {
         Font = FontLookup[Ch][i] << 2;
      b1 = 0x00;
         b2 = 0x00;
         b3 = 0x00;
         b4 = 0x00;

         if (Font & 0x01) b4 |= 0x0f;
         if (Font & 0x02) b4 |= 0xf0;
         if (Font & 0x04) b3 |= 0x0f;
         if (Font & 0x08) b3 |= 0xf0;
         if (Font & 0x10) b2 |= 0x0f;
         if (Font & 0x20) b2 |= 0xf0;
         if (Font & 0x40) b1 |= 0x0f;
         if (Font & 0x80) b1 |= 0xf0;

         for (j=0;j<4;j++)
         {
            LCDWriteCmd(0x42);      // LCD WRITE MEMORY
            LCDWriteData(b1);
            LCDWriteData(b2);
            LCDWriteData(b3);
            LCDWriteData(b4);
            LCDGraphSetRamPointer(Address += LCD_X / 8);
         }
      }
   }
}

/******************************************************************************

Name:         void LCDGraphSetRamPointer(int Address)

Description:  Setup the address register of the LCD

Input:        int -> Address done by combination of X and Y

Output:       none

Misc:

******************************************************************************/
void LCDGraphSetRamPointer(int Address)
{
   ushort low;
   ushort high;

   low = (ushort) (Address & 0x00ff);
   high = (ushort) (((Address & 0xff00) >> 8) + 0x10);

   LCDWriteCmd(0x46);      // LCDCursor WRITE COMMAND
   LCDWriteData(low);      // LCDCursor position low byte
   LCDWriteData(high);     // LCDCursor position high byte
}

/******************************************************************************

Name:         void LCDGraphPix(int x, int y, ushort stat)

Description:  Set of Clear a pixel

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDGraphPix(int x, int y, ushort stat)
{
  uint Address;
  ushort Offset;
  ushort low;
  ushort high;
  ushort byte;

  x--;
  y--;
  Address = (y * (LCD_X/8)) + (x / 8);
  Offset = x - ((x / 8) * 8);

  low = (ushort) (Address & 0x00ff);
  high = (ushort) (((Address & 0xff00) >> 8) + 0x10);

  LCDWriteCmd(0x46);      // LCDCursor WRITE COMMAND
  LCDWriteData(low);      // LCDCursor position low byte
  LCDWriteData(high);     // LCDCursor position high byte

  LCDWriteCmd(0x43);      // READ LCD MEMORY COMMAND
  byte = LCDReadData();   // Read data at position

  if (stat != 0) byte |= (0x80 >> Offset);
  else byte &= (~(0x80 >> Offset));

  LCDWriteCmd(0x46);      // LCDCursor WRITE COMMAND
  LCDWriteData(low);      // LCDCursor position low byte
  LCDWriteData(high);     // LCDCursor position high byte

  LCDWriteCmd(0x42);      // LCD WRITE MEMORY COMMAND
  LCDWriteData(byte);     // Write byte
}

/******************************************************************************

Name:         void LCDGraphBox(int x1, int y1, int x2, int y2)

Description:  draw a box

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDGraphBox(int x1, int y1, int x2, int y2,int stat)
{
  int i;

  for (i=x1;i<=x2;i++) LCDGraphPix(i,y1,stat);    // Top line
  for (i=x1;i<=x2;i++) LCDGraphPix(i,y2,stat);    // Bottom line
  for (i=y1;i<=y2;i++) LCDGraphPix(x1,i,stat);    // Left side
  for (i=y1;i<=y2;i++) LCDGraphPix(x2,i,stat);    // Right side
}

/******************************************************************************

Name:         void LCDTextBox(int x, int y, int length,int stat)

Description:

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDTextBox(int x, int y, int length,int stat)
{
  LCDGraphBox(((x-1)*8),((y-1)*8),(((length*8)+((x-1)*8))-2),(y*8),stat);
}

/******************************************************************************

Name:         void LCDGraphLine(int x1, int y1, int x2, int y2)

Description:  draw a line

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDGraphLine(int x1, int y1, int x2, int y2)
{
  int dx,dy,stepx,stepy,fraction;

  dy = y2 - y1;
  dx = x2 - x1;

  if (dy < 0)
  {
    dy = -dy;
    stepy = -1;
  }
  else
  {
    stepy = 1;
  }

  if (dx < 0)
  {
    dx = -dx;
    stepx = -1;
  }
  else
  {
    stepx = 1;
  }

  dy <<= 1;
  dx <<= 1;

  LCDGraphPix(x1,y1,1);

  if (dx > dy)
  {
    fraction = dy - (dx >> 1);
    while (x1 != x2)
    {
      if (fraction >= 0)
      {
        y1 += stepy;
        fraction -= dx;
      }
      x1 += stepx;
      fraction += dy;
      LCDGraphPix(x1,y1,1);
    }
  }
  else
  {
    fraction = dx - (dy >> 1);
    while (y1 != y2)
    {
      if (fraction >= 0)
      {
        x1 += stepx;
        fraction -= dy;
      }
      y1 += stepy;
      fraction += dx;
      LCDGraphPix(x1,y1,1);
    }
  }
}

/******************************************************************************

Name:         void LCDWriteCmd(ushort byte)

Description:  write a Cmd byte to the LCD

Input:        Command (Byte)

Output:       none

Misc:

******************************************************************************/
void LCDWriteCmd(ushort byte)
{
  LCDDATA_DDR = 0xff;           // Data Port as output
  LCDDATA_PORT = byte;
  LCDCTRL_PORT |= LCD_A0;      // LCD_A0 -> 1
  LCDCTRL_PORT &=~LCD_WR;      // LCD_WR -> 0
  WDR();
  LCDCTRL_PORT |=LCD_WR;       // LCD_WR -> 1
}

/******************************************************************************

Name:         void LCDWriteData(ushort byte)

Description:  write a data byte to the LCD

Input:        ushort byte -> data to write on the LCD

Output:       none

Misc:

******************************************************************************/
void LCDWriteData(ushort byte)
{
  LCDDATA_DDR = 0xff;           // Data Port as output
  LCDDATA_PORT = byte;
  LCDCTRL_PORT &= ~LCD_A0;     // LCD_A0 -> 0
  LCDCTRL_PORT &=~LCD_WR;      // LCD_WR -> 0
  WDR();
  LCDCTRL_PORT |=LCD_WR;       // LCD_WR -> 1
}

/******************************************************************************

Name:         ushort LCDReadData(void)

Description:  read a data byte to the LCD

Input:        none

Output:       ushort byte -> Data read from the LCD

Misc:

******************************************************************************/
ushort LCDReadData(void)
{
  ushort byte;
  int i;

  WDR();
  LCDDATA_DDR = 0x00;         // Data Port as input
  LCDCTRL_PORT |= LCD_A0;    // LCD_A0 -> 1
  LCDDelay1us();
  LCDCTRL_PORT &=~LCD_RD;    // LCD_RD -> 0
  byte = LCDDATA_PIN;         // read byte
  byte = LCDDATA_PIN;         // read byte
  byte = LCDDATA_PIN;         // read byte
  byte = LCDDATA_PIN;         // read byte
  LCDCTRL_PORT  |=LCD_RD;    // LCD_RD -> 1
  return byte;
}

/******************************************************************************

Name:         void LCDDelay2ms(void)

Description:  Delay of 2ms

Input:        void

Output:       void

Misc:

******************************************************************************/
void LCDDelay2ms(void)
{
  int i,j;

  for (i=0;i<(XTAL/36363);i++)
  {
    for (j=1;j<20;j++);
    asm("WDR");
  }
}

/******************************************************************************

Name:         void LCDDelay1us()

Description:  Delay of 1us

Input:        none

Output:       none

Misc:

******************************************************************************/
void LCDDelay1us(void)
{
  int i;

  for (i=0;i<6;i++) WDR();
}

/*****************************************************************************

Name:             void ScanSwitch(void)

Description:  

Input:            none

Output:           none

Misc:      

******************************************************************************/
void SwitchInit(void)
{
   SWITCH_DDR &= ~(LEFT + RIGHT);
   SWITCH_PORT |= (LEFT + RIGHT);
}

/*****************************************************************************

Name:             void SwitchScan(void)

Description:  

Input:            none

Output:           none

Misc:      

******************************************************************************/
void SwitchScan(void)
{
static unsigned char LastSwitch;
unsigned char SwitchRead;

SwitchRead = NULL;
if (!(SWITCH_PIN & RIGHT)) SwitchRead = RIGHT;
if (!(SWITCH_PIN & LEFT)) SwitchRead = LEFT;
if (!(SWITCH_PIN & (LEFT+RIGHT))) SwitchRead = BOTH;

if (SwitchRead != LastSwitch)
   {
   Switch = SwitchRead;
   LastSwitch = SwitchRead;
   }
}

 

//*****************************************************************************
// TaskManager
// Version 2.0 Fev 2005
//
// 2.0 -> -Re work all the interrupt code
// 1.0 -> -Everything is new
//
// Sylvain Bissonnette
//*****************************************************************************
// Editor : UltraEdit32
//*****************************************************************************
//                T I M E R   U S A G E
//
// Timer 0 is use by Task Manager
//
//*****************************************************************************
//
//*****************************************************************************
//                      I N C L U D E
//*****************************************************************************
#include <iom32v.h>
#include <shortnametype.h>
#include <macros.h>
#include <stdlib.h>
#include <STRING.H>
#include "TaskManager.h"
//#define MINIMUM_CODE    // if def save 71 words of code but no more
                          // checking of Register and UnRegister

//*****************************************************************************
//            G L O B A L   V A R I A B L E
//*****************************************************************************
typedef struct Task
{
  void (*FunctionPTR)(void);
  uint Interval;
  uint Ticker;
  ushort Persiste;
}Task;
Task TaskList[MAX_TASK];
Task TaskAdd;
Task TaskDel;
int TaskMax = 0;

/******************************************************************************

Name:         void TaskInit(void)

Description:  Init task system

Input:        none

Output:       none

Misc:         Use Timer 0

******************************************************************************/
void TaskInit(void)
{
  //Timer0
  TCCR0 = 0x02;               // Timer0 / 8
  TIMSK |= (1<<TOIE0);        // int enable on Timer 0 overflow
}

/******************************************************************************

Name:         int TaskRegister( void(*FunctionPTR)(void),
                                int Interval,
                                ushort Persiste)

Description:  Register a function to be call

Input:        void  Function pointer
              int   Interval
              uchar Persiste

Output:       0 -> Task not registrated (error)
              1 -> Task is now registrated

Misc:

******************************************************************************/
int TaskRegister(void(*FunctionPTR)(void),
                 uint Interval,
                 ushort Persiste)
{
  #ifndef MINIMUM_CODE
  uint i = 0;

  if (FunctionPTR == NULL) return 0;
  if (TaskMax >= MAX_TASK) return 0;

  while (TaskAdd.FunctionPTR != NULL)
  {
    WDR();
    if (i++ > 65530) return 0;
  }
  #endif
  TaskAdd.FunctionPTR = FunctionPTR;
  TaskAdd.Interval = Interval;
  TaskAdd.Persiste = Persiste;
  return 1;
}

/******************************************************************************

Name:         int TaskUnRegister(void(*FunctionPTR)(void))

Description:  UnRegister a function

Input:        Function pointer

Output:       0 -> Task not find
              1 -> Task is unregistrated

Misc:

******************************************************************************/
int TaskUnRegister(void(*FunctionPTR)(void))
{
  #ifndef MINIMUM_CODE
  uint i = 0;

  if (FunctionPTR == NULL) return 0;

  while(TaskDel.FunctionPTR != NULL)
  {
    WDR();
    if (i++ > 65530) return 0;
  }
  #endif
  TaskDel.FunctionPTR = FunctionPTR;
  return 1;
}

/**********************************************************

Name:         int TaskCheckRegister(void(*FunctionPTR)(void))

Description:  Check if a function is register

Input:        Function pointer

Output:       0 -> Not register
              1 -> Register

Misc:

**********************************************************/
int TaskCheckRegister(void(*FunctionPTR)(void))
{
  ushort i;

  for (i=0; i < TaskMax; i++)
  {
    if (TaskList[i].FunctionPTR == FunctionPTR) return 1;
  }
  return 0;
}

/**********************************************************

Name:         void TaskBlock(int Time)

Description:  Block for x time

Input:        none

Output:       none

Misc:

**********************************************************/
void TaskBlock(uint Time)
{
  TaskRegister(TaskDummy,Time,FALSE);
  while (TaskCheckRegister(TaskDummy)) WDR();
}

void TaskDummy(void)
{
}

/**********************************************************

Name:         void TaskStop(void)

Description:  Stop Task Execution

Input:        none

Output:       none

Misc:

**********************************************************/
void TaskStop(void)
{
  TIMSK &= ~(1<<TOIE0);   // int disable on Timer 0 overflow
}

/**********************************************************

Name:         void TaskStart(void)

Description:  Start Task Execution

Input:        none

Output:       none

Misc:

**********************************************************/
void TaskStart(void)
{
  TIMSK |= (1<<TOIE0);    // int enable on Timer 0 overflow
}

/**********************************************************

Name:         void TaskExecute(void)

Description:  TaskExecute

Input:        none

Output:       none

Misc:         TaskExecute is execute each 100us

**********************************************************/
#pragma interrupt_handler TaskExecute:12
void TaskExecute(void)
{
  static ushort i,j;
  static void (*FunctionPTR)(void);

  TCNT0 = 255 - (XTAL / 8 / 10000);
  TaskStop();
  WDR();

  if (TaskDel.FunctionPTR != NULL) _TaskUnRegister();
  if (TaskAdd.FunctionPTR != NULL) _TaskRegister();

  for (i=0;i<TaskMax;i++)
  {
    if (TaskList[i].Ticker++ >= TaskList[i].Interval)
    {
      FunctionPTR = TaskList[i].FunctionPTR;
      if (!TaskList[i].Persiste)
      {
        for (j=i;j<TaskMax;j++) memcpy(&TaskList[j],&TaskList[j+1],sizeof(Task));
        TaskMax--;
      }
      else
      {
        TaskList[i].Ticker = 0;
      }
      SEI();
      FunctionPTR();
      CLI();
    }
  }
  TaskStart();
}

/******************************************************************************

Name:         void _TaskUnRegister(void)

Description:  UnRegister a function

Input:        TaskDel struct

Output:       none

Misc:

******************************************************************************/
void _TaskUnRegister(void)
{
  ushort i,j;

  for (i=0;i<TaskMax;i++)
  {
    if (TaskList[i].FunctionPTR == TaskDel.FunctionPTR)
    {
      for (j=i;j<TaskMax;j++) memcpy(&TaskList[j],&TaskList[j+1],sizeof(Task));
      TaskMax--;
      TaskDel.FunctionPTR = NULL;
      return;
    }
  }
  TaskDel.FunctionPTR = NULL;
}

/******************************************************************************

Name:         int _TaskRegister(void)

Description:  Register a function

Input:        TaskAdd struct

Output:       none

Misc:

******************************************************************************/
void _TaskRegister(void)
{
  TaskList[TaskMax].FunctionPTR = TaskAdd.FunctionPTR;
  TaskList[TaskMax].Interval = TaskAdd.Interval;
  TaskList[TaskMax].Ticker = 0;
  TaskList[TaskMax].Persiste = TaskAdd.Persiste;
  TaskAdd.FunctionPTR = NULL;
  TaskMax++;
}

 

//*****************************************************************************
// TaskManager.h
// Version 1.0 Dec 2004
//
// 1.0 -> -Everything is new
//
// Sylvain Bissonnette
//*****************************************************************************
//
//*****************************************************************************
//                      D E F I N E
//*****************************************************************************
#define TASK_MAN_VER    10
#define TRUE            1
#define FALSE           0
#define XTAL            8000000

#define MAX_TASK        10

#define T100US          1
#define T200US          2
#define T300US          3
#define T400US          4
#define T500US          5
#define T600US          6
#define T700US          7
#define T800US          8
#define T900US          9

#define T1MS            10
#define T2MS            20
#define T3MS            30
#define T4MS            40
#define T5MS            50
#define T6MS            60
#define T7MS            70
#define T8MS            80
#define T9MS            90

#define T10MS           100
#define T20MS           200
#define T30MS           300
#define T40MS           400
#define T50MS           500
#define T60MS           600
#define T70MS           700
#define T80MS           800
#define T90MS           900

#define T100MS          1000
#define T110MS          1100
#define T120MS          1200
#define T130MS          1300
#define T140MS          1400
#define T150MS          1500
#define T160MS          1600
#define T170MS          1700
#define T180MS          1800
#define T190MS          1900

#define T200MS          2000
#define T210MS          2100
#define T220MS          2200
#define T230MS          2300
#define T240MS          2400
#define T250MS          2500
#define T260MS          2600
#define T270MS          2700
#define T280MS          2800
#define T290MS          2900

#define T300MS          3000
#define T310MS          3100
#define T320MS          3200
#define T330MS          3300
#define T340MS          3400
#define T350MS          3500
#define T360MS          3600
#define T370MS          3700
#define T380MS          3800
#define T390MS          3900

#define T400MS          4000
#define T410MS          4100
#define T420MS          4200
#define T430MS          4300
#define T440MS          4400
#define T450MS          4500
#define T460MS          4600
#define T470MS          4700
#define T480MS          4800
#define T490MS          4900

#define T500MS          5000
#define T510MS          5100
#define T520MS          5200
#define T530MS          5300
#define T540MS          5400
#define T550MS          5500
#define T560MS          5600
#define T570MS          5700
#define T580MS          5800
#define T590MS          5900

#define T600MS          6000
#define T610MS          6100
#define T620MS          6200
#define T630MS          6300
#define T640MS          6400
#define T650MS          6500
#define T660MS          6600
#define T670MS          6700
#define T680MS          6800
#define T690MS          6900

#define T700MS          7000
#define T710MS          7100
#define T720MS          7200
#define T730MS          7300
#define T740MS          7400
#define T750MS          7500
#define T760MS          7600
#define T770MS          7700
#define T780MS          7800
#define T790MS          7900

#define T800MS          8000
#define T810MS          8100
#define T820MS          8200
#define T830MS          8300
#define T840MS          8400
#define T850MS          8500
#define T860MS          8600
#define T870MS          8700
#define T880MS          8800
#define T890MS          8900

#define T900MS          9000
#define T910MS          9100
#define T920MS          9200
#define T930MS          9300
#define T940MS          9400
#define T950MS          9500
#define T960MS          9600
#define T970MS          9700
#define T980MS          9800
#define T990MS          9900

#define T1S             10000
#define T2S             20000
#define T3S             30000
#define T4S             40000
#define T5S             50000
#define T6S             60000
#define T7S             70000
#define T8S             80000
#define T9S             90000

#define T10S            100000
#define T11S            110000
#define T12S            120000
#define T13S            130000
#define T14S            140000
#define T15S            150000
#define T16S            160000
#define T17S            170000
#define T18S            180000
#define T19S            190000

#define T20S            200000
#define T21S            210000
#define T22S            220000
#define T23S            230000
#define T24S            240000
#define T25S            250000
#define T26S            260000
#define T27S            270000
#define T28S            280000
#define T29S            290000

#define T30S            300000
#define T31S            310000
#define T32S            320000

//*****************************************************************************
//                  P R O T O T Y P E
//*****************************************************************************
void TaskInit(void);
int TaskRegister(void(*CallBack)(void),
         unsigned int Interval, // was long
         unsigned char Persiste);
int TaskUnRegister(void(*CallBack)(void));
int TaskCheckRegister(void(*CallBack)(void));
void TaskBlock(unsigned int Time); // was long
void TaskDummy(void);
void TaskStop(void);
void TaskStart(void);
void TaskExecute(void);
void _TaskUnRegister(void);
void _TaskRegister(void);