eg. If I draw 18 amps from a 18aH battery the battery should discharge completely in 1 hour and if I draw 6 amps it should discharge in 3 hours. I have done the simulation in Proteus and actual hardware also. The time remaining doesn't change instantly. Explanation in Proteus, If the switch is on 6 Amp, the Time remaining is 3 hours which is right but if I switch it to 18 Amps ,time remaining doesn't drop down instantly to 1 hour and vice versa. How to achieve instant change in display of time remaining. Please help
I have attached the complete project files and Proteus Simulation files.
Code: Select all
// LCD module connections
sbit LCD_RS at RC2_bit;
sbit LCD_EN at RC3_bit;
sbit LCD_D4 at RC4_bit;
sbit LCD_D5 at RC5_bit;
sbit LCD_D6 at RC6_bit;
sbit LCD_D7 at RC7_bit;
sbit LCD_RS_Direction at TRISC2_bit;
sbit LCD_EN_Direction at TRISC3_bit;
sbit LCD_D4_Direction at TRISC4_bit;
sbit LCD_D5_Direction at TRISC5_bit;
sbit LCD_D6_Direction at TRISC6_bit;
sbit LCD_D7_Direction at TRISC7_bit;
// End LCD module connections
// Define Ports
#define MENU PORTB.RB4
#define PLUS PORTB.RB1
#define MINUS PORTB.RB2
//#define VSENSE PORTA.RA1 // Battery Voltage Sense
#define ALARM PORTA.RA5 // Charging Limit Alarm
//#define RPM PORTB.RB0 // Speedometer/Odometer Input
//functions prototypes
void CustomChar(char pos_row, char pos_char);
//void Lcd_COut(char row, char col, const char *cptr);
void menu();
void battery_capacity();
void charge_alarm();
void tire_size();
void power_calc();
void save_data();
void batt_percNbar();
void delay_100ms(unsigned char n);
char look(int a)
{
switch(a)
{
case 0:
return '0';
case 1:
return '1';
case 2:
return '2';
case 3:
return '3';
case 4:
return '4';
case 5:
return '5';
case 6:
return '6';
case 7:
return '7';
case 8:
return '8';
case 9:
return '9';
default:
return '.';
}
}
const char character[] = {31,31,31,31,31,31,31,31};
const char character1[] = {31,31,31,31,31,31,31,31};
// global variables
unsigned char count_1ms = 0; // count number of 1ms interrupts
unsigned char flag_200ms = 0; // set HIGH once 0.2 second (200ms)
unsigned int a,vadc,save_maH;
unsigned long int aH;
unsigned int batt_cap;
unsigned short int batt_max = 0;
unsigned short int disarm_alarm = 0; // Battery Full Alarm
unsigned short int DspUpdInt = 0; // Display Update interval
float mAsec;
unsigned short idx = 0; // Loop index to read msg1 array
unsigned short Col = 1; // Loop index for Column position
unsigned char *ampHour = "00.000aH";
//Timer1
//Prescaler 1:1; TMR1 Preload = 61536; Actual Interrupt Time : 1 ms
// MCU frequency 16 MHz
//Place/Copy this part in declaration section
void InitTimer1(){
T1CON = 0x01;
TMR1IF_bit = 0;
TMR1H = 0xF0;
TMR1L = 0x60;
TMR1IE_bit = 1;
INTCON = 0xC0;
}
// Interrupt from timer 1 ever 1 millisecond
void Interrupt(){
if (TMR1IF_bit){ // timer 1 interrupt
TMR1IF_bit = 0; // clear Interrupt bit
TMR1H = 0xF0; // load new timer value
TMR1L = 0x60;
count_1ms++; // count up every 1ms
if(count_1ms > 200){ // 200 times 1ms is 0.2 second(200mSec)
count_1ms = 0; // reset counter
flag_200ms = 1; // indicate that 0.2 second has passed
}
}
}
void CustomChar(char pos_row, char pos_char)
{
char jp;
Lcd_Cmd(64);
for (jp = 0; jp<=7; jp++) Lcd_Chr_CP(character[jp]);
Lcd_Cmd(_LCD_RETURN_HOME);
Lcd_Chr(pos_row, pos_char, 0);
}
void delay_ms100(unsigned char n)
{
while (n-- != 0) {
delay_ms(100);
}
}
void battery_capacity() {
unsigned short int setup = 1;
unsigned short int batt_cap_new = 0;
char *capacity = "00.000aH";
const unsigned char msg1[] = "Battery Capacity";
//batt_cap=18000; // 18A x 1000mA = 18aH
batt_cap = (EEPROM_Read(4) << 8) | (EEPROM_Read(3));
Lcd_Cmd(_LCD_CLEAR);
Delay_ms(50);
Col =1;
for (idx =0; idx != sizeof(msg1)-1; idx++) Lcd_Chr(1,Col++,msg1[idx]);
while(setup == 1)
{
if(PLUS == 0 & batt_cap<65500) //PORTB.F3(RB3)
{
Delay_ms(2); // Switch Debouncing Protection
if(PLUS == 0) batt_cap += 100;
}
else if (MINUS == 0 & batt_cap !=0) //PORTB.F2(RB2)
{
Delay_ms(2); // Switch Debouncing Protection
if (MINUS == 0) batt_cap -= 100;
}
Delay_ms(100);
if (batt_cap_new != batt_cap)
{
capacity[0] = look(batt_cap/10000);
capacity[1] = look((batt_cap/1000)%10);
capacity[3] = look((batt_cap/100)%10);
capacity[4] = look((batt_cap/10)%10);
capacity[5] = look((batt_cap/1)%10);
Lcd_Out(2,1,capacity);
}
batt_cap_new = batt_cap;
if(MENU == 0) // PORTB.F4 (RB4)
{
Delay_ms(2); // Switch Debouncing Protection
if(MENU == 0)
{
EEPROM_Write(3, (batt_cap & 0xFF));
EEPROM_Write(4, ((batt_cap >> 8) & 0xff));
Lcd_chr(4,1,'*');
Lcd_chr(4,2,'*');
Lcd_chr(4,3,'*');
Lcd_out(4,4,"SAVED");
Lcd_chr(4,9,'*');
Lcd_chr(4,10,'*');
Lcd_chr(4,11,'*');
setup = 0;
Delay_ms(1000);
Delay_ms(1000);
Lcd_Cmd(_LCD_CLEAR);
}
}
}
}
void charge_alarm() {
unsigned short int chargelimit;
unsigned short int setup = 1;
unsigned short int level_new = 0;
unsigned char *level = "000%";
const unsigned char msg1[] = "Charge Alarm";
const unsigned char msg2[] = "***SAVED***";
Lcd_Cmd(_LCD_CLEAR);
Delay_ms(50);
Col =1;
for (idx =0; idx != sizeof(msg1)-1; idx++) Lcd_Chr(1,Col++,msg1[idx]);
chargelimit = EEPROM_Read(5);
while(setup == 1)
{
if(PLUS == 0 & chargelimit<250)
{
Delay_ms(2); // Switch Debouncing Protection
if(PLUS == 0) chargelimit += 1;
}
else if (MINUS == 0 & chargelimit !=0)
{
Delay_ms(2); // Switch Debouncing Protection
if (MINUS == 0) chargelimit -= 1;
}
Delay_ms(200); // 0.2 Second delay
if (level_new != chargelimit)
{
level[0] = look(chargelimit/100);
level[1] = look((chargelimit/10)%10);
level[2] = look((chargelimit/1)%10);
Lcd_Out(2,2,level);
}
level_new = chargelimit;
if(MENU == 0)
{
Delay_ms(2); // Switch Debouncing Protection
if(MENU == 0)
{
EEPROM_Write(5, (chargelimit));
Col = 1;
for (idx =0; idx != sizeof(msg2)-1; idx++) Lcd_Chr(4,Col++,msg2[idx]);
setup = 0;
delay_ms100(20); // 2 Second Delay
Lcd_Cmd(_LCD_CLEAR);
}
}
}
}
void tire_size() {
const unsigned char msg1[] = "Coming Soon";
Lcd_Cmd(_LCD_CLEAR);
Col = 1;
for (idx =0; idx != sizeof(msg1)-1; idx++) Lcd_Chr(2,Col++,msg1[idx]);
delay_ms100(30); // 3 Second Delay
Lcd_Cmd(_LCD_CLEAR);
}
void menu() {
unsigned int ex = 1;
unsigned int sw = 1;
const unsigned char msg1[] = "Entering Main Menu";
const unsigned char msg2[] = "Please Wait...";
const unsigned char BattCap[] = "Battery Capacity";
const unsigned char ChrgAlr[] = "Charge Alarm";
const unsigned char TSize[] = "Tire Size";
const unsigned char Exit[] = "Exit";
/// ***How to call this as Function
////////////////////////////////////////////////////////////////////
Col =1;
for (idx =0; idx != sizeof(msg1)-1; idx++) Lcd_Chr(1,Col++,msg1[idx]);
////////////////////////////////////////////////////////////////////
Col =1;
for (idx =0; idx != sizeof(msg2)-1; idx++) Lcd_Chr(2,Col++,msg2[idx]);
delay_ms100(30); // Delay 3 Second
Lcd_Cmd(_LCD_CLEAR);
startmenu:
CustomChar(sw,1);
Col =3;
for (idx =0; idx != sizeof(BattCap)-1; idx++) Lcd_Chr(1,Col++,BattCap[idx]);
Col =3;
for (idx =0; idx != sizeof(ChrgAlr)-1; idx++) Lcd_Chr(2,Col++,ChrgAlr[idx]);
Col =3;
for (idx =0; idx != sizeof(TSize)-1; idx++) Lcd_Chr(3,Col++,TSize[idx]);
Col =3;
for (idx =0; idx != sizeof(Exit)-1; idx++) Lcd_Chr(4,Col++,Exit[idx]);
do
{
if(PLUS == 0 & sw<4) //PORTB.F3
{
Delay_ms(2); // Switch Debouncing Protection
if(PLUS == 0)
{
Lcd_out(sw,1," ");
sw++;
CustomChar(sw,1);
}
}
else if (MINUS == 0 & sw !=1) //PORTB.F2
{
Delay_ms(2); // Switch Debouncing Protection
if (MINUS == 0)
{
Lcd_out(sw,1," ");
sw--;
CustomChar(sw,1);
}
}
delay_ms100(10);
if(MENU == 0 & ex == 1) //PORTB.F4
{
Delay_ms(2); // Switch Debouncing Protection
if(MENU == 0 & ex == 1); //PORTB.F4
{
if(sw==1)
{
battery_capacity();
goto startmenu;
}
else if(sw==2)
{
charge_alarm();
goto startmenu;
}
else if(sw==3)
{
tire_size();
goto startmenu;
}
else if(sw==4) ex=0;
}
}
}while(ex==1);
ex=0;
}
void power_calc(){
//unsigned int dloop;
unsigned int v,amps;
unsigned long int wt;
float i;
char *volt = "00.00V";
char *current = "00.00A";
char *watt = "000W";
char *sign;
ADCON1 = 0x00;
vadc = ADC_Read(0); // Read AN0/RA0 for voltage
v = ((vadc*4.89));
//Delay_ms(10);
//for (dloop=0; dloop<20;dloop++) //Read value for 10 Times
//{
{
a = ADC_Read(3); // Read AN2/RA2 for current
if (a>=511)
{
i = (float)(((a-511)*4.89)/6.6);
sign = "-"; //Battery Discharging
}
else if (a<510)
{
i = (float)(((511-a)*4.89)/6.6);
sign = "+"; // Battery Charging
}
}
//}
//i/=20;
amps = (int)(i*10);
mAsec =(float)(i/180); // mA/0.2Sec
if(DspUpdInt > 4) //Display Voltage,Current,Watts every 1 Second
{
wt = ((long)v*i)/1000;
//////////////////////
//***LCD Line 2 ***//
/// Voltage Display ///
volt[0] = look(v/1000);
volt[1] = look((v/100)%10);
volt[3] = look((v/10)%10);
volt[4] = look((v/11)%10);
Lcd_Out(1,1,volt);
/// Display Current ///
current[0] = look(amps/1000);
current[1] = look((amps/100)%10);
current[3] = look((amps/10)%10);
current[4] = look((amps/1)%10);
Lcd_Out(1,8,sign);
Lcd_Out(1,9,current);
/// Display Wattage ///
watt[0] = look(wt/100);
watt[1] = look((wt/10)%10);
watt[2] = look((wt/1)%10);
Lcd_Out(1,16,sign);
Lcd_Out(1,17,watt);
}
}
void batt_percNbar() {
unsigned long int batt_perc;
unsigned long int BarSegmentNum;
unsigned int bm;
char z;
char battcap[] = " 0%";
batt_perc = (100*aH)/batt_cap;
BarSegmentNum = (batt_perc/5) + 1;
if (a<510 & batt_perc >= (EEPROM_Read(5)))
{
if(disarm_alarm != 1)
{ ALARM = !ALARM; // Toggle RB5
if(MENU == 0 || PLUS == 0 || MINUS == 0)
{
disarm_alarm = 1;
ALARM = 0;
}
}
}
else ALARM = 0;
//////////////////////////////////
//***LCD Line 3 ***//
// Display Battery Percentage
if (DspUpdInt > 4)
{
if (batt_perc >= 100)
battcap[0] = look(batt_perc/100);
battcap[1] = look((batt_perc/10)%10);
battcap[2] = look((batt_perc/1)%10);
Lcd_out(3,8,battcap);
}
////////////////////////////
//***LCD Line 4 ***//
// Display Battery Percentage in Bar Graph
if (BarSegmentNum>21) BarSegmentNum=21;
if (batt_max<BarSegmentNum)
{
for (z=batt_max;z<BarSegmentNum;z++) // Loop to print each bar segment in 4th row
{
if (!z<1) CustomChar(4,z); // Print custom character for bargraph segment
}
}
else if (batt_max>BarSegmentNum)
{
{
for (bm=BarSegmentNum;bm<21;bm++)
{
Lcd_out(4,bm," "); // Delete unused bar segment
}
}
}
batt_max = BarSegmentNum;
}
void save_data() {
/////////////////////////////////////////////////
// ** EEPROM Save Last aH Value on Power OFF **//
////////////////////////////////////////////////
const unsigned char msg1[] = "Last Data Saved";
Lcd_Cmd(_LCD_CLEAR);
if (aH > batt_cap) aH = batt_cap;
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
EEPROM_Write(1, (aH & 0xFF));
EEPROM_Write(2, ((aH >> 8) & 0xff));
Col = 1;
for (idx =0; idx != sizeof(msg1)-1; idx++) Lcd_Chr(1,Col++,msg1[idx]);
amphour[0] = look(aH/10000);
amphour[1] = look((aH/1000)%10);
amphour[3] = look((aH/100)%10);
amphour[4] = look((aH/10)%10);
amphour[5] = look((aH/1)%10);
Lcd_Out(2,1,amphour);
/////////////////////////////////////
}
void main()
{
unsigned int sample,hrs,min,sec;
float maH,maH_tmp,mAavg,total_aH,timeSec;
//unsigned int atimeSec;//,timeSec;
unsigned char *TimeRemain = "00:00:00";
//char timet;
PORTA = 0x00; // Clear PORTA before use
ANSEL = 0b00001001; // Enable Analog function only on RA0,RA2
// Set Input / Output Pins on PORTA
TRISA = 0b11001001;//RA0=I,RA1=O,RA2=O,RA3=I,RA4=0,RA5=0,RA6=I,RA7=I
PORTB = 0x00; // Clear PORTB before use
ANSELH = 0x00; // Disable Analog/ADC function on PortB
// Set Input / Output Pins on PORTA
TRISB = 0b00011110;//RB0=O,RB1=I,RB2=I,RB3=I,RB4=I,RB5=O,RB6=O,RB7=O
OPTION_REG.NOT_RBPU=0;
//WPUB = 0xFD; // no pull up resistor on RB1
WPUB = 0b00011110; // Pull up resistor on RB1,RB2,RB3,RB4
Lcd_Init();
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
sample = 0;
maH_tmp = 0;
if(MENU == 0) menu();// Button at RB4 pressed
batt_cap = (EEPROM_Read(4) << 8) | (EEPROM_Read(3));
total_aH = (EEPROM_Read(2) << 8) | (EEPROM_Read(1));
// If stored capacity>set capacty,reset to set capacity
if (total_aH>batt_cap) total_aH = batt_cap;
if(MINUS == 0) total_aH = batt_cap;// Reset ampHour to Battery MAX Capacity
Lcd_Cmd(_LCD_CLEAR);
InitTimer1(); // set up timer 1 for Interrupt every 1 milliseconds
///////////////////////////////
// Initiate main calculations //
///////////////////////////////
Lcd_out(3,1,"0");
Lcd_chr(3,2,'%');
Lcd_out(3,17,"100");
Lcd_chr(3,20,'%');
do
{
{
while(!flag_200ms);
flag_200ms = 0; // reset the 0.2 Second flag
{
DspUpdInt++;
power_calc(); // Run Voltage, Current and Wattage Calculations
{
if (a>=511) // Discharging
{
maH += mAsec;
if (maH>batt_cap) maH = batt_cap;
if (total_aH<mAsec) total_aH = 0;
else total_aH -= mAsec;
if (maH_tmp != maH)
sample++;
mAavg = maH / sample;
maH_tmp = maH;
if (aH !=0) timeSec = (float)((total_aH/mAavg)/5); // time remaining in seconds;
//if (aH !=0) timeSec = (total_aH/mAavg); // time remaining in seconds;
//timeSec = timeSec/5;
}
else if (a<510) // Charging
{
maH += mAsec ;
total_aH += mAsec;
//if (total_aH>batt_cap) total_aH = batt_cap;
if (maH_tmp != maH)
sample++;
mAavg = (float)maH/sample;
maH_tmp = maH;
if (batt_cap>total_aH)
timeSec = (float)(((batt_cap-total_aH)/mAavg)/5); // time remaining in seconds
//timeSec = (((batt_cap-total_aH)/mAavg)/5); // time remaining in seconds
else if (batt_cap<total_aH)
timeSec = (float)(((total_aH-batt_cap)/mAavg)/5); // time remaining in seconds
//timeSec = (((total_aH-batt_cap)/mAavg)/5); // time remaining in seconds
}
}
aH = (int)total_aH;
{
if (timeSec >= 3600) hrs = (timeSec/3600);
else hrs = 0;
if (timeSec >= 60) min = (timeSec-(hrs*3600))/60;
else min = 0;
if (timeSec != 0) sec = timeSec-((hrs*3600)+(min*60));
else sec = 0;
}
//////////////////////
//***LCD Line 2 ***//
/// Ams-Hour Display ///
amphour[0] = look((aH/10000)%10);
amphour[1] = look((aH/1000)%10);
amphour[3] = look((aH/100)%10);
amphour[4] = look((aH/10)%10);
amphour[5] = look((aH/1)%10);
Lcd_Out(2,1,amphour);
/// Charge-Discharge Time Remaining ///
////////////////////////////////////////////////////
//****Problem - Time remaining doest change instantly
//if(DspUpdInt > 4)
{
TimeRemain[0] = look(hrs/10);
TimeRemain[1] = look((hrs/1)%10);
TimeRemain[3] = look(min/10);
TimeRemain[4] = look((min/1)%10);
TimeRemain[6] = look(sec/10);
TimeRemain[7] = look((sec/1)%10);
Lcd_Out(2,11,TimeRemain);
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
batt_percNbar(); //Calculate & Display Battery Percentage/Bar
if(DspUpdInt >= 5) DspUpdInt = 0; // 1 Second passed, Reset
}
}
} while(vadc>500); //loop until Voltage more than 25 Volts on RA0 Pin
save_data(); // save last capacity on Power Off
}