Timer0 Problems

General discussion on mikroC.
Post Reply
Author
Message
ignite
Posts: 15
Joined: 02 Nov 2009 22:23

Timer0 Problems

#1 Post by ignite » 17 Nov 2009 20:05

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!!

janni
Posts: 5373
Joined: 18 Feb 2006 13:17
Contact:

Re: Timer0 Problems

#2 Post by janni » 18 Nov 2009 02:52

ignite wrote:How do I select correct prescaler for min frequency of 5Hz and max of 250Hz??
Prescaler of 1:8 will give 50000 counts at 5Hz and 1000 at 250Hz while measuring period.
When I find the timer value do I multiply by a number to convert this value into seconds??
Sure, multiply it by 4 to get time in us, then divide by 1000 to get time in ms.
How can I find the frequency when I have the period?
Frequency is reverse of period - simply divide 250000 by the count (250000/50000=5Hz, 250000/1000=250Hz).
This is the code which I have written but it does not work!!!
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.

ignite
Posts: 15
Joined: 02 Nov 2009 22:23

#3 Post by ignite » 18 Nov 2009 12:56

you enable interrupts without servicing them (can't do that in main) so the code is stuck
I dont understand what this means I'm new to dealing with interrupts! Could you please give an example?? I have tried looking in the complier for examples but I dont no what I am looking for!

Please Help

janni
Posts: 5373
Joined: 18 Feb 2006 13:17
Contact:

#4 Post by janni » 18 Nov 2009 16:24

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.

ignite
Posts: 15
Joined: 02 Nov 2009 22:23

#5 Post by ignite » 18 Nov 2009 18:04

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();
  
  }
}

janni
Posts: 5373
Joined: 18 Feb 2006 13:17
Contact:

#6 Post by janni » 18 Nov 2009 21:49

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

Code: Select all

frequency = period/250000;
should be changed to

Code: Select all

frequency = 250000/period;
but take care to keep period>0.

UR90
Posts: 29
Joined: 10 Mar 2010 19:00
Location: Slovenia

Re: Timer0 Problems

#7 Post by UR90 » 27 Dec 2010 13:24

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 :roll: .

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.
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
excuse my english

Post Reply

Return to “mikroC General”