PIC18F4550 problem with TIMER interupt

Status
Not open for further replies.

mikimtb

Newbie level 1
Joined
Dec 16, 2010
Messages
1
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Visit site
Activity points
1,296
Hi everybody, my name is Miroslav and I'm from Serbia.
I'm trying to write a code for controlling four RC servo motors with PIC18F4550. Till now I finished all things about USB HID and UART communication, and it's working perfectly.

Today I try to write a code for timer0 configuration. Because I have four motors to control, I need timer0 interrupts on every ~5ms. I configured timer0 as 16bit timer/counter, increment on internal clock, with prescaler of 1:2. After that I configured interrupt priority low for timer0 and enable timer0 interrupt. With timer0 prescaler 1:2 I have to write offset of 35398 into TMR0H:TMR0L and timer will overflow on every 5ms (30137*0.083us * 2 = 5002us).
Firstly, I tested this in main loop and its work perfectly. Code for my test is below:

Code:
void TIMER0Init(void)
{
	T0CONbits.TMR0ON = 0;	// Disable TMR0
	T0CONbits.T08BIT = 0;	// Timer0 is 16bit timer/counter
	T0CONbits.T0CS = 0;		// Internal clock source	
	T0CONbits.PSA = 0;		// Prescaler enabled
	T0CONbits.T0PS2 = 0;	// 1:2 Prescaler ratio	
	T0CONbits.T0PS1 = 0;
	T0CONbits.T0PS0 = 0;
	
	/* Make Timer0 interrupt low priority */
	INTCON2bits.TMR0IP = 0;
	/* Enalbe TMR0 interrupt*/
	INTCONbits.TMR0IE = 0;
	/* Enable all low priority interrupts */
	INTCONbits.GIEL = 0;
	/*Clear TMR0 interrupt flag*/
	INTCONbits.TMR0IF = 0;
	
	/* Write Timer0 offset for ~5ms interrupt */
	TMR0H = 0;
	TMR0L = 0;
	
	T0CONbits.TMR0ON = 1; // Start the timer
.
.
.
// infinite loop inside main function
while(1)
    {
        #if defined(USB_POLLING)
			// If we are in polling mode the USB device tasks must be processed here
			// (otherwise the interrupt is performing this task)
	        USBDeviceTasks();
        #endif
    	
    	// Process USB Commands
        processUsbCommands();  
        
        // Process UART Commands
        processUartCommand();
        
        // timer0 test
        timerValuePtr = (unsigned char*)&timerValue;
	*timerValuePtr = TMR0L;
	timerValuePtr++;
	*timerValuePtr = TMR0H;

	if(timerValue >= 30137) 
	{ 
		PORTBbits.RB0 ^= 1;
		
		timerValue = 0;
		TMR0H = 0;
		TMR0L = 0;
	}
        // timer0 test end
}

After proofing this with oscilloscope, I changed the code to do the same thing with interrupt. The code is below:
Code:
void TIMER0Init(void)
{
	T0CONbits.TMR0ON = 0;	// Disable TMR0
	T0CONbits.T08BIT = 0;	// Timer0 is 16bit timer/counter
	T0CONbits.T0CS = 0;		// Internal clock source	
	T0CONbits.PSA = 0;		// Prescaler enabled
	T0CONbits.T0PS2 = 0;	// 1:2 Prescaler ratio	
	T0CONbits.T0PS1 = 0;
	T0CONbits.T0PS0 = 0;
	
	/* Make Timer0 interrupt low priority */
	INTCON2bits.TMR0IP = 0;
	/* Enalbe TMR0 interrupt*/
	INTCONbits.TMR0IE = 1;
	/* Enable all low priority interrupts */
	INTCONbits.GIEL = 1;
	/*Clear TMR0 interrupt flag*/
	INTCONbits.TMR0IF = 0;
	
	/* Write Timer0 offset for ~5ms interrupt */
	TMR0H = 138;
	TMR0L = 70;
	
	T0CONbits.TMR0ON = 1; // Start the timer
}


// Low-priority ISR handling function
#pragma interruptlow lowPriorityISRCode
void lowPriorityISRCode()
{
	// Application specific low-priority ISR code goes here
	
	// TMR0 interrupt
	if(INTCONbits.TMR0IF)
	{
		TMR0H = 138;							// Write offset for 5ms overflow
		TMR0L = 70;						
		PORTBbits.RB0 ^= 1; 					// Toggle PORTB.0
		INTCONbits.TMR0IF;						// Clear interrupt flag
	}
}

Again I had PWM signal on RB0 pin but the frequency wasn't 200Hz. Instead that frequency is 193kHz. I try to change prescaler value, or offset value but the frequency is constant 193kHz. In code above I didn't copy RCONbits.IPEN = 1; for interrupt priority enables. This configuration is in picInit function.

Does somebody had problem like this? I mentioned that I had uart and usb communication, does that can be a problem? I'm using PIC C18 compiler.

- - - Updated - - -

I found the error,
INCONBits.TMR0IF; has to be INCONBits.TMR0IF = 0;
I was blind almost four hour, wtf.
 
Last edited:

check this code its working its for 4520 but hopefully will work also for 4550
Code:
#include <p18f4520.h>
#include <usart.h>
#include <timers.h>
#pragma config OSC = HS
#pragma config PWRT = OFF
#pragma config MCLRE = ON
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config DEBUG = ON
#pragma config PBADEN = OFF
#define SERVO_PULSE_HIGH LATCbits.LATC0 =1
#define SERVO_PULSE_LOW LATCbits.LATC0 =0
#define CONVERT_mS_PULSE 10000.0 
void chk_handler (void);
void chk_handler_low (void);
unsigned char val1=0,val2=0,int1=0,int2=0,servo=0,dc=0,state=0,state1=0;
unsigned int timer0=0,t1=0,timer1=0;
unsigned long s=0,d=0;
float t=0,dt=0;
////high priority interrupt
#pragma code interrupt = 0x8
void _interrupt (void)
{
  _asm goto chk_handler _endasm
}
///LOW priority interrupt
#pragma code interruptlow = 0x18
void interruptlow (void)
{
  _asm goto chk_handler_low _endasm
}

#pragma code
#pragma interruptlow chk_handler_low
void chk_handler_low (void)
{
unsigned char c=0;
/* as timer is included in low priority interrupt so when its interrupt come*/ 
if (INTCONbits.TMR0IF)
{ 
///we r deviding the 20ms as///////
//0----->servo on time(ms) for state 0///
//and       off time=20-servo on time for state 1----->19//// 
if(state==0)
{
////for state zero on the on servo///
PORTCbits.RC0=1;
///time devision if less then 50 pressed the its move right but with deviosion will be of 8us/////
if(servo<=50)
{
t=servo*.008+.960;///0-50 the devision will be 8us
}
///if greater than 50 its moves let but devision of 8.68us////   
else
{
t=servo*.00868+.960;
}
}
/////servo of for 20-ontime////
else if(state==1)
{
PORTCbits.RC0=0;
////time interrupt will come after 2ms-ontime for making calculation easy for next 18ms
t=2.0-t;
}
else if(state>1&&state<19)
{
PORTCbits.RC0=0;
////1ms timer interrupt
t=1.0;
}
///////put value to timero variable/////
timer0=(unsigned int)(65536-(t*CONVERT_mS_PULSE));//(t*CONVERT_mS_PULSE));
INTCONbits.TMR0IF=0;
T0CONbits.TMR0ON = 1;
////write timer0
WriteTimer0(timer0);
state++;
//////after 20ms state value should be zero for next pulse
if(state>19)
state=0;
}
if (PIR1bits.TMR1IF)
{  
if(state1==0)
{
////for state1 zero on the on DC///
PORTCbits.RC1=1;
///time devision if less then 150 pressed the its move right but with deviosion will be of 8us/////
dt=dt*.010;///the devision will be 10us
}
else if(state1==1)
{
PORTCbits.RC1=0;
////time interrupt will come after ontime for making calculation easy for next
dt=1.0-dt;
}
///////put value to timero variable/////
timer1=(unsigned int)(65536-(dt*CONVERT_mS_PULSE));
PIR1bits.TMR1IF=0;
T1CONbits.TMR1ON = 1;
////write timer0
WriteTimer1(timer1);
state1++;
//////after 20ms state value should be zero for next pulse
if(state1>1)
state1=0;
} 
if(PIR1bits.RCIF==1)
{
  c = ReadUSART();
  WriteUSART(c);
////if value is in between then get as data////
  if (c >= '0' && c <= '9')
   {
///ascii o 0 is 48 and 1 is 48 and so on////
////so subsrtat 48 or getting actual value///// 
   c=c-48;
    val1=val1*10+c;
   // PORTD=val1;
    }
///////////////enter/////////////
////if enetr pressed then get value///
    else if(c==13)
   {
    val2=val1;
  //  PORTD=val2;
///is this for servo////
if(val2<100&&val2>=0)
{
servo=val2;
}
////or for dc///
if(val2>=100&&val2<200)
{
////if for dc subtratc from 100 as user is enterring off by 100 for dc///
dc=val2-100;
}
//PORTD=servo;
     val1=0;
    }
////////back space//////////////
  else if(c==8)
   {
    val1=(val1-(val1%10))/10;
     PORTD=val1;
    }
c=0;
   // PORTD=c;
PIR1bits.RCIF = 0;
}
}
#pragma code
#pragma interrupt chk_handler
void chk_handler (void)
{
if(INTCONbits.INT0IF)////if from portb 1st pin(servo robot)
{
if(servo==0)
{
int1++;
INTCONbits.INT0IF = 0;
INTCONbits.INT0IE = 1;
if(int1==1)//////rising edge
{
PORTCbits.RC0 = 1;
INTCON2bits.INTEDG0 = 0;///set interrupt on falling edge
}
if(int1==2)////falling edge
{

PORTCbits.RC0 = 0;
INTCON2bits.INTEDG0 = 1;///set interrupt on rising edge edge
int1=0;
}
}
else
{
INTCONbits.INT0IF = 0;
INTCONbits.INT0IE = 1;
}
}
if(INTCON3bits.INT1IF)////if from portb 1st pin(servo robot)
{
if(dc==0)
{
int2++;
INTCON3bits.INT1IF = 0;
INTCON3bits.INT1IE = 1;
if(int2==1)//////rising edge 
{
PORTCbits.RC1 = 1;
INTCON2bits.INTEDG1 = 0;///set interrupt on falling edge
}
if(int2==2)////falling edge
{
PORTCbits.RC1 = 0;
INTCON2bits.INTEDG1 = 1;///set interrupt on rising edge edge
int2=0;
} 
}
else
{
INTCON3bits.INT1IF = 0;
INTCON3bits.INT1IE = 1;
}
}
}

void main (void)
{
INTCONbits.INT0IF = 0;///interrupt0 interrupt flag set to 0
INTCONbits.INT0IE = 1;///interrupt0 enable
INTCON2bits.INTEDG0 = 1;//interrupt on rising edge
TRISCbits.TRISC0 = 0;/////////////////O/p for servo
TRISCbits.TRISC1 = 0;/////////////////O/p for servo
TRISBbits.TRISB0 = 1;/////interrupt i/p
TRISBbits.TRISB1 = 1;/////interrupt i/p
INTCON3bits.INT1IE=1;///EXTERNAL INTERRUPT 1
INTCON3bits.INT1IF=1;///EXTERNAL INTERRUPT FLAG CLEARED
//INTCON3bits.INT2IP=0;
//INTCON3bits.INT1IP=0;
PORTC = 0x00;/////no movement
TRISD = 0;////CHECKING WHETHER IT IS GETTING DATA FROM SERIAL
PORTD=0;
  /* 4800 baud for 4 mhz crystal by adjusting value to 64, */
  OpenUSART (USART_TX_INT_OFF &
             USART_RX_INT_ON &
             USART_ASYNCH_MODE &
             USART_EIGHT_BIT &
             USART_CONT_RX &
             USART_BRGH_LOW, 64);

  /* Display a prompt to the USART */
  putrsUSART ((const far rom char *)"\n\rEnter a digit 0-99 for servo and 100-199 for dc motor!\n\r");

  /* Enable interrupt priority */
  RCONbits.IPEN = 1;
/* Clear the peripheral interrupt flags */
   PIR1 = 0;
//////TIMER0///////////
t=1.0;
dt=0;
OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_1);

/*timer0 interrupt priority low*/
INTCON2bits.TMR0IP=0;
////timer interrupt calculation ///
timer0=(unsigned int)(65536-(t*CONVERT_mS_PULSE));//(t*CONVERT_mS_PULSE));
WriteTimer0(timer0);
///TIMER1/////////
///interrupt priority low//
IPR1bits.TMR1IP=0;
OpenTimer1(TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_1 & T1_OSC1EN_OFF);
T1CONbits.TMR1CS = 0; //Timer 1Clock internal source
timer1=(unsigned int)(65536-(dt*CONVERT_mS_PULSE));//(t*CONVERT_mS_PULSE));
WriteTimer1(timer1);
  /* Make receive interrupt high priority */
  IPR1bits.RCIP = 0;

  /* Enable all high priority interrupts */
  INTCONbits.GIEH = 1;
/* Enable all low priority interrupts */
  INTCONbits.GIEL = 1;
  /* Loop forever */
while (1)
{
if(servo>0)/////ON
{
//PORTDbits.RD3=~PORTDbits.RD3;
T0CONbits.TMR0ON = 1;
}
else//////////OFF
{     
T0CONbits.TMR0ON = 0;
}
if(dc>0)
{
T1CONbits.TMR1ON = 1;
}
else
{
T1CONbits.TMR1ON = 0;
}
       
}
}
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…