1. 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.
    Dismiss Notice

C18 Questions

Discussion in 'Microcontrollers' started by 3v0, Jun 25, 2009.

  1. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
    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?
     
  2. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    The function prototypes are required by C compilers in general. I did not include them because I was lazy.

    In this case I could do without them but that is not always the case.

    3v0
     
    Last edited: Sep 5, 2009
  3. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
    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 (text):

      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: Sep 5, 2009
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area

    I've got a bit of an odd result here, to the above I've added this:

    Code (text):

    //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: Sep 5, 2009
  6. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    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
     
  7. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    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: Sep 6, 2009
  8. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
    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: Sep 6, 2009
  9. qratman

    qratman New Member

    Joined:
    Oct 5, 2005
    Messages:
    34
    Likes:
    1
    Location:
    Estonia
    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.
     
  10. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
    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 (text):

    //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: Sep 6, 2009
  11. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    You are correct sorry heh 1 digit off... thanks
     

    Attached Files:

    • here.jpg
      here.jpg
      File size:
      151.7 KB
      Views:
      89
  12. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    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 (text):

    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: Sep 6, 2009
  13. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
    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?
     
  14. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    We need to be precise with words here or it will be confusing.

    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: Sep 6, 2009
  15. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
    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)
     
  16. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    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 (text):

    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
     
  17. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
    sorry, what do you mean by doing it using hardware? You mean like the capture compare module on the chip?
     
    Last edited: Sep 6, 2009
  18. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    Not sure I have never done this.
    There must be an example of this somewhere.
    3v0
     
    Last edited: Sep 6, 2009
  19. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
  20. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    I found an appnote that should make you day.

    PICmicro CCP and ECCP Tips ‘n Tricks

    http://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: Sep 6, 2009
  21. Triode

    Triode Member

    Joined:
    Feb 11, 2009
    Messages:
    925
    Likes:
    22
    Location:
    Bay Area
    Well hey! that pretty much hands it to me. I'm just getting my PWM source going, and this should really speed things along!
     

Share This Page