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.
I know so little about PIC timers. (or arm ) but i have a question since on the subject here. And not sure if you know but may benefit from a answer.

If i have 2 times on a pic can i have both on at the same time?
Also if so ... if both are on and 1 triggers. will the other continue counting?
if so.... if the other triggers then which function will i be in?
 
I learned C++ programming mostly online, though I did take one class on it. And I've taken one other computer science class that went through all sorts of math and structure concepts, but that was focused on PC programming. So I am learning MCU programming from the internet. Trying to anyway, I'm just reading whatever microchip document seems related to what I'm doing and tutorials I find online, probably similar to what you're doing. I just get stuck a lot because there's so much out there, and cause I keep having long breaks in working on this where I'm too busy for my hobby.

Anyway, once I develop a general structure for timed multitasking in C18 I'll be sure to post it, but its been slow going.

right now I'm working off of this document
https://www.electro-tech-online.com/custompdfs/2009/09/TIMER_FUNCTIONS_18F4550.pdf

and in general, the manuals for C18 released by microchip, data sheets, errata and that whole mess.
 
I have, that's actually what I was using, I just lost track of it, like I said I was away from this hobby for a few months, so I forgot where some of the resources I was using were. Thanks.

Its kind of hard to keep up a hobby when your life goes between super busy and a lot of free time, when you get a break you spend most of it just picking up where you left off. Oh well.
 
3v0 i think i finally understand that Multitasking stuff a bit thanks to your PDF. But i noticed some error or something you forgot to edit..

For instance check out page 8 on the left side the line of code:

Code:
#define DUR 500

Where since KMAX is thought of as (per your example) to be 3. should that have not been a "2" like in the appendix code?
 
I will try to create my own code following yours but with 3 task!

1. Blink LED 1/4 Second. (not half)
2. Sound speaker (just for fun)
3. Something complicated like write to a char LCD

What should happen if one TASK last to long? Would it be ok to mix some Non Multitasking like normal init stuff with some multitasking after? this way i have a normal flow of items initializing and then the multi. stuff after
 
Last edited:
What should happen if one TASK last to long?
As you know each task is broken down into states. It is up to the author to ensure that no task state runs too long. If a state runs too long other tasks that are ready to run will be delayed. In some cases that is no problem. In time critical tasks it is.
Would it be ok to mix some Non Multitasking like normal init stuff with some multitasking after?
There is no problem with running non multitasking code prior to starting multitasking. Once you start the multitasking engine any code that executes must yield or it will screw up the scheduling system.

You can also run non multitasking code after the engine is started. If you do this none of the tasks will run until you return execution to the engine. I have never done this and would look at what other implications it will have on your code.

The use of cooperative multitasking does not limit the complexity of the code or any given task. As long as you ensure that each state yields instead of waits, and never runs longer then the timer without yielding, any task length is possible.

The one thing I did not address was interrupts. The system works much better will polling. With a little work you can extend the system to block waiting for any given register flag. But putting a IO task first in the list it will execute with within 1 timer period of the interrupt.

You can use interrupts but you need to be sure the interrupt routine + any task does not exceed the length of the timer. If the interrupt happens more then once during the execution of a task state it may fall apart.

If you increase the timer duration tasks can run longer prior to yielding but it will be impossible to run tasks that require frequent execution.

Thank for the info on the error in the text.

3v0
 
heh my help was small yours help is better heh thanks. I understand it more now.

So it would be best to cut my code into sections like you did with the blink ...

Like when sending characters send about 2 to lcd then run back to main and then if free time then it will resume until all characters are sent. since this is fast most likey it shouldnt bother.

Also instead of 2 characters maybe around 5 at a time before yielding and checking if another item needs time.
 
Yes. That is a blunder on my part. DUR is just the index of a timer used for the duration. It has been fixed and uploaded thanks.

3v0

3v0 i think i finally understand that Multitasking stuff a bit thanks to your PDF. But i noticed some error or something you forgot to edit..

For instance check out page 8 on the left side the line of code:

Code:
#define DUR 500
Where since KMAX is thought of as (per your example) to be 3. should that have not been a "2" like in the appendix code?
 
heh my help was small yours help is better heh thanks. I understand it more now.
I am glad you are enjoying it.
So it would be best to cut my code into sections like you did with the blink ...
You need to cut the code into sections/states. If you do not tasks will not run on time. That is the big pain with this sort of system. But it is not that hard to do when you understand it.
Like when sending characters send about 2 to lcd then run back to main and then if free time then it will resume until all characters are sent. since this is fast most likey it shouldnt bother.
The LCD is not a fast device. LCD drivers generally either delay after each character or wait for the LCD to indicate it is ready for the next. In a multitasking system we NEVER wait or delay. Instead we yield to the next task. If your code needs to wait or delay end the state instead. If it is a delay set a kTimer to allow the the task to run after the time is up. If you are waiting setup some code to let the task run after the flag is set.

You need to write one char in the state then yield. That allows other tasks to run while the LCD is doing its job. That is where this type of multitasking shines. Instead of wasting the time waiting we are off doing other tasks.

Also instead of 2 characters maybe around 5 at a time before yielding and checking if another item needs time.
As I said above write just the one character in the state.

3v0 .... keep the posting engine happy.
 
Last edited:
You're already ahead of me Jason, I still haven't got a timer interupt to fire properly, not that I can tell anyway.
 
if i start college soon (as i plan to) i will create videos of all my workings this way i can reteach myself since ill be busy with work, school and family. i will of course share my vids. But im in no way ahead. I just understand the theory.

I think in my C18 sheet i have timer code but not 100% sure :( but as 3v0 said his code is downloadable and working . at least you can download that step through it a bit and then edit it to your liking. Then when you get better you can create a template and reuse it when ever.
 
I'm not sure what is keeping this timer interrupt from acting as expected. I know it could be a lot of thigns, since I haven't done much with timers. I'm working on modifying code from chapter 5 of this pdf (the Mplab c18 compiler users guide)

Code:
#include <p18cxxx.h>
#include <timers.h>

#define NUMBER_OF_LEDS 8

long int counter = 0;

/* 6 */ void timer_isr (void);
/* 7 */
/* 8 */ static unsigned char s_count = 0;
/* 9 */
/* 10 */ #pragma code low_vector=0x18
/* 11 */ void low_interrupt (void)
/* 12 */ {
/* 13 */ _asm GOTO timer_isr _endasm
/* 14 */ }
/* 15 */
/* 16 */ #pragma code
/* 17 */
/* 18 */ #pragma interruptlow timer_isr save=PROD
/* 19 */ void
/* 20 */ timer_isr (void)
/* 21 */ {
/* 22 */ static unsigned char led_display = 0;
/* 23 */
/* 24 */ INTCONbits.TMR0IF = 0;
			counter += 1;
/* 25 */
/* 26 */ s_count = s_count % (NUMBER_OF_LEDS + 1);
/* 27 */
/* 28 */ led_display = (1 << s_count++) - 1;
/* 29 */
/* 30 */ PORTB = led_display;
/* 31 */ }
/* 32 */
/* 33 */ void
/* 34 */ main (void)
/* 35 */ {
/* 36 */ TRISB = 0;
/* 37 */ PORTB = 0;
/* 38 */
/* 39 */ OpenTimer0 (TIMER_INT_ON & T0_SOURCE_INT & T0_16BIT);
/* 40 */ INTCONbits.GIE = 1;
/* 41 */
/* 42 */ while (1)
/* 43 */ {
/* 44 */ }
/* 45 */ }

its only slightly modified from the version in the manual, I just added a variable to increment so I can see what its doing. Then I'm trying to watch that variable using an Mplab sim watch window. It isnt increasing. It could even be a problem with varaible scope, since I haven't worked with C18 much, and as I mentioned, ive been away from it for a while. It could even be that the simulator doesnt work that way, or perhapse slower than I expect. But thats why I come to you guys, when I'm this clueless, I'll just lead myself further from the answer.

edit, forgot the details, if I monitor timer0L I get seemingly random variation, perhapse because its looping too fast for me to really tell. The counter varaible seems to stay the same.
 
Last edited:
Timer1 is classed as a peripheral and so you need to set INTCONbits.PEIE.

Mike.
 
3v0, Ive been trying your tutorial, but I'm having the same problem as when I write my own timer programs, it just sits as if the timer isn't ticking. I have the code unedited, except for arranging the files into a project so it compiles in C18, and for example, now I have it set to pattern four, and the first two LEDs light, and stay lit. I just cant get that timer to actually run.

the only warning I get is a few "call of function with out prototype" ones, referring to the part where the switch executes the led patterns.

In case any thing is wrong, or for those who haven't seen the code, here it is. The only change Ive made is to lock the selection to pattern 4, just so I know that the switching isn't the problem. I did that just recently, but the problem with stalling at the first step of the pattern was the same.

Code:
/* 
 * Junebug Demo 
 * Purpose: Demonstrate cooporative multitasking 
 *     using only the Junebug LED display
 *
 * File: DJ_coop.c 
 * Software: BoostC or Microchip C18 compilers
 * Hardware: Junebug (or other debugger + breadboarded circuit)
 *
 * by Daniel Johnson
 * July 2008
 */

#include "multiCompiler.h"   

//
// defines & macros
//
#define byte unsigned char 

#define TRUE 1
#define FALSE 0

#define LED_PATTERN_MAX 4
#define INITIAL_PATTERN_ID 2


#define COUNTER_MAX 3
#define C_DEBOUNCE 0
#define C_DELAY0 1
#define setCounter(X,Y) counter[X] = Y

#define SET_LATA(val,mask) lata_=(lata_&~mask)|(val&mask)
#define SET_TRISA(val,mask) trisa_=(trisa_&~mask)|(val&mask)
// 
// global vars
//

// counters triggered by timer0
unsigned int counter[COUNTER_MAX];

byte ledPatternChanged;
byte seenTimerInterrupt; 
  
#include "LED.c"  

//
// functions
//

// Update counters and set seenTimerInterrupt flag
void interrupt(void)
{
  byte cNum;

  intcon_.TMR0IF = 0; // always clear the IF  
  for (cNum=0; cNum<COUNTER_MAX; cNum++)
  {
    if (counter[cNum] != 0)  // hold at 0
    {
      counter[cNum]--;
    }
  }
  seenTimerInterrupt = TRUE;
}

// ---
// Read portb and determine switch settings
byte readSwitches(void)
{
  byte readVal,switchVal;

  readVal = portb_;
  switchVal = 0;
  if (!(readVal & 0x01)) switchVal += 0x01;  
  if (!(readVal & 0x04)) switchVal += 0x02;
  if (!(readVal & 0x20)) switchVal += 0x04;
  return switchVal;
}

// ---
// Determine led pattern base on switches
byte setPattern(byte switchVal)
{ 
  static byte ledPatternId_ = INITIAL_PATTERN_ID;
  
  ledPatternChanged = TRUE;

  if (switchVal==1)
  {
    ledPatternId_=0;
  } 
  else if ((switchVal==2) && (ledPatternId_<LED_PATTERN_MAX))
  {
    ++ledPatternId_;
  }  
  else if ((switchVal==4) && (ledPatternId_>0))
  {
    --ledPatternId_;
  } 
  else
  {
    ledPatternChanged = FALSE;
  }  
  return ledPatternId_;
}

//
// ---
//
void main (void)
{
  byte switchVal = 4;
  byte i, ledPatternId;
  
  // sundry setup
  {
    // speed up the clock to 8MHz, 18F1320
    osccon_.IRCF0=1;   
    osccon_.IRCF1=1;
    osccon_.IRCF2=1;
    
    // configure ports
    adcon1_ = 0xFF;    // all digital
    intcon2_.RBPU = 0; // PORTB weak pullups on
    trisb_ = 0xFF;     // all inputs
    lata_ = 0;
    trisa_ = 0;        // all outputs
  
    // configure Timer0
    t0con_ = 0xD0;  
    intcon_.TMR0IF = 0;    // clear the IF
    intcon_.TMR0IE = 1;    // Enable Timer0 overflow interrupt
    t0con__.TMR0ON = 1;
    intcon_.GIE = 1;
  }
  
  // general init 
  {
    ledScan = 1;
    ledIdx = 0;
    seenTimerInterrupt = FALSE;
    ledBits = 0x3F;
    ledPatternId = INITIAL_PATTERN_ID;
    ledPatternChanged = TRUE;
        
    // zero out the counters
    for (i=0; i<COUNTER_MAX;i++) counter[i] = 0;
  }

  while (1)
  {      
    ledPatternChanged = FALSE;
    
    // task1 - turn on the correct LEDs  
    serviceLEDs();

    // task2 - read the switches to select correct LED action
    if ((!counter[C_DEBOUNCE]) && (switchVal=readSwitches()))
    {
      setCounter(C_DEBOUNCE,1000);
      ledPatternId = setPattern(switchVal);
    }  

    // task3 - animate the LED display
	
	//for testing
	ledPatternId = 4;

    switch (ledPatternId)   
    {
      case 0:            // turn off the display
        ledBits = 0;
        break;
      case 1:            // 1st LED to blinks
        blinkLed();
        break;
      case 2:            // alternate 135 and 246
        alternateLEDs(); 
        break;
      case 3:            // 2 LEDs left to right
        marchLEDs();
        break;
      case 4:            // 2 LEDs left to right and back
        marchBackLEDs(); 
        break;
    }
    
    { // option sychronization
      #ifdef sync_loop
      while(! seenTimerInterrupt); // wait for timer interrupt
      seenTimerInterrupt = FALSE;
      #endif
    }   
  }
}
 
Last edited:
In file multicompiler.h change

Code:
  #pragma code low_vector=0x18
to
Code:
  #pragma code low_vector=0x08
Or download the new zip file which contains the fix.

This is a bug in my code that did not cause problems until Microchip changed to the new header files. I think it has now been fixed in all the project zip files.

3v0
 
Last edited:
call of function with out prototype means that function is not seen by the main.

Try adding:
Code:
void interrupt(void);
byte readSwitches(void);
byte setPattern(byte switchVal);
void main (void);

right after the:
#include "multiCompiler.h"
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top