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
I have a PIC microcontroller that delivers a 1hz output at RB0 and I want to deliver a 150 hertz also to another pin--say RB3. The 150 hertz does not need to be accurate. How do I modify the program and keep the 1hertz code because it seems to be accurate with my 16mhz crystal. I use a PIC 16F627A and program it with a PICKIT3 using MPLAB IDE 6.05 on my Linux machine. The code that is provided for the 1 hertz output works but I don't have knowledge of programming. I got the program with an internet search.

Merry Christmas Everyone!

Code:
#include <xc.h>

// Configuration Bits: 16MHz HS Crystal, Watchdog Off, MCLR On, LVP Off
#pragma config FOSC = HS, WDTE = OFF, PWRTE = ON, MCLRE = ON, BOREN = OFF, LVP = OFF, CPD = OFF, CP = OFF

#define _XTAL_FREQ 16000000 // 16 MHz Crystal
#define CLOCK_OUT PORTBbits.RB0

unsigned int timer_counter = 0;

void __interrupt() isr(void) {
    if (PIR1bits.TMR1IF) { // Check Timer 1 Overflow Flag
        // Preload Timer 1 for 100ms delay:
        // Instruction frequency = 16MHz / 4 = 4MHz
        // Timer 1 with 1:8 Prescaler = 500kHz (2us per tick)
        // 100ms / 2us = 50,000 ticks.
        // Preload value = 65536 - 50000 = 15536 (0x3CB0)
        TMR1H = 0x3C;
        TMR1L = 0xB0;

        timer_counter++;
        if (timer_counter >= 5) { // 10 * 100ms = 1 second
            CLOCK_OUT = ~CLOCK_OUT; // Toggle the pin
            timer_counter = 0;
        }
        PIR1bits.TMR1IF = 0; // Clear interrupt flag
    }
}

void main(void) {
    CMCON = 0x07;      // Disable comparators to use PORTA/B as digital I/O
    TRISBbits.TRISB0 = 0; // Set RB0 as output
    CLOCK_OUT = 0;

    // Timer 1 Configuration
    T1CONbits.T1CKPS = 0b11; // 1:8 Prescaler
    T1CONbits.TMR1CS = 0;    // Internal clock (Fosc/4)
    TMR1H = 0x3C;            // Initial preload
    TMR1L = 0xB0;
  
    // Interrupt Configuration
    PIE1bits.TMR1IE = 1;     // Enable Timer 1 interrupt
    INTCONbits.PEIE = 1;     // Enable peripheral interrupts
    INTCONbits.GIE = 1;      // Enable global interrupts
    T1CONbits.TMR1ON = 1;    // Start Timer 1

    while (1) {
        // Main loop remains empty; logic is handled in ISR
    }
}
Merry Christmas Everyone!
 

Papabravo

Joined Feb 24, 2006
22,058
150 Hz. cannot be achieved using integer multiples of the basic time unit. That would require 1666.6666... ticks of 2 µs each. Your choices would be 1666 or 1667

\( 1666\times\;2\;\mu\text{sec}\;=\;300.120048\;\text{ Hz.} \)
\( 1667\times\;2\;\mu\text{sec}\;=\;299.940012\;\text{ Hz.} \)

Choose either one of those preload values for Timer 1 and you will be close. I would choose 1667 since it is closer to 300 than choosing 1666.

The conversion is:

1666 = 0x0682, and
1667 = 0x683

The code would be
TMR1H = 0x06;
TMR1L = 0x82;

or
TMR1H = 0x06;
TMR1L = 0x83;
 
Last edited:

Thread Starter

Arjune

Joined Jan 6, 2018
354
150 Hz. cannot be achieved using integer multiples of the basic time unit. That would require 1666.6666... ticks of 2 µs each. Your choices would be 1666 or 1667

\( 1666\times\;2\;\mu\text{sec}\;=\;300.120048\;\text{ Hz.} \)
\( 1667\times\;2\;\mu\text{sec}\;=\;299.940012\;\text{ Hz.} \)

Choose either one of those preload values for Timer 1 and you will be close. I would choose 1667 since it is closer to 300 than choosing 1666.

The conversion is:

1666 = 0x0682, and
1667 = 0x683

The code would be
TMR1H = 0x06;
TMR1L = 0x82;

or
TMR1H = 0x06;
TMR1L = 0x83;
I can't use 300hertz.
 

Papabravo

Joined Feb 24, 2006
22,058
I can't use 300hertz.
Sure you can. If you follow the algorithm of the program, you have 300 times 2 µsec high followed by 300 times 2 µsec low. Rinse and repeat gives you a square wave with a frequency of approximately 150 Hz. which is what I think you asked for. Without going into detail there are other "cute tricks" you can use to get even closer to the desired 150 Hz. Those tricks are a good deal more complicated to explain. Let me know if you are up for it.
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
150 Hz. cannot be achieved using integer multiples of the basic time unit. That would require 1666.6666... ticks of 2 µs each. Your choices would be 1666 or 1667

\( 1666\times\;2\;\mu\text{sec}\;=\;300.120048\;\text{ Hz.} \)
\( 1667\times\;2\;\mu\text{sec}\;=\;299.940012\;\text{ Hz.} \)

Choose either one of those preload values for Timer 1 and you will be close. I would choose 1667 since it is closer to 300 than choosing 1666.

The conversion is:

1666 = 0x0682, and
1667 = 0x683

The code would be
TMR1H = 0x06;
TMR1L = 0x82;

or
TMR1H = 0x06;
TMR1L = 0x83;
I can't use 300hertz.
what do you understand what the interupt service routine is doing ?
when you say the 1hz seems accurate , how accurate do you want the 1Hz ?
do you want the 150 Hz to be phase locked to the 1 Hz ?
I don't understand the interrupt service routine. The 1hz is for a clock that I may build, so it has to be accurate. I don't need the 150 hertz to be phase locked--it would be used for setting the clock via the seconds counter.
 

drjohsmith

Joined Dec 13, 2021
1,548
I can't use 300hertz.

I don't understand the interrupt service routine. The 1hz is for a clock that I may build, so it has to be accurate. I don't need the 150 hertz to be phase locked--it would be used for setting the clock via the seconds counter.
you need to read up on isr
rough description,
the main code runs from "top to botom" and keeps looping,
but when the interupt happens, in this case from the programable timer, the main code jumps to the isr routine.
but you need to understand the baaics by reading a lit more on line

how are you finding it , learning to code by asking the forum ?
have you looked to follow a cource / book to learn
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
Sure you can. If you follow the algorithm of the program, you have 300 times 2 µsec high followed by 300 times 2 µsec low. Rinse and repeat gives you a square wave with a frequency of approximately 150 Hz. which is what I think you asked for. Without going into detail there are other "cute tricks" you can use to get even closer to the desired 150 Hz. Those tricks are a good deal more complicated to explain. Let me know if you are up for it.
So it would be ~150hz--I was confused. I don't need it to be closer. I don't understand what code I would put where in my program. What does TMR1H = 0x06; mean and TMR1L = 0x83; -where do I put them exactly in my program and there must be other code to put an output to RB3 for the ~150 hz, right? Please explain.
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
you need to read up on isr
rough description,
the main code runs from "top to botom" and keeps looping,
but when the interupt happens, in this case from the programable timer, the main code jumps to the isr routine.
but you need to understand the baaics by reading a lit more on line

how are you finding it , learning to code by asking the forum ?
have you looked to follow a cource / book to learn
I'm learning somewhat on the forum. When I try to learn code it becomes confusing. I have considered buying a book on programming a PIC microcontroller on amazon Kindle but thought they wouldn't reflect my mind's way of thinking and would get lost due to difficulty.
 

Papabravo

Joined Feb 24, 2006
22,058
So it would be ~150hz--I was confused. I don't need it to be closer. I don't understand what code I would put where in my program. What does TMR1H = 0x06; mean and TMR1L = 0x83; -where do I put them exactly in my program and there must be other code to put an output to RB3 for the ~150 hz, right? Please explain.
I apologize I made a mistake in post #2. I thought Timer 1 was a down counter, rather than an up counter.

TMR1H and TMR1L are the two 8-bit halves of the 16 bit Timer 1 register. This register contains the current value for Timer#1. Each time the 16-bit timer, Timer1, overflows from 0xFFFF to 0x0000 The contents of the Timer 1 register TMR1H and TMR1L are loaded the initial value that gives the desired interval. In the original example you quoted in post #1, the desired interval was 100 milliseconds which corresponds to 50,000 ticks of 2 µsec each. That is:

\( 50,000\;\times\;2\;\mu\text{sec}\;=\; 100\;m\text{sec} \)

The remaining logic in the ISR sets the output high for five100 msec intervals and that toggles the output for 5 additional 100 msec intervals. This causes the output to beat up and down at approximately 1 Hz.

To change the frequency from 1 HZ to 150 Hz, we proceed as follows

\( 150\;\text{Hz}\;\equiv\;6.66...\;\text{msec} \)
\( 6.66...\text{msec}\;\div\;5\;=\;1.33...\;\text{msec} \)
\( 1.33...\;\text{msec}\;\div\;2\;=\;[666, 667]\;\text{µsec} \)

We intend to change the counter reload value from 50,000 to either 666, or 667. To do this we subtract this number form 65536 to get the actual reload value. We use this reload value to replace lines 18 & 19 in the original code.

\( 65,536\;-666\;=\;64,870\;=\;\text{0xfd66} \)
\( 65,536\;-\;667\;=\;64,869\;=\;\text{0xfd65} \)

The code would be for 666
TMR1H = 0xFD;
TMR1L = 0x66;

or for 667
TMR1H = 0xFD;
TMR1L = 0x65;

To double check the values:

\( 666\;\times\;2\;\text{µsec}\;=\;1.332\;\text{msec} \)
\( 1.332\;\text{msec}\;\times\;5\;=\;6.66\;\text{msec} \)
\( 6.66\;\text{msec}\;\equiv\;150.150...\;\text{Hz} \)

and

\( 667\;\times\;2\;\text{µsec}\;=\;1.334\;\text{msec} \)
\( 1.334\;\text{msec}\;\times\;5\;=\;6.67\;\text{msec} \)
\( 6.67\;\text{msec}\;\equiv\;149.925037...\;\text{Hz} \)
 
Last edited:

Thread Starter

Arjune

Joined Jan 6, 2018
354
I apologize I made a mistake in post #2. I thought Timer 1 was a down counter, rather than an up counter.

TMR1H and TMR1L are the two 8-bit halves of the 16 bit Timer 1 register. This register contains the current value for Timer#1. Each time the 16-bit timer, Timer1, overflows from 0xFFFF to 0x0000 The contents of the Timer 1 register TMR1H and TMR1L are loaded the initial value that gives the desired interval. In the original example you quoted in post #1, the desired interval was 100 milliseconds which corresponds to 50,000 ticks of 2 µsec each. That is:

\( 50,000\;\times\;2\;\mu\text{sec}\;=\; 100\;m\text{sec} \)

The remaining logic in the ISR sets the output high for five100 msec intervals and that toggles the output for 5 additional 100 msec intervals. This causes the output to beat up and down at approximately 1 Hz.

To change the frequency from 1 HZ to 150 Hz, we proceed as follows

\( 150\;\text{Hz}\;\equiv\;6.66...\;\text{msec} \)
\( 6.66...\text{msec}\;\div\;5\;=\;1.33...\;\text{msec} \)
\( 1.33...\;\text{msec}\;\div\;2\;=\;[666, 667]\;\text{µsec} \)

We intend to change the counter reload value from 50,000 to either 666, or 667. To do this we subtract this number form 65536 to get the actual reload value. We use this reload value to replace lines 18 & 19 in the original code.

\( 65,536\;-666\;=\;64,870\;=\;\text{0xfd66} \)
\( 65,536\;-\;667\;=\;64,869\;=\;\text{0xfd65} \)

The code would be for 666
TMR1H = 0xFD;
TMR1L = 0x66;

or for 667
TMR1H = 0xFD;
TMR1L = 0x65;

To double check the values:

\( 666\;\times\;2\;\text{µsec}\;=\;1.332\;\text{msec} \)
\( 1.332\;\text{msec}\;\times\;5\;=\;6.66\;\text{msec} \)
\( 6.66\;\text{msec}\;\equiv\;150.150...\;\text{Hz} \)

and

\( 667\;\times\;2\;\text{µsec}\;=\;1.334\;\text{msec} \)
\( 1.334\;\text{msec}\;\times\;5\;=\;6.67\;\text{msec} \)
\( 6.67\;\text{msec}\;\equiv\;149.925037...\;\text{Hz} \)
OK, thank you for your effort to make me understand--although I don't. I need both the 1hz and ~150hz outputs.
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
When all else fails, GPIO controlled 150hz output.
View attachment 361213
I thought of a 555, but don't want to do that. Please show me the code for the microcontroller and where to put them in my program, I'm OK with that--it's not impossible as you all have explained. It's hard for my mind to synchronize with my body to think clearly and learn code. When I try to learn, it starts our easy but I think the Illuminati makes it difficult with cryptic information changes afterwards to throw me off because they don't want to adhere to my decisions in the process of thought. I'm targeted.
 

Thread Starter

Arjune

Joined Jan 6, 2018
354
I thought of a 555, but don't want to do that. That's what I did for my previous clocks. Please show me the code for the microcontroller and where to put them in my program, I'm OK with that--it's not impossible as you all have explained. It's hard for my mind to synchronize with my body to think clearly and learn code. When I try to learn, it starts our easy but I think the Illuminati makes it difficult with cryptic information changes afterwards to throw me off because they don't want to adhere to my decisions in the process of thought. I'm targeted--they don't want me to learn my way.
 

drjohsmith

Joined Dec 13, 2021
1,548
hi
yes learning code is hard, and its easy to gom9ff in different directions
the forums are great source of information, but like all open forums , there are many ways to solve any problem, and on the forums you are likely to get many conflicting suggestions
Thats why I was discussing the option of a book,
it should take you in a linear fashion over all the concepts you need to be a confident engineer.
with little lee way to be distracted
 
Top