Multiplexing 7Segs and using timer Countdown

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
By the way..
The 10th digit is at RE1

I am attaching the code just in case
It's C file. Just rename the extension.
I changed it to .txt to attach to the forum

Apparently AAC does not support .rar files either

Code added at post #45
 
Last edited:

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Update.

I added 0SCCON = 0x77;
Internal 8 MHz Oscillator.

Now the buzzer works fine and still the LED flashes at the same rate.

Something is wrong. When I select HS and the 8MHz Xtal. Buzzer is messed up.
But the internal is just fine.

Any Ideas ?

OK, another funny thing.
When I switch off and on the easyPIC power sw the buzzer is messed up and flashing is slow.
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
This thing is messing with me.
I ommitted the OSCCON value and did as before. HS osc.
Now this thing won't flash anything.......
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
OK ..managed to fix the issue but the flashing is now slow.
Buzzer is OK.
Code is changed a bit.


ED{}
I changed to
Rich (BB code):
PORTD = DigitsBuf[0];
And PortD 0 to 5 are lit.


so back to
Rich (BB code):
PORTD = DigitsBuf[9];
PortD 0 and 1 are flashing as in 3 to 4 times/S
 

Attachments

Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
First things first. Comment out the buzzer code.

By the way..
The 10th digit is at RE1
Remember that the discrete flashing LEDs are 'segments' in a 'digit'. When the entire 10 digit (9*7segment LEDs + 1 group of discrete LEDs mapped as the 10th digit) display. RE1 is the digit select for the discrete LEDs. Since our multiplexer consists only of the discrete LEDs, I left that out. If you have wired the discrete LEDs as the 10th digit (with RE1 as the 'digit select') then turn it on to select the LEDs. (My test version assumes that the anodes of the LEDs are on PORTD and the cathodes are connected to ground - through the appropriate resistor). This setup is sufficient to debug all of the timer/interrupt stuff and gain experience with how to use this design paradigm.

Next would be to resolve the issues with the reset/oscillator in different configurations. Decide on one and get that working. Assuming no 'morning sickness' in the code (due to any poor inits on my part) you should be be able to reset it, change oscillator types (keeping the same speed) etc and it should continue to flash the LEDs at the set rate.

Don't add anything else until this part is working solid. Its not unlikely that the buzzer library may be interfering with something we have done... especially since it looks like Sound_Play uses dumb delays which WILL affect the LED flashing... Get rid of it for now.

Before we go too much further.. Does EasyPIC 7 have the equivalent of the MicroICE on board? The MicroC simulator does not show timers/interrupts so is essentially worthless for the task at hand. You can find out by opening a watch window, selecting TMR0 and see if it reports it changing value. If so - GREAT.

I'm actually studying for the last final so may be hit and miss until Tues PM - after that, I may be temporarily *impaired*.

Good luck (to both of us)

EDIT: Something to chew on - the IRQ-driven approach is more along the lines of a real time OS. The MicroC libraries are, from what I've gathered messing with it, single thread procedural oriented e.g. beeping the beeper using Sound_Play may use dumb delays which isn't really compatible with a real time approach.. BUT.. one step at a time.

EDIT2:
And PortD 0 to 5 are lit.
We are crossing posts but PORTD = DigitsBuf[0]; will output the decoded 7segment pattern of the MSdigit of SystemTime_Secs to the discrete LEDs - the 6 segs lit is what you would expect when the MSdigit is 0, yes? Because we have not yet implemented the sequential digit select function, its one digit per build. The rest of the mux should happen right after sorting out the hardware/config/oscillator issues.



Then, experiment with this line:
LEDs_toggle(GREEN_LED + YELLOW_LED);

If there is something you are fuzzy on about how the LEDs / segments etc. are specified, ask away.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
OK, another funny thing.
When I switch off and on the easyPIC power sw the buzzer is messed up and flashing is slow.
That is because the Sound_Play code uses dumb delays as I suspected. So when you play that cute sound, your system can do nothing else while the beep is beeping, including polling the derived timer that drives the flashing LED.

If you take a moment to think about it, the programming model that I have proposed and what MicroC uses is quite different, and quite incompatible. My way is slicker but requires some investment in a code structure that doesn't hog the CPU and learning some new concepts maybe. MicroC provides huge library of useful stuff, but you have to code it in sequence.. beep then flash, OK. Beep while flash, not so much.

To check it out, I added this:
Rich (BB code):
void main() {
    initIO();
    initLEDdisplay();     // init multiplexer
    initTimers();        //Init Timers
    
   Sound_Init(&PORTC, 3);    // for looking at compiled code only!
   Sound_Play(1000, 100);

   Volts = 456;
The code grew from 375 to 1086 bytes AND used dumb delays that consume 100% of the CPU, less interrupts. That's why your LEDs slowed down.
 

THE_RB

Joined Feb 11, 2008
5,438
I do display multiplexing in the interrupt.

As a general rule during every int the program switches off the last digit and turns on the new digit. So for a 4 digit clock it takes 4 interrupts total to display all 4 digits.

Because the entire display is done in the interrupt all display updating happens effortlessly. The main code just changes the values for the digits and they appear on the display.

The main code can do the beeping and ADC measuring etc.
:)
 

THE_RB

Joined Feb 11, 2008
5,438
I'd start with that, getting the 1mS int and digit multiplexing working first.

Then worry about ADCs and beeping later, in the main code. ;)
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
OK then no beeping.
I understand the delay is messing up if I use ISR.

The VA project does not use ISR so the beeping and and all that worked well.

I dunno about mikroICE. It has hardware microProg debugger and it can step through the code in real time I believe.

RB knows about that stuff far better than me :).
He can explain this stuff better.

I will try what you suggest tonight.
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
The beeping is commented out.
Programed tand now all the PORTD 5 leds are lit. A little dim.
So changed to
PORTD = DigitsBuf[9];
and now no lit leds.
Switch of the PSU and on, now first two led are on.

Switch and back, now nothing is lit.

I think power on messing up the code.

I am set at HS 8MHz. No change will be done there.

This part
Then, experiment with this line:
LEDs_toggle(GREEN_LED + YELLOW_LED);
Does not do anything.

I am having doubts about the PIC or is it the code?
 

JohnInTX

Joined Jun 26, 2012
4,787
Hmmm..

OK. Set this one aside and write a simple LED flasher. Use the IO init code from this one but leave out all interrupts, digit bufs etc. Make a counter on PORTD with a 50ms dumb delay in the loop i.e.

Rich (BB code):
short k;

// copy IO definitions and initIO() from the original code i.e. 
// PORTD is a digital output- this test will help identify problems with
// the initIO function.

main(){

 initIO()// the same one for the other code
k = 0;

while(1){
 PORTD = k;
 k++;
 Delay_ms(50);
}//while
When this is working perfectly i.e. binary count on PORTD, change the delay etc. a few times to make sure that code changes get to the target. Cycle the power, reprogram the chip, play with the debugger (breakpoint on PORTD=k to see it increment when you step).

When that is working SOLID, we know that the target is reliable and we can work through the issues with the more advanced code.

BTW: Make sure that the oscillator jumpers are set per the EasyPIC7 manual AND that the config settings are getting to the chip. When I was simulating in MPSIM, I noticed that the PIC CONFIG fuzes (HS et al) were NOT part of the .HEX file so if I had been programming a PIC, it would not be run correctly.. like yours may be not doing.. Grammer! I haven't used any of MicroC's boards so have not been through the jumper/setup process on them..

Passed my performance final!
 
Last edited:

THE_RB

Joined Feb 11, 2008
5,438
...
I dunno about mikroICE. It has hardware microProg debugger and it can step through the code in real time I believe.

RB knows about that stuff far better than me :).
He can explain this stuff better.
...
MikroC has an ICD, but I'm the wrong person to ask. I haven't bothered to use a debugger in about 7 or 8 years. :)

First i would do what John suggests and strip your code back to almost nothing. Just the ports setup and flash a LED or output binary sequence to PORTB etc.

Personally I like to do this and compare the flash rate to a ticking house clock;
Rich (BB code):
while(1)
{
  PORTB = 0xFF;    // flashes PORTB LEDs at very close to 1Hz
  Delay_mS(100);
  PORTB = 0x00;
  Delay_mS(900);
}
That shows your osc setting etc is fine and your delays are right.

Then get the TMR2 int going at 1mS per interrupt (as previously discussed).

After that, make main empty again and put a count variable in the interrupt (16bit!) and then when it reaches 500 interrupts toggle PORTB LEDs. That will show the interrupt is working by flashing the LEDs at 1Hz and again you can compare with a ticking clock.

After that you have proved the int is exactly 1mS, so you can put the display digit sequencing in the interrupt.
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
I thought of doing a simple program to check the PIC.
Later that night but was too tired.
I was out watching Amazing Spider man 2 in 3D. That wasn't so bad.
I will check the PIC tonight and report.

You passed the finals.? What was the prize.
Congrats by the way.
 

JohnInTX

Joined Jun 26, 2012
4,787
Personally I like to do this and compare the flash rate to a ticking house clock;
That's a great idea.

Then get the TMR2 int going at 1mS per interrupt (as previously discussed).
Maybe. But TMR1 is working OK and I'm guessing that he might want to drive the buzzer with the PWM. The MicroC library routines for the buzzer use dumb delays that will make for a sluggish system or require moving more stuff to the interrupt routines which I would discourage - especially on midrange. Just my .02
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
OK...
So John one is a binary counter. All ports working. Continues on off also works.
HS and internal and switch over works.
RB suggest is on time with the clock. I second toggling is A-OK.

Nothing wrong with board or PIC so far.

Trying the interrupt now. This is what I can't wrap my head around still. Gonna learn one way or the other this time.
 
Last edited:

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
So I did everything.

Did it step by step and reprogrammed each try

First the InitIO and just flashing the ports.

Add the timer routine programed and flashed slowed to 2seconds. Reset the PIC and back to 1 second. All good powering down and back again. No problem

So did the interrupt, Just the 1sec part (TMR1).
The Timers are all ready. TMR0 @ 3ms and TMR1 @ 1 sec.

Moved the while loop to TMR1 Interrupt and guess what. Still flashes at 1 sec.
After that I added all the PORTS to flash and it's all good.
Of course the RA6 & 7 are the HS osc. and the MCLR.
Except these 3 all ports now work. Reset few times, good. Power cycled and still all good. :D

Rich (BB code):
/*
  PIC 16F887.
  HS 8MHz Oscillator


/* Config setting for reference (set by compiler)
CONFIG1 0x2BF2, b'00101011 11110010'
CONFIG2 0x0600, b'00000110 00000000'
Config -- Brown Out at 2.1V
          HS Osc
          Clock Fail safe enabled.
*/

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

/*********** Variables ****************************/
unsigned int Volts,Amps,Time;     // Voltage, Ampere and Timer Vars.
short SysTIK_LEDtimer;            // sysTIK timer for LED (as an example)
short SecsTimerPS;                // prescaler for seconds derived timer
bit SecElapsed;                   // set by sysTIK when one second has elapsed
unsigned int SystemTime_Secs;     // system Time runs in seconds

/* TMR0 Set up Values (interrupt at 3ms)*/
#define Option_Reg_init 0b10000101// Clock at Tcyc/64 Prescaler assigned to TMR0,
                                  // RBPU off
// Setting is 256 - (3ms / .5usTcyc) / 64Prescaler = 256 - 93.755 counts = 162.25 ~= 162
#define TMR0_Set 162              // counts 162->255 then rolls over and interrupts
/*TMR1 Set up values (interrupt at 1s)*/
#define T1CON_init 0b00110000     // no gate, internal Tcyc/8, timer STOPPED
#define CCP1CON_init 0b00001011   // compare CCPR1 to TIMER1, IRQ and reset TMR1 on match
#define CCPR1_init 1250           // 0.5usTcyc *8 Prescale * 1250 = 5msec
#define SecsTimerPrcSet 200       // 200 * 5ms sysTIK = 1 sec
#define LED_Flash_TimeSet 20      // about 5ms*20 = 100ms flash time


void initTimers(){
    INTCOn = 0x00;                // No interrupts whatsoever.
    OPTION_REG = Option_Reg_init; // Load Option Register value(defined)
    TMR0 = TMR0_Set;              // Load Timer 0 value(defined)
    T1CON = T1CON_init;           // Timer 1 OFF
    TMR1H = TMR1L = 0;            // Timer counts UP to CCP value (no 16bit definition in MicroC)
    CCPR1 = CCPR1_init;           // Load CCPR1 value(defined
    CCP1CON = CCP1CON_init;       // Set up the CCP
/* Initaite derived timers*/
    SecsTimerPS = SecsTimerPrcSet;// Initiate seconds timer prescaler
    SecElapsed = 0;               // Reset flag
    SysTIK_LEDtimer = 0;          // Reset LED Timer
/* Fire it up */
    TMR1IF_bit = 0;               //PIR1 Reg; Clear the Timer1 overflow Interrupt flag bit
    CCP1IF_bit = 0;               //Clear Timer1 Interrupt flag
    T1CON.TMR1ON = 1;             //Start timer 1
/* Then Enable Interrupts */
    TMR1IE_bit = 1;
    CCP1IE_bit = 1;
    INTCON.T0IE = 1;
    INTCON.PEIE = 1;              //Enable Peripheral Interrupts
    INTCON.GIE = 1;               //Enable Global Interrupts
}

/******** INTERRUPT ************************************/
void interrupt(){
/* This is Timer 1 interrupt */
  if (CCP1IE_bit)                 // System Tik
  if (CCP1IF_bit){                // Interrupt on Timer1 = CCP
      CCP1IF_bit = 0;             // Ack IRQ
    if (SysTIK_LEDtimer) SysTIK_LEDtimer--;// Decrement derived timers
        SecsTimerPS--;            // Decrement Seconds timer prescaler
    if(SecsTimerPS == 0){         // If one second passed.....
        SecsTimerPS = SecsTimerPrcSet;// Reload the prescaler
        SecElapsed = 1;           // signal main program
     }
    // more code goes here
    PORTA = 0xFF;
    PORTB = 0xFF;
    PORTC = 0xFF;
    PORTD = 0xFF;
    PORTE = 0xFF;
    delay_ms(100);
    PORTA = 0x00;
    PORTB = 0x00;
    PORTC = 0x00;
    PORTD = 0x00;
    PORTE = 0x00;
    delay_ms(900);
   }
}
/* IO Initializing Routine */
void initIO(){
    ANSEL = 0x00;
    ANSELH = 0x00;                // Rest are Digital IO's.
     
    CM1CON0.C1ON = 0;             // Disable Comparator 1.
    CM2CON0.C2ON = 0;             // Disable Comparator 2.

    PORTA = 0;                    // Clear PORTs.
    PORTB = 0;                    // Clear PORTs.
    PORTC = 0;                    // Clear PORTs.
    PORTD = 0;                    // Clear PORTs.
    PORTE = 0;                    // Clear PORTs.

    TRISA = 0;
    TRISB = 0;
    TRISC = 0;
    TRISD = 0;
    TRISE = 0;
 }

/********** MAIN ********************************/
void main(){
     initIO();                    // Initialize IO's
     initTimers();                // Initialize the Timers
     
  while(1){

 }
}
I am learning this Interrupt a bit now :)
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
The reason it still flashes at 1 sec is that you have swamped the interrupt routines with the dumb delays within the interrupts. You should never have delays inside an interrupt routine. And you don't need to. With interrupt-derived timers, all the interrupts do is count registers down to 0. Especially with a PIC with its limited interrupt capability, you must get through the interrupt stuff fast and let the main code do the work.

Something to be aware of: Timer 1 is running and you have enabled its interrupt (TMR1IE) but you have no service routine for TMR1IF. When setting up an interrupt system there must be a service routine if (xxxIF) for each interrupt enable xxxIE=1. Recall that you are not using TIMER1's interrupt for a sysTIK, you are just running the timer and comparing its count to the stored value in CCPR1. When they match, timer 1 will be reset and CCP1IF will be raised. So you look for CCP1IF as you are but don't enable TMR1IE.

Now that we can code on the EasyPIC7, try the original code again. I have it running on a test board (using a 16F884 but its close enough).
It toggles 3 LEDs on RD0,1, and 2 and would be a good jumping off place for the next step.

See if it works and let us know. We can proceed from there.

Good luck
 

Attachments

Last edited:

THE_RB

Joined Feb 11, 2008
5,438
I think there's a bug in your interrupt too;
Rich (BB code):
if (CCP1IE_bit)                 // System Tik

should that be;
if (CCP1IE_bit) {               // System Tik
I prefer to make braces {} line up vertically, it is much better for visually checking the code;

Rich (BB code):
// this is hard to check visually
while(blah) {
  stuff;
}

// this is much better for checking visually
while(blah)
{
  stuff;
}
:)
 
Top