Hy im using TIMER0 in the 18F4520 PIC to measure frequency. This is then converted into wind speed. Im using an 8MHz crystal on the EasyPic5 Dev board and programming with MikroC v8.1.
How do I select correct prescaler for min frequency of 5Hz and max of 250Hz??
When I find the timer value do I multiply by a number to convert this value into seconds??
How can I find the frequency when I have the period?
This is the code which I have written but it does not work!!!
unsigned int timeL, timeH, display, time1H, period, speed1, speed2, frequency, speed;
char Wind_Speed[6];
char Wind_Speed1[6];
void initMain() {
ADCON0 = 0x00; // ACD off
ADCON1= 0x0F; // All I/O pins are configured as digital
TRISB = 0x00;
TRISD = 0x00;
Glcd_Init(&PORTB,0, 1, 2, 3, 5, 4, &PORTD); // Glcd_Init_EP5, see Autocomplete
Glcd_Fill(0x00); // Clear GLCD
T0CON = 0b00000111; // Initialise timer0 with prescale of 256
INTCON2.RBPU = 0x1; // Disable RB pull-ups
INTCON2.INTEDG0 = 0x1; // External Interrupt0 Rising Edge select bit
INTCON.TMR0IF = 0x0; // Clear timer0 overflow interrupt flag
INTCON.INT0IF = 0x0; // Clear external interrupt flag
INTCON.TMR0IE = 0x1; // Enable Timer0 overflow interrupt
INTCON.INT0IE = 0x1; // Enable external interrupts
INTCON.GIE = 0x1; // Enable gobal interrupts
Glcd_Fill(0x00); // Clear Screen
Glcd_Set_Font(FontSystem5x8, 5, 8, 32);
Glcd_Write_Text("Wind Speed Monitor", 12, 1, 1);
GLCD_Write_Text("Wind Speed", 30, 3, 1);
GLCD_Write_Text("0 mph", 60, 5, 1); //Display Wind speed on GLCD
}
void calc_display() {
time1H = timeH<<8;
period = time1H | timeL;
frequency = period/(period*period); // Freq = 1/T
speed = (frequency*25); // Wind Speed Conversion
speed1 = speed/10;
speed2 = speed%10;
WordToStr(speed1,Wind_Speed); // Convert to text string
LATB.RB0 = 0x0;
TRISB.RB0 = 0x0;
GLCD_Write_Text(Wind_Speed, 40, 5, 1); // Convert to text string
GLCD_Write_Text(".", 46, 5, 1);
WordToStr(speed2,Wind_Speed1); // Convert to text string
GLCD_Write_Text(Wind_Speed1, 47, 5, 1);
LATB.RB0 = 0x1;
TRISB.RB0 = 0x1;
}
void main() {
initMain();
LATB.RB0 = 0x1; // Port B set as input
TRISB.RB0 = 0x1;
display = 0;
while(1){
if((INTCON.INT0IF) && (!T0CON.TMR0ON) == 1){ // Test external interrupt and timer0 not running
TMR0L = 0x0; // Clear timer0 lower byte
TMR0H = 0x0; // Clear timer0 upper byte
INTCON.TMR0IF = 0x0; //Clear timer0 overflow interrupt flag
T0CON.TMR0ON = 0x1; // Start timer0
timeL = 0x0; // Reset measuring variables
timeH = 0x0;
display = 0;
INTCON.INT0IF = 0x0; // Reset external interrupt flag
}
if((INTCON.INT0IF) && (T0CON.TMR0ON) == 1){ // Test external interrupt and timer0 running
T0CON.TMR0ON = 0x0; // Stop timer0
INTCON.INT0IF = 0x0; // Clear timer0 interrupt flag
timeL = TMR0L; // Save lower byte to variable
timeH = TMR0H; // Save lower byte to variable
display = 1;
INTCON.INT0IF = 0x0; // Reset external interrupt flag
}
if(INTCON.TMR0IF == 1){ // Timer0 expired
TMR0L = 0x0; // Clear timer0 lower byte
TMR0H = 0x0; // Clear timer0 upper byte
INTCON.TMR0IF = 0x0; //Clear timer0 overflow interrupt flag
timeL = 0x0; // Reset upper and lower byte
timeH = 0x0;
display = 1;
}
if(display ==1)
calc_display();
}
}
Help Plez!!
Timer0 Problems
Re: Timer0 Problems
Prescaler of 1:8 will give 50000 counts at 5Hz and 1000 at 250Hz while measuring period.ignite wrote:How do I select correct prescaler for min frequency of 5Hz and max of 250Hz??
Sure, multiply it by 4 to get time in us, then divide by 1000 to get time in ms.When I find the timer value do I multiply by a number to convert this value into seconds??
Frequency is reverse of period - simply divide 250000 by the count (250000/50000=5Hz, 250000/1000=250Hz).How can I find the frequency when I have the period?
Well, you enable interrupts without servicing them (can't do that in main) so the code is stuck. The interrupt flags will be set even with interrupts disabled, so it's possible to check them in main, but it's rather ineffective use of timers. Check examples provided with the compiler, like how to service interrupts.This is the code which I have written but it does not work!!!
Interrupt, as the name indicate, is a feature allowing to break flow of main code. When an interrupt event, like timer overflow happens and this interrupt is enabled, processor stops executing main code and jumps to predefined address in code memory where an interrupt service routine (ISR) should be placed.
If you intend to use interrupts, you should add a routine called interrupt and handle enabled interrupts there. See the simple example in Examples\Internal MCU modules\P18F8520\Timer0 Interrupt.
If you intend to use interrupts, you should add a routine called interrupt and handle enabled interrupts there. See the simple example in Examples\Internal MCU modules\P18F8520\Timer0 Interrupt.
Ive tried putting the code in an ISR but the code does not jump there for some reason. Ive been analysing it using the ICD. Do you have any ideas how to fix this?
Code: Select all
unsigned int timeL, timeH, display; // Define variables
unsigned int time1H, period, speed1, speed2;
unsigned int frequency, speed;
char Wind_Speed[6];
char Wind_Speed1[6];
void initMain() {
ADCON0 = 0x00; // ACD off
ADCON1= 0x0F; // All I/O pins are configured as digital
TRISB = 0x00;
TRISD = 0x00;
T0CON = 0b00000010; // Initialise timer0 with prescale of 256
INTCON2.RBPU = 0x1; // Disable RB pull-ups
INTCON2.INTEDG0 = 0x1; // External Interrupt0 Rising Edge select bit
INTCON.TMR0IF = 0x0; // Clear timer0 overflow interrupt flag
INTCON.INT0IF = 0x0; // Clear external interrupt flag
INTCON.TMR0IE = 0x1; // Enable Timer0 overflow interrupt
INTCON.INT0IE = 0x1; // Enable external interrupts
INTCON.GIE = 0x1; // Enable gobal interrupts
Glcd_Init(&PORTB,0, 1, 2, 3, 5, 4, &PORTD); // Glcd_Init_EP5, see Autocomplete
Glcd_Fill(0x00); // Clear Screen
Glcd_Set_Font(FontSystem5x8, 5, 8, 32);
Glcd_Write_Text("Wind Speed Monitor", 12, 1, 1);
GLCD_Write_Text("Wind Speed", 30, 3, 1);
GLCD_Write_Text("0 mph", 60, 5, 1); //Display Wind speed on GLCD
}
void calc_display() {
time1H = timeH<<8;
period = time1H | timeL;
frequency = period/250000; // Freq = 1/T (Divide count by 250,000)
speed = (frequency*25); // Wind Speed Conversion
speed1 = speed/10;
speed2 = speed%10;
WordToStr(speed1,Wind_Speed); // Convert to text string
LATB.RB0 = 0x0;
TRISB.RB0 = 0x0;
GLCD_Write_Text(Wind_Speed, 40, 5, 1); // Convert to text string
GLCD_Write_Text(".", 46, 5, 1);
WordToStr(speed2,Wind_Speed1); // Convert to text string
GLCD_Write_Text(Wind_Speed1, 47, 5, 1);
LATB.RB0 = 0x1;
TRISB.RB0 = 0x1;
display = 0;
TMR0L = 0x0; // Clear timer0 lower byte
TMR0H = 0x0; // Clear timer0 upper byte
timeL = 0x0; // Reset measuring variables
timeH = 0x0;
}
void interrupt() {
if((INTCON.INT0IF) && (!T0CON.TMR0ON) == 1){ // Test external interrupt and timer0 not running
INTCON.TMR0IF = 0x0; //Clear timer0 overflow interrupt flag
T0CON.TMR0ON = 0x1; // Start timer0
display = 0;
INTCON.INT0IF = 0x0; // Reset external interrupt flag
}
if((INTCON.INT0IF) && (T0CON.TMR0ON) == 1){ // Test external interrupt and timer0 running
T0CON.TMR0ON = 0x0; // Stop timer0
INTCON.INT0IF = 0x0; // Clear timer0 interrupt flag
timeL = TMR0L; // Save lower byte to variable
timeH = TMR0H; // Save lower byte to variable
display = 1;
INTCON.INT0IF = 0x0; // Reset external interrupt flag
}
if(INTCON.TMR0IF == 1){ // Timer0 expired
TMR0L = 0x0; // Clear timer0 lower byte
TMR0H = 0x0; // Clear timer0 upper byte
INTCON.TMR0IF = 0x0; //Clear timer0 overflow interrupt flag
timeL = 0x0; // Reset upper and lower byte
timeH = 0x0;
display = 1;
}
}
void main() {
initMain();
LATB.RB0 = 0x1; // Port B set as input
TRISB.RB0 = 0x1;
display = 0;
TMR0L = 0x0; // Clear timer0 lower byte
TMR0H = 0x0; // Clear timer0 upper byte
timeL = 0x0; // Reset measuring variables
timeH = 0x0;
while(1){
if(display ==1)
calc_display();
}
}
Better simply switch on a LED in ISR to see if it's beging jumped to. mikroICD is not best suited for debugging programs using timers.
As you use Timer0 in 16-bit mode, take care about the sequence in which it's registers are read/written (TMR1H is a buffer, not a real register). You use wrong order in writes.
I'm not sure I understand what you want to achieve in ISR (and why Timer0 interrupt is enabled, if all you want is to start/stop it with external interrupt), but one thing I'm sure of - interrupts will happen much faster than GLCD may be updated, so the solution with display variable is not the best. If you need a variable to organise ISR's work, use a separate one that the one signalling to main that data is ready.
You should not configure PORTB.0 as output if you have some signal connected to it (you set it later as input - why not from the beginning?).
This
should be changed to
but take care to keep period>0.
As you use Timer0 in 16-bit mode, take care about the sequence in which it's registers are read/written (TMR1H is a buffer, not a real register). You use wrong order in writes.
I'm not sure I understand what you want to achieve in ISR (and why Timer0 interrupt is enabled, if all you want is to start/stop it with external interrupt), but one thing I'm sure of - interrupts will happen much faster than GLCD may be updated, so the solution with display variable is not the best. If you need a variable to organise ISR's work, use a separate one that the one signalling to main that data is ready.
You should not configure PORTB.0 as output if you have some signal connected to it (you set it later as input - why not from the beginning?).
This
Code: Select all
frequency = period/250000;
Code: Select all
frequency = 250000/period;
Re: Timer0 Problems
Hi, i tried to mesaure speed with timer but i don't know how to correctly set the timer and prescaler. I looked up for example in mikroC and try to modified it for my purpose. But it seems not working .
distance increments by external interrupt. Question is, is that code corretly written for my purpose ? I don't know how to set prescaler to let say i'll get my speed on each 40ms. I'm running my MCU on 16Mhz.
Don't take care about SREG,TOIE2_bit,... its for AVR
Code: Select all
void Timer2Overflow_ISR() org IVT_ADDR_TIMER2_OVF {
if (counter >= _THRESHOLD) {
speed=distance/counter;
counter = 0;
distance=0; // reset counter
}
else
counter++; // increment counter
void main() {
SREG_I_bit = 1; // interrupt enable
TOIE2_bit = 1; // timer2 overflow interrupt enable
TCCR2 = 7; // start timer with 1024 prescaler
while (1) // endless loop, displaying speed on lcd.
Don't take care about SREG,TOIE2_bit,... its for AVR
excuse my english