Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Facing a problem when saving Timer1 value to a long variable

Status
Not open for further replies.

ADGAN

Full Member level 5
Full Member level 5
Joined
Oct 9, 2013
Messages
295
Helped
4
Reputation
8
Reaction score
4
Trophy points
18
Visit site
Activity points
1,837
Hello everybody! I want to count TMR1L and TMR1H value with timer1 interrupts to a single variable. So that I can know the total no of pulses. This is how I tried:

Code:
Monthly_consumption = ((count*65535)+(TMR1H<<8 | TMR1L));

But when the timer1 overflow, the total no of pulses are displayed as 0. And also it seems to be that timer1 overflows. What is the mistake I have done? This is my source code.

Code:
#define Lo(param) ((char *)&param)[0]
#define Hi(param) ((char *)&param)[1]

// LCD module connections
sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;
// End LCD module connections


unsigned char txt1[] = "ENERGY CONSUMPTION";
unsigned char txt2[] = "FROM";
unsigned char txt3[] = "TO";
unsigned char txt4[] = "20";
unsigned char txt5[] = "KWh";

unsigned char txt[14],txt6[14];
unsigned char SMS[14];
unsigned int count = 0;                 //No of tmr1 overflow interrupts
unsigned short count_low = 0,count_high = 0;
unsigned long monthly_consumption = 0;  //Total no of pulses that accumulated for a month
double Meter_reading = 0;               //Energy consumption in KWh
const double Meter_Constant = 1000;     //Meter constant, indicates how many pulses required for a KWh


unsigned char *FloattoAscii (float x, unsigned char *str,char precision)
{
 /* converts a floating point number to an ascii string */
 /* x is stored into str, which should be at least 30 chars long */
 unsigned char *adpt;
 int ie, i, k, ndig;
 double y;
 adpt=str;
 ndig = ( precision<=0) ? 7 : (precision > 22 ? 23 : precision+1);
 ie = 0;
 /* if x negative, write minus and reverse */
 if ( x < 0)
 {
   *str++ = '-';
   x = -x;
 }
 /* put x in range 1 <= x < 10 */
 if (x > 0.0) while (x < 1.0)
 {
   x *= 10.0;                // the place of = *
   ie--;
 }
 while (x >= 10.0)
 {
   x = x/10.0;   ie++;
 }
 // in f format, number of digits is related to size
 ndig += ie;                                // the place of =+
 //round. x is between 1 and 10 and ndig will be printed to
 // right of decimal point so rounding is ...
 for (y = i = 1; i < ndig; i++)
 y = y/10.;
 x += y/2.;
 if (x >= 10.0) {x = 1.0; ie++;}
 if (ie<0)
 {
   *str++ = '0'; *str++ = '.';
   if (ndig < 0) ie = ie-ndig;
   for (i = -1; i > ie; i--)  *str++ = '0';
 }

 for (i=0; i < ndig; i++)
 {
   k = x;
   *str++ = k + '0';
   if (i ==  ie ) *str++ = '.';
   x -= (y=k);
   x *= 10.0;
  }

 *str = '\0';
return (adpt);
}


/**************************************************************************************************
* Interrupt service routine
**************************************************************************************************/
void interrupt(){
if (PIR1.TMR1IF == 1)
{
count++;            //increment the count variable
PIR1.TMR1IF = 0;    //Clear the TMR1 interrupt flag
T1CON.TMR1ON = 0;
TMR1L = 0;
TMR1H = 0;
T1CON.TMR1ON = 1;

}
}

/**************************************************************************************************
* Main function
**************************************************************************************************/
void main()
{
     ANSEL = 0;      //All ports are digital
     ANSELH = 0;     //
     TRISA = 0;      //PortA configured as output
     PORTA = 0;      //Reset port A
     PORTA.RA0 = 1;  //Switch ON the Power indicator LED
     C1ON_bit = 0;   // Disable comparators
     C2ON_bit = 0;
     TRISB = 0;      //PortB confgured as output
     PORTB = 0;      //Reset PORTB
     PORTC = 0;      //Reset PORTC
     TRISC = 0x99;
     INTCON = 0xC0;  //Enable global and peripheral interrupts

     PIE1.TMR1IE = 1;  //Enable TMR1 interrupt
     PIR1.TMR1IF = 0;  //Clear the TMR1 interrupt flag

     TMR1L = 0;      //Reset TMR1L
     TMR1H = 0;      //Reset TMR1H
     count = 0;     //Reset
     T1CON = 0x07;  //Configure timer1 as an asynchronous counter

     Lcd_Init();               //Initialize the LCD
     Delay_ms(100);            // Delay 100ms
     Lcd_Cmd(_LCD_CURSOR_OFF); //Cursor off
     Lcd_Cmd(_LCD_CLEAR);      //Clear the LCD
     I2C1_Init(100000);       //Initialize I2C to 100KHz

     LCD_Out(1,2,txt1);
     LCD_Out(2,1,txt2);
     LCD_Out(3,1,txt3);
     LCD_Out(2,14,txt4);
     LCD_Out(3,14,txt4);
     LCD_Out(4,14,txt5);

     UART1_Init(9600);   //Initialize UART to 9600bps
     Delay_ms (100);     //Delay 100ms

      T1CON.TMR1ON = 0;           //Switch OFF TMR1
      TMR1L = EEPROM_Read(0x00);  //Write previous value to TMR1L
      TMR1H = EEPROM_Read(0x01);  //Write previous value to TMR1H
      T1CON.TMR1ON = 1;           //Switch ON TMR1
      Lo(count) = EEPROM_Read(0x02);  //Write previous value to count
      Hi(count) = EEPROM_Read(0x03);

      Delay_ms(20);

      while(1){

      Monthly_consumption = ((count*65535)+(TMR1H<<8 | TMR1L));  //Load TMR1 value and interrupt values to one variable

      //Clear the energy consumptinon at the beginning of a new month
      if((day == 1) && (hours == 0) && (minutes == 0) && (seconds == 4))
      {
       T1CON.TMR1ON = 0;        //Switch OFF TMR1
       TMR1L = 0;               //Reset TMR1L register
       TMR1H = 0;               //Reset TMR1H register
       T1CON.TMR1ON = 1;        //Switch ON TMR1
       Count = 0;               //Reset count variable
       Monthly_consumption = 0; //Reset monthly consumption variable
      }

      Meter_reading = Monthly_consumption/Meter_Constant; //Calculate KWh
      FloattoAscii(Meter_reading,txt6,3);
      Lcd_Out(4,7,txt6);

      EEPROM_Write(0x00,TMR1L);     //Write TMR1L value to EEPROM
      EEPROM_Write(0x01,TMR1H);     //Write TMR1H value to EEPROM
      EEPROM_Write(0x02,Lo(count));  //Write count value to EEPROM
      EEPROM_Write(0x03,Hi(count));  //

      Delay_ms(20);

      }


   }
 

The code doesn't work according to C language rules for automatic type conversion. TMR1H<<8 is still a byte value and count*65535 an unsigned int value. The input values have to be converted to the result data type to force a calculation without overflow. More elegantly, Monthly_consumption can be defined as a struct.

The calculation of Monthly_consumption must be expected to give sporadically wrong results when a carry to TMR1H or count takes place between access to the individual variables. To assure consistency, timer interrupts must be disabled and pending timer interrupts checked during the calculation.
 
  • Like
Reactions: ADGAN

    ADGAN

    Points: 2
    Helpful Answer Positive Rating
Thanks for the reply. Can you help me to do it in the code?
 

Something like this
Code:
union
{
  unsigned long total;
  struct
  {
    byte tl, th;
    unsigned count;
  } part;
} consumption;

//Load TMR1 value and interrupt values to one variable
PIE1.TMR1IE = 0;
// See Mid-Range MCU Family Reference Manual,
// Example 12-2: Reading a 16-bit Free-Running Timer
consumption.part.th = TMR1H;
consumption.part.tl = TMR1L;
if (consumption.part.th != TMR1H)
{
  consumption.part.th = TMR1H;
  consumption.part.tl = TMR1L;
}
consumption.part.count = count;
// check if timer overflow occurred without being reflected in count  
if (PIR1.TMR1IF && consumption.part.th == 0)
  consumption.part.count++;
PIE1.TMR1IE = 1;
 

Sir can you pls explain this. I haven't use union and struct keywords before. I can't understand this.
 

hello,


i suppose count is an unsigned int !

Code:
union
{
  unsigned long total;
  struct
  {
    byte tl, th;
    unsigned int count;
  } part;
} consumption;

here is a drawing to show struct and union
with union we can define the same adresse for both total and the structure part wich is 4 bytes (32 bits) long
and trough the structure we can associate other variable 8bits + 8bits + 16 bits =32 bits
and can acces of each element of this structure.
so you have many possibilty to manage the datas inside variables.



Structure_Union.jpg

:-DHelp other , is for me ,like exercice to keep my memory..
I take care about my last neurone..
.
 

i suppose count is an unsigned int
According to the C standard, unsigned int and unsigned are synonyms when used as a type specifier.
Although understood by many embedded compilers, byte isn't a generic type specifier, so I should write unsigned char for clarity.
 

Thank you all for the replies. Do I need to declare tl, th, part, consumption? I'm using MikroC PRO and it gives errors. If so what is the data type of those variables.
 

The suggested declarations are legal C and should be understood by mikroC, instead of byte you should write char or unsigned char.

I also presume that mikroC gives meaningful error messages that allow to debug syntax errors.
 

I'm still getting an error message "Invalid expression". Pls can you correct the error.

Code:
void main()
{
     ANSEL = 0;      //All ports are digital
     ANSELH = 0;     //
     TRISA = 0;      //PortA configured as output
     PORTA = 0;      //Reset port A
     PORTA.RA0 = 1;  //Switch ON the Power indicator LED
     C1ON_bit = 0;   // Disable comparators
     C2ON_bit = 0;
     TRISB = 0;      //PortB confgured as output
     PORTB = 0;      //Reset PORTB
     PORTC = 0;      //Reset PORTC
     TRISC = 0x99;
     INTCON = 0xC0;  //Enable global and peripheral interrupts

     PIE1.TMR1IE = 1;  //Enable TMR1 interrupt
     PIR1.TMR1IF = 0;  //Clear the TMR1 interrupt flag

     TMR1L = 0;      //Reset TMR1L
     TMR1H = 0;      //Reset TMR1H
     count = 0;     //Reset
     T1CON = 0x07;  //Configure timer1 as an asynchronous counter

     Lcd_Init();               //Initialize the LCD
     Delay_ms(100);            // Delay 100ms
     Lcd_Cmd(_LCD_CURSOR_OFF); //Cursor off
     Lcd_Cmd(_LCD_CLEAR);      //Clear the LCD
     I2C1_Init(100000);       //Initialize I2C to 100KHz

     LCD_Out(1,2,txt1);
     LCD_Out(2,1,txt2);
     LCD_Out(3,1,txt3);
     LCD_Out(2,14,txt4);
     LCD_Out(3,14,txt4);
     LCD_Out(4,14,txt5);

      T1CON.TMR1ON = 0;           //Switch OFF TMR1
      TMR1L = EEPROM_Read(0x00);  //Write previous value to TMR1L
      TMR1H = EEPROM_Read(0x01);  //Write previous value to TMR1H
      T1CON.TMR1ON = 1;           //Switch ON TMR1
      Lo(count) = EEPROM_Read(0x02);  //Write previous value to count
      Hi(count) = EEPROM_Read(0x03);

      Delay_ms(20);

      while(1){

     
      union {
      unsigned long Monthly_consumption;
      struct
      {
       unsigned char tl, th;
       unsigned int count;
      } part;
      } consumption;

      //Load TMR1 value and interrupt values to one variable
      PIE1.TMR1IE = 0;
      // See Mid-Range MCU Family Reference Manual,
      // Example 12-2: Reading a 16-bit Free-Running Timer
       consumption.part.th = TMR1H;
       consumption.part.tl = TMR1L;
       if (consumption.part.th != TMR1H)
       {
       consumption.part.th = TMR1H;
       consumption.part.tl = TMR1L;
       }
       consumption.part.count = count;
       // check if timer overflow occurred without being reflected in count
       if (PIR1.TMR1IF && consumption.part.th == 0)
       consumption.part.count++;
       PIE1.TMR1IE = 1;

      Monthly_consumption = ((count*65535)+(TMR1H<<8 | TMR1L));  //Load TMR1 value and interrupt values to one variable

      Meter_reading = Monthly_consumption/Meter_Constant; //Calculate KWh
      FloattoAscii(Meter_reading,txt6,3);
      Ltrim(txt6);
      Lcd_Out(4,7,txt6);

      EEPROM_Write(0x00,TMR1L);     //Write TMR1L value to EEPROM
      EEPROM_Write(0x01,TMR1H);     //Write TMR1H value to EEPROM
      EEPROM_Write(0x02,Lo(count));  //Write count value to EEPROM
      EEPROM_Write(0x03,Hi(count));  //

      Delay_ms(20);

      }

   }
 

Problem solved after declaring count variable as a unsigned long.
 

Reporting an error message would tell in which line the error occurs.

The union definition was intended to go with the other global variables. It's legal to define variables at the begin of a new block, e.g. after while(1){, but it brings no advantage.

The assignment to union members should replace the previous assignment to Monthly_consumption. You have both now, and probably also previous variable definitions that aren't shown in the posted code snippet.

The result would be read from consumption.total, or consumption.Monthly_consumption in your union definition.

Final remark. I once learned the C language by studying Kernighan & Ritchie. Much better than pure trial and error method.
 
The compiler is displaying the error in the line which has the union keyword. I don't know how but when I declare the count variable as a long integer, it works.
 

hello,

it's abnormal..
try to put the union definition outside of the main programme,so it means as global variable
is not usual to declare something on the way in the main program.
 

Yes you are correct I totally forgot that, but still I'm getting an error message in the following line

Code:
unsigned char tl,th;
 

Code:
#define Lo(param) ((char *)&param)[0]
#define Hi(param) ((char *)&param)[1]

// LCD module connections
sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;
// End LCD module connections


unsigned char txt1[] = "ENERGY CONSUMPTION";
unsigned char txt2[] = "FROM";
unsigned char txt3[] = "TO";
unsigned char txt4[] = "20";
unsigned char txt5[] = "KWh";

/**************************************************************************************************
* Custom Character functions & definitions
**************************************************************************************************/

const char character1[] = {0,4,2,31,31,2,4,0}; //Display arrow
const char character2[] = {0,0,0,0,0,0,0,0};   //Clear the LCD block

//Function to display the arrow
void CustomChar1(char pos_row, char pos_char) {
  char i;
    Lcd_Cmd(64);
    for (i = 0; i<=7; i++) Lcd_Chr_CP(character1[i]);
    Lcd_Cmd(_LCD_RETURN_HOME);
    Lcd_Chr(pos_row, pos_char, 0);
}

void CustomChar2(char pos_row, char pos_char) {
  char i;
    Lcd_Cmd(64);
    for (i = 0; i<=7; i++) Lcd_Chr_CP(character2[i]);
    Lcd_Cmd(_LCD_RETURN_HOME);
    Lcd_Chr(pos_row, pos_char, 0);
}

unsigned char txt[14],txt6[14];
unsigned char SMS[14];
unsigned long count = 0;                 //No of tmr1 overflow interrupts
unsigned short count_low = 0,count_high = 0;
unsigned long monthly_consumption = 0;  //Total no of pulses that accumulated for a month
double Meter_reading = 0;               //Energy consumption in KWh
const double Meter_Constant = 1000;     //Meter constant, indicates how many pulses required for a KWh

/**************************************************************************************************
* DS1307 Functions
**************************************************************************************************/
// RTC Definitions
#define RTC_ADDR  0xD0

unsigned char seconds, minutes, hours,  day, week, month, year;    // Global date/time variables
unsigned char last_date;                                           //last date of the previous month

/**************************************************************************************************
* Read time from RTC DS1307
* input : pointer to variables where RTC data will be stored
* output: variables with RTC data
**************************************************************************************************/
void Read_Time(unsigned char *hours, unsigned char *minutes, unsigned char *seconds,
               unsigned char *day, unsigned char *week, unsigned char *month, unsigned char *year){
  I2C1_Start();              // Issue start signal
  I2C1_Wr(RTC_ADDR);         // Address DS1307, see DS1307 datasheet
  I2C1_Wr(0);                // Start from address 0
  I2C1_Repeated_Start();     // Issue repeated start signal
  I2C1_Wr(RTC_ADDR + 1);     // Address DS1307 for reading R/W=1

  *seconds = I2C1_Rd(1);     // Read seconds byte
  *minutes = I2C1_Rd(1);     // Read minutes byte
  *hours = I2C1_Rd(1);       // Read hours byte
  *week =I2C1_Rd(1);         // Read week day byte
  *day =I2C1_Rd(1);          // Read day byte
  *month =I2C1_Rd(1);        // Read month byte
  *year =I2C1_Rd(0);         // Read year byte

  I2C1_Stop();               // Issue stop signal
}

/**************************************************************************************************
* Write time to RTC DS1307
* input : variables with RTC data
**************************************************************************************************/
void Write_Time(unsigned char hours, unsigned char minutes, unsigned char seconds,
                unsigned char day, unsigned char week, unsigned char month, unsigned char year){
   I2C1_Start();                   // issue start signal
   I2C1_Wr(RTC_ADDR);              // address DS1307
   I2C1_Wr(0);                     // start from word at address (REG0)
   I2C1_Wr(0x80);                  // write $80 to REG0. (pause counter + 0 sec)

   I2C1_Wr(minutes);               // write 0 to minutes word to (REG1)
   I2C1_Wr(hours);                 // write 17 to hours word (24-hours mode)(REG2)
   I2C1_Wr(week);                  // write 2 - Monday (REG3)
   I2C1_Wr(day);                   // write 4 to date word (REG4)
   I2C1_Wr(month);                 // write 5 (May) to month word (REG5)
   I2C1_Wr(year);                  // write 01 to year word (REG6)
   I2C1_Stop();                    // issue stop signal

   I2C1_Start();                   // issue start signal
   I2C1_Wr(RTC_ADDR);              // address DS1307
   I2C1_Wr(0);                     // start from word at address 0
   I2C1_Wr(0 | seconds);           // write 0 to REG0 (enable counting + 0 sec)
   I2C1_Stop();                    // issue stop signal
}

/**************************************************************************************************
* Show on the LCD display
* input : variables with RTC data
**************************************************************************************************/
void Show_Time(){
  char *txt;

  seconds  =  ((seconds & 0x70) >> 4)*10 + (seconds & 0x0F);   //Converts seconds from BCD to decimal
  minutes  =  ((minutes & 0xF0) >> 4)*10 + (minutes & 0x0F);   //Converts minutes from BCD to decimal
  hours    =  ((hours & 0x30) >> 4)*10 + (hours & 0x0F);       //Converts hours from BCD to decimal
  week     =  (week & 0x07);                                   //Converts week from BCD to decimal
  day      =  ((day & 0xF0) >> 4)*10 + (day & 0x0F);           //Converts day from BCD to decimal
  month    =  ((month & 0x10) >> 4)*10 + (month & 0x0F);       //Converts month from BCD to decimal
  year     =  ((year & 0xF0)>>4)*10+(year & 0x0F);             //Converts year from BCD to decimal

  switch(week)
  {
    case 1: txt="Sun"; break;
    case 2: txt="Mon"; break;
    case 3: txt="Tue"; break;
    case 4: txt="Wed"; break;
    case 5: txt="Thu"; break;
    case 6: txt="Fri"; break;
    case 7: txt="Sat"; break;
  }

  Lcd_Out(3,4,txt);                       //Display the current day
  Lcd_Chr(3, 8, (day / 10)   + 48);       // Print tens digit of day variable
  Lcd_Chr(3, 9, (day % 10)   + 48);       // Print ones digit of day variable
  Lcd_Chr_CP('/');
  Lcd_Chr(3, 11, (month / 10) + 48);      // Print tens digit of month variable
  Lcd_Chr(3,12, (month % 10) + 48);       // Print oness digit of month variable
  Lcd_Chr_CP('/');
  Lcd_Chr(3,16, (year / 10)  + 48);       // Print tenss digit of year variable
  Lcd_Chr(3,17, (year % 10)  + 48);       // Print oness digit of year variable

}

//Function to check the last date of the previous month
void lastdate_check(char day, char month, char year, int last_date)
{
if (month == 1 || month == 2 || month ==4 || month ==6 || month == 8 || month ==9 || month == 11)
{
      last_date = 31;
      Lcd_Chr(2, 8, (last_date / 10)   + 48);
      Lcd_Chr(2, 9, (last_date% 10)   + 48);
      Lcd_Chr_CP('/');
}
else
{
 if(month == 3 )
 {
   if(year%4 == 0)
   {
                last_date = 29;
                Lcd_Chr(2, 8, (last_date / 10)   + 48);
                Lcd_Chr(2, 9, (last_date% 10)   + 48);
                Lcd_Chr_CP('/');
   }
   else
   {
                last_date = 28;
                Lcd_Chr(2, 8, (last_date / 10)   + 48);
                Lcd_Chr(2, 9, (last_date% 10)   + 48);
                Lcd_Chr_CP('/');
   }
 }

last_date = 30;
Lcd_Chr(2, 8, (last_date / 10)   + 48);
Lcd_Chr(2, 9, (last_date% 10)   + 48);
Lcd_Chr_CP('/');
}
}

//Function to check the last month
void lastmonth_check(char day, char month, char year)
{
char last_mn;

if (month>2)
{
last_mn = month - 1;
Lcd_Chr(2, 11, (last_mn / 10)   + 48);
Lcd_Chr(2, 12, (last_mn% 10)   + 48);
Lcd_Chr_CP('/');
}

else
{
last_mn = 12;
Lcd_Chr(2, 11, (last_mn / 10)   + 48);
Lcd_Chr(2, 12, (last_mn% 10)   + 48);
Lcd_Chr_CP('/');
}

}

//Function to check the last year
void lastyear_check(char day,char mmonthn,char year)
{
char last_year;

if (month == 1)
{
 last_year = year-1;
 Lcd_Chr(2, 16, (last_year / 10)   + 48);
 Lcd_Chr(2, 17, (last_year % 10)   + 48);
}
else
{
 Lcd_Chr(2, 16, (year / 10)   + 48);
 Lcd_Chr(2, 17, (year % 10)   + 48);
}
}

unsigned char *FloattoAscii (float x, unsigned char *str,char precision)
{
 /* converts a floating point number to an ascii string */
 /* x is stored into str, which should be at least 30 chars long */
 unsigned char *adpt;
 int ie, i, k, ndig;
 double y;
 adpt=str;
 ndig = ( precision<=0) ? 7 : (precision > 22 ? 23 : precision+1);
 ie = 0;
 /* if x negative, write minus and reverse */
 if ( x < 0)
 {
   *str++ = '-';
   x = -x;
 }
 /* put x in range 1 <= x < 10 */
 if (x > 0.0) while (x < 1.0)
 {
   x *= 10.0;                // the place of = *
   ie--;
 }
 while (x >= 10.0)
 {
   x = x/10.0;   ie++;
 }
 // in f format, number of digits is related to size
 ndig += ie;                                // the place of =+
 //round. x is between 1 and 10 and ndig will be printed to
 // right of decimal point so rounding is ...
 for (y = i = 1; i < ndig; i++)
 y = y/10.;
 x += y/2.;
 if (x >= 10.0) {x = 1.0; ie++;}
 if (ie<0)
 {
   *str++ = '0'; *str++ = '.';
   if (ndig < 0) ie = ie-ndig;
   for (i = -1; i > ie; i--)  *str++ = '0';
 }

 for (i=0; i < ndig; i++)
 {
   k = x;
   *str++ = k + '0';
   if (i ==  ie ) *str++ = '.';
   x -= (y=k);
   x *= 10.0;
  }

 *str = '\0';
return (adpt);
}

/**************************************************************************************************
* GSM modem functions & definitions
**************************************************************************************************/

unsigned char Command_ATE0[] = "ATE0";                    //Disable echo commands
unsigned char Command_CMGF[] = "AT+CMGF=1";               //Enable SMS text writing mode
unsigned char Command_CMGS[] = "AT+CMGS=+94723284003";    //Sending SMS to the service providers number

void sendATC(char *s)
{
   while(*s) {
      UART1_Write(*s++);  //Enter the command string
   }
   UART1_Write('\r');     //Send CR command execution
}

void SMS_Send(double Meter_reading){
PORTA.RA1 = 1;                  //Switch ON the SMS LED
CustomChar1(4,18);              //Display arrow
sendATC (Command_ATE0);         //Send the echo disable command
Delay_ms (1000);                //Delay 1s
CustomChar2(4,18);              //Clear LCD block
CustomChar1(4,19);              //Display arrow
sendATC (Command_CMGF);         //Set as SMS text mode
Delay_ms (1000);                //Delay 1s
CustomChar2(4,19);              //Clear LCD block
CustomChar1(4,18);              //Display arrow
FloattoAscii(Meter_reading,SMS,3);  //Convert meter reading to a string
CustomChar2(4,18);              //Clear LCD block
CustomChar2(4,19);              //Clear LCD block
CustomChar1(4,20);              //Display arrow
sendATC(Command_CMGS);          //Send the service providers phone no
Delay_ms (1000);                //Delay 1s
UART1_Write_Text(SMS);          //send the energy consumption
UART1_Write (0x1A);             //Carriage return to terminate
CustomChar2(4,19);              //Clear LCD block
CustomChar1(4,18);              //Display arrow
Delay_ms (1000);                //Delay 1s
CustomChar2(4,18);              //Clear LCD block
CustomChar2(4,19);              //Clear LCD block
CustomChar2(4,20);              //Clear LCD block
PORTA.RA1 = 0;                  //Switch OFF the SMS LED
}

/**************************************************************************************************
* Interrupt service routine
**************************************************************************************************/
void interrupt(){
if (PIR1.TMR1IF == 1)
{
count++;            //increment the count variable
PIR1.TMR1IF = 0;    //Clear the TMR1 interrupt flag
T1CON.TMR1ON = 0;
TMR1L = 0;
TMR1H = 0;
T1CON.TMR1ON = 1;

}
}

union
{
  unsigned long total;
  struct
  {
    unsigned char tl,th;
    unsigned int count;
  } part;
} consumption;



/**************************************************************************************************
* Main function
**************************************************************************************************/
void main()
{
     ANSEL = 0;      //All ports are digital
     ANSELH = 0;     //
     TRISA = 0;      //PortA configured as output
     PORTA = 0;      //Reset port A
     PORTA.RA0 = 1;  //Switch ON the Power indicator LED
     C1ON_bit = 0;   // Disable comparators
     C2ON_bit = 0;
     TRISB = 0;      //PortB confgured as output
     PORTB = 0;      //Reset PORTB
     PORTC = 0;      //Reset PORTC
     TRISC = 0x99;
     INTCON = 0xC0;  //Enable global and peripheral interrupts

     PIE1.TMR1IE = 1;  //Enable TMR1 interrupt
     PIR1.TMR1IF = 0;  //Clear the TMR1 interrupt flag

     TMR1L = 0;      //Reset TMR1L
     TMR1H = 0;      //Reset TMR1H
     count = 0;     //Reset
     T1CON = 0x07;  //Configure timer1 as an asynchronous counter

     Lcd_Init();               //Initialize the LCD
     Delay_ms(100);            // Delay 100ms
     Lcd_Cmd(_LCD_CURSOR_OFF); //Cursor off
     Lcd_Cmd(_LCD_CLEAR);      //Clear the LCD
     I2C1_Init(100000);       //Initialize I2C to 100KHz

     LCD_Out(1,2,txt1);
     LCD_Out(2,1,txt2);
     LCD_Out(3,1,txt3);
     LCD_Out(2,14,txt4);
     LCD_Out(3,14,txt4);
     LCD_Out(4,14,txt5);

     UART1_Init(9600);   //Initialize UART to 9600bps
     Delay_ms (100);     //Delay 100ms

      //Function to set time if necessary
      //hour/minutes/seconds/date/week day/month/year
      Write_Time(0x00, 0x00, 0x00, 0x24, 0x06, 0x01, 0x14);

      T1CON.TMR1ON = 0;           //Switch OFF TMR1
      TMR1L = EEPROM_Read(0x00);  //Write previous value to TMR1L
      TMR1H = EEPROM_Read(0x01);  //Write previous value to TMR1H
      T1CON.TMR1ON = 1;           //Switch ON TMR1
      Lo(count) = EEPROM_Read(0x02);  //Write previous value to count
      Hi(count) = EEPROM_Read(0x03);

      Delay_ms(20);

      while(1){

      Read_Time(&hours, &minutes, &seconds, &day, &week, &month, &year); // Read time from RTC(DS1307)
      Show_Time();  //Display time on the LCD
      lastdate_check(day, month, year, last_date);   //Display last billing date on the LCD
      lastmonth_check(day,month, year);              //Display last month on the LCD
      lastyear_check(day, month, year);              //Display last year on the LCD

      Monthly_consumption = ((count*65535)+(TMR1H<<8 | TMR1L));  //Load TMR1 value and interrupt values to one variable

      //Send energy consumption before clearing it
      if((day == 1) && (hours == 0) && (minutes == 0) && (seconds == 0))
      {
      SMS_Send(Meter_reading);      //Send the energy consumption to the service provider
      }

      //Clear the energy consumptinon at the beginning of a new month
      if((day == 1) && (hours == 0) && (minutes == 0) && (seconds == 4))
      {
       T1CON.TMR1ON = 0;        //Switch OFF TMR1
       TMR1L = 0;               //Reset TMR1L register
       TMR1H = 0;               //Reset TMR1H register
       T1CON.TMR1ON = 1;        //Switch ON TMR1
       Count = 0;               //Reset count variable
       Monthly_consumption = 0; //Reset monthly consumption variable
      }

      Meter_reading = Monthly_consumption/Meter_Constant; //Calculate KWh
      FloattoAscii(Meter_reading,txt6,3);
      Ltrim(txt6);
      Lcd_Out(4,5,txt6);

      EEPROM_Write(0x00,TMR1L);     //Write TMR1L value to EEPROM
      EEPROM_Write(0x01,TMR1H);     //Write TMR1H value to EEPROM
      EEPROM_Write(0x02,Lo(count));  //Write count value to EEPROM
      EEPROM_Write(0x03,Hi(count));  //

      Delay_ms(20);

      if (minutes%2 != 0 &&  seconds == 30){
      SMS_Send(Meter_reading);
      }

      }


   }
 

hello,

Why you don't use the defined union & structure ?

Code:
[I]union
{
  unsigned long total;
  struct
  {
    unsigned char tl,th;
    unsigned int count;
  } part;
} consumption;[/I]

replace variable count by another name , to avoid mixing and confusion..

Code:
// unsigned long count = 0;                 //No of tmr1 overflow interrupts
[B]volatile unsigned int Count_Over_T1;[/B]
and change it also inside interup

Code:
void interrupt(){
if (PIR1.TMR1IF == 1)
{
[B]Count_Over_T1++; [/B]           //increment the count variable
PIR1.TMR1IF = 0;    //Clear the TMR1 interrupt flag
T1CON.TMR1ON = 0;
TMR1L = 0;
TMR1H = 0;
T1CON.TMR1ON = 1;
}
}

and in the main

Code:
void main()
{

     ANSEL = 0;      //All ports are digital
    .....
     ....
     PIE1.TMR1IE = 1;  //Enable TMR1 interrupt
     PIR1.TMR1IF = 0;  //Clear the TMR1 interrupt flag

     TMR1L = 0;      //Reset TMR1L
     TMR1H = 0;      //Reset TMR1H
   //  count = 0;     //Reset
  [B]   Count_Over_T1=0;[/B]


//   Monthly_consumption = ((count*65535)+(TMR1H<<8 | TMR1L));  //Load TMR1 value and interrupt values to one variable
// so use the union and struct like this, and no need to do shift value or multiplication by 6553[B]6[/B]
 [B]  consumption.part.tl=TMR1L;
   consumption.part.th=TMR1H;
   consumption.part.count=  Count_Over_T1;[/B]

      //Send energy consumption before clearing it
      if((day == 1) && (hours == 0) && (minutes == 0) && (seconds == 0))
      {
      SMS_Send(Meter_reading);      //Send the energy consumption to the service provider
      }

      //Clear the energy consumptinon at the beginning of a new month
      if((day == 1) && (hours == 0) && (minutes == 0) && (seconds == 4))
      {
       T1CON.TMR1ON = 0;        //Switch OFF TMR1
       TMR1L = 0;               //Reset TMR1L register
       TMR1H = 0;               //Reset TMR1H register
       T1CON.TMR1ON = 1;        //Switch ON TMR1
       //Count = 0;               //Reset count variable
  [B]     Count_Over_T1=0;[/B]
       Monthly_consumption = 0; //Reset monthly consumption variable
      }

      Meter_reading = Monthly_consumption / Meter_Constant;    //Calculate KWh
      FloattoAscii(Meter_reading,txt6,3);
      Ltrim(txt6);
      Lcd_Out(4,5,txt6);

  ..etc ....
 
  • Like
Reactions: ADGAN

    ADGAN

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top