PDA

View Full Version : How to set TMRO & TMR3 as Counter?.



NatureTech
- 13th April 2007, 10:41
Hi all,

I am a bit confused on how to set TMR0 and TMR3 as a Counter in PIC18F4550?.I plan to use these 2 Counter as a pulse counter from my robots encoder.Thanks for your guidance guys.I am kinda new in this.

HenrikOlsson
- 13th April 2007, 12:16
Hi,
TMR3 seems to share it's clock pin with TMR1 and I haven't really looked into what effects that has but here's what I'd try:


TRISA.4 = 1 'TMR0 CKI Pin as input
TRISC.0 = 1 'TMR3 (and TMR1) CKI Pin as input

'From Datasheet Section 11
T0CON.7 = 1 'TMR0 is ON
T0CON.6 = 0 'TMR0 is 16 bits
T0CON.5 = 1 'TMR0 clock source is EXTERNAL...
T0CON.4 = 0 '...and counts on rising edge
T0CON.3 = 1 'NO prescaler is assigned
T0CON.2 = 0 'Prescaler 1:1
T0CON.1 = 0 'Prescaler 1:1
T0CON.0 = 0 'Prescaler 1:1


'From Datasheet Section 14
T3CON.7 = 0 'Disables 16bit read/write
T3CON.6 = 0 'TMR1 is clock for both CCP's (together with BIT 3)
T3CON.5 = 0 'Prescaler 1:1
T3CON.4 = 0 'Prescaler 1:1
T3CON.3 = 0 'TMR1 is clock for both CCP's (together with BIT 5)
T3CON.2 = 1 'Don't sync with internal clock.
T3CON.1 = 1 'TMR3 clock source is EXTERNAL
T3CON.0 = 1 'TMR3 is ON

I've set the bits one by one here so that it's easier to see what each one does. Note that I haven't tested this so it's perfectly normal if it doesn't work...

/Henrik Olsson.

NatureTech
- 14th April 2007, 05:00
Thats a great guide HenrikOlsson,

Well,the truth is .. this is my first time in my life setting up Counter in PIC.Although i know whats it function would work like,i am still confused ( Well,not the pre-scaler part,rising edge or falling edge and so on ..) but how to set it,accumulate it and clear it?.That's what something new to me.I am able to read the datasheet but understand 50/50...

HenrikOlsson
- 14th April 2007, 10:32
Hi,
Ahh, well the TMR registers are like any other register in the PIC so you can read/write to/from them as you would with any other register. So to set the TMR0 registers to 0 (assuming a 16 bit TMR0 here):


MyCount var WORD 'This is my counter...

TMR0L = 0 'Reset lower byte
TMR0H = 0 'Reset hogher byte

Start:
MyCount.HighByte = TMR0H 'Get high byte of counter
MyCount.LowByte = TMR0L 'Get low byte of counter
LCDOUT $FE,1,#MyCount 'Display it
Pause 100
Goto Start

To PRESET it you write whatever value you wish to the two registers:


TMR0H = 3 'Preset TMR0 to 878....
TMR0L = 110 ' ( 3 * 256 + 110 )


That's really all there is to it. Well, one more thing. When reading the two TMR registers in the way shown above there is a slight chance the lower byte rolls over in the time between reading TMR0H and TMR0L. To come around that problem you can either enable 16bits read/writes (on PICs that supports it) or read the high byte two times, like:


MyCount VAR WORD
Temp var byte


MyCount.HighByte = TMR0H 'Get high byte of counter
MyCount.LowByte = TMR0L 'Get low byte of counter
Temp = TMR0H 'Get high byte again

IF Temp <> MyCount.HighByte then 'Do a fresh read
MyCount.HighByte = TMR0H 'Get high byte of counter
MyCount.LowByte = TMR0L 'Get low byte of counter
EndIf

HTH
/Henrik Olsson.

NatureTech
- 15th April 2007, 09:01
Hi HenrikOlsson,

Ok.I understand now.I gonna give a try and let you know the result.Thanks a bunch my "Sail on the same ship" friend.

NatureTech
- 7th May 2007, 05:09
To HenrikOlsson,

Hope you remember me.

Is the TMR0 and TMR3 were shared?.So that means i could only use 1 counter at a time right?.

HenrikOlsson
- 7th May 2007, 06:20
Hi,
No it seems like TMR1 and TMR3 has it's external clock input connected to the same physical PIC pin (Pin15 on the 4550). That means that you can't use both TMR1 and TMR3 as counters with external clockinput. You would still be able to use, for example, TMR1 as a counter and TMR3 as timer (internaly clocked) though.

So TMR0 and TMR3 as counters should be fine!

/Henrik Olsson.

NatureTech
- 10th May 2007, 05:16
So that means i can only use 1 counter for a time?.Geez,it seems 16F877 is more easy to use.It supports WDT scale for PORTA.4 interrupt.1:1.I am a bit confused?.

HenrikOlsson
- 10th May 2007, 06:30
Hi,
I'm sorry but I'm not quite sure what the problem is...?

You can use TMR0 AND TMR1 as counters at the same time. OR you can use TMR0 AND TMR3 as counters at the same time. BUT you can NOT use TMR1 AND TMR3 as counters at the same time since they both share the same clock-pin (pin 15 on the 40-pin DIP package)

If this doesn't help please explain what the problem is , if you can.

/Henrik Olsson.

NatureTech
- 13th May 2007, 12:31
Hi Henrik,

Yes,that exactly i wanted to know ( you can NOT use TMR1 AND TMR3 as counters at the same time ).Ok,my doubt is cleared.Seems like i got to use an interrrupt pin and a counter.I hope it would work.And 1 more thing,the selection of QEI in PIC18F4431.If i don't want to use INDEX and wish to reset it using software (POSCNT=MAXCNT),am i have to set value of the maxcount ( Ex : MAXCNT = 1500 ) ??.And could i use single channel encoder output from 2 encoder which is from 2 different motor?.

I am sorry if i am bothering you alot,but this things is new to me and locally nobody had tried this kind of stuff due to the price of these electronics and availibility.

HenrikOlsson
- 13th May 2007, 16:18
Hi,


Ok,my doubt is cleared.Seems like i got to use an interrrupt pin and a counter.
Well, if you say so.... If you could explain what it is you're trying to do it may be easier for me or anyone else to suggest a solution. If you don't use TMR0 for anything you CAN use that AND TMR3, both as counters. If you ARE using TMR0 for something ELSE than a counter, perhaps you can shift that work to TMR3 thus making TMR0 and TMR1 available as counters - it all depends....



And 1 more thing,the selection of QEI in PIC18F4431.
I'm a bit confused...I thought we were talking about the 18F4550 here, the 18F4431 doesn't even have a TMR3.....

Regarding the QEI, if you don't want to use the Index channel you can either just let the position register overflow or use the position counter reset on period match. In the later case you set MAXCNT to the value at which you want the postion counter to reset to zero, 1500 for example.... You can NOT use just one channel from the encoder. The QEI module needs two channels, 90 degrees phase shifted with respec to each other. Otherwise it can't tell which way the motor is turning.



I am sorry if i am bothering you alot,but this things is new to me and locally nobody had tried this kind of stuff due to the price of these electronics and availibility.
No problem at all. That's what the forum is here for.

/Henrik Olsson.

NatureTech
- 14th May 2007, 14:54
Thanks Henrik.You understand my pain.

Well,what i am trying to do here is actually to have single channel encoder from each encoder (2 encoder) and feed it into PIC.I want to use interrupt but i belive when the interrupt occured,you got to clear it right?.Is this might lead to missing pulse as you have to loop to clear the interrupt?.Although without pause?.I even thought about using RB Port Change Interrupt as i belive i could hook up quadrature encoder to RB7:RB4 but i belive it could make some delay in clearing and again lead to missing pulse.

My apologise for confusing you with 18F4550 and 18F4431.I do own this chip and it's more awsome than LM629.

ra68gi
- 14th May 2007, 17:25
Hi nature tech,
Its been a long time since i last posted on this forum. I have written a program for a rotary encoder. But i have written it in C. I have used pic16f72 and have made 1x, 2x, 4x measurements. In 1x it increments counter only once for every pulse. I had used a 1000ppr(pulse per rev) encoder & the count value displayed on a LCD. So the resolution is 360degrees/1000. With 2x you will get double & with 4x you get 360/4000.
I have used different interrupt sources like portb int0, ccp,timer0, timer1.
If you are interested i will send you the source code.
The compiler Iam using is free version & you can write upto 2k code. And all this with instant interrupts.
If you are interested let me know & i will post it.

Raghunathan.

mister_e
- 15th May 2007, 03:11
Mikro C :D

ra68gi
- 15th May 2007, 03:59
No. It's BoostC.
If you are new to C & interested to learn it quickly, see this link..http://forum.sourceboost.com/index.php?showtopic=2399. C is more structured & universal language. I migrated to C recently & its power is awsome as regards to microcontroller programming. If you intend to impliment rtos on small ram pics, that too is available called nova rtos. Have a try.
Regards

Raghunathan.

mister_e
- 15th May 2007, 04:14
Sounds good... yet another C compiler :D

Well, i'm not going to move on it as long as i'll don't have any customer asking for OR if a free and legit full-version appear in my mail-box ;).

I have and use too much different compiler now (C, BASIC)... hard to get comfortable with all of them...

My favourites
PicBasicPro
SwordFish
Hi-Tech C

NatureTech
- 15th May 2007, 05:36
Hi ra68gi,

I think i wanna have a look on your code as well.Is your code is an adaptation from "instant interrupt" which you mix with asm or else?Well,1x, 2x,4x resolution sounds great.It might be a choice which i will skip using PLD or CPLD to do the job.If this doesnt work then i will opt for 2 PIC18F4331 which is connected through I2C that will enable me to control 2 motors almost at the same time.

Talk about C,yes it's a great stuff.You just have to include the related <.h> file and tweak a bit in you code,and there you go.I think you could download sourceboost free?Or limited somehow.

ra68gi
- 15th May 2007, 08:26
Yes, you get 2k version absolutely free with all the frills like a beautiful simulator / debugger with no other limitation other then 2k code limit. Floating point routines is also available. Consider the pic basic compiler(2k page limit pbc) which is sold at $100. And for just $70 you get a full version BoostC compiler( no limit).

All compilers have instant interrupts its only pic basic compilers that don't have instant interrupts (God knows why)ie. the interrupt latency is much higher than generated by other compilers. more over the pbc commands are non re-enterent, meaning that only after it completes executing the whole command( say pause 1000) will it enter the ISR. Which is very bad & thats why Darrel has created the instant interrupt routines for PBC.

coming to the project..
Both clockwise & anti clockwise the LCD is made to display only positive values. If you wish you can rewrite the code to get -ve value displayed.
Any thing is possible with this compiler.

The 1x code is commented well but not the 4x( i didn't have time).
Ask me if you need the 2x code. I suppose the 4x will give you all the information to build the 2x.

The 1x code is as follows...


--------------------------------------------------------------------------
// this test builds & works properly.
#include "system.h"
#include "lcd_driver.h"
#include "stdio.h"
// Set clock frequency to 4MHz.

#pragma CLOCK_FREQ 4000000

//set configuration fuse.
#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF

#define LCD_ARGS 2, /* Interface type: mode 0 = 8bit, 1 = 4bit(low nibble), 2 = 4bit(upper nibble) */ \
0, /* Use busy signal: 1 = use busy, 0 = use time delays */\
PORTC, TRISC, /* Data port and data port tris register */ \
PORTB, TRISB, /* Control port and control port tris register */ \
2, /* Bit number of control port is connected to RS */ \
7, /* Bit number of control port is connected to RW */ \
3 /* Bit number of control port is connected to Enable */



signed long counter;
unsigned long counter1;
unsigned int value1;
bit update_flag;

/*Interrupt service routine (ISR).On ccp capture interrupt, program
will jump to this code location. */
void interrupt( void )
{
update_flag = 1 ;

if(portb.0 == 0) //check the quadrature signal
{
counter ++ ; // increment counter
}
else //else decrement counter.
{
counter -- ;
}
pir1.2 = 0; //clear ccp1if
}




/* function to display counter. */
void display (unsigned int x)
{
unsigned int xn ;
unsigned int xd ;
char buf[ 10 ];
lcd_clear();
lprintf("count=");
sprintf( buf, "%d", x );
lprintf( buf );
}


/* The main code configures the intcon, pie1, t1con & ccpcon1
registers.*/

void main()
{
trisb = 1; //configure portb.0 as input & rest as
portb = 0; //clear port B
trisc = 0b00000100; //RC2/ccp1 pin as input.


// enable interrupts: interrupt control register.
intcon.6=1; //enable peripheral interrupts
intcon.7=1; //enable global interrupt

//peripheral interrupt enable register 1.
pie1.2 = 1; //enable ccp1 interrupt.




/*ccpcon1: capture/compare/pwm control register1.

bit3-0.....ccpxm3:ccpxm0: ccpx mode select bits.
we will use...
0100 = capture mode, every falling edge.
0101 = capture mode, every rising edge.
we can choose any one of the above mode.
but we will use 0101 in our project.
to get less count use 0110( divide by 4).
or 0111 for divide by 16.
*/

/* setup LCD */
lcd_setup();


update_flag = 1; // start counter from 0
ccp1con = 0b00000101; //set capture mode.
counter = 0; //reset counter.
while(1)
{
while (update_flag == 1)
{
if(counter < 0 )
{
counter1 = (-1)* counter;
display(counter1) ;
}
else
{
display(counter) ;
}
update_flag = 0 ;
}
}
}

--------------------------------------------------------------------------
code for the 4x...



// this test builds & works properly.

#include "system.h"
#include "lcd_driver.h"
#include "stdio.h"
// Set clock frequency to 20MHz.

#pragma CLOCK_FREQ 20000000

//set configuration fuse.
#pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF

#define LCD_ARGS 2, /* Interface type: mode 0 = 8bit, 1 = 4bit(low nibble), 2 = 4bit(upper nibble) */ \
0, /* Use busy signal: 1 = use busy, 0 = use time delays */\
PORTC, TRISC, /* Data port and data port tris register */ \
PORTB, TRISB, /* Control port and control port tris register */ \
2, /* Bit number of control port is connected to RS */ \
7, /* Bit number of control port is connected to RW */ \
3 /* Bit number of control port is connected to Enable */



signed long counter;
unsigned int value1;
bit update_flag;

/*Interrupt service routine (ISR).On ccp capture interrupt, program
will jump to this code location. */
void interrupt( void )
{
update_flag = 1 ;

if(intcon.1) //RB0/int interrupt(rising edge)
{
if(portc.1 == 0)
{
counter ++ ; // increment counter
}
else //else decrement counter.
{
counter -- ;
}
intcon.1 = 0; //clear intf
}
else
if(intcon.2) //tmr0if (falling edge)
{
if(portc.1 == 1)
{
counter ++ ;
}
else
{
counter -- ;
}
tmr0 = 255 ;
intcon.2 = 0;
}
else
if(pir1.0) //tmr1if
{
if(portc.3 == 1)
{
counter ++ ;
}
else
{
counter -- ;
}
t1con.0 = 0 ;
tmr1l = 255 ;
tmr1h = 255 ;
t1con.0 = 1 ;
pir1.0 = 0 ;
}
else
if(pir1.2) //ccp1if
{
if(portc.3 == 0)
{
counter ++ ;
}
else
{
counter -- ;
}
pir1.2 = 0;
}
}




/* function to display counter. */
void display (unsigned long x)
{
char buff [ 10 ] ;
sprintf32(buff,"%d",x);
lcd_clear();
lprintf("count=");
lprintf (buff);

}


/* The main code configures the intcon, pie1, t1con & ccpcon1
registers.*/

void main()
{
trisb = 1; //configure portb.0 as input & rest as
portb = 0; //clear port B
trisc = 0b00000111; //RC2/ccp1, RC0, RC1 as inputs.

//configure option register bits
//portb pull-ups(rbpu)(disable)...bit7
//interrupt on rising edge(RB0/int)(intedg)...bit6
//tmr0 clock source(tocs) is transition on RA4...bit5
//tmr0 source edge select(tose) is high to low transition...bit4
//bit3-bit0...don't care.
option_reg.6 = 0b11111111;

// enable interrupts: interrupt control register.
// intcon.6=1; enable peripheral interrupts
// intcon.7=1; enable global interrupt
// intcon.5=1; enable tmr0 overflow interrupt.
// intcon.4=1; enable inte (RB0/int)
// intcon.1=0; intf ( RB0/int flag)

// intcon = 0b11110000 ;
//i will enable tmr0 & RB0/int along with ccp and tmr1 interrupt.


//timer1 module: configure t1con.
/*TIMER1 INCREMENTS ONLY IN RISING EDGE*/
//bit7-6....00
//bit5-4....00...prescaler 1:1
//bit3......0....t1oscen cleared.(makes RC0 as clk input)
//bit2......0....synchronize external clock input.
//bit1......1....external clock on pin RC0.
//bit0......1....start timer1.
// t1con = 0b00000011;
//we will start all interrupts at one go a bit latter.

//peripheral interrupt enable register 1.
pie1.2 = 1; //enable ccp1 interrupt.
pie1.0 = 1; //enable tmr1 interrupt.

/*ccpcon1: capture/compare/pwm control register1.

bit3-0.....ccpxm3:ccpxm0: ccpx mode select bits.
we will use...
0100 = capture mode, every falling edge.
0101 = capture mode, every rising edge.
we can choose any one of the above mode.
but we will use 0101 in our project.
to get less count use 0110( divide by 4).
or 0111 for divide by 16.
*/

// LCD setup
lcd_setup();

update_flag = 1; // start counter from 0
ccp1con = 0b00000100; //set capture mode in falling edge.
tmr0 = 255; // a pulse will generate an overflow interrupt.
tmr1l = 255;
tmr1h = 255; // a single pulse input will gen an interrupt.
t1con = 0b00000011; // start timer1 as pulse counter.
intcon = 0b11110000 ; //enable RB0/int, tmr0 interrupt
counter = 0; //start measurement.
while(1)
{
while (update_flag == 1)
{
if(counter < 0 )
{
counter = (-1)*counter;
}
update_flag = 0 ;
display(counter) ;
}
}
}

--------------------------------------------------------------------------
Regards
Raghunathan.

mister_e
- 15th May 2007, 16:11
All compilers have instant interrupts its only pic basic compilers that don't have instant interrupts (God knows why)

Yeah... but god did it for us...

Instant interrupts - Revisited (http://www.picbasic.co.uk/forum/showthread.php?t=3251)

Archangel
- 15th May 2007, 21:30
Yeah... but god did it for us...

Instant interrupts - Revisited (http://www.picbasic.co.uk/forum/showthread.php?t=3251)
Don't let it go to your head Darrel, Steve spelled god with a lower case G :)

NatureTech
- 16th May 2007, 14:53
LOL,

Thanks a lot everyone.I got it now.

Thanks RA68GI and Henrik.

tapir
- 18th May 2007, 08:52
hello friends

ı try to make a phase failure relay for three phase main power there is a lot of phase failure relay on the bazaar but its not really effective because if one phase loss during motor running in that situation occur an regenerative effect in notor so the loss phase reproducing by motor and phase failure relay does not effect in this position
and whe ı mesure the phase angle by scop ı see that occur an phase shifting
so this is my question how can ı measure the phase angle for three phase