Author Topic: Help Please - New to Pic's and suffering - Emulating timing wheels - MikroeC  (Read 5462 times)

0 Members and 1 Guest are viewing this topic.

Offline ClintTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: gb
Hi, I am fairly new to programming PIC's, I have been dabbling for a few years but never really needed to create much more than timed switches which I have created by hacking up example code from the Development kit I purchased a few years back; a MikroElectronica EasyPIC 5.

Right now I am off work ill and while sat here decided to get more involved with Microcontrollers to keep my mind active so I found a small project to keep me busy and I am stuck at the first stage.

The first part of the project to to emulate on the bench 2 timing wheels so I can then play with the control unit without it being attached to the mechanics.
There are 2 wheels, one is effectively a speed sensor that has 4 x 5 degree lugs on a steel wheel 90 degrees apart this wheel turns twice every cycle, so I am basing all other events on the 720 degree cycle of this wheel, then there is a second wheel that spins at 50% the speed  of wheel 1 that has 2 lugs on it 45 degrees apart that pulses at 45 and 135 degrees in the cycle. Below is a graphics overview of the cycle:

DE 0                                     90                                   180                                   270                              360/450/540/630/
W1 =================^=================^=================^=================^===..................
W2                 ^                              ^      

WHEEL 1 PULSE @ 0/90/180/270/350/450/540/630
WHEEL 2 PULSE    @ 45/135

I thought the best way of doing this would be to use the timer of a pic, but although I can create perfectly the pulse of wheel 1, as soon as I add code to add the second wheels pulse it stops working; it looks like it works but then about every 5 pulses it seems to reset.

Below is the code I have tried to use which is simply a hacked up Microelectronics example.

Code: [Select]
unsigned cnt;

void interrupt() {
  cnt++;                   // Increment value of cnt on every interrupt
  TMR0   = 96;
  INTCON = 0x20;           // Set T0IE, clear T0IF
}

void main() {
  OPTION_REG = 0x87;       // Assign prescaler to TMR0        prescale 7=256 4=32
  ANSEL  = 0;              // Configure AN pins as digital I/O
  ANSELH = 0;
  TRISB = 0;               // PORTB is output
  TRISD = 0;               // PORTD is output
  PORTB = 0x00;            // Initialize PORTB
  PORTD = 0x00;            // Initialize PORTD
  TMR0  = 96;              // Timer0 initial value
  INTCON = 0xA0;           // Enable TMRO interrupt
  cnt = 0;                 // Initialize cnt

  do {
    if (cnt < 18){         // 1 - 17 pulse on port B
      PORTB = ~PORTB;      // Toggle PORTB LEDs
      }
      if (cnt == 18){                // 18 2nd pulse port D
               PORTB = ~PORTB;      // Toggle PORTB LEDs
               PORTD = ~PORTD;      // Toggle PORTD LEDs
      }
      if (cnt == 19){         // 2nd Pluse Off 5 degrees
               PORTB = ~PORTB;      // Toggle PORTB LEDs
               PORTD = ~PORTD;      // Toggle PORTD LEDs
          cnt = 1;
      }
  } while(1);
}

Can someone point me in the right direction to recreate these pluses with a Pic, I am sure its either me using the timer wrong (not understanding it fully) or simply I am trying to use the wrong feature to do this, maybe a pwm output may be better ?
=-=-=-=-=-=-=-=-=
g33K5 L1k3 80085
 

Online PA0PBZ

  • Super Contributor
  • ***
  • Posts: 5121
  • Country: nl
I had a quick look at your code and I think that you are not waiting for a change in cnt in main(),  so the if (cnt <18) will be executed as fast as possible as long as cnt < 18?
Keyboard error: Press F1 to continue.
 

Offline ClintTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: gb
I had a quick look at your code and I think that you are not waiting for a change in cnt in main(),  so the if (cnt <18) will be executed as fast as possible as long as cnt < 18?

Thanks for looking :)

Your right it will always flash regardless of interrupt because the cnt may not have increased and is still below 17 !

I hadn't thought of this because it works (for wheel 1 only) if you put a cnt=0 in the first if statement, however it trips over about every 5 cycles with the extended code.

Let me think of a way to catch that :)
=-=-=-=-=-=-=-=-=
g33K5 L1k3 80085
 

Online PA0PBZ

  • Super Contributor
  • ***
  • Posts: 5121
  • Country: nl
Let me think of a way to catch that :)

An easy hack would be an updated flag, UPD=1 in the interrupt routine and then in the main

do {
   If (UPD==1) {

   do your stuff}

   UPD = 0;
   }
} while (1);
« Last Edit: August 28, 2013, 10:45:02 am by PA0PBZ »
Keyboard error: Press F1 to continue.
 

Offline ClintTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: gb
Well I am quite amazed at the speed and exactness of the replies this morning, big smiles here as we have one problem solved the pulse is now rock stable :D

Problem number 2: I am getting the 2nd wheels pulse every 10 of the first wheel's pulse.....

Some pics to help:

Nice and stable now:


But not once every 18:
=-=-=-=-=-=-=-=-=
g33K5 L1k3 80085
 

Offline jaxbird

  • Frequent Contributor
  • **
  • Posts: 778
  • Country: 00
I think this is more of a general programming problem than a PIC specific issue :)

You could simply move the code from inside your main loop to the timer interrupt.

In general, if you modify variables during an interrupt and use them elsewhere, it's a good idea to declare them volatile to prevent the compiler from making assumptions about their values.

Edit: this is a reply to your first post.
Analog Discovery Projects: http://www.thestuffmade.com
Youtube random project videos: https://www.youtube.com/user/TheStuffMade
 

Offline ClintTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: gb
In general, if you modify variables during an interrupt and use them elsewhere, it's a good idea to declare them volatile to prevent the compiler from making assumptions about their values.

I have looked this up and added it to my code; current code now looks like this:

Code: [Select]
unsigned volatile cnt;
unsigned volatile upd;

void interrupt() {
  cnt++;                   // Increment value of cnt on every interrupt
  upd++;
  TMR0   = 96;
  INTCON = 0x20;           // Set T0IE, clear T0IF
}

void main() {
  OPTION_REG = 0x87;       // Assign prescaler to TMR0        prescale 7=256 4=32
  ANSEL  = 0;              // Configure AN pins as digital I/O
  ANSELH = 0;
  TRISB = 0;               // PORTB is output
  TRISD = 0;               // PORTD is output
  PORTB = 0x00;            // Initialize PORTB
  PORTD = 0x00;            // Initialize PORTD
  TMR0  = 96;              // Timer0 initial value
  INTCON = 0xA0;           // Enable TMRO interrupt
  cnt = 0;                 // Initialize cnt
  upd = 0;              // Initialize cntchk

do {
    if (upd==1) {
    if (cnt < 18 ){         // 1 - 17 pulse on port B
      PORTB = ~PORTB;      // Toggle PORTB LEDs
      }
      if (cnt == 18){                // 18 2nd pulse port D
               PORTB = ~PORTB;      // Toggle PORTB LEDs
               PORTD = ~PORTD;      // Toggle PORTD LEDs
      }
      if (cnt == 19){         // 2nd Pluse Off 5 degrees
               PORTB = ~PORTB;      // Toggle PORTB LEDs
               PORTD = ~PORTD;      // Toggle PORTD LEDs
          cnt = 1;
      }
        UPD = 0;   
        }
} while (1);
}
=-=-=-=-=-=-=-=-=
g33K5 L1k3 80085
 

Offline ClintTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: gb
Ok sussed the problem, I am turning it on then off which is 2 not 1 :)
=-=-=-=-=-=-=-=-=
g33K5 L1k3 80085
 

Offline ClintTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: gb
Ok I have managed to change the rate for the second pulse but now have an issue where the first pulse gets twisted, similar to my original issue.

A picture and the current code:



Here is the code:
Code: [Select]
unsigned volatile cnt;
unsigned volatile upd;

void interrupt() {
  cnt++;                   // Increment value of cnt on every interrupt
  upd++;
  TMR0   = 96;
  INTCON = 0x20;           // Set T0IE, clear T0IF
}

void main() {
  OPTION_REG = 0x87;       // Assign prescaler to TMR0        prescale 7=256 4=32
  ANSEL  = 0;              // Configure AN pins as digital I/O
  ANSELH = 0;
  TRISB = 0;               // PORTB is output
  TRISD = 0;               // PORTD is output
  PORTB = 0x00;            // Initialize PORTB
  PORTD = 0x00;            // Initialize PORTD
  TMR0  = 96;              // Timer0 initial value
  INTCON = 0xA0;           // Enable TMRO interrupt
  cnt = 0;                 // Initialize cnt
  upd = 0;              // Initialize cntchk

do {
    if (upd==1) {
                if (cnt < 34 ){         // 1 - 17 pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }
                if (cnt == 35){                // 18 2nd pulse port D
                        PORTB = ~PORTB;      // Toggle PORTB LEDs
                        PORTD = ~PORTD;      // Toggle PORTD LEDs
                }
                if (cnt == 36){         // 2nd Pluse Off 5 degrees
                      PORTB = ~PORTB;      // Toggle PORTB LEDs
                      PORTD = ~PORTD;      // Toggle PORTD LEDs
                      cnt = 0;
                }
        UPD = 0;
    }
} while (1);
}
=-=-=-=-=-=-=-=-=
g33K5 L1k3 80085
 

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2095
Ok I have managed to change the rate for the second pulse but now have an issue where the first pulse gets twisted, similar to my original issue.

Because you don't do anything when the count is 34.

You need the PORTB stuff every update there is no need for any test to control it.

If your PIC has latches (LATB) you should write the latches not the ports.

It isn't good to toggle. If the output gets flipped by a transient or something it will stay inverted.
 

Online PA0PBZ

  • Super Contributor
  • ***
  • Posts: 5121
  • Country: nl
Because you don't do anything when the count is 34.

Exactly  :)
Keyboard error: Press F1 to continue.
 

Offline ClintTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: gb
Rufus I am in a love hate relationship with you; its now perfect and since I now feel stupid for missing an = out I have decided its time for a break, so for me its hammock, sun, rest and maybe a little sleep.... ill be back much fresher later and might even complete this today :)



Code: [Select]
    if (upd==1) {
                if (cnt <= 34 ){
=-=-=-=-=-=-=-=-=
g33K5 L1k3 80085
 

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2095
Rufus I am in a love hate relationship with you

The hate side will no doubt increase when I say you are doing it all wrong:)

If you create a 48 element const initialised array you can have data for each 15 degree step of your 720 degree cycle. Just index into the array with your count and write the array data to a port. Fast, pretty much constant run time and complete flexibility in the pattern generated on multiple pins.
 

Offline ClintTopic starter

  • Regular Contributor
  • *
  • Posts: 119
  • Country: gb
Rufus can you show me an example of using an array :)

In the mean time I have messed it all up again and my brain has burst, this is where I am and its far from working:

Code: [Select]
unsigned volatile cnt;
unsigned volatile upd;

void interrupt() {
  cnt++;                   // Increment value of cnt on every interrupt
  upd++;
  TMR0   = 96;
  INTCON = 0x20;           // Set T0IE, clear T0IF
}

void main() {
  OPTION_REG = 0x87;       // Assign prescaler to TMR0        prescale 7=256 4=32
  ANSEL  = 0;              // Configure AN pins as digital I/O
  ANSELH = 0;
  TRISB = 0;               // PORTB is output
  TRISD = 0;               // PORTD is output
  PORTB = 0x00;            // Initialize PORTB
  PORTD = 0x00;            // Initialize PORTD
  TMR0  = 96;              // Timer0 initial value
  INTCON = 0xA0;           // Enable TMRO interrupt
  cnt = 0;                 // Initialize cnt
  upd = 0;              // Initialize cntchk

do {
    if (upd==1) {
   
/* REQUIRED WHEEL PULSES
 1   1  0  1  0  1  0  1  0  1  0  1  0  1  0  1
 2   0  1  0  1  0  0  0  0  0  0  0  0  0  0  0
*/
                if (cnt == 0){         // 0 degree pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }
               
                // WHEEL 2 PULSE
                if (cnt == 9){           // 45 degree pulse port D
                   PORTD = ~PORTD;      // Toggle PORTD LEDs
                }
                if (cnt == 10){         // 2nd Pluse Off 5 degrees
                   PORTD = ~PORTD;      // Toggle PORTD LEDs
                }// END WHEEL 2 PULSE
               
                if (cnt == 18){         // 90 degree pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }
               
                // WHEEL 2 PULSE
                if (cnt == 27){         // 135 degree pulse port D
                   PORTD = ~PORTD;      // Toggle PORTD LEDs
                }
                if (cnt == 28){         // 2nd Pluse Off 5 degrees
                   PORTD = ~PORTD;      // Toggle PORTD LEDs
                }// END WHEEL 2 PULSE
               
                if (cnt == 36){         // 90 degree pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }
                if (cnt == 54){         // 180 degree pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }
                if (cnt == 72){         // 270 degree pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }               
                if (cnt == 90){         // 360 degree pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }
                if (cnt == 108){         // 540 degree pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }
                if (cnt == 126){         // 630 degree pulse on port B
                   PORTB = ~PORTB;      // Toggle PORTB LEDs
                }
                if (cnt == 143){         // reset cnt to set up next cycle
                   cnt =0;
                }
        UPD = 0;
    }
} while (1);
}
=-=-=-=-=-=-=-=-=
g33K5 L1k3 80085
 

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2095
Rufus can you show me an example of using an array :)

Something like
Code: [Select]
const unsigned char patterns[] = {
    0,          // 15
    1,          // 30
    0,          // 45
    1,          // 60
    0,          // 75
    1,          // 90
    0,          // 105
    1,          // 120
    0,          // 135
    1,          // 150
    0,          // 165
    1,          // 180
    0,          // 195
    1,          // 210
    0,          // 225
    1,          // 240
    0,          // 255
    1,          // 270
    0,          // 285
    1,          // 300
    0,          // 315
    1,          // 330
    0,          // 345
    1,          // 360
    0,          // 375
    1,          // 390
    0,          // 405
    1,          // 420
    0,          // 435
    1,          // 450
    0,          // 465
    1,          // 480
    0,          // 495
    1,          // 510
    0,          // 525
    1,          // 540
    0,          // 555
    1,          // 570
    0,          // 585
    1,          // 600
    0,          // 615
    1,          // 630
    0,          // 645
    1,          // 660
    0,          // 675
    1,          // 690
    0           // 705
};

void interrupt() {

    static unsigned char cnt = 0;

    PORTB = patterns[cnt];
    cnt++;                 

    TMR0   = 96;
    INTCON = 0x20;   
    if(cnt >= sizeof(patterns) ) {
        cnt = 0;
    }
}

Which should generate a square wave on RB0 and you can fill in whatever you like on the other 7 bits.
 

Offline Deepak

  • Regular Contributor
  • *
  • Posts: 76
  • Country: us
I wanted to offer some stylistic advice on your code.

Code: [Select]
    do
    {
...
    } while (1);

Get out of the habit of using do while loops. This is a perfect example where a while loop would work exactly the same as your do while, that is to say - an infinite loop. The reason you'd use a do while loop is if you know you need the loop to run at least once regardless of the while condition, and getting into the habit of regularly using do while loops will cause you to run into frustrating-to-debug-for-a-beginner issues.

So in the following example - someCode() will run once.

Code: [Select]
    do
    {
         someCode();
    } while (0);

In my professional programming career I can probably count on my fingers the number of times I've needed to use a do while rather than a while loop.

Code: [Select]
            if (cnt == 0)
            { // 0 degree pulse on port B
                PORTB = ~PORTB; // Toggle PORTB LEDs
            }

            // WHEEL 2 PULSE
            if (cnt == 9)
            { // 45 degree pulse port D
                PORTD = ~PORTD; // Toggle PORTD LEDs
            }
            if (cnt == 10)
            { // 2nd Pluse Off 5 degrees
                PORTD = ~PORTD; // Toggle PORTD LEDs
            }// END WHEEL 2 PULSE

Not quite as big of a deal, but if you are doing multiple comparisons on a single variable a switch case statement can save you some typing. I actually prefer not to use them, but food for thought.

More importantly if you have mutually exclusive conditions you should get into the habit of using if else if statements. It's clearer to read, and especially with compilers that are bad at optimizing (like the free pic compilers) you're probably wasting cycles making each of these checks when only one could possibly be true.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf