Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Using timer in PIC18F

Status
Not open for further replies.

engr_joni_ee

Advanced Member level 3
Joined
Nov 3, 2018
Messages
750
Helped
2
Reputation
4
Reaction score
4
Trophy points
18
Activity points
6,233
Hi,

I am working on a program which has the following task to do every second

Turn ON pin B1 as output and wait for 100 ms
Read another pin B2 as input
Send a string to UART

Turn OFF the pin B1
Read again B2
Send a string to UART

Wait until the next second is over and then start again the process

Can I use timer in this case ? i.e., just hold the program until the next second using timer and then start the process again
 

i agree with you, it was my proposal in post#2
your application is simple and (maybe) don't need use of interrupt .. to get a loop time of 1 sec
but depends of your MCU Type ? and FOSC value ?
old 16F MCU with 8bits TMR0 could not reah 1sec elapsed time
in this case you must use interrupt to count accumulate elementary times ie =100mS * 10 times => 1sec
and it is a good way to increase your knowlege about PIC
Hi, I am using PIC18F25K80 with FOSC = 16 MHz internal oscillator.
 

Hi,

did you read the datasheet? especially the timer0 section?

Then you know:
* it can be operted in 8 bit mode and 16 bit mode (0...255 or 0...65535)
* it may use Fosc/4 input
* it may use 1/256 prescaler

so fosc = 16MHz
thus fosc/4 = 4MHz
with prescaler of 256 you get 4MHz/256 = 1/64 MHz or 15.625kHz or 15,625 Hz
since 1Hz is 1 tick/second --> 15625 Hz = 15625 ticks/second
or the other way round: you need to count 15625 ticks to get 1 second. (since 15625 is more than 255 you now you you need to operate in 16 bit mode)

now you say you want 100ms. this is 1/10 s which means 15625/10 ticks this is 1562.5 ticks.
Sadly you can´t count 0.5 ticks = "half ticks".

thus set the prescaler to 128 instead of 256
do the above math on your own (and get 3125 ticks per 100ms)

Klaus
 

Here are my calculations.

FOSC = 16 MHz

FOSC/4 = 4 MHz

1 second timer: Prescaler of 256 will give 4 MHz / 256 = 1 / 64 MHz or 15.625 KHz or 15625 Hz

This means there must be 15625 ticks in timer registers (TMR0L and TMR0H) to reach 1 second.

100 ms timer: Prescaler of 128 will 4 MHz / 128 = 1 / 32 MHz or 31.25 KHz or 31250 Hz

This means there must be 31250 ticks in timer registers (TMR0L and TMR0H) to reach 1 second and in order to have 100 ms timer there must be 31250 / 10 = 3125 ticks in timer registers (TMR0L and TMR0H) to reach 1 ms
--- Updated ---

Hi,
I have read about the timer chapter. There is a timer clock which is FOSC/4 that gives 4 MHz because I am running the internal Oscillator with 16 MHz.

The time period will be then 1/4MHz = 0.25 us

In order to make it 1 s, I need to load 16 bit register TMR0L and TMR0H. These registers increment and when they reach 0xFFFF, there is a timer interrupt that need to be clear and the timer need to be stared again by loading new starting values to the registers TMR0L and TMR0H.

If I load the registers TMR0L and TMR0H with 0x0000 then the timer interrupt will appear after 65535 x 0.25 us = 16384 us which is 16.384 ms and can not reach 1 s which I need.

Here I have two questions, one the correct value of these two registers TMR0L and TMR0H and the second question is that if I am calling the functions at the right sequence ?
Hi again, I see a problem here. If I use prescaler of 256 then 1 tick will be of 0.25 us x 256 = 64 us
64 us x 15625 = 1 sec
The timer registers (TMR0L and TMR0H) must be loaded with 15625 to get 1 second timer.
 
Last edited:

there must be 31250 ticks in timer registers (TMR0L and TMR0H)
Note that the timer is upcounting until overflow.
so to get a timeout of 3125 ticks you need to initialize the (TMR0L/TMR0H) to 65536-3125 = 62411
... so it counts 62411, 62412, 62413 ... 65534, 65535, 0 (TMR0IF is set), 1, 2, 3...

You need to read section 13 completely and carefully.

Klaus
 
Hi,

I just have got an access to the lab and I have tried to run the timer in free mode but not able to implement it.

Summary of program: I need to start timer of duration one second and check by polling if overflow happens or not.

If overflow happens, I need to stop the timer and perform a particular task. Here I just indicate the task as two LEDs connected to Port C which turn on for 100 ms.

After the task, I need to again start the timer and then continue checking by polling when the overflow of 1 second timer happens.

My program is not working. The main file and the timer file are below.

Target device is PIC18F25K80.

Code:
#include "mcc_generated_files/mcc.h"
#include <xc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void putch(char txData)
{
    EUSART1_Write(txData) ;
}

void EUSART_Write(const char *x)
{
     __delay_ms (1);
     while(*x)
     {
        if(EUSART1_is_tx_ready())
        {
            EUSART1_Write(*x++);
        }
     }
}


/*
                         Main application
*/
void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();

     __delay_ms (500);
  
    // Timer Initialize and Start
    TMR0_Initialize();
    TMR0_StartTimer();
       
    int i = 1;
    char string_1[50] = "";
    char string_2[50] = "";

    // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
    // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global and Peripheral Interrupts
    // Use the following macros to:

    // Enable the Global Interrupts
    //INTERRUPT_GlobalInterruptEnable();

    // Disable the Global Interrupts
    //INTERRUPT_GlobalInterruptDisable();

    // Enable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptEnable();

    // Disable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptDisable();

    while (1)
    {
        // Add your application code
      
    i++;
    strcpy(string_1, "\r\n\r\n\Count = ");
    sprintf(string_2, "%d", i);
    strcat(string_1 , string_2);
    EUSART_Write(string_1);
  
    PORTCbits.RC4 = 0;
    PORTCbits.RC5 = 0;
  
   if (TMR0_HasOverflowOccured())
   {
       EUSART_Write(" Timer Overflowed ");
       TMR0_StopTimer();
     
       PORTCbits.RC4 = 1;
       PORTCbits.RC5 = 1;
      
       __delay_ms (100);
     
       TMR0_Initialize();
       TMR0_StartTimer();

   }      
  
    }
}
/**
End of File

}

The timer file is here.

Code:
/**
  Section: Included Files
*/

#include <xc.h>
#include "tmr0.h"

/**
  Section: Global Variables Definitions
*/


volatile uint8_t timer0ReloadVal;

/**
  Section: TMR0 APIs
*/


void TMR0_Initialize(void)
{
    // Set TMR0 to the options selected in the User Interface

    // FOSC = 16 MHz
    // FOSC/4 = 4 MHz
    // 1 Second timer: Prescaler = 256 will give 4 MHz / 256 = 1 / 64 MHz or 15.625 KHz or 15625 Hz
    // There must be 15625 ticks in timer registers (TMR0L and TMR0H) to reach 0xFFFF or 1 second
    // 65535 - 15625 = 49910 
      
    // TMR0H C2;
    TMR0H = 0xC2;

    // TMR0L F6;
    TMR0L = 0xF6;
  
    // Load TMR0 value to the 8-bit reload variable
    timer0ReloadVal = 216;

    // Clearing IF flag
    INTCONbits.TMR0IF = 0;

    // T0PS 1:256; T08BIT 8-bit; T0SE Increment_hi_lo; T0CS FOSC/4; TMR0ON enabled; PSA assigned;
    T0CON = 0xD7;
}

void TMR0_StartTimer(void)
{
    // Start the Timer by writing to TMR0ON bit
    T0CONbits.TMR0ON = 1;
}

void TMR0_StopTimer(void)
{
    // Stop the Timer by writing to TMR0ON bit
    T0CONbits.TMR0ON = 0;
}

uint8_t TMR0_ReadTimer(void)
{
    uint8_t readVal;

    // read Timer0, low register only
    readVal = TMR0L;

    return readVal;
}

void TMR0_WriteTimer(uint8_t timerVal)
{
    // Write to the Timer0 registers, low register only
    TMR0L = timerVal;
}

void TMR0_Reload(void)
{
    //Write to the Timer0 register
    TMR0L = timer0ReloadVal;
}


bool TMR0_HasOverflowOccured(void)
{
    // check if  overflow has occurred by checking the TMRIF bit
    return(INTCONbits.TMR0IF);
}
/**
  End of File
*/
 

Hi,

from post#22:
(since 15625 is more than 255 you now you you need to operate in 16 bit mode)
did you follow this?

****
did you implement it step by step? ... and proceeded to the next step only if the previous worked properly?

****
please learn to debug your code step by step and give useful informations.
but not able to implement it.
Why exactly not?

My program is not working.
What exactly does work like expected and what exactly does not work like expected?

Klaus
 

Hi,

Yes now it works. I have forgotten before to enable 16 bit timer mode in MCC.

Code:
#include <xc.h>
#include "tmr0.h"

/**
  Section: Global Variables Definitions
*/


volatile uint16_t timer0ReloadVal;

/**
  Section: TMR0 APIs
*/


void TMR0_Initialize(void)
{
    // Set TMR0 to the options selected in the User Interface

    //Enable 16bit timer mode before assigning value to TMR0H
    T0CONbits.T08BIT = 0;
 
    // FOSC = 16 MHz
    // FOSC/4 = 4 MHz
    // 1 Second timer: Prescaler = 256 will give 4 MHz / 256 = 1 / 64 MHz or 15.625 KHz or 15625 Hz
    // There must be 15625 ticks in timer registers (TMR0L and TMR0H) to reach 0xFFFF or 1 second
    // 65535 - 15625 = 49910
    
    // TMR0H C2;
    TMR0H = 0xC2;

    // TMR0L F6;
    TMR0L = 0xF6;
    
    // Load TMR0 value to the 16-bit reload variable
    timer0ReloadVal = (uint16_t)((TMR0H << 8) | TMR0L);

    // Clearing IF flag
    INTCONbits.TMR0IF = 0;

    // T0PS 1:256; T08BIT 16-bit; T0SE Increment_hi_lo; T0CS FOSC/4; TMR0ON enabled; PSA assigned;
    T0CON = 0x97;
}

void TMR0_StartTimer(void)
{
    // Start the Timer by writing to TMR0ON bit
    T0CONbits.TMR0ON = 1;
}

void TMR0_StopTimer(void)
{
    // Stop the Timer by writing to TMR0ON bit
    T0CONbits.TMR0ON = 0;
}

uint16_t TMR0_ReadTimer(void)
{
    uint16_t readVal;
    uint8_t readValLow;
    uint8_t readValHigh;

    readValLow  = TMR0L;
    readValHigh = TMR0H;
    readVal  = ((uint16_t)readValHigh << 8) + readValLow;

    return readVal;
}

void TMR0_WriteTimer(uint16_t timerVal)
{
    // Write to the Timer0 register
    TMR0H = timerVal >> 8;
    TMR0L = (uint8_t) timerVal;
 }

void TMR0_Reload(void)
{
    // Write to the Timer0 register
    TMR0H = timer0ReloadVal >> 8;
    TMR0L = (uint8_t) timer0ReloadVal;
}

bool TMR0_HasOverflowOccured(void)
{
    // check if  overflow has occurred by checking the TMRIF bit
    return(INTCONbits.TMR0IF);
}
/**
  End of File
*/
 

By the way, you could make things a little simpler for yourself when you want to output your string to the UART. You could replace all of your string handling etc in the main loop with
Code:
printf("\r\nCount = %d\r\n", i);
Because you have a 'putch' function defined, the 'printf' function will use that to output each character.
(I've also changed the way the <CR><LF> work to the way I prefer: unless you deliberately intend to add more characters on the same line later on, I always like to end with '\r\n' - and often '\n' on its own will do - so that whatever may come later is on a line of its own.)
Susan
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top