T3STY
Full Member level 4
- Joined
- Apr 17, 2012
- Messages
- 239
- Helped
- 24
- Reputation
- 48
- Reaction score
- 24
- Trophy points
- 1,308
- Activity points
- 3,715
I'm working on making the 16F84A work with an LCD display, as you may know already. Meanwhile I'm using the LED test circuit to test some timings.
I'm trying now to achieve a 1 second counter using TMR0, which, supposedly, should be far more precise than a SW delay routine, with no success. This is the code I am using:
What it does though, is counting... too much? I'm not sure what is it counting at all, but I get the first "second" after a few minutes, and that's on the real PIC. Simulation fails too pretty much the same way, at longer time. The reasoning behind all of this code was:
I have 4MHz crystal, which means that every macro instruction will be executed at the real speed of 1MHz. 1MHz means that 1 second equals 1,000,000 (marco)instructions. I have TMR0 that could not use the same speed to be triggered, it must use at least a prescaler of 1:2. The highest prescaler value that gives me an integer result is 1:32, which triggers TMR0 overflow every 31250 CKs of the main CK. If so, I should count 32 times the 31250 CK to get back 1MHz. So if count this in a variable, at counter value 32 I should have reached 1s with a very low approximation due to some non-counting instructions.
What is wrong then? Why am I not getting the 1 second counter?
I'm trying now to achieve a 1 second counter using TMR0, which, supposedly, should be far more precise than a SW delay routine, with no success. This is the code I am using:
Code:
#define _XTAL_FREQ 4000000
#include <htc.h>
/* XTAL Oscillator
* Watchdog timer OFF
* Power up timer OFF
* Code protection OFF
*/
__CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & CP_OFF);
int TMR0_CK=0; // here I'll count how many TMR0 CKs have been generated
char cnt=0; // Here I count, every 32 TMR0 CKs, how many seconds have passed
void main(void){
// Intializing ports as outputs, and port value 0
TRISA=0x00;
TRISB=0x00;
PORTA=0x00;
PORTB=0x00;
// Interrupts {GIE=1, T0IE=1}
INTCON=0xA1; // | GIE=1 | EEIE | T0IE=1 | INTE | RBIE | T0IF | INTF | RBIF |
// Prescaler assignment: TMR0
// Prescaler value: (bin) 100 -> 1/32
// Human translated: 1 TMR0 CK is generated every 31250 main XTAL clocks ( (4MHz/4)/32 )
OPTION_REG=0x84; // | RBPU | INTEDG | T0CS | T0SE | PSA=0 | PS2=1 | PS1=0 | PS0=0 |
// The code runs from the interrupt routine from now on,
// it will count clocks and update PORTB value
// the counters and other intructions will take up a few cycles
// but they're actually very few, not really important
}
void interrupt T0ISR(){
if (T0IF){ // TMR0 CK has been generated (TMR0 overflow)
TMR0_CK++; // Update TMR0 CK counter
if (TMR0_CK == 32){
// We reached 1s
// 32*31250 = 1MHz = 1s
// Resetting TMR0 CK counter
TMR0_CK=0;
// Updating the output
PORTB = cnt++;
}
// Releasing interrupt
T0IF=0;
}
}
I have 4MHz crystal, which means that every macro instruction will be executed at the real speed of 1MHz. 1MHz means that 1 second equals 1,000,000 (marco)instructions. I have TMR0 that could not use the same speed to be triggered, it must use at least a prescaler of 1:2. The highest prescaler value that gives me an integer result is 1:32, which triggers TMR0 overflow every 31250 CKs of the main CK. If so, I should count 32 times the 31250 CK to get back 1MHz. So if count this in a variable, at counter value 32 I should have reached 1s with a very low approximation due to some non-counting instructions.
What is wrong then? Why am I not getting the 1 second counter?