Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

16f628 understanding TMR0

Status
Not open for further replies.

RogerWhitfield

New Member
Hi, sorry if this seems an obvious question but I am struggeling to understand how to use TMR0 on the 16f628.

I am using Hi-Tech C.

void interrupt isr(void)
{
T0IF=0; // Clear Inturrupt Flag
PORTB++;
if(PORTB>16) PORTB=0x00;
}

void main(void){
OSCF=0; // Set Processor to 37KHz Mode
MSG1=0; // Clear MSG1
GIE=0x01; // Global Interrupt Enable
T0IE=1; // Timer0 Interrupt Enable
TMR0=0; // Set TMR0 to 0
PSA=0; // Prescalar assigned to TMR0
PS0=1; // Prescalar 111 = /256
PS1=1; // 110= /128
PS2=1; // 101= /64 etc
CMCON = 0x07; // turn off comparator
TRISB = 0b00000000; // 8bits of port B are outputs
TRISA = 0b00001111; // 4 high bits of port A are outputs and 4 low bits are inputs
OPTION_REG = 0b11010111; // Turn on Timer 0
while (1){ // loops forever
}
}

So I think I have set the internal oscillator to 37Khz and TMR0 is assigned a prescalar of 256, I believe this means that the timer increments once every 37 / 4 / 256 = 36ms and therefore the interrupt should fire when TMR0 reaches 255 which should be 36ms * 255 = every 9.21 seconds.

When I run the code on the chip the interrupt seems to fire about once every 7 seconds (close but not exact), but if I change the prescalar to 2 or any other value
PS0=0; // Prescalar 111 = /256
PS1=0; // 110= /128
PS2=0; // 101= /64 etc
I would expect the interrupt to fire once every 37 / 4 / 2 = 4.625 seconds * 255 = 1179 seconds, but if I change the code as above it still takes about 7 seconds.

I guess that I have misunderstood something, can anyone help, I have been searching the net all day and I am lost.
 
Changing your prescaler PS0 through PS2 will do nothing as you reset them when you set OPTION_REG,,,, If I set PS0 .. PS2 to 0 the interrupt fires every 55ms

and 1,1,1 gives 7.09 seconds
 
Last edited:
Thanks for the reply.

OPTION_REG! - How could I have missed that? I have been tearing my hair out trying to see why changing the prescalar made no difference, this is the problem of being new to PIC programming.

So if my maths is more or less correct, then it seems I can proceed to test the different setting by changing OPTION_REG, or I guess replace OPTION_REG with the individual settings, which may help me to understand what is happening.

Once I understand the timer a little better I am going to have a stab at some simple multitasking, to see if I can put the thoery into practice.

Thanks again for the help.
 
OK, for the benefit of others who may be suffering the same problems as me here is the solution.

I am running this on the Velleman VM111 board, with 6 LED's on PORTB and 4 push switches on PORTA. I am only using the first 4 LED's as I will be converting this to a simple multitaksing system and will use the other 2 LED's for the other tasks.

void interrupt isr(void)
{
T0IF=0; // Clear Inturrupt Flag
// Increment PORTB until ==15 then reset to 0 (4 digit binary counter)
if(PORTB==15) {PORTB=0x00;} else {PORTB++;}
}

void main(void){
OSCF=0; // Set Processor to 37KHz Mode
MSG1=0; // Clear MSG1
GIE=0x01; // Global Interrupt Enable
T0IE=1; // Timer0 Interrupt Enable
CMCON = 0x07; // turn off comparator
TRISB = 0b00000000; // 8bits of port B are outputs
TRISA = 0b00001111; // 4 high bits of port A are outputs and 4 low bits are inputs
//OPTION_REG = 0b11010111; // Turn on Timer 0
nRBPU = 1;
INTEDG=1;
T0CS=0;
T0SE=1;
PSA = 0; // Use prescalar for TMR0 (1 assigns it to WDT)
PS2=0; // Prescalar 111 = /256, 110= /128,
PS1=1; // 101= /64, 100= /32, 011= /16,
PS0=1; // 010= /8, 001= /4, 000= /2
// Address Name Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
// OPTION_REG nRBPU INTEDG T0CS T0SE PSA PS2 PS1 PS0
TMR0=0; // Set TMR0 to 0

while (1){ // loops forever
}
}

Now you can experement with the clock speed by setting OSCF to 0 for 37Khz and 1 for 4Mhz. You can experiment with the effects of the prescalar by setting PS2, PS1, PS0 to one of the bit patterns and see the effects in the speed of the LED's.

I hope this helps someone as much as it has helped me.
 
Why would you want to do it without interrupt? The whole point of using TMR0 for LED display multiplexing is to NOT tie the main code to driving the display, which requires the use of the TMR0 interrupt.
 
Why would you want to do it without interrupt? The whole point of using TMR0 for LED display multiplexing is to NOT tie the main code to driving the display, which requires the use of the TMR0 interrupt.

There are numerous reasons for not using interrupts (polling the timer instead), but I would agree that for multiplexing a display there are massive advantages in using interrupts (which is why my display multiplexing tutorials do just that). Essentially it completely separates the multiplexing section from the rest of the program, and you can just forget about it entirely.
 
Last edited:
I actually have a 4 digit 7 segment LED display board that's being driven by a 16F628A. TMR0 interrupts are exactly how I did it. Using the internal 4MHz oscillator I have it on a 1:8 prescale which gives me a 120Hz refresh rate and the way the instructions in the interrupt handler are timed I get a near perfect 25% duty cycle with no longer than 3-4uS blank time. Works quite well.

Then I use the on chip UART to send display data from another PIC via SPI (you have to have a software routine that reverses the received bit order since the UART receives LSB first to make this work).
 
Then I use the on chip UART to send display data from another PIC via SPI (you have to have a software routine that reverses the received bit order since the UART receives LSB first to make this work).

Surely the send and receive are both hardware and don't care which bit is sent first? If the receive is software then just reverse the shift order - put bit in carry and shift right - same with software transmit.

Mike.
 
Jon, I was bewildered by your comment too. What are you talking about? Is this a project you posted somewhere (I don't believe I've ever seen anything from you)?

Happy Holidays everyone...
 
I didn't post the project itself no. But basically I used the MSSP on a PIC 16F887 operating in SPI master mode to a PIC 16F628A's UART in synchronous slave mode.

Now...the MSSP sends the byte out MSB first. The USART shifts the bits in LSB first...meaning that when the byte is transferred from the SSR to the receive buffer RCREG, the byte that was sent as the MSB from the MSSP ends up in the LSB position in RCREG.

So...once in RCREG, you transfer it to another buffer, then run a routine that reverses the order of the bits.
 
Well, you learn something new everyday. Never realized that the two were different.

Thanks,

Mike.
 
I didn't either until I interfaced the two and was getting erroneous readouts on the LED display. Then did some research and found that the USART sends/receives LSB first whether you're in synchronous or asynchronous modes (I already was aware that the MSSP sends/receives MSB first). Once I coded up the bit reversal routine it worked like a charm.

Code goes something like -

Code:
RXBIT		EQU		0x20
RXDATA		EQU		0x21



		movfw		RCREG
		movwf		RXBIT
		clrf		RXDATA


		btfsc		RXBIT,7
		bsf		RXDATA,0

		btfsc		RXBIT,6
		bsf		RXDATA,1
		
		btfsc		RXBIT,5
		bsf		RXDATA,2
	
		btfsc		RXBIT,4
		bsf		RXDATA,3

		btfsc		RXBIT,3
		bsf		RXDATA,4
		
		btfsc		RXBIT,2
		bsf		RXDATA,5

		btfsc		RXBIT,1
		bsf		RXDATA,6

		btfsc		RXBIT,0
		bsf		RXDATA,7

After this routine, the data in RXDATA ends up matching the data as was sent from the MSSP.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top