Multiplexing 7Segs and using timer Countdown

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
This what I wrote so far

Rich (BB code):
  Indicators are CC 7 Segments Muxed(PortD).
      3 Digits for 0.00 to 8.40 Volts
      3 Digits for 0.00 to 5.00 Amps
      3 Digits for 2.00 Hour Timer
      
  LED's are connected as CC and Muxed with the 7 segments and controlled by RE1
  (anodes are connected as indicated below)
   There are total of 5 Led indicators
      1. Charging / Charge completed (blinks when Charging) - RD0
      2. Constant Voltage mode - RD1
      3. Constant Current mode - RD2
      4. Battery inserted indicator - RD3
      5. Battery Over heat indicator - RD4
      
==============================================================================
 *Pin Connections:
      RE3 is the MCLR

 *PortA Connections
     RA0 - Voltage ADC input
     RA1 - Current ADC input
     RA2 - Battery temperature ADC input
     RA3 - Heat Sink temperature ADC input
     RA4 - Buzzer
     RA5 - Not used
     RA6 - HS
     RA7 - HS

 *PortB Connections
     RB0 - Charger Relay
     RB1 - Battery Voltage Checker Relay
     RB2 - 4.2V or 8.4V Selector Relay
     RB3 - Charge Start/Halt/Stop Switch
     RB4 - Battery Insert Switch
     RB5 - Selector Sw, Voltage & Charge Termination Current & Timer (works with encoder)
     RB6 - RotaryEncoder input A
     RB7 - RotaryEncoder input B

     
 *PortC + RE1 & RE2 are the digit/LED drivers:
     RC0 - Digit 1(Timer Hr digit)
     RC1 - Digit 2(Timer Min digit)
     RC2 - Digit 3(Timer Min digit)
     RC3 - Digit 4(Voltmeter digit)
     RC4 - Digit 5(Voltmeter digit)
     RC5 - Digit 6(Voltmeter digit)
     RC6 - Digit 7(Ammeter digit)
     RC7 - Digit 8(Ammeter digit)
     RE2 - Digit 9(Ammeter digit)
     RE1 - LED Drive
   
 *PortE
     RE0 - Fan Diver(heatsink)

 *PortD are the segment drives:
     RD0 - Segment A
     RD1 - Segment B
     RD2 - Segment C
     RD3 - Segment D
     RD4 - Segment E
     RD5 - Segment F
     RD6 - Segment G
     RD7 - Decimal point
     
     
==============================================================================
Configuration bits set ny compiler :
CONFIG1  0x2FF2
CONFIG2  0x0600
=============================================================================*/

// Control bit assignement
sbit Bzr at RA7_bit;          //Buzzer at RA7
sbit ChargerRelay at RB0_bit; //Charge ON Relay at RB0
sbit VtestRelay at RB1_bit;   //Battery Voltage test Relay at RB1
sbit VselectRelay at RB2_bit; //Charge Voltage selector Relay at RB2
sbit StartSw at RB3_bit;      //Start/Halt/Terminate (Charge) Sw at RB3
sbit BatIn at RB4_bit;        //Battery inserted Sw at RB4
sbit EncdSw at RB5_bit;       //Encoder Sw at RB5
sbit EncdA at RB6_bit;        //Encoder input A at RB6
sbit EncdB at RB7_bit;        //Encoder input B at RB7
sbit Fan at RE0_bit;          //Fan Control out at RE0

/*********** Defines ******************************/
//Segments on Ports
#define SegA (0x01)           //Segment A on Port0
#define SegB (0x02)           //Segment B on Port1
#define SegC (0x04)           //Segment C on Port2
#define SegD (0x08)           //Segment D on Port3
#define SegE (0x10)           //Segment E on Port4
#define SegF (0x20)           //Segment F on Port5
#define SegG (0x40)           //Segment G on Port6
#define SegDP (0x80)          //Segment dp on Port7
//Digits Make up
#define Digit0 (SegA + SegB + SegC + SegD + SegE + SegF)
#define Digit1 (SegA + SegB)
#define Digit2 (SegA + SegB + SegD + SegE + SegG)
#define Digit3 (SegA + SegB + SegC + SegD + SegG)
#define Digit4 (SegB + SegC + SegF + SegG)
#define Digit5 (SegA + SegC + SegD + SegF + SegG)
#define Digit6 (SegA + SegC + SegD + SegE + SegF + SegG)
#define Digit7 (SegA + SegB + SegC)
#define Digit8 (SegA + SegB + SegC + SegD + SegE + SegF + SegG)
#define Digit9 (SegA + SegB + SegC + SegD + SegF + SegG)
#define DP
//Segment Look-up table
const unsigned char SegTable[] = {Digit0,Digit1,Digit2,Digit3,Digit4,Digit5,\
                                  Digit6,Digit7,Digit8,Digit9,DP};
//Segment Buffer - Mux will fetch these Segments patterns in Seq.
#define N_DIGITS 10
unsigned char DigitsBuf[N_DIGITS];// 10 Digits including LED's
//Display Map - 3 Groups of Digits into Buffer
#define dTime 0              //Digits 0-2 are time
#define dVolts 3             //Digits 3-5 are Volts
#define dAmps 6              //Digits 6-8 are Current
#define dLeds 9              //LED's are offset 9, i.e 10th Digit

//Variables
unsigned int Volts,Amps,Time;

/*********** Timer Init ***************************/
/* 2 Timers are used
   TMR0 is used to Muxing the 7 Segments and Leds, set at 5ms
   TMR0 set is 256-(5ms/0.5usTcyc)/64Prescale = 256-156.25 counts = 99.75; almost 100
   TMR1 is ued to generate System Tick */

void Timers(){
  INTCON = 0;                  //No Interrupts
//Timer0 Interrupt Time is like 4.992 ms (close to 5ms - so good enuf)
  OPTION_REG = 0x85;          //Option Reg; Pull ups disable, Prescale to Timer0 & 1:64
//Timer1 Interrupt Time is 10 ms
  T1CON = 0x01;               //Timer1 control; 1:1 prescale & Enable timer
  TMR1H = 0xB1;               //Load the Timer1 MSB &
  TMR1L = 0xE0;               //load the Timer1 LSB
  TMR0 = 100;               //Load Timer0
  TMR1IF_bit = 0;             //PIR1 Reg; Clear the Timer1 overflow Interrupt flag bit
  CCP1IF_bit = 0;             //Clear Timer1 Interrupt flag
//Then Enable Interrupts
  TMR1IF_bit = 1;
  CCP1IF_bit = 1;
  T1CON.TMR1ON = 1;           //Start timer
  INTCON.PEIE = 1;            //Enable Peripheral Interrupts
  INTCON.GIE = 1;             //Enable Global Interrupts
}
/*********** Interrupt Service Routine ***************/
void Interrupt(){
//Used for Display Muxing.
  if (TMR0IF_bit){
    TMR0IF_bit = 0;           //Ack IRQ
    TMR0 = 100;               //Reset Timer0
    //Code goes here
    
    
  }
                              //System Tik = 10ms
  if (CCP1IF_bit){            // Interrupt on Timer1 = CCP
    CCP1IF_bit = 0;           //Ack IRQ
    TMR1H = 0xB1;             //Load the Timer1 MSB &
    TMR1L = 0xE0;             //load the Timer1 LSB
    //Code goes here
    
    
  }
}
//Conversion routine
void Int2Segs(unsigned int i, short ofs){
    short x;
    x = i/100;
    DigitsBuf[ofs] = SegTable[x];

    x = (i%100)/10;
    DigitsBuf[ofs+1] = SegTable[x];

    x = (i%10);
    DigitsBuf[ofs+2] = SegTable[x];
}
/*********** Main Routine ****************************/
void main() {
    PORTA = 0;                // Clear PortA
    ANSEL = 0x0F;             // RA0 to RA3 as Analog Inputs
    ANSELH = 0x00;            // Rest are Digital I/O's
    CM1CON0.C1ON = 0;         // Disable Comparator 1
    CM2CON0.C2ON = 0;         // Disable Comparator 2
    TRISA = 0x7F;             // All Inputs except RA7 as Output
    PORTB = 0;                // Clear PORTS
    TRISB = 0xF8;             // RB <7:3> Inputs & RB <2:0> Ouputs
    PORTC = 0;                // Clear PORTS
    TRISC = 0x00;             // PORTC are Ouputs
    PORTD = 0;                // Clear PORTS
    TRISD = 0x00;             // PORTD are Ouputs
    PORTE = 0;                // Clear PORTS
    TRISE = 0x00;             // PORTE are Ouputs (MCLR is an input)
    
    Timers();                 //Initiate Timers

    Time = 123;
    Volts = 456;
    Amps = 789;
    while(1){
    Int2Segs(Time,dTime);
    Int2Segs(Volts,dVolts);
 }  Int2Segs(Amps,dAmps);
}
It compiles and programs but as you know there is no output yet.
Needs to make sure if I got this right.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Just got done w/juries and off to a performance final so quick again.
You got most of the timer stuff but review the code I posted back in #19 here.

Here are some things to look at apologies if I missed that you already did it.
CCP1CON isn't set up to let timer 1 count up to the value in CCPR1, reset the timer and interrupt.

In the interrupt routine, you don't need or want to reload timer 1, the CCP does it for you.

I'd discourage the use of literals i.e. TMR0=100 as it does not convey much information as to how you got the number. Same for the other init values - I'd have to check the databook to see what was being done and.. too busy for that. It may seem silly now since the code is small (and I get criticized for being pedantic. ) But as the code grows, you'll appreciate the value of being verbose and posters here and peers reviewing your stuff will be able to provide much greater insight and good critiques.

Remove #define DP, its not defined as a something.

If you haven't done so, fire up MicroC's debugger and step the code, watching things work. If you haven't used it yet, now's the time.

Off to play!
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Something is wrong.

TMR1 =0; cannot be added..gives --- Undeclared identifier 'TMR1' in expression Li-On Charger Controller.c

TMR1 is 16bit so it has H and L

And the OPTION_REG binary value is wrong for 16F887.

Take a look at the data sheet.

I am confused why we are using the CCP module..i.e

Rich (BB code):
#define T1CONinit 0b0011000    // no gate, internal Tcyc/8, timer STOPPED 
#define CCP1CONinit 0b00001011    // compare CCPR1 to TIMER1, IRQ and reset TMR1 on match 
#define CCPR1init 1250        // .5usTcyc *8Prescale * 1250 = 5msec
 

THE_RB

Joined Feb 11, 2008
5,438
The CCP module is one way of getting a timer interrupt in actual mS.

I prefer two other ways;
1. using TMR2 and PR2 to make a 1mS interrupt, or;
2. using TMR0 and zero-error bresenham code

Number 1 gives you exactly 1mS per interrupt with no jitter, number 2 has other advantages and will give exactly 1mS or 10mS per event (perfect average) but may have some jitter in each event.

If you want to use number 1, you have 8MHz xtal HS osc so your PIC timers run at 2MHz. So to make a 1mS interrupt using TMR2 needs 2000 timer ticks. You set PR2 to make an interrupt every 125 TMR2 ticks; PR2 = (125-1);
Then set TMR2 to 16:1 prescaler (because 2000 / 16 = 125).

After that your TMR2 will automatically overflow (and interrupt) every 1mS. And it still leaves both CCP modules and their timers free for other tasks.
 

JohnInTX

Joined Jun 26, 2012
4,787
Roman (The RB) is right about TMR2 but I was thinking of saving it for a possible PWM. If you don't need a PWM, TMR2 is the way to go. And his TMR0 implementation is very cool if you need exact periods. For a display mux, it doesn't have to be real accurate.

I'm wrestling with the MicroC debugger right now.. will post some code revs later. There are some config problems in the OP's last one. For now, go to the Output Window and turn case sensitivity ON... I didn't know that it was off by default but that gives me the heebie-jeebies..

TMR1 can't be loaded as a 16 bit register in MicroC - I didn't know that either.. But we will be just clearing it. This implementation counts from 0000h to whatever is in CCPR1 then auto-resets to 0000 and does it again.

Passed juries and we slayed em' at the performance, thanks for asking. Just for a grade for now but next time you see a good musician, give some props... or throw a few coins into the case. It ain't easy.
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Roman (The RB) is right about TMR2 but I was thinking of saving it for a possible PWM. If you don't need a PWM, TMR2 is the way to go. And his TMR0 implementation is very cool if you need exact periods. For a display mux, it doesn't have to be real accurate.
No PWM for this baby.

There are some config problems in the OP's last one. For now, go to the Output Window and turn case sensitivity ON... I didn't know that it was off by default but that gives me the heebie-jeebies..
Config issues. Config is set at project start. Me did not do any Config settings. Blame it on MikroC :D

heebie-jeebies.. ???? :confused:

TMR1 can't be loaded as a 16 bit register in MicroC - I didn't know that either.. But we will be just clearing it. This implementation counts from 0000h to whatever is in CCPR1 then auto-resets to 0000 and does it again.

Since it cannot be loaded, will what I wrote work.

Passed juries and we slayed em' at the performance, thanks for asking. Just for a grade for now but next time you see a good musician, give some props... or throw a few coins into the case. It ain't easy.
Congrats..Break a leg .
If you can't break a leg, break an instrument ;)
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Did the changes
To config as TRIS A was wrong and made the CCP part .
Changes the literals to defines and am debugging now to check.

Code is below if any one wanna see the changes
Rich (BB code):
/*  Indicators are CC 7 Segments Muxed(PortD).
      3 Digits for 0.00 to 8.40 Volts
      3 Digits for 0.00 to 5.00 Amps
      3 Digits for 2.00 Hour Timer
      
  LED's are connected as CC and Muxed with the 7 segments and controlled by RE1
  (anodes are connected as indicated below)
   There are total of 5 Led indicators
      1. Charging / Charge completed (blinks when Charging) - RD0
      2. Constant Voltage mode - RD1
      3. Constant Current mode - RD2
      4. Battery inserted indicator - RD3
      5. Battery Over heat indicator - RD4 
      
==============================================================================
 *Pin Connections:
      RE3 is the MCLR

   *PortA Connections
     RA0 - Voltage ADC input
     RA1 - Current ADC input
     RA2 - Battery temperature ADC input
     RA3 - Heat Sink temperature ADC input
     RA4 - Buzzer
     RA5 - Not used
     RA6 - HS Osc
     RA7 - HS Osc

   *PortB Connections
     RB0 - Charger Relay
     RB1 - Battery Voltage Checker Relay
     RB2 - 4.2V or 8.4V Selector Relay
     RB3 - Charge Start/Halt/Stop Switch
     RB4 - Battery Insert Switch
     RB5 - Selector Sw, Voltage & Charge Termination Current & Timer (works with encoder)
     RB6 - RotaryEncoder input A
     RB7 - RotaryEncoder input B

       
 *PortC + RE1 & RE2 are the digit/LED drivers:
     RC0 - Digit 1(Timer Hr digit)
     RC1 - Digit 2(Timer Min digit)
     RC2 - Digit 3(Timer Min digit)
     RC3 - Digit 4(Voltmeter digit)
     RC4 - Digit 5(Voltmeter digit)
     RC5 - Digit 6(Voltmeter digit)
     RC6 - Digit 7(Ammeter digit)
     RC7 - Digit 8(Ammeter digit)
     RE2 - Digit 9(Ammeter digit)
     RE1 - LED Drive
   
 *PortE
     RE0 - Fan Diver(heatsink)

   *PortD are the segment drives:
     RD0 - Segment A
     RD1 - Segment B
     RD2 - Segment C
     RD3 - Segment D
     RD4 - Segment E
     RD5 - Segment F
     RD6 - Segment G
     RD7 - Decimal point
     
     
=============================================================================
Configuration bits set by compiler :
CONFIG1  0x2FF2
CONFIG2  0x0600
=============================================================================*/
*/
// Control bit assignement
sbit Bzr at RA5_bit;          //Buzzer at RA7
sbit ChargerRelay at RB0_bit; //Charge ON Relay at RB0
sbit VtestRelay at RB1_bit;   //Battery Voltage test Relay at RB1
sbit VselectRelay at RB2_bit; //Charge Voltage selector Relay at RB2
sbit StartSw at RB3_bit;      //Start/Halt/Terminate (Charge) Sw at RB3
sbit BatIn at RB4_bit;        //Battery inserted Sw at RB4
sbit EncdSw at RB5_bit;       //Encoder Sw at RB5
sbit EncdA at RB6_bit;        //Encoder input A at RB6
sbit EncdB at RB7_bit;        //Encoder input B at RB7
sbit Fan at RE0_bit;          //Fan Control out at RE0

/*********** Defines ******************************/
//Segments on Ports
#define SegA (0x01)           //Segment A on Port0
#define SegB (0x02)           //Segment B on Port1
#define SegC (0x04)           //Segment C on Port2
#define SegD (0x08)           //Segment D on Port3
#define SegE (0x10)           //Segment E on Port4
#define SegF (0x20)           //Segment F on Port5
#define SegG (0x40)           //Segment G on Port6
#define SegDP (0x80)          //Segment dp on Port7
//Digits Make up
#define Digit0 (SegA + SegB + SegC + SegD + SegE + SegF)
#define Digit1 (SegA + SegB)
#define Digit2 (SegA + SegB + SegD + SegE + SegG)
#define Digit3 (SegA + SegB + SegC + SegD + SegG)
#define Digit4 (SegB + SegC + SegF + SegG)
#define Digit5 (SegA + SegC + SegD + SegF + SegG)
#define Digit6 (SegA + SegC + SegD + SegE + SegF + SegG)
#define Digit7 (SegA + SegB + SegC)
#define Digit8 (SegA + SegB + SegC + SegD + SegE + SegF + SegG)
#define Digit9 (SegA + SegB + SegC + SegD + SegF + SegG)

//Segment Look-up table
const unsigned char SegTable[] = {Digit0,Digit1,Digit2,Digit3,Digit4,Digit5,\
                                  Digit6,Digit7,Digit8,Digit9};
//Segment Buffer - Mux will fetch these Segments patterns in Seq.
#define N_DIGITS 10
unsigned char DigitsBuf[N_DIGITS];// 10 Digits including LED's
//Display Map - 3 Groups of Digits into Buffer
#define dTime 0               //Digits 0-2 are time
#define dVolts 3              //Digits 3-5 are Volts
#define dAmps 6               //Digits 6-8 are Current
#define dLeds 9               //LED's are offset 9, i.e 10th Digit
//Timer 0 set to Interrupt about 5ms
//Setting is2 56- (5ms / .5usTcyc) / 64Prescaler = 256 - 156.25 counts = 99.75 ~= 100
#define TMR0set 100           // counts 100->255 then rolls over and interrupts
#define OPTION_RegInit 0x85   //'b10000101' Option Reg; Pull ups disable, Prescale to Timer0 & 1:64
// Timer 1 setup - counts from 0000h to value in CCPR1, resets timer automatically and interrupts
#define T1CONInit 0x18        //'b0011000' no gate, internal Tcyc/8, timer STOPPED
#define CCP1CONInit 0x0B      //'b00001011' compare CCPR1 to TIMER1, IRQ and reset TMR1 on match
#define CCPR1Init 1250        // .5usTcyc *8Prescale * 1250 = 5msec
//Variables
unsigned int Volts,Amps,Time;

/*********** Timer Init ***************************/
/* 2 Timers are used
   TMR0 is used to Muxing the 7 Segments and Leds, set at 5ms
   TMR0 set is 256-(5ms/0.5usTcyc)/64Prescale = 256-156.25 counts = 99.75; almost 100
   TMR1 is ued to generate System Tick */
//Sound
void BuzzerStart() {          // Output On Bzr routine
  Sound_Init(&PORTA, 5);      // Set Buzzer port
  Sound_Play(1000, 100);      //Startup buzzer
  Sound_Play(800, 50);
  Sound_Play(1000, 100);
 }
void Buzzer(){
  Sound_Init(&PORTA, 5);      // Set Buzzer port
  Sound_Play(800,25);
}
void Timers(){
  INTCON = 0;                 //No Interrupts
//Timer0 Interrupt Time is like 4.992 ms (close to 5ms - so good enuf)
  OPTION_REG = OPTION_RegInit;
//Timer1 Interrupt Time is 10 ms
  T1CON = T1CONInit;          //Init T1CON
  CCP1CON = CCP1CONInit;
  CCPR1 = CCPR1Init;
  TMR1H = 0x00;               //Clear TMR1 MSB
  TMR1L = 0x00;               //Clear TMR1 LSB
  TMR0 += TMR0set;            //Load Timer0
  TMR1IF_bit = 0;             //PIR1 Reg; Clear the Timer1 overflow Interrupt flag bit
  CCP1IF_bit = 0;             //Clear Timer1 Interrupt flag
//Then Enable Interrupts
  TMR1IF_bit = 1;
  CCP1IF_bit = 1;
  T1CON.TMR1ON = 1;           //Start timer
  INTCON.PEIE = 1;            //Enable Peripheral Interrupts
  INTCON.GIE = 1;             //Enable Global Interrupts
}
/*********** Interrupt Service Routine ***************/
void Interrupt(){
//Used for Display Muxing.
  if (TMR0IF_bit){
    TMR0IF_bit = 0;           //Ack IRQ
    TMR0 = 100;               //Reset Timer0
    //Code goes here
    
    
  }
                              //System Tik = 10ms
  if (CCP1IF_bit){            // Interrupt on Timer1 = CCP
    CCP1IF_bit = 0;           //Ack IRQ
    TMR1H = 0xB1;             //Load the Timer1 MSB &
    TMR1L = 0xE0;             //load the Timer1 LSB
    //Code goes here
    
    
  }
}
//Conversion routine
void Int2Segs(unsigned int i, short ofs){
    short x;
    x = i/100;
    DigitsBuf[ofs] = SegTable[x];

    x = (i%100)/10;
    DigitsBuf[ofs+1] = SegTable[x];

    x = (i%10);
    DigitsBuf[ofs+2] = SegTable[x];
}

/*********** Main Routine ****************************/
void main() {
    PORTA = 0;                // Clear PortA
    ANSEL = 0x0F;             // RA0 to RA3 as Analog Inputs
    ANSELH = 0x00;            // Rest are Digital I/O's
    CM1CON0.C1ON = 0;         // Disable Comparator 1
    CM2CON0.C2ON = 0;         // Disable Comparator 2
    TRISA = 0x0F;             // RA <0:3> Inputs rest outputs
    PORTB = 0;                // Clear PORTS
    TRISB = 0xF8;             // RB <7:3> Inputs & RB <2:0> Ouputs
    PORTC = 0;                // Clear PORTS
    TRISC = 0x00;             // PORTC are Ouputs
    PORTD = 0;                // Clear PORTS
    TRISD = 0x00;             // PORTD are Ouputs
    PORTE = 0;                // Clear PORTS
    TRISE = 0x00;             // PORTE are Ouputs (MCLR is an input)
    
    Timers();                 //Initiate  Timers
  //  BuzzerStart();            //Swtich on sound, cause I like it.
    Time = 123;
    Volts = 456;
    Amps = 789;
  while(1){
    Int2Segs(Time,dTime);
    Int2Segs(Volts,dVolts);
    Int2Segs(Amps,dAmps);
  }
}
Configs are commented out and it is set by compiler, just wrote it for convenience
 
Last edited:

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
During debugging it is working.
Volt, Amps and Time changes when I change the values.

So how am I suppose to send the value to Ports
I like to know how to set up the ISR
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
There is a problem in using CCP module
I am using RC0 & RC1

I checked to see if the PORTs are working or not.
I cannot seem to get an output from the RC0 & RC1

When I disable the TimerInit routine it is working.
It seems the CCP module is using those Ports.

I have to do without CCP.

Is it possible ?
 

JohnInTX

Joined Jun 26, 2012
4,787
This fixes up the TIMER1/CCP so it doesn't uses the ports. It also fixes TMR0 init and adds derived timer demos on CCP1 IRQ. You can change it to use TMR2/PR2 if you like but its not required. It also adds controls for the LEDs in the mux display and a seconds timer to show how its done.

One big problem was that you declared the interrupt routine as void Interrupt(). Because case sensitivity in MicroC always applies to keywords, this compiled as just another routine. Changing it to void interrupt() made it an interrupt routine. I confirmed this bizarre behavior by looking at the .asm output and noting how the math library occupied the interrupt vector location when Interrupt() was declared. See 'heebie jeebies' below for my feelings on this.

I compiled it in MicroC but simulated it in MPLAB 8.63 by importing the .COF file. I need to get more fluent in MicroC debugging I guess..
UPDATE: This little missive in the manual tells the story:
Note: The Software Simulator simulates the program flow and execution of instruction
lines, but it cannot fully emulate PIC device behavior, i.e. it doesn’t update
timers, interrupt flags, etc.
So for simulation (without the MicroC ICEdebugger), perhaps the best way is indeed to use MPSIM. Importing the .COF file brings the source too so you get source level simulation that's way better than MicroC's - much faster too.

Caveat: MicroC does not appear to put the PIC configuration fuzes in the .COF file by default. You'll need to figure out how to do that or set the PIC config fuzes manually in MPSIM. Presumably, it DOES include the fuzes in the .HEX when its time to program the chip.

Anyway, if you use MPSIM, you can set breakpoints on the two timer interrupt handlers to convince yourself that it works. Check out how the seconds timer is implemented in main as well. The reason for a flag to signal incrementing the timer instead of doing it in the interrupt is that you'd have to disable interrupts to read the timer.. easy enough but trying to limit the scope of new things here..

Probably time to break this into multiple files too.. can't post all of the source.

Have fun.

BTW: heebie jeebies
 

Attachments

Last edited:

THE_RB

Joined Feb 11, 2008
5,438
...
TMR1 can't be loaded as a 16 bit register in MicroC - I didn't know that either.. But we will be just clearing it. This implementation counts from 0000h to whatever is in CCPR1 then auto-resets to 0000 and does it again.
...
Maybe I'm misunderstanding this? But you just set the TMR1 control bits to "16bit mode" then to write to TMR1 in 16bits you do it the same as in assembler;
TMR1H = blah;
TMR1L = boop; // 16bit write happens here

writing a 16bit variable (unsigned int foo) like this;
TMR1H = (foo / 256);
TMR1L = (foo | 0x00FF);

personally I prefer to overload variables and save the math;
TMR1H = foo_H;
TMR1L = foo_L;

which compiles to much smaller and faster code.
 

JohnInTX

Joined Jun 26, 2012
4,787
RB: Fair enough. I was referring to the fact that in MicroC, you can't specify TMR1 as a 16 bit reg like you can CCPR1 et al. You have to explicitly indicate the H/L bytes.

In HiTech and XC8 you can write
Rich (BB code):
TMR1 = 0x1234;
and it compiles to the order you indicate for the write-at-once option selected manually.
 
Last edited:

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
OK.
I changed everything as per ur attached C file.
Complied but I can't seem to get any activity on the output.
The segment board is not connected, I just switched on the Port LED's to see if the Ports are atleast pulsing, but nothing.

The PIC is working. I get the Buzzer sound.
And the PortC are now working. I checked the individual Ports for output before putting ur while (1) code

Something is a miss
 

JohnInTX

Joined Jun 26, 2012
4,787
OK.
I changed everything as per ur attached C file.
Complied but I can't seem to get any activity on the output.
The segment board is not connected, I just switched on the Port LED's to see if the Ports are atleast pulsing, but nothing.

The PIC is working. I get the Buzzer sound.
And the PortC are now working. I checked the individual Ports for output before putting ur while (1) code

Something is a miss
If you are trying to get an LED output of the code I posted, what is missing is the display mux. The sample code assumes that the discrete LEDs are the 10th 'digit' and will be part of the multiplexed display. The LED control routines just flip bits in the buf so.. No mux = no LEDs.

For starters, make your 'multiplexer' just copy DigitsBuf[9] to the segment port D i.e.
Rich (BB code):
PORTD = DigitsBuf[9];
Put it in the while loop first then when you have the LEDs working, move that statement to the TIMER 0 service code where it says //Display Multiplex Code goes here. That will be the starting point of the whole display mux.

The code assumes a '1' out turns the LED on.

Have fun.
 

THE_RB

Joined Feb 11, 2008
5,438
RB: Fair enough. I was referring to the fact that in MicroC, you can't specify TMR1 as a 16 bit reg like you can CCPR1 et al. You have to explicitly indicate the H/L bytes.

In HiTech and XC8 you can write
Rich (BB code):
TMR1 = 0x1234;
and it compiles to the order you indicate for the write-at-once option selected manually.
Thanks for clarifying, I get your point now. :) It never occured to me that the compiler would let you write to two hardware registers with one = assignment. I'm not sure I like that idea.
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Rich (BB code):
  while(1){
      Int2Segs(Volts,dVolts); // show each time for demo purposes
      Int2Segs(Amps,dAmps);
      PORTD = DigitsBuf[9];
      if(SecElapsed){      // maintain multibyte timers
        SecElapsed = 0;      // ack flag
        SystemTime_Secs++;   // bump system timer by one sec
        Int2Segs(SystemTime_Secs,dTime);// update display
        } // one second elapsed

        if(SysTIK_LEDtimer == 0){ // maintain 'flashing LEDs' (demo only)
          SysTIK_LEDtimer = LED_FLASH_TIMEset;
          LEDs_toggle(GREEN_LED + YELLOW_LED);
             } // LED timer ran out
   } //while
OK.
RD0 and RD1 leds are flashing at around 3 to 4 times a second.

And also at the same rate at TIMER 0 service code :D

So what's next.

Funny thing is my buzzer code is messing the whole thing up now. I have to comment it out to flash LED's :eek:

I don't know why. :confused:
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Update.
Flash rate doubles after I reset the uC.
Some how after programing it works slow.
But once reset flashing is faster.
Still it is flashing. I mean I can see it flash. U know, not like 1ms flashing.
 

JohnInTX

Joined Jun 26, 2012
4,787
?? I added the output 'mux' as shown and it seems to work in MPSIM.

Rich (BB code):
/*********** Interrupt Service Routine ***************/
void interrupt(){
//Used for Display Muxing.
  if (TMR0IE_bit)
    if (TMR0IF_bit){
      TMR0IF_bit = 0;           //Ack IRQ
      TMR0 = TMR0set;           //Reset Timer0
      //Display Multiplex Code goes here
      PORTD = DigitsBuf[9];     // 'mulitiplex' the LED display - only discrete LEDs so far
    }
  if (CCP1IE_bit)                //System Tik (dont specify Time here, it may change then this will be confusing)
    if (CCP1IF_bit){            // Interrupt on Timer1 = CCP
      CCP1IF_bit = 0;           //Ack IRQ
                                // Decrement derived timers
      if (SysTIK_LEDtimer) SysTIK_LEDtimer--;
      
      SecsTimerPS--;       // dec Seconds timer prescaler
      if(SecsTimerPS == 0){  // iff one second passed..
        SecsTimerPS = SecsTimerPSset;  // reload the prescaler
        SecElapsed = 1;                // signal main program
       }
         // more code goes here
    }
}
 
Top