in this session i am going to show you how to use the tmr1 ... · from timer1 and will be used to...

12
In this session I am going to show you how to use the TMR1 Gate feature to measure the width of a pulse. There are many ways to measure a pulse but I like this one because it can be done in the background and the gate feature is available on many of Microchip’s PIC12F and 16F devices. In this session I’ll explain how the gate feature works and then I will show you some sample code to help you get going. 1

Upload: others

Post on 11-Jun-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

In this session I am going to show you how to use the TMR1 Gate feature to measure the width of a pulse. There are many ways to measure a pulse but I like this one because it can be done in the background and the gate feature is available on many of Microchip’s PIC12F and 16F devices. In this session I’ll explain how the gate feature works and then I will show you some sample code to help you get going.

1

Page 2: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

In order to get a high level view of how the Timer1 Gate Feature works, lets take a look at this simple block diagram.

On the left of our diagram, we have a clock, which can be selected from 4 different sources. I’ll come back and talk more about those sources in a second.

O th i ht h Ti 1 hi h i 16bit tiOn the right, we have our Timer 1, which is a 16bit timer.

In the middle we have the gate itself which open and closes to determines when the clock source you selected gets through the gate to increment Timer1.

Opening and closing the gate is controlled by the Gate Input which can also beOpening and closing the gate is controlled by the Gate Input which can also be selected from several sources, the state of an I/O pin, Timer0 overflow or outputs from either of the comparators.

The gate also has several control options including the ability to select if the gate is closed on a low active or high active signal and another feature called ‘Single Pulse Mode’ which will automatically open the gate after a pulse has been captured andMode which will automatically open the gate after a pulse has been captured and fire an interrupt. At that point you can just read the Timer 1 counter value which corresponds to how long the pulse was.

Now moving back to the clock source, I mentioned before that there are several options you can select from here. You can use the system clock frequency (or Fosc) Fosc/4 the internal cap sense oscillator or an external clock

2

Page 3: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

For our example we’ll use the PIC12F1822 which is a 8 pin device. Well use the MCU’s internal oscillator so we don’t have to use an external crystal.

We have the PWM signal from the servo controller tied directly into the RA4 pin. This would be the same type of servo controller used for controlling the little servo motors in RC cars and planes. The controller outputs 5V pulses with a width of 1 to 2 ms and period of about 50hz. We’ll use the timer1 gate feature in single pulse mode to capture the incoming pulse and then generate an interrupt.

I’ve also connected an LED to pin RA2 just for debugging purposes.

3

Page 4: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

Here are the flow charts for the main routine and the interrupt service routine.

For the main routine we first need to set up the oscillator for the MCU and then initialize the I/O pins. We configure Timer 1 to use the gate feature in single pulse mode, and setup the Timer1 Gate interrupt so it fires when the pulse is captured. Then we initialize some variables used to determine if a pulse has been captured and if it has, what the count value was. Then before we drop down into the main routine we set the Timer1 Gate Go bit which tells the gate function to start looking for a pulse.

Since this is just an example program, the main routine is not really doing anything but sitting in an endless loop waiting for a pulse to be captured. When that happens we read the value from Timer1 and for example, we turn the LED on or off based on pwhat the value is.

Over on the right is the flow for our interrupt service routine. When the interrupt is called, it means that the pulse has been captured so the first thing we do is transfer the count value to another variable called PulseValue that will be used in our main routine. We don’t want to be using the actual Timer1 value because after we exit gthe interrupt we may get another pulse coming in which would mean that Timer1 would be counting again. After we have the count value we set a flag called PulseFound that tells the main routine that a pulse has been captured. We then set Timer1 back to zero, clear the interrupt flag and then set the Timer1 Gate Go bit back to 1 so it starts looking for a pulse again.

4

Page 5: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

When working through this example, you should keep in mind that there are several variables in play that you need to consider in order to get the best resolution you can when counting a pulse.

The first variable to consider is Timer 1 itself which is a 16 bit counter. Ideally, you want to set up your application so that the minimum pulse you are measuring gets you a timer 1 value of close to zero and the maximum pulse you are measuring gets you a timer1 value at its max value of 65535. In practice this best case is seldom achievable but this is what your goal is.

The second and third variables to consider are the MCU Oscillator, or Fosc, and the Timer 1 Clock select bits. If you configure Timer 1 to use Fosc or Fosc/4 as the clock then the MCU clock frequency will have a direct affect on how fast Timer1 q ycounts when the gate is closed.

The fourth variable is the Timer 1 prescalar which can be divided by a maximum of 8 to slow down the timer1 count if you are measuring longer pulses.

5

Page 6: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

Before we go any further, it may be helpful for you to download the 12F1822 datasheet and print out the pages with the register maps for the OSCCON, T1CON, T1GCON, INTCON, PIR1 and PIE1 registers. You will find that when writing code for something like this you end up going back and forth between the registers and you may find it easier to have printed copies of the register maps in front of you.

6

Page 7: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

Lets go ahead and take a look at the code for our example project here. We’re using MPLAB X and the XC8 compiler and we’ll be using the simulator so no hardwareMPLAB X and the XC8 compiler and we’ll be using the simulator so no hardware is needed. We have the standard header file included, we set the Config bits and then we have some define statements. The Crystal Frequency definition here is for when you use the built in DelayMS and DelayUs functions and this crystal frequency value has to match your mcu clock frequency or the delay statements won’t work correctly.Our pulse from the servo controller is attached to our Timer1 Gate input which is the RA4 pin so I have that defined as PWM IN. I’m attaching an LED to pin RA2 e p so ve de ed s W N. c g o pjust for debugging purposes so I have that defined as LED. I have a constant called Pulse Limit set to 30000 which is used in the main routine to determine if the LED should be turned off or on based on the value of the pulse width coming in.We have 2 global variables, one I is the value called Pulse Value which we copy the Timer1 Value into inside our interrupt routine. The other one is a flag defined inside this bit field structure called PulseFound which will be used by the main routine to determine when a pulse has been captured.Y ill t th t I h d th ‘ l til ’ lifi f b th t th i blYou will note that I have used the ‘volatile’ qualifier for both to these variables which is done because these variables are changed inside the ISR. By using the volatile qualifier, it tells the compiler that these variables may change outside of the main loop and it should read these variables every time a comparison is done in the main routine. Without this qualifier, the compiler may use a cached value for one of these variables instead and the program would not function properly.Lets move down to the interrupt service routine. When this routine is called it means that a pulse has been captured so the first thing we do is copy the value of

i i h i bl ll d l l h h l d flTimer1 into the variable called Pulse Value. Then we set the Pulse Found flag so the main routine will know that we have a pulse, then we clear Timer1 back to zero, we clear the Timer1 Gate interrupt flag and set the Timer1Gate Go bit back to 1 so it starts looking for the next pulse.

7

Page 8: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

Dropping down into our main routine, the first thing we do is define a new pp g gvariable called Timer1Count which will ultimately contain the counter value from Timer1 and will be used to determine if we turn the LED on or off. With the OSC Con register, we set up the system clock to use the internal oscillator at 16Mhz and the PLL is turned off.

We are not using any analog pins so we turn the analog pins to digital I/O pins and turn off the ADC and the DAC.and turn off the ADC and the DAC.

For the TRIS assignments we set RA4 as an input because that’s the pin for our incoming pulse and RA2 is set as an output to drive the LED.

With the Timer 1 Control register we setup the clock source as the same as the system clock (or FOSC), set the prescalar to divide by 1 and turn the timer on.

8

Page 9: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

Next is the Timer1 Gate Control Register, where we enable the timer 1 gate g gcontrol, turn on the single pulse mode and set the source of our gate control as the timer1 gate pin which is RA4.

Here we clear Timer1, make sure the Timer1 Gate interrupt is clear and then enable our interrupts and set the timer1 Gate Go flag so it can start looking for a pulse.

We make s re the P lse Fo nd flag is clear and clear the P lseVal e ariableWe make sure the Pulse Found flag is clear and clear the PulseValue variable and now we drop into our main loop.

9

Page 10: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

The main loop is just an endless loop that waits for the pulse found flag to be p j p p gset. If the flag is set, it turns the LED on or off based on the value of timer1, which corresponds the width of the incoming pulse.

Now we need to be a bit careful on how we read the pulsevalue number because that value is modified in the interrupt routine which could occur at an time incl ding hile e are in the middle of reading that al e So toanytime, including while we are in the middle of reading that value. So to make sure that doesn’t happen, I use the Disable All Interrupts function to prevent he interrupt from firing and then copy the Pulse Value number into the new variable I created called Timer1Count. Then I use the Enable All Interrupts function to turn the interrupt back on. So now I have my count value stored in a variable that has nothing to do with the interrupt routine and regardless of what happens in that interrupt I can take as much time as I needregardless of what happens in that interrupt, I can take as much time as I need to evaluate this number and take whatever action I want and not have to worry about it changing on me until the next pass through the loop.

So after I have the count value I compare it against the constant that I defined above called Pulse Limit and based on that comparison I turn the LED on or poff. Then before exiting this part of the loop I clear the Pulse found flag, and we go back and start the whole loop over again.

10

Page 11: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

11

Page 12: In this session I am going to show you how to use the TMR1 ... · from Timer1 and will be used to determ ine if we turn the LED on or off. With the OSC Con register, we set up the

In this session I have shown how the Timer1 Gate function works and how it can be used to measure the width of a pulse.

Hopefully the example we went through demonstrated that this function is easy to use and shows you how to configure the gate feature to measure the pulse width as a background task and then generate in interrupt when the pulse has been captured.

The Timer 1 gate feature is currently available on PIC12 and PIC16 F and LF 15xx, 182x, 178x and 193x devices and is being added to additional future devices.

For more details on the 12F1822 device that we used in our example and the gate feature refer to the PIC12F 1822 datasheet.

12