Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

C18 Questions

Status
Not open for further replies.
Thanks 3v0, that did the trick. This should really help me understand timers, now that I have working code I can play with and see what is effected.

and also thanks for the tip Jason. Adding those will make the warning go away, but since I'm new to C18 I wasn't sure if there might be a reason they weren't included. In boost C are they not required?
 
Makes sense, I usually included them in my C++ code, but its mainly to stop the warnings. I suppose in some situations it could prevent errors.

edit:
I made a simple fading script to see that the multitasking is working, besides that shown, its just the code by 3v0, and the declarations for the new variables.
Code:
  while (1)
  {      

	    // cycles led according to brightness
    if (!counter[C_TEST])
    {
      
		if (lighton == 1)
			{
			lighton = 0;
			ledBits = 0x03;
			setCounter(C_TEST,brightness);
			}
		else
			{
			lighton = 1;
			ledBits = 0x00;
			setCounter(C_TEST,10-brightness);
			}
	serviceLEDs();
		
    }  
	
//causes fade variable to slowly increase and decrease from 1 to 10 and back
if (!counter[C_TEST2])
    {
	setCounter(C_TEST2,2400);

	if (fadedirection == 0)
	{
		brightness--;
		if(brightness <= 0){fadedirection = 1;}
	}
	else
	{
		brightness++;
		if(brightness >= 10){fadedirection = 0;}
	}
}

  }


}

it works as expected, now I'm going to work on using it to generate two motor speed controlling pwm outputs, then see if I can get it to work bidirectionally with an h bridge. And once I get that working if I can make it read servo receiver PWM output, I should have all I need for my tank drive controller.
 
Last edited:
I've got a bit of an odd result here, to the above I've added this:

Code:
//This pulses the servo line
if (!counter[C_SERVO])
{
		if (ServoPortOn == 1)
			{
			ServoPortOn = 0;
			ServoPin = 1;
			setCounter(C_SERVO,ServoPulseLength);
			}
		else
			{
			ServoPortOn = 1;
			ServoPin = 0;
			setCounter(C_SERVO,ServoPulseLength);
			}
}

the odd part is, if i set ServoPulseLenth below 100 or so, it pulses as would be expected (I have an led on it right now) at a speed just visible to the eye, but if I increase that to 200 or over, it takes about 15 seconds between blinking. Somewhere there's a snag here.

edit: Ive narrowed it down. It starts going slow at 128, below that it pulses at what appears to be the correct speed.
 
Last edited:
are you sure at 128? i would suspect at 255 since most c18 functions contain char types. 254 should be a max limit ..

please be aware its 6am and i just read the latest post so i dont know what ya up to yet :D
 
ok a char is -128 to +127 and a unsigned char is 0-254 so maybe your issue is its a overrun where your value is more than the function can handle try to change it to a int or unsigned char
 
Last edited:
Yeah, that was the problem, thanks man. I've done PC programming, I shouldn't have missed a variable range thing, but oh well, haha. Now to work on timing.
 
Last edited:
ok a char is -128 to +127 and a unsigned char is 0-254 ...

Actually unsigned char is 0...255.

Max can be found with: max=2^bit_length-1. For 8 bits that makes 2^8=256 steps and max. value is 2^8-1 = 255.
 
Ok, it seems like in 3v0's multitasking code, a timer delay of 4000 is roughly 1 second at this speed. But if I read it correctly, it will be thrown off a little by the time taken for commands between the timer hitting zero and whenever the routine that triggers is reached and gets to the part where it resets the timer. Does much care need to be taken to compensate for this? or will it not be substantial in applications like reading and generating PWM signals for servos?

edit:
Ive changed the code a bit and added a servo instead of an led
Code:
//This pulses the servo line

//4000 = 1 second so 80 = 20mS  2 = 0.5 mS and 10 = 2.5mS

ServoPulseLength = brightness;
if(ServoPulseLength > 10){ServoPulseLength = 10;}
if(ServoPulseLength < 2){ServoPulseLength = 2;}

if (!counter[C_SERVO])
{
		if (ServoPortOn == 1)
			{
			ServoPortOn = 0;
			ServoPin = 1;
			setCounter(C_SERVO,ServoPulseLength);
			}
		else
			{
			ServoPortOn = 1;
			ServoPin = 0;
			setCounter(C_SERVO,80-ServoPulseLength);
			}
}

brightness is just the variable I'm using to control the fade led, I wanted the servo to turn back and forth and this was a way that I could see a correlation between the led and the servo position. I've noticed that at high speed the servo seems to move normally. But when its slowed down so that it stays at each position for a short time, it buzzes and rattles, as if the signal isn't steady. Is this likely to be from the indescrepencies in time I mentioned before, due to other commands, which may or may not occur, taking up time inconsistently?
 
Last edited:
Actually unsigned char is 0...255.

Max can be found with: max=2^bit_length-1. For 8 bits that makes 2^8=256 steps and max. value is 2^8-1 = 255.

You are correct sorry heh 1 digit off... thanks
 

Attachments

  • here.jpg
    here.jpg
    151.7 KB · Views: 176
It is easy to get kTimers confused with physical timer timer0. You are talking about a kTimer.

Timer0 feeds the kTimers, is free running, and updated by an interrupt. The kTimers are exact in this sense.

In the example both tasks can execute one state (if ready) and not have the timer hit zero till they were done.

If the number of tasks and the length of your states are such that you miss the kTimer change, then waitForTimer will be false and you will go right back to the top of the task loop. The next task may run a bit late. This is a indicator that your states are too long or the system is overloaded.

If it is a busy system put the most time critical tasks at the top of the list and do not allow the anytime tasks to run in the same kTimer period.

Code:
while(1) // main loop
{
    if (!kTimer[CRITICAL])
    {
        taskCritical();
    }
    else
    {
        // other tasks here
        if (!kTimer[BLINK])
        {
            taskBlink();
        }
        if (!kTimer[BEEP])
        {
            taskBeep();
        }
    }
    while(waitForTimer);
    waitForTimer = TRUE;
}

-------------
If you were so inclined you could read timer0 and determine when time is short and go to the bottom of the loop.

3v0
 
Last edited:
Thanks. And I do realize they're different. I was just meaning that when you do this

1.Ktimer event start
2.Stuff that decides how long untill event should reoccur
3.Set Ktimer delay
4.Do other stuff in this event

But it sounds like what you're saying is that unless the next Ktimer update happens while 2 is occuring, nothing will be missed. Is that right?
 
We need to be precise with words here or it will be confusing.

But it sounds like what you're saying is that unless the next Ktimer update happens while 2 is occuring, nothing will be missed. Is that right?
As a rule the kTimer update should only happen while we are waiting at the bottom of the loop.

When we set a kTimer to 1 we get end up with 1 kTimer period plus the time left in the current kTimer period. That is not much of an error with large counts but for small counts it is significant.

So what happens when kTimers update prior to us getting to the bottom of the loop?

If it changes prior to use setting the new kTimer, the new kTimer is not effected.

If the kTimers cycle after we set the new kTimer the time will be shorted by 1 kTimer cycle minus the time it from here to the bottom the loop. In reality we loose one count but since the expected time is always a bit over it is not a full count.

3v0
 
Last edited:
Are there any suggestions you could give me about how to arrange my code to minimize error in using this multitasking method to capture a PWM servo signal? (Pulses 1.5 to 2.5 mS in length every 20mS)
 
I assume device is sending you data as a PWM signal.

It would be best to use the hardware to capture the length of the pulse and use a task to manage the hardware.

It is a good bet that there is a timer mode that starts the count when a pin goes high and stops when it goes low and sets some status bit.

Your task would have these states
Code:
1. (INIT) 
setup hardware to capture pulse length
block on hardware done flag
seq=2

2. (DOIT)  
copy pulse length to some var
clear done flag
setup hardware to capture pulse length
block on done flag
seq=2

It should be possible to do it all in software but not with near the precision. If you are interested in a software solution I can give you a hand.

3v0
 
sorry, what do you mean by doing it using hardware? You mean like the capture compare module on the chip?
 
Last edited:
I found an appnote that should make you day.

PICmicro CCP and ECCP Tips ‘n Tricks

https://www.electro-tech-online.com/custompdfs/2009/09/41214a.pdf

Check out
TIP #3 Measuring Pulse Width
1. Configure control bits CCPxM3:CCPxM0
(CCPxCON<3:0>) to capture every rising
edge of the waveform.
2. Configure Timer1 prescaler so that Timer1 will
run WMAX without overflowing.
3. Enable the CCP interrupt (CCPxIE bit).
4. When CCP interrupt occurs, save the captured
timer value (t1) and reconfigure control bits to
capture every falling edge.
5. When CCP interrupt occurs again, subtract
saved value (t1) from current captured value
(t2) – this result is the pulse width (W).
6. Reconfigure control bits to capture the next
rising edge and start process all over again
(repeat steps 3 through 6).
I would try to break the task up into 3 states and some ISR code. I used letters for the states to prevent confusion with the above steps.

(state A) step 1-2 seq=B
(state B) step 3, block on ISR finding value, seq=C
step 4 and 5 will be done in the ISR
(state C) copy or process W value, seq=A

The thing that get a bit more difficult is that you now have another source of interrupts. Also within the timer1 ISR code you need to know if you have just found a leading or a trailing edge.

My suggestion is to get the method working as simple example then break it up into states.

If it was easy everybody would do it :)

3v0
 
Last edited:
Well hey! that pretty much hands it to me. I'm just getting my PWM source going, and this should really speed things along!
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top