PIC18F asm pin control

Discussion in 'Embedded Systems and Microcontrollers' started by Sparky49, Jun 2, 2014.

  1. Sparky49

    Thread Starter Active Member

    Jul 16, 2011
    834
    417
    Hi all,

    I'm currently working on a project where I would like to be able to turn on and off individual pins across different ports of a P18F. Ideally, I would like to be able to tell one pin to go high for x amount of time, but also control other pins whilst that pin is still high.

    I've drawn this little sketch to try to show what I mean.

    [​IMG]

    Basically, is there a way to get the pic to 'keep track' of where, say, the a0 time is at, whilst still being able to switch b2, and c1? It seems to me that if the delay is running for a0, it can't continue whilst I set b2 high. Of course, this is with my limited knowledge, just curious if there is a way to do it.

    I could set shorter delays for a0, until I need to turn b2 on, but that starts to make things a bit more confusing.

    Anyhow, thanks for your time. I realise that I have perhaps not explained my thinking very well, but if it is too confusing, please say, and I will do my best to rethink.

    Best regards,

    Sparky
     
  2. MaxHeadRoom

    Expert

    Jul 18, 2013
    10,552
    2,374
    Rather than a software delay, why not use a timer to detect the time you require to set A0 for. and interrupt if neccessary?
    Max.
     
    Sparky49 likes this.
  3. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    You've encountered the problem with using dumb delays - its hard to get anything else done. While you can use ad-hoc ways of splitting delays up into some small fraction and run around doing multiples of that, I do it like this.

    First, configure an interrupt controlled timer (TMR2/PR2 works nicely) to provide an interrupt at some small interval. Lets say 1 ms. Tik tik.

    Second, set up as many registers as you need that get decremented to 0 and stay there on each 1 ms SystemTik. These are derived timers. Code like this - 3 timers for 3 LEDs:
    Code ( (Unknown Language)):
    1. movf time1_tiks,F ; decrement derived timer 1 to 0 then stop
    2.  skpz
    3.  decf time1_tiks,F
    4.  
    5. movf time2_tiks,F ; ..and derived timer 2
    6.  skpz
    7.  decf time2_tiks,F
    8.  
    9. movf time3_tiks,F ; decrement to 0 then stop
    10.  skpz
    11.  decf time3_tiks,F
    Next, in your code, you break each LED into its own little functional block. To turn it on load the timer, it turns off when the timer runs out. These little blocks are in turn called from a master main loop, each doing its own thing but NEVER waiting by using a dumb delay.

    Since you'll be leaving each LED block each time there is nothing to do e.g. still timing, you'll need a way to know in which state you left it. Sometimes a flag or just looking at the timer is sufficient, for more advanced stuff, you can use a state machine.

    For LEDs, I'll frequently combine something like this with a control string which is parsed to do the LED. Sequences of coded data are easy to do. A typical control string might look like this:
    Code ( (Unknown Language)):
    1. dt 1,.50 ; turn it on for 50 tiks
    2. dt 0,.100 ; turn it off for 100 tiks
    3. dt 0,0   ; end of pattern, repeat from the top
    You would parse the string using table lookups. For this the table index is the state indicator.:
    Fetch the first byte. It says turn the LED on. Fetch the next byte and set the timer then return.

    When called again, look at the timer. If <>0 yet, return.

    Do for each call until the timer is 0;

    Fetch the next pair, it turns the LED off and sets the timer for 100 tiks.

    When the timer runs out again, fetch the next pair - this time its 0,0 so reset the index and restart. Done. Make a different string for each LED pattern you need.

    That's only one of many ways to do it but the main point is to write all functions so that they never hold the CPU.

    Its simpler to do than to say.. give it a try.

    Good luck.

    Edit: good to see Max is on board as well
     
    Sparky49 likes this.
  4. Sparky49

    Thread Starter Active Member

    Jul 16, 2011
    834
    417
    Thanks, guys.

    The advice makes sense. I'll read it through a couple more times, to hopefully fully understand, but again, thanks.

    One thing I am not too sure about is the individual string for each output combination. I intend to have 88 outputs (a lot, yep :p), wouldn't that result in me having to create 2e^134 strings?

    Sparky

    P.S. Any other posts/advice is always welcome!
     
    Last edited: Jun 2, 2014
  5. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    Boy howdy, you just overflowed the 'Lil Professor so.. no, you don't.

    If you have 88 independent outputs whose operation is unrelated to each other, you need 88 tasks to control them. If one task controls more than one output e.g. alternating LEDs, then you don't need as many. Look at it from a task point of view i.e. how many different functions are happening at once, each controlling whatever output(s) it needs to do the task.

    The string example is just a way to implement a task, in this case flash an LED. You could do the same thing by inspecting the current state of the LED and just doing the opposite. I threw the string idea in so that you could see a way to do more than just regular flashing, you can do patterns. If a pattern uses a group of LEDs, one of the bytes could determine which LEDs in the group are on and off on each tik.

    Other tasks will require other implementation strategies. The key is to do what has to be done at a particular time, maybe in response to external events (pushbutton?), remember what you were doing, then leave to do other things. Upon returning, resume from what you were doing and see if its time to do the next thing.

    If this sounds like a state-machine running each function (task), you're right. The couple of ways of doing LEDs I described are simple state-machines.

    Whew!
     
    Sparky49 likes this.
  6. Sparky49

    Thread Starter Active Member

    Jul 16, 2011
    834
    417
    Hehehe, I'm glad the processor would overflow before I would. :D

    Understood with regards to the string.

    I'm hoping to use it to control a series of oscillators to create some tunes - kind of like a player piano. I have thought about creating a paper tape 'memory', which is read by a series of phototransistors (instead of air). But rather than try to do everything at once, I thought I would see about controlling the oscillators (really just astable 555's) with a uC.

    Perhaps I am going about this entirely the wrong way, feel free to offer any ideas. :)

    Sparky

    P.S. I loved the 'Boy howdy', made my day!
     
  7. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    May I ask if there's a least common denominator, in terms of times allotted to these LED outputs? For example, could you use increments of 25-msecs for the on times and off times of the LEDs?

    Also, what logic or events will be used to trigger these LED outputs? Will you be using push button inputs or something else?

    Answering these questions may significantly affect your program design.

    Cheerful regards, Mike
     
    Sparky49 likes this.
  8. Sparky49

    Thread Starter Active Member

    Jul 16, 2011
    834
    417
    Hi MMcLaren. Thanks for the reply.

    I can't see where people think I am turning on and off LEDs? Sorry if I've been misleading.

    I plan to program the sequence myself. Much like the old player pianos would be programmed with a roll of moving paper, I eventually hope to create something similar. However to begin with, I would like to program the output in a uC, and control the oscillators with the uC.

    There would be no input (aside from perhaps a start switch, but even I can handle that), just a preprogrammed melody.

    Regards,

    Sparky
     
  9. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
    Are these melodies played with chords or just single notes?

    Let's look at the latter case first. Let the uC generate the tones. Create a function that takes frequency (or note) and duration as input. One output/ task. Not 88.

    Then, you create a table of those value pairs and call the function.

    If it is chords, then parallelizing the tone generation presents another challenge. One that can be resolved using timer interrupts. Even then, you're probably talking about four tasks rather than 88.
     
    Sparky49 likes this.
  10. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Perhaps you could store it as a timestamp and then just several bytes with a bit for each pin. Every time you want a pin (or pins) to change, just put the time difference since the last change (maybe a 16 bit number and 1/100ths of a second) and then the state that you want all the pins to be in. Of course this uses program memory pretty fast, you only get 78 changes per 1k of code with 88 notes (11 bytes) and 2 bytes of timestamp.
    <ed> You could add a few special cases to save a bit of space, eg use the timestamp 0xFFFF to mean all notes off </ed>
     
    Last edited: Jun 2, 2014
    Sparky49 likes this.
  11. Sparky49

    Thread Starter Active Member

    Jul 16, 2011
    834
    417
    This include chords. Again, this is trying to emulate the player pianos, which could play all 88 notes at once, if need be.

    I'll be back at home this weekend, so hopefully I'll have some progress to post up. :)

    Sparky
     
  12. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    My little LED Sequencer Demo in the completed projects sub-forum did something like this for eight pins. The sequence was contained in tables and each table entry (element) included a byte for the output "pattern" and a byte for the "duration" (1-255 -> 10..2550 msecs). The very simple assembly launguage program could probably be expanded quite easily. A newer version posted on another forum uses a 16F1828 "enhanced mid-range" device.

    Good luck. Mike
     
    Last edited: Jun 2, 2014
    Sparky49 likes this.
  13. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Thanks for finally posting the actual application. :)

    I did a project with a single PIC playing up to 8 notes simultaneously, generating the actual notes in the PIC and output on 8 digital output pins.

    It was not that easy, especially if you have overheads for note sequencing. The timeslice was pretty full. There's no way the PIC18F would have done 16 separate notes and sequencing simultaneously (not with that quality anyway), never mind 88!

    Even if you are not generating the note frequency (sound) onboard the PIC, sequencing and OUTPUTTING 88 sets of note data is a massive task.

    How can you simplify this task? The reason player pianos had 88 data lines was to make it easier to drive the 88 available notes. You don't have that limitation!

    How many notes need to play at once, in your data? Probably not more than 10 (human fingers on a piano)?

    If so, you only need to play back 10 streams, with note data and on/off data. That is now quite do-able.
     
    Sparky49 likes this.
Loading...