PWM with Timer0

General discussion on mikroC.
Post Reply
Author
Message
Silverback
Posts: 11
Joined: 01 Aug 2010 16:17

PWM with Timer0

#1 Post by Silverback » 26 Aug 2010 19:16

I'm working on a PWM program to run four servos, however when I compile it I get the error, "Operator '.' is not applicable to these operands 'INTCON' ". The error refers to line 9 and 11, and the way I reference TMR0IF. Apparently I can't use INTCON.TMR0IF, or even just TMR0IF without getting an error. I have an empty While statement, so you can ignore that unless it is somehow the cause of the problem.

Any ideas?

Thank you.

Code: Select all


unsigned int POS0, POS1, POS2, POS3;       // Servo position variables
unsigned int RTC=0;                        // Real Time Counter variable


void interrupt(void) {

  if (INTCON.TMR0IF) {
    RTC++;                  // Real Time Counter
    INTCON.TMR0IF=0;               // Reset Timer0 Interrupt Flag

    if(RTC >= POS0) && (POS0 > 0) && (POS0 < 40) {
      RC0.bit=0b00000000;   // Bring servo 1 bit low
    }
    
    if(RTC >= POS1) && (POS1 > 0) && (POS1 < 40) {
      RC1.bit=0b00000000;   // Bring servo 2 bit low
    }
    
    if(RTC >= POS2) && (POS2 > 0) && (POS2 < 40) {
      RC2.bit=0b00000000;   // Bring servo 3 bit low
    }
    
    if(RTC >=POS3) && (POS3 > 0) && (POS3 < 40) {
      RC3.bit=0b00000000;   // Bring servo 4 bit low
    }
    
    if(RTC >= 400) {
      PORTC=0b00001111;     // Bring servo pins high high
    }

}
}
void main() {

//Timer0 Registers Prescaler= 1; TMR0 Preset = 156; Freq = 20000.00 Hz; Period = 0.000050 seconds, Oscillator = 8MHz
//Equation: Delay=(2^8-TMR0)*1/(Fosc/(4*Prescaler))=50us

OPTION_REG.T0CS = 0;  // bit 5  TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
OPTION_REG.T0SE = 0;  // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
OPTION_REG.PSA = 1;   // bit 3  Prescaler Assignment bit...0 = Prescaler is assigned to the WDT
OPTION_REG.PS2 = 0;   // bits 2-0  PS2:PS0: Prescaler Rate Select bits
OPTION_REG.PS1 = 0;
OPTION_REG.PS0 = 0;
TMR0 = 156;             // preset for timer register

  while(1) {
  
  }
}

braus
Posts: 167
Joined: 25 Jul 2007 22:55
Location: Mexico, city.

Re: PWM with Timer0

#2 Post by braus » 26 Aug 2010 20:02

Hello Silverback, it will be helpful that you tell us what PIC are you using, where are you getting those errors, etc.
Nevertheless I have som comments

Code: Select all

unsigned int POS0, POS1, POS2, POS3;       // Servo position variables
unsigned int RTC=0;                        // Real Time Counter variable


void interrupt(void) {

  if (INTCON.TMR0IF) {
    RTC++;                  // Real Time Counter
    INTCON.TMR0IF=0;               // Reset Timer0 Interrupt Flag

    if(RTC >= POS0) && (POS0 > 0) && (POS0 < 40) {
      RC0.bit=0b00000000;   // Did you try type PORTC.F0 or PORTC.B0 besides, as you are referring
    }                                //to a single bit it is enough to use 1 or 0 as value. 
    
    if(RTC >= POS1) && (POS1 > 0) && (POS1 < 40) {
      RC1.bit=0b00000000;   // Bring servo 2 bit low
    }
    
    if(RTC >= POS2) && (POS2 > 0) && (POS2 < 40) {
      RC2.bit=0b00000000;   // Bring servo 3 bit low
    }
    
    if(RTC >=POS3) && (POS3 > 0) && (POS3 < 40) {
      RC3.bit=0b00000000;   // Bring servo 4 bit low
    }
    
    if(RTC >= 400) {
      PORTC=0b00001111;     // Bring servo pins high high
    }

}   //prior to leave interrupt service routine you have to set INTCON.GIE bit
}
void main() {

//Timer0 Registers Prescaler= 1; TMR0 Preset = 156; Freq = 20000.00 Hz; Period = 0.000050 seconds, Oscillator = 8MHz
//Equation: Delay=(2^8-TMR0)*1/(Fosc/(4*Prescaler))=50us

OPTION_REG.T0CS = 0;  // bit 5  TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
OPTION_REG.T0SE = 0;  // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
OPTION_REG.PSA = 1;   // bit 3  Prescaler Assignment bit...0 = Prescaler is assigned to the WDT
OPTION_REG.PS2 = 0;   // bits 2-0  PS2:PS0: Prescaler Rate Select bits
OPTION_REG.PS1 = 0;
OPTION_REG.PS0 = 0;   //Sometimes it is best to write the whole register I mean OPTION_REG=0xHH.
TMR0 = 156;             // You are setting a value in TMR0 and actually you wrote code to attend an
  while(1) {              //interrupt generated by TMR0 but you never configured INTCON to enable that
                             //interrupt flag.
  }
}
Best Regards
Omar Galicia
Mexico City

Silverback
Posts: 11
Joined: 01 Aug 2010 16:17

Re: PWM with Timer0

#3 Post by Silverback » 26 Aug 2010 21:34

Thanks for the reply. I know the code looks pretty bad but I compile my code frequently just to keep my errors from compounding. The chip is a 28 pin 16f876. I finally figured out that instead of using the register name in the datasheet (TMR0IF), that I have to use T0IF. I'm used to a different compiler, and this one's taking a bit of getting used to.

Thank you. I'm sure I'll have another post once I get a little further.

Silverback
Posts: 11
Joined: 01 Aug 2010 16:17

Re: PWM with Timer0

#4 Post by Silverback » 27 Aug 2010 17:47

Here's that post I mentioned might come a little later.

The program seems to be working to the extent I have it programmed. All that is but the timer interrupt. I've run the debugger to ensure the proper steps are being taken with all of my assigned variables. Apparently the timer does not function in the debugger mode, and after hooking the circuit up to an oscilloscope the pulse width appears to be 83us instead of 20ms.

I would also like to know if reinitializing TMR0 at the end of the interrupt routine is necessary or not.


Thank you.

Code: Select all

// Servo control for 4 servos
// Timer0 is set for 50us, so 30 counts = 1.5ms, 400 counts = 20ms
// MCU: PIC16f876
// Oscillator: 8MHz
// Servos: 4x "T Pro SG-50"s

#define LEFT  22       // Servo position references
#define CENTER  30     //
#define RIGHT  38      //

#define GAIN0 1        // Servo gains
#define GAIN1 1        //
#define GAIN2 1        //
#define GAIN3 1        //

unsigned int POS0, POS1, POS2, POS3;       // Servo position variables
unsigned int RTC=0;                        // Real Time Counter variable
unsigned int i=0, j=0, k=0, l=0;           // Servo loop counters

void interrupt() {

     // RTC counts from 0 to 400. POSx variables will fall between 22 counts (1.1ms)
     // and 38 counts (1.9ms). Pins corresponding to MCU pins are individually brought
     // high and low to generate the required pulse width.

  if (T0IF_bit) {
    RTC++;                  // Real Time Counter
    INTCON.T0IF=0;          // Reset Timer0 Interrupt Flag
    
    if(RTC >= POS0) {
      RC0_bit=0;   // Bring servo 1 bit low
    }
    
    if(RTC >= POS1) {
      RC1_bit=0;   // Bring servo 2 bit low
    }
    
    if(RTC >= POS2) {
      RC2_bit=0;   // Bring servo 3 bit low
    }
    
    if(RTC >= POS3) {
      RC3_bit=0;   // Bring servo 4 bit low
    }
    
    if(RTC >= 400) {
      PORTC=0b00001111;     // Bring servo pins high
    }

    TMR0=156;               // Reinitialize Timer0
}
}

void FORWARD() {
  for(i = POS0; i >= LEFT; i -= GAIN0) {    // Move front-left leg back
    POS0 = i;
  }
  
  for(j = POS1; j >= LEFT; j -= GAIN1) {    // Move front-right leg forward
    POS1 = j;
  }
  
  for(k = POS2; k >= LEFT; k -= GAIN2) {     // Move rear-left leg back
    POS2 = k;
  }
  
  for(l = POS3; l >= LEFT; l -= GAIN3) {    // Move rear-right leg forward
    POS3 = l;
  }
}

void main() {

//Timer0 Registers Prescaler= 1; TMR0 Preset = 156; Freq = 20000.00 Hz; Period = 0.000050 seconds
//Equation: Delay=(2^8-TMR0)*1/(Fosc/(4*Prescaler))=50us

OPTION_REG=0b11001000;// See following 6 lines
//OPTION_REG.T0CS = 0;  // bit 5  TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
//OPTION_REG.T0SE = 0;  // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
//OPTION_REG.PSA = 1;   // bit 3  Prescaler Assignment bit...0 = Prescaler is assigned to the WDT
//OPTION_REG.PS2 = 0;   // bits 2-0  PS2:PS0: Prescaler Rate Select bits
//OPTION_REG.PS1 = 0;
//OPTION_REG.PS0 = 0;
TMR0 = 156;             // preset for timer register
INTCON=0b10100000;      // See following 2 lines
//INTCON.T0IE=1;      // Enable Timer0
//INTCON.GIE=1;       // Enable global interrupts

// Initialize servos

POS0 = RIGHT;
POS1 = RIGHT;
POS2 = RIGHT;
POS3 = RIGHT;

TRISA=0b11111111;
PORTA=0b11111111;
TRISB=0b00000000;
PORTB=0b00000000;
TRISC=0b00000000;
PORTC=0b00000000;

Delay_ms(1000);     // Wait 1s before starting
  while(1) {
    FORWARD();      // Move forward

  }
}

User avatar
ranko.rankovic
Posts: 433
Joined: 11 Jun 2010 09:22

Re: PWM with Timer0

#5 Post by ranko.rankovic » 31 Aug 2010 14:55

Hello Silverback,

While in code, you can use code assistant (CTRL+Space) to see possibilities for Timer0. When pressed it should pop out screen like this:
post.JPG
post.JPG (16.95 KiB) Viewed 3066 times
Best regards
Ranko Rankovic
mikroElektronika [Support Department]

Post Reply

Return to “mikroC General”