PIC 12F629 Question.

JohnInTX

Joined Jun 26, 2012
4,787
John, may I ask why there's an 11 cycle delay in the PWM routine, please?
Beats me. I didn't write that (or any beep stuff) *whew*. I don't use dumb delays and would never delay inside an interrupt routine at any rate.

One way to mitigate PWM jitter as things get longer in the IRQ service is to set it up to write a pre-calculated PWM value to the port as the first thing in the interrupt service routine. Just slam it out there including copying GPIOimg to GPIO. Then you have time to go through things and calculate the PWM value to be output on the next interrupt. As it is, I didn't see any jitter to speak of but I wasn't looking at it real hard.
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
If I understand correctly, would this modified beep routine be compatible with the shadow mechanism? The routine doesn't write to the GPIO port but relies instead on the PWM routine updating the port from the modified 'GPIOimg' shadow register.
Code:
/*                                                                 *
*  Mike McLaren's non-blocking "beep task" runs at 250-usec       *
*  intervals and produces one or more 32-msec 2000-Hz beeps       *
*  spaced 32-msecs apart.  Set 'beep' to a value of 'N+N-1'       *
*  for the number of beeps desired (with a 128 beep limit).       *
*                                                                 */
    static unsigned char duration;

    if(beep)                    // if beep task running
    { if(beep & 1)              // if beep bit 0 == '1'
        GPIOimg ^= 0b00000100;  // toggle skpr (GP2) bit
      if(--duration == 0)       // if duration timeout
      { duration = 32000/250;   // reset 32-ms duration
        beep--;                 // and decrement 'beep'
      }                         //
    }                           //
This code is not isochronous so it shouldn't be placed in front of the PWM driver where it could add jitter to the PWM output. So far I have not been able to eliminate the conditional code to make it isochronous. Any suggestions appreciated.
I will check this out
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
By jitter, do you mean flickering in the PWM with the beep.
If so ..NO.
But the beep sound changes (freq drops) if I keep the button pressed (beeping)and change the encoder.
 

MMcLaren

Joined Feb 14, 2010
861
Beats me. I didn't write that (or any beep stuff) *whew*. I don't use dumb delays and would never delay inside an interrupt routine at any rate.
You're right, there's no delay in your original code. Sorry. Don't know where that came from.
One way to mitigate PWM jitter as things get longer in the IRQ service is to set it up to write a pre-calculated PWM value to the port as the first thing in the interrupt service routine. Just slam it out there including copying GPIOimg to GPIO. Then you have time to go through things and calculate the PWM value to be output on the next interrupt. As it is, I didn't see any jitter to speak of but I wasn't looking at it real hard.
Writing the port from a precalculated 'GPIOimg' at the beginning of the ISR would reduce potential PWM output jitter. Not that that's a big problem here. I only see about four cycles of jitter in the PWM routine and I doubt you would notice that with these 250-usec PWM steps.

I tested a simpler PWM routine (below) but it didn't improve jitter much.
Code:
  #define step PWMbaseK
  #define duty PWMdutyK
  #define shadow GPIOimg

  shadow |= 0b00000011;         // LED shadow bits 'on'
  if(step >= duty)              //
    shadow ^= 0b00000011;       // LED shadow bits 'off'
  if(++step == 50)              // if 'end-of-period'
    step = 0;                   // reset PWM 'step' var
  GPIO = shadow;                // write port via shadow
 
Last edited:

MMcLaren

Joined Feb 14, 2010
861
OK...now I am confused :confused:
I'm also using John's original code from post 46 but I've been playing with it, inserting test routines, etc., so it's quite a bit different from the original. So far I haven't figured out the changes necessary to get your Mikro Pro C source to work in my XC8 environment. Anyway, I apologize for contributing to the confusion, guys.
 

JohnInTX

Joined Jun 26, 2012
4,787
Things like this do have a way of spinning out of control. So... specifically,
What problems are you currently having?
 

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
OK...
I am at home. After Dinner I will try the suggestions.
As for Problem.
1. The flash is there. I just switched on the adapter and easy pic together, The flash is coming from the PIC.
2. Not a problem yet as I will try to figure out a way to toggle the output from single strip to 4 strip output.
So far that I believe.

I like to know how to save the PWM value at power down and start with that at next power cycle.
 

JohnInTX

Joined Jun 26, 2012
4,787
Are you using the #70 code? If not, post what you currently have and we can take a look at it.
Speaking of the beeper, if that's still a problem, is it driven like the one on EasyPIC 7? i.e.
Buzzer starts "singing" when you provide
PWM signal from the microcontroller
to the buzzer driver. The pitch of the
sound is determined by the frequency,
and amplitude is determined by the
duty cycle of the PWM signal.

Piezo buzzer’s resonant frequency (where you can expect it's
best performance) is 3.8kHz, but you can also use it to create
sound in the range between 2kHz and 4kHz.
?

Don't do it now, but to save to EEPROM you pretty much just have to save the current duty count. On power up, you read EE then jam that value onto the duty count register to restore it.
How to actually save it is another story. You don't want to save/save/save on each encoder tik. The EEPROM has a limited number of writes that it will handle before breaking.

What I do is create an EEdirty bit. Its cleared on init (because you have read the EE duty value and jammed it onto the duty register - they are the same i.e. not dirty).
Every time the duty cycle changes (in increment()/decrement(), you set the EEdirty bit - the duty cycle has changed. You also load a new derived timer (like the old heartbeat timer). Maybe one or two seconds. Set EEdirty and reload the timer each time you detect NEW_ENCODER_STATE in main.
Add a test to main:
If EEdirty AND timer==0, 1 or 2 sec after the last encoder tik, update the EEPROM with the current duty cycle and clear EEdirty.
The result is you can spin the encoder to your heart's content. When you stop awhile, the EEprom will be updated with the resulting duty cycle value.
 
Last edited:

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
I am using the same code as in post #70.
The beep suggestions after post#70 creates an additional problem. It does not improve anything as far as I can see. Problem is when I press the switch the port is sometimes high ( not beeping. Led is ON ). This is not good as the buzzer driver transistor is on without beep. So I skipped that post and am back to code in post #70.

Problems in this code is that I do not get a beep but a continuous beep as long as the switch is pressed and releasing the switch stops the beep.
And I am yet unable to figure out a way to switch the PWM to port 0 or 1 by switch.

As for the EEPROM saving. Can't we just save the encoder value when powering down. That is after 1 second key press. A 1 second press will be used to turn on and off the PIC.
Or yes and there is that flash too.
 

JohnInTX

Joined Jun 26, 2012
4,787
The button is to turn it on and off?
The beeper is supposed to do what? Beep twice on power up then once on each encoder click?
Sorry, I kind of got lost here.

Let's defer the EE until we are happy with everything else.
 

MMcLaren

Joined Feb 14, 2010
861
You're not debouncing or applying any sort of switch state logic to the push button connected to GP3... You seem to have taken the code snippet where I showed how to insert beeps and used it out of context from the earlier "short"/"long" press snippet. Basically you're missing a mechanism to run the code at 25-msec intervals and you're missing some important switch state logic.

Unfortunately, I can't get your source code to work with the XC8 compiler so I'm unable to edit/alter/test your source file.

Here's the original "short"/"long" press example that uses BoostC code (below) and I've added the beep task lines. Hang in there and let me see if I can come up with an example that works in XC8 and will fit within the framework of John's example program.

Code:
  char swnew = 0;              // switch sample var
  char swold = 0;              // switch state latch
  char flags = 0;              // switch new press flags


  #define norm 0               // flag for "short" press
  #define long 1               // flag for "long" press


  #define newpress    swnew.3 == 1 && swold.3 == 0
  #define newrelease  swnew.3 == 0 && swold.3 == 1




  while(1)                      //
  { bam();                      // do 25-msecs worth of PWM
    swold = swnew;              // update switch state latch
    swnew = ~gpio;              // sample active lo switches


    if(newpress)                // if "new press"
    { swtmr = 1000/25           // start 1-second timer
      beep = 1;                 // task a "new press" beep
    }                           //


    if(newrelease)              // if "new release"
    { if(swtmr)                 // if not 1-second timeout
      { flags.norm ^= 1;        // toggle "short" flag and
        swtmr = 0;              // clear 1 second timer
      }                         //
    }                           //


    if(swtmr)                   // if timer running
    { swtmr--;                  // decrement it
      if(swtmr == 0)            // if timed out
      { flags.long ^= 1;        // toggle "long" flag
      beeps = 3;                // task two beeps
      }                         //
    }                           //


    if(flags.long)              // if long new press
    {                           //
    }                           //


    if(flags.norm)              // if short new press
    {                           //
    }                           //
  }                             //
Hi John... The "beep" task provides a mechanism for producing one or more beeps that you can use for audible feedback for some event. In this case I recommended using it to generate a single beep on a debounced "new press" so you know the push button press was recognized, and to generate a double beep on the one second timeout so you know when you've reached the timeout during a "long press" letting you know you can release the push button.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
I'm not sure if @R!f@@ 's beeper is working but here's one that does - probably similar to @MMcLaren 's approach. Instead of a counter I used a 16bit int as a beep pattern to make a few long/short ones. You could use a 'long' for more but that's probably overkill.
The output in the IRQ looks at soundBEEPER and if its 1, toggles the beep output at the IRQ rate - at 250us its 2KHz. There is time left in the interrupt routine to push up the interrupt rate to 131us to get the 3.8KHz rate that the EasyPIC7 piezo requires.
setBeepPattern(p) is a function that sets loads the beep pattern and kicks the timer.
soundBEEPER is controlled in main by parsing that pattern at a rate set in the #defines. Currently its 50ms/TIK.
Personally, I like little engines like this that take some data and do their thing rather than having to write on/off code for each beep pattern. There are limitations to my approach but for this one, it seems to work OK.

In operation, it sets the pattern for 2 long beeps on power up init and 1 short beep every time the encoder changes the duty cycle. I defined a few other patterns for grins.

I'm not trying to force the beep issue either way. I wasn't sure what the status of the beep code in the thread was so thought I'd show another way to do it.
Have fun.

C:
/*
* File:   PWMplay.c
* Author: JohnInTX
* Created on November 4, 2015, 18:23
* XC8 FREE or PRO, Ver 1.35
* This implements a quadrature encoder, PWM output and a PWM piezo driver.
* All timing-sensitive functions are interrupt driven including
* encoder switch debounce, PWM output and derived timers (to do things like
* flash LEDs).
* PIC16F629
*
* Updates:
* Replace heartbeat with beeper on same pin
* Changed TMR0 reload to +=

* Known issues:
* ENstate not fully initialized on power up
* CONFIG should be visited for final target.
*/

#include <xc.h>

//********************* PIC CONFIG  ***********************************
// CONFIG
#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON      // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)

//********************** PROGRAM CONFIGURATION  *****************************
// Change these as required
#define TMR0period_us  250            // how many usec per TMR0 irq
#define ENdebounce_ms  5              // how many ms to debounce the encoder
#define HeartBeatPeriod_ms 150        // how fast to flash the HB LED

#define PWMbaseN 50                   // how many TMR0 IRQs in one PWM cycle
#define PWMchangePerClick 1           // how much to change duty cycle each encoder click
#define InitialPWMDutyK 12             //PWM on power up (actual counts, not percent)

//********************* IO DEFINITIONS  *******************************
// IO is shadowed i.e. set/clear bits in GPIOimg, NOT on GPIO directly.
// The interrupt will write the port.
// This avoids having to turn off the IRQ when main does IO

// IO PINOUT:
// GP0 Encoder PhaseA input - pulled up with 10K
// GP1 Heartbeat LED output - 1 = LED ON
// GP2 Encoder PhaseB input - pulled up with 10K
// GP3/MCLR - Pulled up with 10K (can disable in CONFIG)
// GP4 Not used in standard program.
// GP5 PWM output: 1 = PWM ON

#define ENphaseAmask  0x01      //Phase A is on GPIO.0
#define Beepermask 0x02         // BEEPER PWM on GPIO.1
#define ENphaseBmask  0x04      //Phase B is on GPIO.2
#define ScopeOutmask  0x10      // Extra output for scope monitoring
#define PWMoutmask    0x20      // PWM out is GPIO.5

#define TOGGLE_HEARTBEAT (GPIOimg ^= HeartBeatmask)

#define ENCODER_MASK (ENphaseAmask | ENphaseBmask) // bits with encoder inputs
#define TRISinit 0b11000101     // Encoder is input, others out
#define GPIOinit 0b11000101     // Inputs 1, outputs 0
#define CMCONinit 0x7           // Comparators OFF
#define OPTIONinit 0b10001000   // No pullups, TMR0 runs at Tcyc

// *************** CALCULATED CONSTANTS  *******************************

#define TMR0reload 256-TMR0period_us;    // what to reload TMR0 to
#define msec5PSset 5000/TMR0period_us  // count this many IRQs for 5msec
#define ENdebTIKS   ((ENdebounce_ms *1000) / TMR0period_us)
#define HeartBeatTimerSET (HeartBeatPeriod_ms /(5*2)) // flash heartbeat period
#define PWMdutyKinit ((InitialPWMpct * PWMbaseK)/100);

//********************** VARIABLES  **********************************
// Encoder
unsigned char curENCODER,newENCODER,lastENCODER,ENdebK,ENstate,GPIOimg;
bit NEW_ENCODER_STATE;

// PWM
unsigned char PWMbaseK,PWMdutyK,PWMduty;
//bit PWMoutput;

// Derived timers
unsigned char msec5PreScaler;
unsigned char BeepTimer_5ms;     // times beep pattern

// Beeper
bit soundBEEPER;            // 1 = output 50% duty cycle on beep out at 1/2 IRQ rate

// Beeper pattern.  Bit mapped variable gets shifted right each BeepTIK.
// Iff LSbit==1 beeper sounds for one BeepTIK.  If 0, beeper is off for that TIK.
// By scattering bits in BeepPattern, patterns and different beep times can be
// generated.
typedef unsigned int BeepPatternType;
BeepPatternType BeepPattern;
unsigned char CurrentDuty;  // for duty cycle change test (beeps)
#define BeepCtrlmask ((BeepPatternType) 1)   // tests LSbit in char or int or long
#define BeepTIK_ms  50     // ms per tik
#define BeepTimerSet (BeepTIK_ms / 5)

// Beeper patterns for int
#define Beep_OFF 0b0000000000000000     // no beep (copy/paste for new pattern)
#define Beep_Short1 0b0000000000000001  // 1 short beep
#define Beep_Short2 0b0000000000000101  // 2 short beeps
#define Beep_Long1 0b0000000000001111   // 1 long beep
#define Beep_Long2 0b0000111100001111   // 2 long beeps
#define Beep_Alarm 0b0101010101010101   // 8 short beeps
                                        // for you Roger Rabbit fans
#define Beep_Shave_AndA_Haircut 0b1010010110101011

//********************** INTERRUPT SERVICE  **************************
// Interrupts when TMR0 rolls over. Reloads it to trim period then
// processes items below.
// Timer 1 is unused.
// Note that IO is done here.  No direct outputs to GPIO in main is allowed
// unless interrupts are disabled - not super good when running a software
// PWM.  See Heartbeat in main to see how its done.

void interrupt isr(void)
{
    //GPIOimg |= ScopeOutmask; // 1= entering IRQ
    //GPIO = GPIOimg;
 
    TMR0 += TMR0reload;      // reload TMR0 to trim period
    T0IF = 0;               // clear IRQ flag
 
    //------------------ SERVICE PWM  --------------------------------
    // PWMbaseK counts PWMbaseN interrupts to make the PWM period
    // The PWM output will be high for the fraction of this period
    // determined by PWMdutyK.
    GPIOimg &= ~PWMoutmask;     // assume it will be 0
    if(PWMbaseK){
        PWMbaseK--;
        if(PWMdutyK){
           PWMdutyK--;
           GPIOimg |= PWMoutmask;
        }
    }     
    else{
        PWMbaseK = PWMbaseN;
        PWMdutyK = PWMduty;
        //GPIOimg |= PWMoutmask;
        }
    GPIO = GPIOimg;         // update port
 
    //------------------- SERVICE BEEPER  ---------------------------
    if(soundBEEPER)
        GPIOimg ^= Beepermask;       // 50% duty PWM at TMR0 rate
    else
        GPIOimg &= ~Beepermask;    // else, beeper output 0
     
    GPIO = GPIOimg;                 // update port             
 
    //------------------- SERVICE ENCODER  ---------------------------
    // Reads switch and compares current value to last valid one.
    // Iff its different, it attempts to debounce it by counting
    // each time it enters the interrupt.  When the switch is stable
    // for ENdebTIKS, the previous and current value are combined into
    // one 4bit value which indicates which way the switch turned.
    // See the encoder processor in main for more details.
    // Note that the switch inputs can be on any GPIO input.  This sorts that
    // out.
 
    curENCODER = (GPIO & ENCODER_MASK);
    if(ENdebK == 0){        // 0 means not debouncing any changes
        if(curENCODER != lastENCODER){  // but it has just changed so..
            ENdebK = ENdebTIKS;
            newENCODER = curENCODER;    // save value to compare
        }
        else;   // else its not changed, do nothing        
    } // was not debouncing, debK >0 iff it just started a new one
    else{  // it is currently debouncing
        if(curENCODER != newENCODER){  // changed during debounce!
            ENdebK = ENdebTIKS;         // reset debouncer w/new value
            newENCODER = curENCODER;              
        }
        else{   // still same value
            if(--ENdebK == 0){ // dec and test debounce counter iff Z..
                lastENCODER=newENCODER; // update 'last' value for next click
                ENstate = (ENstate << 2);       // shift is to was
                ENstate &= 0b00001100;  // clear out old and unused bits
                                        // then combine new inputs to two bits
                if(newENCODER & ENphaseAmask) ENstate |= 0x01;
                if(newENCODER & ENphaseBmask) ENstate |= 0x02;
                NEW_ENCODER_STATE = 1;    
            } // debounce complete-new ENstate
        }// encoder value was same during debounce
    }// its currently debouncing
 
    //---------------------- SERVICE DERIVED TIMERS  ---------------------------
    // Prescaler counts msec5PSset interrupts to make a 5msec period.
    // From that, as many timers can be created as desired.  Set the timer
    // to the number of IRQ periods to time.  The timer will run to 0 and stop.
    // Poll the timer, when its 0, time is out. Do something, reload and go.
    if(msec5PreScaler == 0){            // iff prescaler ran out..
        msec5PreScaler = msec5PSset;    // reset it and run timer(s)
        if(BeepTimer_5ms) BeepTimer_5ms--;
    }
    else
      msec5PreScaler--;
 
  //GPIOimg &= ~ScopeOutmask; // 1= entering IRQ
  //GPIO = GPIOimg;     
}// IRQ service

//********************* INCREMENT AND DECREMENT  *****************************
// Called by the encoder switch state decoder.  Increments/Decrements PWMduty
void increment(void)
{
    if ((PWMduty + PWMchangePerClick) >= PWMbaseN)
        PWMduty = PWMbaseN;
    else
        PWMduty += PWMchangePerClick;
}

void decrement(void)
{
   if (PWMduty < PWMchangePerClick)
           PWMduty = 0;
   else
       PWMduty -= PWMchangePerClick;
}
//********************* BEEPER CONTROL  *************************************
// Sets pattern, clears timer to force immediate service/terminate current one
void setBeepPattern(BeepPatternType p)
{
    BeepPattern = p;
    BeepTimer_5ms = 0;
}

//************************ MAIN  *********************************************
void main(void) {
    INTCON = 0;         // zap all IRQs
    PIE1 = 0;
    //--------------- CONFIGURE THE SYSTEM  -------------------
    OPTION_REG = OPTIONinit;
    CMCON = CMCONinit;
 
    //---------------- INIT HARDWARE IO  ----------------------
    GPIOimg = GPIOinit; // this must agree with the next line
    GPIO = GPIOinit;    // Init the I/O f/fs first.. then TRIS
    TRISIO = TRISinit;  //GP3 AND GP2 INPUT, ALL OTHERS OUTPUT
 
    //--------------- INIT VARIABLES  --------------------------
    ENdebK = 0;
    NEW_ENCODER_STATE = 0;
    PWMduty = InitialPWMDutyK;       // starting output
    lastENCODER = (GPIO & ENCODER_MASK);  // init the encoder
  
    //---------------  START TIMER 0 IRQ  -----------------------
    TMR0 = 0;
    T0IF = 0;
    T0IE = 1;
    GIE = 1;
 
    setBeepPattern(Beep_Long2);     // beep twice on PUP
 
    while(1){
        //--------------------- PROCESS ENCODER  ---------------------
        // Iff NEW state has been posted, process it.
        // ENstate is formatted as 0000llcc where
        //  ll is the last value of the switch
        //  nn is the current value.
        //  The switch runs a gray code (only one bit changes at a time). By
        //  combining the last and current bit inputs, a unique number
        //  0000 to 1111 is created.  This number indicates what happened when
        //  the switch was turned.  For example:
        //  Last value  Current value   State   What happened
        //-------------------------------------------
        //  00          01              1       Rotated CW one click
        //  00          10              2       Rotated CCW one click
        //  and
        //  10          00              8       Rotated CW one click
        //  10          11              11      Rotated CCW one click
        //  also
        //  00          11              3       Illegal, both bits changed,
        //                                      ignored.
        // A total of 4 states indicate CW and 4 indicate CCW.  The other 8
        // possibilities are the 4 possible both bit changes and 4
        // possible no bit changes.  These are ignored.
        // A valid CW or CCW calls increment/decrement which adjusts the PWM.
     
        if(NEW_ENCODER_STATE){
            NEW_ENCODER_STATE = 0;
            CurrentDuty = PWMduty;          // save to check for changes at end
            switch (ENstate){
                case 0b00000001: 
                case 0b00000111:
                case 0b00001000:
                case 0b00001110:
                    increment();
                    break;
                 
                case 0b00000010:
                case 0b00000100:
                case 0b00001011:
                case 0b00001101:
                    decrement();
                    break;
                // ignore others: bad reading                   
            }// switch
            if (CurrentDuty != PWMduty) // did duty cycle change?
                setBeepPattern(Beep_Short1);  // yep, one beep
        }// if NEW_ENCODER_STATE
     
        //------------------- GENERATE BEEP PATTERN  --------------------
       // Shifts BeepPattern each time period turning beeper on/off in pattern
     
        if(BeepTimer_5ms==0){                       // time to do something?
            if(BeepPattern != 0){                   // more to do?            
                if(BeepPattern & BeepCtrlmask)      // yes, beep on/off according bit in pattern
                    soundBEEPER = 1;
                else
                    soundBEEPER = 0;
             
                BeepTimer_5ms = BeepTimerSet;       // then reload timer
                BeepPattern = BeepPattern >> 1;     // shift it right for next pattern bit
            }
            else
                 soundBEEPER = 0;                   // no bits in pattern, turn it off
        }
     
    }// main while loop 
}
 
Last edited:

MMcLaren

Joined Feb 14, 2010
861
Rifaa, could you clarify some of the program features, please?

What does the "long" press "on/off" function actually do? Does it toggle both LED outputs between a zero duty cycle (LEDs off) and the duty cycle value from the rotary encoder? If so, is a "long" press on/off function really needed? That is, if the program was written to allow you to adjust the brightness of each LED output independently via the rotary encoder after it was selected via a "short" press and you could adjust the brightness between 0 (off) and 50 (full on), would you really need an on/off function?

What does the "short" press do? Does it toggle one or the other LED outputs from on-to-off or from off-to-on? Or, does it select which LED output is being controlled by the rotary encoder brightness control? Or, is it multi-function, ie; 1st press LED 1 'on' and LED 2 'off', 2nd press LED 1 'off' and LED 2 'on', 3rd press both LED 1 and LED 2 'on', 4th press both LED 1 and LED 2 'off'?

Do you want the encoder to adjust a single duty cycle value that's used for both LED outputs or does it adjust separate duty cycle values for each LED output?

How many LED brightness levels do you need? Is 8, 16, 32, or 50 'coarse' levels enough? Would you prefer linear brightness level steps to the non-linear brightness level steps produced when using linear PWM steps?

We really should have asked some of these questions early on as they have a dramatic affect on program design. For example, when I designed an RGB Accent Light controller (see below), I found the original 256 PWM brightness level steps per channel unsatisfactory since the biggest brightness level changes occur between lower PWM duty cycle settings and hardly any change in perceived brightness level occurs between higher PWM duty cycle settings. Changing the program to use 64 linear brightness levels per channel (using duty cycle values spanning the 256 PWM duty cycle range) worked very well.

.SIRC RGB.png
 
Last edited:

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
I admit I got lost in the beep routine.
I am very new to PIC PWM and Interrupter stuff. I can do most that does not require an interrupt or anything that does not include timers.
I wanted to learn so I tried the methods suggested, and I know I was missing the 25ms part and I cannot figure out a way to do this.

The code in post #70 works. I am listing the working part & bugs as of now below.
The encoder controls the brightness, in steps. I can see the brightness variation jumping. So it is not that linear but works. This is just a table top sorta lamp so that is OK. The minimum brightness after power up is also what I needed now. But this will not matter if the PIC can save the previous PWM value at power down and load it in the next power on ( I prefer this ). The IO configuration is as I have drawn the ckt. So tht part is OK. I can hear the beep as long as the switch is pressed. But I know it is not properly debouncing as I can hear the buzzer beeping twice as I release the switch. I think that is all. There is no flickering as of now.

What I like the PIC to do.
The encoder just controls the brightness. Nothing more. There are two PWM outputs both same PWM signal on GP0 (controls one 1 strip) and GP1 (controls one 4 strip) .
The switch is used for two function.
1. A normal press to route the output from GP0 to GP1 or vice-versa. So in short, a normal press just switches between one strip to four strip and back always. Always one output is active at any given time.
2. 1 sec press to switch the PWM on or off. When Off both output ports are OFF. When ON it starts the output from GP0 always and load the PWM that is saved (if possible). No need to save which port was on (PWM) at power down.
3. Beep was the addition I really liked so with your help it is added.
4. A short beep for normal press release. And Long or double beep when switching off and on.

Is there any thing else ?

I will try the above suggestions tonight.

PS...Happy to hear we have a Mikro consultant.
Is John a consultant too ?
And The Brightness change is OK for this project. No problem with tht. Maybe some other project in due time you guys could teach the way MMcLaren suggests.
 
Last edited:

Thread Starter

R!f@@

Joined Apr 2, 2009
9,918
Hey John.
Beep code is working nicely.
Nice beep patterns to play. So far I am sticking with long startup beep. It's nice.
Encoder beeping was a good lesson but when you hear it, it's annoying.

The below part I am not using but still working
C:
//unsigned char CurrentDuty;  // for duty cycle change test (beeps)
Is it needed. You see I have slashed it out
If I slash out certain parts it does not build so I know it is needed.
But if it builds and works will it be OK. Just to be sure.

I wanted to try Mike's one but I am having a bit of trouble reading the boost code.

I like to be honest.
John's code works nicely. Beep too. But short beeps are a bit long for me.
I tried the Mike's example (code at post #70) again. His beeps are short and I really like the tiny double beep I get when I turn it on. It's shorter than John's short beeps.

I know John's one can produce shorter beeps but there us a little bug. You the know the flash. Even short beeps are giving the first beep long (duration of the flash ) and flash is over second beep is the short one. The Flash is prolonging the beep. That is why I decided to stick with single long beep at startup. No problem here. thought I will let you know.

I will try the output and on off switching myself and see how it works out.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
unsigned char CurrentDuty; // for duty cycle change test (beeps)
Look at the encoder switch statement. I save the current duty cycle in CurrentDuty then compare it with the possible new value of PWMduty (if the encoder changed it) and beep if it changed. I did it that way so that when the duty cycle hit the limits, it wouldn't beep further even though the encoder state changed. My beep output is the old heartbeat LED but I found it annoying as well..
But short beeps are a bit long for me.
You can change the beep time at line 102 (#define BeepTIK_ms). Its 50msec in the code. It uses the 5msec timer so you can go as low as a setting of 10-15ms or so. (2 or 3 in the actual timer setting).

I know John's one can produce shorter beeps but there us a little bug. You the know the flash. Even short beeps are giving the first beep long (duration of the flash ) and flash is over second beep is the short one. The Flash is prolonging the beep. That is why I decided to stick with single long beep at startup. No problem here. thought I will let you know.
I haven't observed that - or the flash either for that matter. Not sure about that one but its like the flash is an indication that the PIC is getting hung somewhere - still running since the beep is generated by the interrupt PWM... or IS it?

I am assuming that your EasyPIC7 (or is it some other number??) On EasyPIC7 it requires the PIC to generate the tone signal. That's why its puzzling that it looks like its hanging but its obviously running. To have a long beep, my code would have to fire everything up, set soundBEEPER flag then get hung somewhere where is does not get through the main loop beeper service. What do you think?

I don't have any button input code on mine - if yours does, is it possible that it has morning-sickness i.e. not initialized and taking time to get itself together?

Thoughts?
 
Last edited:
Top