General Information

Announcements
Web Resources
Other IAP classes

Lectures

1. The Basics
2. Timing, analog hack
3. IR (sony, irda)
4. Our favorite add-ons

Labs

1. Assembling the board.
2. Intro to programming.
3. Input/Output/IR
4. Your own project?
Hack Your Room:
Introduction to Microcontrollers

Timing

The Four-Fold Way of Timing:
  • Loops:

    Loops are the cheesiest way to handle timing on the pic. They are dependent on clock speed, so they make for hard-to-maintain code; if you go from a 10 MHz clock to an 8 MHz clock, you have to change all the while values appropriately. But if you did use loops for timing, it would look like:

      // generate a 4 us pause (if you have a 10 MHz crystal)
      int i;
    
      for (i = 0; i < 100; i++)
        ;
    

    Be warned, too, that an int is only 8 bits in CCS, so this loop will go forever:

      // you might think this pauses for 12 us, but really it loops forever!
      int i;
    
      for (i = 0; i < 300; i++)
        ;
    
  • delay_us(), delay_ms()

    The "right" way to handle timing for little pauses is with delay_xx. This makes use of the preprocessor directive DELAY, so porting to a different crystal is cake. Examples:

      // pause for 20 milliseconds
      delay_ms(20);
    
      // pause for 200 microseconds
      delay_us(200);
    
      // if you are using constants, you can use a 16 bit argument
      // (variable arguments are limited to 8 bits... just another
      // charming "feature" of PICC)
      delay_ms(1000); // 1 second delay
    
      i = 1000;
      delay_ms(i); // 1000 % 256 = 232 millisecond delay
    
  • Timer0 and Interrupts

    For more complicated programs (like ones that time something, while doing something, the name of the game is interrupts.

    On the 16F84, these interrupts are conveniently generated by timer zero. To make things confusing timer0 is also called counter0 and RTCC. In PICC, you can get access to it by including the code:

    struct {
      short int RBIF;
      short int INTF;
      short int T0IF;
      short int RBIE;
      short int INTE;
      short int T0IE;
      short int PEIE;
      short int GIE;
    } INTCON;
    #byte INTCON= 0x0B
    

    This makes a structure called INTCON. Whenever timer0 rolls over, INTCON.T0IF is set to 1. So if you set it to zero, and then look at it and it's one, you know something happened.

    The other important functions for making this work are set_rtcc(int val) which sets the timer, and setup_counters(RTCC_INTERNAL, RTCC_DIV_xxx) which sets the prescaler.

    See beeper.c for an example.

    The tricky part is the line

      TMR0 = 256 + 2 - NTICS;
    
    The magic +2 is in there because after you change the counter value it takes two ticks before it starts running again.

  • Watchdog Timer

    The Watchdog Timer is key to low power programming. It is also designed for mission critical programs. If it is not reset in about 18 milliseconds, it will power cycle the PIC, unless the PIC is sleeping, in which case instead of cycling the power, it makes the chip wake up. The key functions to making this work are:

    restart_wdt();
    sleep();
    
  • and don't forget to have a #fuses wdt at the beginning.

A perfect application of the precise timing the pic is the analog hack, temper.c.

We also talked a little about RS232 serial protocol and IrDA.