I am teaching my self PIC programming (Oh no another noob!). Actually my code is working I have verified it by checking with an Oscilloscope. I created a simple blinking circuit and I am using Timers 0,1 and 2 to blink at different rates. I used a Timer calculator to get the rates that I am looking for. However The calculator produce spot on numbers for Timer0. Timer1 and Timer2 are off, I have tried this with 2 calculators and they all agree on the settings. When I used those settings the rate was off and I backed into the values that work.
Timer0 1 Sec, Timer1 4 Sec and Timer2, 2 sec. As I have said I have this working but I had to tweak the preload for TMR1H and TMR2. The calculators say to use 0xB for T1 but that is giving me a 5 Sec rate. If I set TMR1H to 0xE I get a 4Sec rate and the Oscilloscope confirms it. What I would like to know is why? Hopefully someone can fill in the blanks.
I have been all through the data sheet and I either dont understand something or I have missed something. Here are the details including the program. If you need additional info I can provide. My assumption is I am missing something simple.
Thanks
Chip: PIC12F1572
Programmer: PICKIT4
Compiler: XC8-22 (V2.05)
MPLAB: 5.20
CPU Clock speed: 125Hz
- Code: Select all
Timer Settings I am using
Timer Prescaler Incs/Sec Count PostScaler Preload HZ Secs Period Actual
0 256 122.07 256 1 133 0.99 1.008 2.02 134
1 2 15,625.00 65536 1 3044 0.25 3.999 8.00 3764
2 64 488.28 256 5 60 0.50 2.007 4.01 98
- Code: Select all
/*
* PIC12F1572.
*
* Pins:
* +----+
* Vdd -|1 8|- Vss
* RA5 -|2 7|- RA0/ICSPDAT ESUART TX
* RA4 -|3 6|- RA1/ICSPLCK ESUART RX
* RA3/MCLR -|4 5|- RA2
* +----+
*/
#pragma config FOSC = INTOSC // INTOSC oscillator: I/O function on CLKIN pin.
#pragma config WDTE = OFF // Watchdog Timer disable.
#pragma config PWRTE = OFF // Power-up Timer enbable.
#pragma config MCLRE = ON // MCLR/VPP pin function is MCLR.
#pragma config CP = OFF // Program memory code protection disabled.
#pragma config BOREN = ON // Brown-out Reset enabled.
#pragma config CLKOUTEN = OFF // CLKOUT function is disabled; I/O or oscillator function on the CLKOUT pin.
#pragma config WRT = OFF // Flash Memory Write protection off.
#pragma config STVREN = ON // Stack Overflow or Underflow will cause a Reset.
#pragma config BORV = LO // Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LVP = OFF // High-voltage on MCLR/VPP must be used for programming.
#include <xc.h>
#define _XTAL_FREQ 500000 // Oscillator frequency.
void init_pic();
void __interrupt() interrupt_handler(void);
//------------------------------------------------------------------------------
// Main Program Loop
//------------------------------------------------------------------------------
int main() {
init_pic();
TRISAbits.TRISA5 = 0;
LATAbits.LATA5 = 1; // Turn the LED on
TRISAbits.TRISA2 = 0; // UART RX pin an input.
LATAbits.LATA2 = 1; // Turn the LED on
TRISAbits.TRISA4 = 0; // UART RX pin an input.
LATAbits.LATA4 = 1; // Turn the LED on
while (1) {
}
}
//------------------------------------------------------------------------------
// Interrupt Handler
//------------------------------------------------------------------------------
void __interrupt() interrupt_handler(void) {
if (INTCONbits.TMR0IF == 1) {
INTCONbits.TMR0IF = 0;
TMR0 = 134;
LATAbits.LATA4 = ~PORTAbits.RA4;
}
if (PIR1bits.TMR1IF == 1) { // This is the 4 second timer
PIR1bits.TMR1IF = 0;
/*** Note ***
setting TMR1H to 0xE gives a period width of 8, I had to back into this value
setting TMR1H to 0xB gives a period width of 10, Calculator gives this value */
TMR1H = 0xE; // preset for timer1 MSB register
TMR1L = 0xE4; // preset for timer1 LSB register
LATAbits.LATA2 = ~PORTAbits.RA2;
}
if (PIR1bits.TMR2IF == 1) {
PIR1bits.TMR2IF = 0;
TMR2 = 98;
PR2 = 98;
LATAbits.LATA5 = ~PORTAbits.RA5;
}
}
//------------------------------------------------------------------------------
// Initialization Routine
//------------------------------------------------------------------------------
void init_pic() {
OSCCONbits.SPLLEN = 0; // PLL Enable
OSCCONbits.IRCF = 5; // CPU Frequency 125 kHz
OSCCONbits.SCS = 0b00; // System Clock
ANSELA = 0; // Analog off
// Timer0 Settings ---------------------------------------------------------
INTCONbits.TMR0IE = 1; // Timer0 enable
INTCONbits.TMR0IF = 0; // Timer0 Overflow flag
OPTION_REGbits.PS = 7; // Timer0 Pre-scaler Rate 256
OPTION_REGbits.PSA = 0; // Timer0 Pre-scaler Assignment
OPTION_REGbits.TMR0SE = 0; // Timer0 Source Edge Select bit
OPTION_REGbits.TMR0CS = 0; // Timer0 Clock Source Select bit
TMR0 = 0;
// Timer1 Settings ---------------------------------------------------------
// Prescaler=1:2; TMR1 Preset=3044; Freq=2.00038Hz; Period=499,968,000 ns
// ISR Timeout cycles:4T1CONbits.TMR1ON = 1; // Timer1 On/Off
T1CONbits.TMR1CS = 0; // bit 1 Timer1 Clock Source Select bit: 0=Internal clock (FOSC/4) / 1 = External clock from pin T13CKI (on the rising edge)
T1CONbits.T1CKPS1 = 0; // Timer1 Input Pre-scaler bits
T1CONbits.T1CKPS0 = 1; // Timer1 Input Pre-scaler bits
T1CONbits.nT1SYNC = 1; // bit 2 Timer1 External Clock Input Synchronization Control bit: 1=Do not synchronize external clock input
PIR1bits.TMR1IF = 0; // Timer1 Flag
PIR1bits.TMR1GIF = 0; // Timer1 Gate Flag
T1GCONbits.TMR1GE = 0; // Timer1 Gate enable ignored if TMR1ON is 1
T1GCONbits.T1GPOL = 0; // Timer1 Gate polarity
T1GCONbits.T1GTM = 0; // Timer1 Gate Toggle
T1GCONbits.T1GSPM = 0; // Timer1 Pulse mode
T1GCONbits.T1GGO_nDONE = 0;
T1CONbits.TMR1ON = 1; // bit 0 enables timer
/*** Note ***
setting TMR1H to 0xE gives a period width of 8, I had to back into this value
setting TMR1H to 0xB gives a period width of 10, Calculator gives this value */
TMR1H = 0xE; // preset for timer1 MSB register)
TMR1L = 0xE4; // preset for timer1 LSB register
// Timer2 Settings ---------------------------------------------------------
T2CONbits.TMR2ON = 1; // Timer2 On/Off
PIR1bits.TMR2IF = 0; // Timer2 Overflow flag
T2CONbits.T2CKPS = 3; // Timer2 Pre-scaler 64
T2CONbits.T2OUTPS = 9; // Timer2 Post scaler 5
PIE1bits.TMR2IE = 0; // TMR2 to PR2 Match Interrupt Enable bit
TMR2 = 0; // 8 bit register
PR2 = 0; // 8 bit register
OPTION_REGbits.INTEDG = 0b0; // Interrupt Edge Select bit
OPTION_REGbits.nWPUEN = 0b1; // WPUx registers
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
INTCONbits.INTE = 0;
INTCONbits.IOCIE = 1;
INTCONbits.INTF = 0;
INTCONbits.IOCIF = 1;