Help Please - New to Pic's and suffering - Emulating timing wheels - MikroeC - Page 1
Forum section: electronics / general

author: Clint
author_rank: Regular Contributor
timestamp: August 28, 2013, 09:28:09 am
content: 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/630WHEEL 2 PULSE @ 45/135I 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:unsigned cnt;void interrupt() {cnt++; // Increment value of cnt on every interruptTMR0 = 96;INTCON = 0x20; // Set T0IE, clear T0IF}void main() {OPTION_REG = 0x87; // Assign prescaler to TMR0 prescale 7=256 4=32ANSEL = 0; // Configure AN pins as digital I/OANSELH = 0;TRISB = 0; // PORTB is outputTRISD = 0; // PORTD is outputPORTB = 0x00; // Initialize PORTBPORTD = 0x00; // Initialize PORTDTMR0 = 96; // Timer0 initial valueINTCON = 0xA0; // Enable TMRO interruptcnt = 0; // Initialize cntdo {if (cnt < 18){ // 1 - 17 pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 18){ // 18 2nd pulse port DPORTB = ~PORTB; // Toggle PORTB LEDsPORTD = ~PORTD; // Toggle PORTD LEDs}if (cnt == 19){ // 2nd Pluse Off 5 degreesPORTB = ~PORTB; // Toggle PORTB LEDsPORTD = ~PORTD; // Toggle PORTD LEDscnt = 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 ?

author: PA0PBZ
author_rank: Super Contributor
timestamp: August 28, 2013, 09:42:21 am
content: 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?

author: Clint
author_rank: Regular Contributor
timestamp: August 28, 2013, 10:16:58 am
content: Quote from: PA0PBZ on August 28, 2013, 09:42:21 amThanks for lookingYour 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

author: PA0PBZ
author_rank: Super Contributor
timestamp: August 28, 2013, 10:25:31 am
content: Quote from: Clint on August 28, 2013, 10:16:58 amAn easy hack would be an updated flag, UPD=1 in the interrupt routine and then in the maindo {If (UPD==1) {do your stuff}UPD = 0;}} while (1);

author: Clint
author_rank: Regular Contributor
timestamp: August 28, 2013, 11:29:17 am
content: 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 stableProblem 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:

author: jaxbird
author_rank: Frequent Contributor
timestamp: August 28, 2013, 11:31:08 am
content: I think this is more of a general programming problem than a PIC specific issueYou 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.

author: Clint
author_rank: Regular Contributor
timestamp: August 28, 2013, 11:45:36 am
content: Quote from: jaxbird on August 28, 2013, 11:31:08 amI have looked this up and added it to my code; current code now looks like this:Code:unsigned volatile cnt;unsigned volatile upd;void interrupt() {cnt++; // Increment value of cnt on every interruptupd++;TMR0 = 96;INTCON = 0x20; // Set T0IE, clear T0IF}void main() {OPTION_REG = 0x87; // Assign prescaler to TMR0 prescale 7=256 4=32ANSEL = 0; // Configure AN pins as digital I/OANSELH = 0;TRISB = 0; // PORTB is outputTRISD = 0; // PORTD is outputPORTB = 0x00; // Initialize PORTBPORTD = 0x00; // Initialize PORTDTMR0 = 96; // Timer0 initial valueINTCON = 0xA0; // Enable TMRO interruptcnt = 0; // Initialize cntupd = 0; // Initialize cntchkdo {if (upd==1) {if (cnt < 18 ){ // 1 - 17 pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 18){ // 18 2nd pulse port DPORTB = ~PORTB; // Toggle PORTB LEDsPORTD = ~PORTD; // Toggle PORTD LEDs}if (cnt == 19){ // 2nd Pluse Off 5 degreesPORTB = ~PORTB; // Toggle PORTB LEDsPORTD = ~PORTD; // Toggle PORTD LEDscnt = 1;}UPD = 0;}} while (1);}

author: Clint
author_rank: Regular Contributor
timestamp: August 28, 2013, 11:49:21 am
content: Ok sussed the problem, I am turning it on then off which is 2 not 1

author: Clint
author_rank: Regular Contributor
timestamp: August 28, 2013, 12:13:00 pm
content: 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:unsigned volatile cnt;unsigned volatile upd;void interrupt() {cnt++; // Increment value of cnt on every interruptupd++;TMR0 = 96;INTCON = 0x20; // Set T0IE, clear T0IF}void main() {OPTION_REG = 0x87; // Assign prescaler to TMR0 prescale 7=256 4=32ANSEL = 0; // Configure AN pins as digital I/OANSELH = 0;TRISB = 0; // PORTB is outputTRISD = 0; // PORTD is outputPORTB = 0x00; // Initialize PORTBPORTD = 0x00; // Initialize PORTDTMR0 = 96; // Timer0 initial valueINTCON = 0xA0; // Enable TMRO interruptcnt = 0; // Initialize cntupd = 0; // Initialize cntchkdo {if (upd==1) {if (cnt < 34 ){ // 1 - 17 pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 35){ // 18 2nd pulse port DPORTB = ~PORTB; // Toggle PORTB LEDsPORTD = ~PORTD; // Toggle PORTD LEDs}if (cnt == 36){ // 2nd Pluse Off 5 degreesPORTB = ~PORTB; // Toggle PORTB LEDsPORTD = ~PORTD; // Toggle PORTD LEDscnt = 0;}UPD = 0;}} while (1);}

author: Rufus
author_rank: Super Contributor
timestamp: August 28, 2013, 12:23:14 pm
content: Quote from: Clint on August 28, 2013, 12:13:00 pmBecause 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.

author: PA0PBZ
author_rank: Super Contributor
timestamp: August 28, 2013, 12:28:34 pm
content: Quote from: Rufus on August 28, 2013, 12:23:14 pmExactly

author: Clint
author_rank: Regular Contributor
timestamp: August 28, 2013, 12:30:56 pm
content: 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 todayCode:if (upd==1) {if (cnt <= 34 ){

author: Rufus
author_rank: Super Contributor
timestamp: August 28, 2013, 01:19:00 pm
content: Quote from: Clint on August 28, 2013, 12:30:56 pmThe 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.

author: Clint
author_rank: Regular Contributor
timestamp: August 28, 2013, 04:51:20 pm
content: Rufus can you show me an example of using an arrayIn 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:unsigned volatile cnt;unsigned volatile upd;void interrupt() {cnt++; // Increment value of cnt on every interruptupd++;TMR0 = 96;INTCON = 0x20; // Set T0IE, clear T0IF}void main() {OPTION_REG = 0x87; // Assign prescaler to TMR0 prescale 7=256 4=32ANSEL = 0; // Configure AN pins as digital I/OANSELH = 0;TRISB = 0; // PORTB is outputTRISD = 0; // PORTD is outputPORTB = 0x00; // Initialize PORTBPORTD = 0x00; // Initialize PORTDTMR0 = 96; // Timer0 initial valueINTCON = 0xA0; // Enable TMRO interruptcnt = 0; // Initialize cntupd = 0; // Initialize cntchkdo {if (upd==1) {/* REQUIRED WHEEL PULSES1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 12 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0*/if (cnt == 0){ // 0 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}// WHEEL 2 PULSEif (cnt == 9){ // 45 degree pulse port DPORTD = ~PORTD; // Toggle PORTD LEDs}if (cnt == 10){ // 2nd Pluse Off 5 degreesPORTD = ~PORTD; // Toggle PORTD LEDs}// END WHEEL 2 PULSEif (cnt == 18){ // 90 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}// WHEEL 2 PULSEif (cnt == 27){ // 135 degree pulse port DPORTD = ~PORTD; // Toggle PORTD LEDs}if (cnt == 28){ // 2nd Pluse Off 5 degreesPORTD = ~PORTD; // Toggle PORTD LEDs}// END WHEEL 2 PULSEif (cnt == 36){ // 90 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 54){ // 180 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 72){ // 270 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 90){ // 360 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 108){ // 540 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 126){ // 630 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}if (cnt == 143){ // reset cnt to set up next cyclecnt =0;}UPD = 0;}} while (1);}

author: Rufus
author_rank: Super Contributor
timestamp: August 28, 2013, 05:09:56 pm
content: Quote from: Clint on August 28, 2013, 04:51:20 pmSomething likeCode:const unsigned char patterns[] = {0, // 151, // 300, // 451, // 600, // 751, // 900, // 1051, // 1200, // 1351, // 1500, // 1651, // 1800, // 1951, // 2100, // 2251, // 2400, // 2551, // 2700, // 2851, // 3000, // 3151, // 3300, // 3451, // 3600, // 3751, // 3900, // 4051, // 4200, // 4351, // 4500, // 4651, // 4800, // 4951, // 5100, // 5251, // 5400, // 5551, // 5700, // 5851, // 6000, // 6151, // 6300, // 6451, // 6600, // 6751, // 6900 // 705};void interrupt() {static unsigned char cnt = 0;PORTB = patterns;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.

author: Deepak
author_rank: Regular Contributor
timestamp: August 29, 2013, 07:38:43 pm
content: I wanted to offer some stylistic advice on your code.Code: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()willrun once.Code: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:if (cnt == 0){ // 0 degree pulse on port BPORTB = ~PORTB; // Toggle PORTB LEDs}// WHEEL 2 PULSEif (cnt == 9){ // 45 degree pulse port DPORTD = ~PORTD; // Toggle PORTD LEDs}if (cnt == 10){ // 2nd Pluse Off 5 degreesPORTD = ~PORTD; // Toggle PORTD LEDs}// END WHEEL 2 PULSENot 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.