How do I modify my PIC microcontroller program to deliver 150 hz also with the existing 1hz output

Thread Starter

Arjune

Joined Jan 6, 2018
354
The 32khz crystal works with this program but I need the output to be twice as fast: 0.5sec on and 0.5sec off. Please tell me how and what code to change. I didn't check for accuracy yet'. I am using the secondary oscillator Timer 1. I had to disconnect the crystal circuit prior to programming because of the two shared pins. After programming I disconnected the Pickit3 leads and reconnected the crystal circuit. Do I preload TMR1 to 65,536 (0x10000)? If so, what would TMR1H and TMR1L be?

Code:
#include <xc.h>

// Configuration Bits
#pragma config FOSC = INTOSCIO  // Use internal osc, RB6/RB7 free
#pragma config WDTE = OFF       // Watchdog Timer Disabled
#pragma config PWRTE = ON       // Power-up Timer Enabled
#pragma config MCLRE = OFF      // MCLR pin is digital I/O
#pragma config BOREN = OFF      // Brown-out Detect Disabled
#pragma config LVP = OFF        // Low-Voltage Programming Disabled

#define _XTAL_FREQ 4000000      // Internal 4MHz osc

void __interrupt() ISR(void) {
    // Check if Timer1 Overflow occurred
    if (PIR1bits.TMR1IF) {
        // Toggle output pin (RB0)
        PORTBbits.RB0 = ~PORTBbits.RB0;

        // Reset Timer1: To get 1Hz (1s), we want to interrupt
        // every 32,768 counts. The 16-bit timer overflows at 65536.
        // Preload TMR1 to 32768 (0x8000)
        TMR1H = 0x80;
        TMR1L = 0x00;

        PIR1bits.TMR1IF = 0; // Clear interrupt flag
    }
}

void main(void) {
    // Port Configuration
    TRISBbits.TRISB0 = 0; // RB0 as output
    PORTBbits.RB0 = 0;    // Initial state
    CMCON = 0x07;         // Turn off comparators

    // Timer1 Configuration
    T1CON = 0b00001111;   // External clock, Async, Osc Enabled, TMR1 On
    // Bits: 7-6: Unused
    //       5-4: T1CKPS1:T1CKPS0 = 00 (1:1 Prescaler)
    //       3: T1OSCEN = 1 (External 32kHz oscillator enabled)
    //       2: T1SYNC = 1 (Do not sync external clock)
    //       1: TMR1CS = 1 (External clock from T1OSI/T1OSO)
    //       0: TMR1ON = 1 (Timer1 on)

    // Interrupt Configuration
    TMR1H = 0x80;         // Preload for 1 second
    TMR1L = 0x00;
    PIE1bits.TMR1IE = 1;  // Enable Timer1 Interrupt
    INTCONbits.PEIE = 1;  // Enable Peripheral Interrupts
    INTCONbits.GIE = 1;   // Enable Global Interrupts

    while (1) {
        // Main loop does nothing, interrupts handle the timing
    }
}
 
Last edited:
Ahhhh ... internal OSC and async counter ...

OK. For toggling 2 times per 1Hz, you need a value of -(32768/Hz)/(2/1Hz) = -16384 = C000h.

With INTOSC running the CPU, there are about 30 instructions per 32768Hz period, so you can write to both bytes without much unhappiness. (LesJones in #74 found that the writing takes place after about 15 instructions, or half-way through the first 32768Hz period after the rollover.) Also, prioritize getting TMR1L written before it increments. (Write to TMR1L before TMR1H.)

1/2 second interrupt for 32.768kHz external async counter:
        // Reset Timer1: To get 1Hz (1s), we want to interrupt
        // every 16,384 counts and toggle 2 times per second.
        // The 16-bit timer overflows at 65536.
        // Preload TMR1 to 65536-16384 (0xC000)
        TMR1L = 0x00;
        TMR1H = 0x0C0;
 
Last edited:
Took another look at the code. Originally thought that you set TMR1 and then toggled RB0. Did not realize that you were toggling first.

The code that the C compiler generates for toggling takes several instruction cycles. You are racing the 32kHz clock source. You must get TMR1L taken care of before the next 32kHz counting edge arrives; the other two steps have plenty of margin.

So, first, quickly do TMR1L. Then you can do TMR1H and RB0 at a relaxed pace.

title:
        // Reset Timer1: To get 1Hz (1s), we want to interrupt
        // every 16,384 counts and toggle 2 times per second.
        // The 16-bit timer overflows at 65536.
        // Preload TMR1 to 65536-16384 (0xC000)
        TMR1L = 0x00;
        TMR1H = 0x0C0;

        // Toggle output pin (RB0)
        PORTBbits.RB0 = ~PORTBbits.RB0;
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
As mentioned earlier
You can't take a circuit designed for day a 16 MHz crystal , and expect it to work with the 32.768 Khz
It's like trying to use jet fuel or diesel , similar but different.
How did you change your circuit to accept the 32.768 Khz ,
I used the same connection on pin 15 and 16 without a 100k resistor but it didn't work so I tried the secondary oscillator at RB6 and RB7 and that worked but I didn't try the Assembly language. I used the program in post number 83
 
Last edited:

Thread Starter

Arjune

Joined Jan 6, 2018
354
Took another look at the code. Originally thought that you set TMR1 and then toggled RB0. Did not realize that you were toggling first.

The code that the C compiler generates for toggling takes several instruction cycles. You are racing the 32kHz clock source. You must get TMR1L taken care of before the next 32kHz counting edge arrives; the other two steps have plenty of margin.

So, first, quickly do TMR1L. Then you can do TMR1H and RB0 at a relaxed pace.

title:
        // Reset Timer1: To get 1Hz (1s), we want to interrupt
        // every 16,384 counts and toggle 2 times per second.
        // The 16-bit timer overflows at 65536.
        // Preload TMR1 to 65536-16384 (0xC000)
        TMR1L = 0x00;
        TMR1H = 0x0C0;

        // Toggle output pin (RB0)
        PORTBbits.RB0 = ~PORTBbits.RB0;
Okay I'll try tomorrow
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
Okay I'll try tomorrow
It appears to be clocking properly-1hz, 0.5 seconds on and off. I made a mistake in the code of post 83-line 22, I put TMR1H = 0x00; instead of TMR1L = 0x00; like @ThatsHimOfficer said but after programming it works. I'll check it after several hours. I'm using the 628a because of a wrong device Id message on the 627a. This happened with several of my chips-including the 628a so I discarded several chips.
 
Last edited:

drjohsmith

Joined Dec 13, 2021
1,630
The 32khz crystal works with this program but I need the output to be twice as fast: 0.5sec on and 0.5sec off. Please tell me how and what code to change. I didn't check for accuracy yet'. I am using the secondary oscillator Timer 1. I had to disconnect the crystal circuit prior to programming because of the two shared pins. After programming I disconnected the Pickit3 leads and reconnected the crystal circuit. Do I preload TMR1 to 65,536 (0x10000)? If so, what would TMR1H and TMR1L be?

Code:
#include <xc.h>

// Configuration Bits
#pragma config FOSC = INTOSCIO  // Use internal osc, RB6/RB7 free
#pragma config WDTE = OFF       // Watchdog Timer Disabled
#pragma config PWRTE = ON       // Power-up Timer Enabled
#pragma config MCLRE = OFF      // MCLR pin is digital I/O
#pragma config BOREN = OFF      // Brown-out Detect Disabled
#pragma config LVP = OFF        // Low-Voltage Programming Disabled

#define _XTAL_FREQ 4000000      // Internal 4MHz osc

void __interrupt() ISR(void) {
    // Check if Timer1 Overflow occurred
    if (PIR1bits.TMR1IF) {
        // Toggle output pin (RB0)
        PORTBbits.RB0 = ~PORTBbits.RB0;

        // Reset Timer1: To get 1Hz (1s), we want to interrupt
        // every 32,768 counts. The 16-bit timer overflows at 65536.
        // Preload TMR1 to 32768 (0x8000)
        TMR1H = 0x80;
        TMR1L = 0x00;

        PIR1bits.TMR1IF = 0; // Clear interrupt flag
    }
}

void main(void) {
    // Port Configuration
    TRISBbits.TRISB0 = 0; // RB0 as output
    PORTBbits.RB0 = 0;    // Initial state
    CMCON = 0x07;         // Turn off comparators

    // Timer1 Configuration
    T1CON = 0b00001111;   // External clock, Async, Osc Enabled, TMR1 On
    // Bits: 7-6: Unused
    //       5-4: T1CKPS1:T1CKPS0 = 00 (1:1 Prescaler)
    //       3: T1OSCEN = 1 (External 32kHz oscillator enabled)
    //       2: T1SYNC = 1 (Do not sync external clock)
    //       1: TMR1CS = 1 (External clock from T1OSI/T1OSO)
    //       0: TMR1ON = 1 (Timer1 on)

    // Interrupt Configuration
    TMR1H = 0x80;         // Preload for 1 second
    TMR1L = 0x00;
    PIE1bits.TMR1IE = 1;  // Enable Timer1 Interrupt
    INTCONbits.PEIE = 1;  // Enable Peripheral Interrupts
    INTCONbits.GIE = 1;   // Enable Global Interrupts

    while (1) {
        // Main loop does nothing, interrupts handle the timing
    }
}
what happens when you try changing these values ?
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
what happens when you try changing these values ?
The pulse is twice as fast or about 1 sec in total frequency. Unfortunately in about 5 hours it ran about 1 second fast. I can't rely on the microcontroller method to generate 1hz to drive a clock.
 

drjohsmith

Joined Dec 13, 2021
1,630
The pulse is twice as fast or about 1 sec in total frequency. Unfortunately in about 5 hours it ran about 1 second fast. I can't rely on the microcontroller method to generate 1hz to drive a clock.
What is stoping you using the microcontroller method , what's causing the trimming drift you quote ?
 

LesJones

Joined Jan 8, 2017
4,522
Have you used the values capacitors reccomended by the crystal manufacturer ? Even if you have you may need to add a trimmer capacitor to fine tune the frequency of the crystal. Have you considdered building a radio controled clock ? There are time standard tronsmitters in Cumria England and Farnkfurt Gemany so I would expedt there to be some in the US. There are also standard frequency tranmitters in the US the you could phase lock an oscillator to.
Les.
 

Futurist

Joined Apr 8, 2025
926
The pulse is twice as fast or about 1 sec in total frequency. Unfortunately in about 5 hours it ran about 1 second fast. I can't rely on the microcontroller method to generate 1hz to drive a clock.
What kind of precision are you aiming for? 1 second/month , 1 second/decade? what are you comparing to? I mean what is your reference clock?
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
What is stoping you using the microcontroller method , what's causing the trimming drift you quote ?
I'm just frustrated with the microcontroller method. I have confidence in my 32khz crystal, people are just not existential in thought like me. The drift may be caused by unseen intelligence wishing me bad.
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
Have you used the values capacitors reccomended by the crystal manufacturer ? Even if you have you may need to add a trimmer capacitor to fine tune the frequency of the crystal. Have you considdered building a radio controled clock ? There are time standard tronsmitters in Cumria England and Farnkfurt Gemany so I would expedt there to be some in the US. There are also standard frequency tranmitters in the US the you could phase lock an oscillator to.
Les.
I'm want to keep things simple. My clairvoyance indicates any capacitor within 10-22 pf would work--why should I struggle with a trimmer capacitor?
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
What kind of precision are you aiming for? 1 second/month , 1 second/decade? what are you comparing to? I mean what is your reference clock?
1 second every 2 months would be nice. My reference clock is a clock I built using a timing unit from a wall clock chat uses a AA battery and it's accurate.
 

drjohsmith

Joined Dec 13, 2021
1,630
I'm just frustrated with the microcontroller method. I have confidence in my 32khz crystal, people are just not existential in thought like me. The drift may be caused by unseen intelligence wishing me bad.
The drift is because the crystal / resonator has a tolerance on it
Or because the code has the wrong divide.
The circuit further pulls the frequency
To get accurate long term time , you need to check where the error is, and maybe use an external oscillator , say 1 ppm or better
 

MrChips

Joined Oct 2, 2009
35,018
1 second every 2 months would be nice. My reference clock is a clock I built using a timing unit from a wall clock chat uses a AA battery and it's accurate.
Do you know the accuracy and stability that you are demanding?

1) What does 1 second every 2 months mean in ppm?
2) How do you know that your reference clock is accurate? What is your calibrated reference?

1 second every 2 months is 0.2 ppm. A typical quartz crystal oscillator is accurate to about 1 to 5 ppm. 1 ppm translates to about 1 second every 12 days. 5 ppm is about 1 second every 2 days. You can trim a 32768 Hz quartz crystal using a trimmer capacitor to better than 1 ppm but you still have to deal with long term instability, besides still needing an accurate frequency standard for calibration.

Believe it or not, the simplest, stable and accurate standard for time keeping purposes is your AC line frequency.
The next simple time keeping oscillator is a trimmed 32768 quartz crystal oscillator, provided that you have access to a calibrated standard.

More complicated standards are:

  1. temperature controlled crystal oscillator
  2. atomic clock
  3. radio transmission frequency and time standards
  4. GPS
  5. internet

In summary, if you want a time keeping circuit with long term stability, use your AC line frequency (depending on the reliability of your electrical utility).
 

Futurist

Joined Apr 8, 2025
926
1 second every 2 months would be nice. My reference clock is a clock I built using a timing unit from a wall clock chat uses a AA battery and it's accurate.
How did you decide that wall clock unit is "accurate"? in order to say that you need another reference. My advice is compare your MCU timing with an international standard. For all you know your MCU might be more accurate than the old wall clock and you've been chasing phantoms all this time.

https://time.is/
 
Last edited:
Top