PIC Timer0 Code Generator and Calculator

I needed an easy way to calculate Microchip PIC timer 0 values, so I created the PIC Timer0 Code Generator and Calculator.  If you are not familiar with PIC timers, there is a handy tutorial HERE.

The calculator part, is a spreadsheet which calculates the timings and timer 0 frequency counter needed, given the  required timer (delay). The code generator part, is a Python script which generates the C source code for the PIC microcontroller XC8 compiler.

Here is what the spreadsheet looks like:

                    PIC TIMER0 Calculator					
					
Clock Source in Mhz                     4 Mhz			
Fosc                                    4000000	Hz			
Fosc / 4                                1000000	Hz			
Time Period                             1E-06    sec			
Prescaler                               32
Timer0 Interrupt Period                 0.008192 sec
Period of Frequency Input To Timer0     3.2E-05  sec
Period of Time for each Timer0 Count    0.008192 sec
					
Preload (TMR0 value)                    6
Delay (Timer0 Period with Preload)      0.008	sec		0.008	sec
					
Required Timer                          1	sec
Number of Interrupts                    125	

Basically, the required timer (i.e. delay) in seconds is specified along with the clock source in Mhz and the prescaler. Optionally a value can be specified for the TMR0 preload to adjust the timing.  All the other values are automatically calculated.  From the example, a 1 second delay is specified with a clock of 4Mhz,  prescaler is 32 and preload is 6.  The calculations show that 125 timer 0 interrupts will take 1 second.

The spreadsheet calculator can be downloaded from HERE.

In these examples, I use the PIC12F675 programmed with a PicKit2 programmer:

PIC Timer0 Code Generator and CalculatorPIC12F675

 

 

 

 

However, even though I use a PIC12F675 for the PIC Timer0 Code Generator and Calculator, it can easily be adapted to any other PIC microcontroller which needs timer 0 calculations. Actually, the spreadsheet part works works for any PIC since it does not generate code. The Python script, which generates code, would only need minor changes for other PIC microcontrollers.

Here is the Python script (gentimer0.py) which generates the C code:

#!/bin/env python
#from earl@microelectronics.com

import os,sys

if (len(sys.argv) < 4):
  print("Syntax: %s clock prescaler TMR0 period") % (sys.argv[0]) 
  sys.exit()

Clock     = int(sys.argv[1])
Prescaler = int(sys.argv[2])
TMR0      = int(sys.argv[3])
Period    = int(sys.argv[4])

print("")
print("//                      _________   __________")
print("//                     |         \\_/          |")
print("//                   __|      _               |__")
print("//                  |  | Vdd (_)          Vss |  |")
print("//        Vdd`  +5V |1 |                      | 8| 	VSS")
print("//                  |__|                      |__|")
print("//                     |                      |")
print("//                   __|                      |__")
print("//                  |  |              ICSPDAT |  |")
print("// GP5 / T1CKI      |2 |                      | 7| GP0 / AN0 / CIN+")
print("//   CLKIN          |__|                      |__| ICSPDAT / ULPWU")
print("//                     |                      |")
print("//                   __|                      |__")
print("//                  |  |              ICSPCLK |  |")
print("// T1G / AN3 / GP4  |3 |                      | 6| GP1 / AN1 / CIN- /Vref")
print("//  OSC2 / CLKOUT   |__|                      |__| ICSPCLK")
print("//                     |                      |")
print("//                   __| ____                 |__")
print("//                  |  | MCLR/Vpp             |  |")
print("// GP3 / MCLR / VPP |4 |                      | 5| GP2 / AN2 / T0CKI / INT")
print("//                  |__|                      |__| COUT / CCP1")
print("//                     |      PIC12F675       |")
print("//                     |______________________|")
print("//")
print("/*")
print("")
print("       PIC TIMER0 Calculator")
print("")

Fosc       = Clock * 1000000.0
Fosc4      = Fosc / 4.0
Cycle      = 1.0 / Fosc4
IntPeriod  = 1.0 / ( Fosc4 / Prescaler / 256)
FreqPeriod = 1.0 / ( Fosc4 / Prescaler)
TCount     = 256 * FreqPeriod
Delay      = ((256 - TMR0) * (Prescaler * 4)) / Fosc
NumInts    = Period / Delay

print("Clock Source in Mhz                   %s Mhz") % (Clock)
print("Fosc                                  %s Hz")  % (Fosc)
print("Fosc / 4                              %s Hz")  % (Fosc4)
print("Time Period                           %s sec") % (Cycle)
print("Prescaler                             %s")     % (Prescaler)

print("Timer0 Interrupt Period               %s sec") % (IntPeriod)
print("Period of Frequency Input To Timer0   %s sec") % (FreqPeriod)
print("Period of Time for each Timer0 Count  %s sec") % (TCount)
print("		")
print("Preload (TMR0 value)                  %s")     % (TMR0)
print("Delay                                 %s	sec") % (Delay)
print("		")
print("Required Timer                        %s sec") % (Period)
print("Number of Interrupts                  %s")     % (NumInts)
print("")
print("*/")
print("")
print("//  xc8 --chip=12F675 main.c")
print("")
print("// CONFIG")
print("#pragma config FOSC  = INTRCIO  // Oscillator Selection bits")
print("                                // (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)")
print("#pragma config WDTE  = OFF      // Watchdog Timer Enable bit (WDT disabled)")
print("#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)")
print("#pragma config MCLRE = OFF      // GP3/MCLR pin function select")
print("                                // (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)")
print("#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)")
print("#pragma config CP    = OFF      // Code Protection bit (Program Memory code protection is disabled)")
print("#pragma config CPD   = OFF      // Data Code Protection bit (Data memory code protection is disabled)")
print("")
print("#include <xc.h>")
print("")
print("#define _XTAL_FREQ %s") % (int(Fosc))
print("")
print("#define Timer0_Counter %s //Timer0 interrupt count") % (int(NumInts)) 
print("unsigned int cycles = 0;")
print("")
print("void interrupt isr(void) {")
print("//If T0IF: TMR0 Overflow Interrupt Flag bit equal 1, service timer interrupt")
print("  if (T0IF == 1) { ")
print("    cycles++;")
print("    TMR0 = %s;  // Preload timer register") % (TMR0)
print("    T0IF = 0;")
print("  }")
print("} ")
print("")
print("void main(void) {")
print("  OSCCAL     = __osccal_val(); // Load Oscillator Calibration")
print("  VRCON      = 0x00;           // Disable voltage reference")
print("  CMCON      = 0b00000111;     // Disable comparator")
print("  ANSEL      = 0x00;           // A/D disabled")
print("  GPIO       = 0;              // Clear GPIO")
print("  TRISIO     = 0b00001111;     // Set GPIO4 AND GPIO5 as outputs. Set GPIO0, GPIO2, GPI01 and GPIO3 as inputs")
print("  WPU        = 0;              // Disable all weak pull up")
print("  INTCON     = 0b10100000;     // Global Interrupt Enabled and TMR0 Overflow Interrupt Enabled")
print("  TMR0       = % -8s;       // Preload timer register") % (TMR0)

if (Prescaler == 2):   print("  OPTION_REG = 0b00000000;     // Start Timer0 and set Prescaler to 1:2")
if (Prescaler == 4):   print("  OPTION_REG = 0b00000001;     // Start Timer0 and set Prescaler to 1:4")
if (Prescaler == 8):   print("  OPTION_REG = 0b00000010;     // Start Timer0 and set Prescaler to 1:8")
if (Prescaler == 16):  print("  OPTION_REG = 0b00000011;     // Start Timer0 and set Prescaler to 1:16")
if (Prescaler == 32):  print("  OPTION_REG = 0b00000100;     // Start Timer0 and set Prescaler to 1:32")
if (Prescaler == 64):  print("  OPTION_REG = 0b00000101;     // Start Timer0 and set Prescaler to 1:64")
if (Prescaler == 128): print("  OPTION_REG = 0b00000110;     // Start Timer0 and set Prescaler to 1:128")
if (Prescaler == 256): print("  OPTION_REG = 0b00000111;     // Start Timer0 and set Prescaler to 1:256")

print("")
print("  GP4 = 1;")
print("  while (1) {")
print("    if (cycles >= Timer0_Counter) {")
print("      cycles = 0;")
print("// Add code here - timer expired")
print("      GP4 ^= 1; // Toggle LED on GP4")
print("")
print("    }")
print("// Main Code goes here")
print("")
print("  }")
print("}")

Here is the command to run it:

./gentimer0.py 4 32 6 1 >timer.c

and here is the resultant output:

//                      _________   __________
//                     |         \_/          |
//                   __|      _               |__
//                  |  | Vdd (_)          Vss |  |
//        Vdd`  +5V |1 |                      | 8| 	VSS
//                  |__|                      |__|
//                     |                      |
//                   __|                      |__
//                  |  |              ICSPDAT |  |
// GP5 / T1CKI      |2 |                      | 7| GP0 / AN0 / CIN+
//   CLKIN          |__|                      |__| ICSPDAT / ULPWU
//                     |                      |
//                   __|                      |__
//                  |  |              ICSPCLK |  |
// T1G / AN3 / GP4  |3 |                      | 6| GP1 / AN1 / CIN- /Vref
//  OSC2 / CLKOUT   |__|                      |__| ICSPCLK
//                     |                      |
//                   __| ____                 |__
//                  |  | MCLR/Vpp             |  |
// GP3 / MCLR / VPP |4 |                      | 5| GP2 / AN2 / T0CKI / INT
//                  |__|                      |__| COUT / CCP1
//                     |      PIC12F675       |
//                     |______________________|
//
/*

       PIC TIMER0 Calculator

Clock Source in Mhz                   4 Mhz
Fosc                                  4000000.0 Hz
Fosc / 4                              1000000.0 Hz
Time Period                           1e-06 sec
Prescaler                             32
Timer0 Interrupt Period               0.008192 sec
Period of Frequency Input To Timer0   3.2e-05 sec
Period of Time for each Timer0 Count  0.008192 sec
		
Preload (TMR0 value)                  6
Delay                                 0.008	sec
		
Required Timer                        1 sec
Number of Interrupts                  125.0

*/

//  xc8 --chip=12F675 main.c

// CONFIG
#pragma config FOSC  = INTRCIO  // Oscillator Selection bits
                                // (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE  = OFF      // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // GP3/MCLR pin function select
                                // (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP    = OFF      // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD   = OFF      // Data Code Protection bit (Data memory code protection is disabled)

#include <xc.h>

#define _XTAL_FREQ 4000000

#define Timer0_Counter 125 //Timer0 interrupt count
unsigned int cycles = 0;

void interrupt isr(void) {
//If T0IF: TMR0 Overflow Interrupt Flag bit equal 1, service timer interrupt
  if (T0IF == 1) { 
    cycles++;
    TMR0 = 6;  // Preload timer register
    T0IF = 0;
  }
} 

void main(void) {
  OSCCAL     = __osccal_val(); // Load Oscillator Calibration
  VRCON      = 0x00;           // Disable voltage reference
  CMCON      = 0b00000111;     // Disable comparator
  ANSEL      = 0x00;           // A/D disabled
  GPIO       = 0;              // Clear GPIO
  TRISIO     = 0b00001111;     // Set GPIO4 AND GPIO5 as outputs. Set GPIO0, GPIO2, GPI01 and GPIO3 as inputs
  WPU        = 0;              // Disable all weak pull up
  INTCON     = 0b10100000;     // Global Interrupt Enabled and TMR0 Overflow Interrupt Enabled
  TMR0       = 6       ;       // Preload timer register
  OPTION_REG = 0b00000100;     // Start Timer0 and set Prescaler to 1:32

  GP4 = 1;
  while (1) {
    if (cycles >= Timer0_Counter) {
      cycles = 0;
// Add code here - timer expired
      GP4 ^= 1; // Toggle LED on GP4

    }
// Main Code goes here

  }
}

The source is complied (via the Microchip XC8 compiler) with this command:

/opt/microchip/xc8/v1.45/bin/xc8 --chip=12F675 timer.c

Then use the PicKit2 programmer:

PICKit2 Clone Programmerwith the command:

/opt/microchip/pk2cmd-master/pk2cmd/pk2cmd -PPIC12F675 -Ftimer.hex -M -B/opt/microchip/pk2cmd-master/pk2cmd/

to send it to the chip.
PIC Timer0 Code Generator and CalculatorNotice, that /opt/microchip/ is where I have installed he XC8 compiler and the PicKit2 software (pk2cmd).  If you have an LED on GPIO pin4, it will blink every 1 second. Basically with this code generator, one has a starting point template to add to. The comments in the code show where to put code to make it more useful.

Leave a Reply

Your email address will not be published.