View previous topic :: View next topic |
Author |
Message |
jemmyduc
Joined: 22 May 2013 Posts: 18
|
interrupt timer0 and timer1 in 18F4431 |
Posted: Fri Nov 22, 2013 8:19 am |
|
|
Hello
I use 18F4431 to read ADC and control RC servo motor. I have problem in interrupt timer0 and timer1. INT_RTCC work properly while INT_TIMER1 no run. INT_RTCC to set time for read ADC, and INT_TIMER1 generate the pulse to control RC servo.
This is my code
#include <Slave.h>
#include <math.h>
#include <RS232_Master.c>
#include <Read_ADC.c>
#include <RCservo.c>
#priority timer1,timer0,ssp,ext,ext1,ext2 //uu tien ngat theo thu tu
#include <I2C_Slave.c>
////////////RC servo////////////////
//Left Limit: duty = 251
//Right Limit: duty = 500
/////RC
#define BOT_VALUE=1000,TOP_VALUE=2000,MAX_VALUE=20000;//BOT_VALUE=10,TOP_VALUE=20,MAX_VALUE=200
int16 dem1,dem2;
int16 RC_duty;
////////////////////////////////////
int16 duty_1=0,duty_2=0,duty_3=0;
int16 count=0;
float angle_zx, angle_zy;
//Function///////////////////////////////
void lcd_number1(float number);
void lcd_number2(float number);
void lcd_number3(float number);
//INTERRUPT
#INT_RTCC
void interrupt_timer0()
{
count++;
if(count=152)//0.5s
{
count=0;
//AN1
set_adc_channel(1);
ReadADC_Init();
adc_1 = read_adc();
//RS232_Float(adc_1);
//AN2
set_adc_channel(2);
ReadADC_Init();
adc_2 = read_adc();
//RS232_Float(adc_2);
//AN3
set_adc_channel(3);
ReadADC_Init();
adc_3 = read_adc();
//RS232_Float(adc_3);
}
}
#INT_TIMER1
void ngat_timer1()
{
dem2++;
if(dem2==65535)
{
dem2=0;
RS232_Float(adc_1);
}
set_timer1(65530);
dem1++;
if (dem1==RC_duty)
{
output_low(pin_c0);
}
if (dem1==MAX_VALUE)
{
dem1=0;
output_high(pin_c0);
}
}
void main()
{
//Set tris port
set_tris_b(0x00);
set_tris_c(0x00);
//Khoi tao ngat
enable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
//Set up ADC
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(sAN0|sAN1|sAN4|VSS_VDD);
//Set up power pwm
// Setup the 4 Power PWM channels as ordinary pwm channels.
setup_power_pwm_pins(PWM_ODD_ON, PWM_ODD_ON, PWM_ODD_ON, PWM_ODD_ON);
// Mode = Free Run
// Postscale = 1 (1-16) Timebase output postscaler
// TimeBase = 0 (0-65355) Initial value of PWM Timebase
// Period = 2000 (0-4095) Max value of PWM TimeBase
// Compare = 0 (Timebase value for special event trigger)
// Compare Postscale = 1 (Postscaler for Compare value)
// Dead Time
setup_power_pwm(PWM_CLOCK_DIV_4|PWM_FREE_RUN,//modes
1, //postscale
0, //time_base
249, // Period // tan so la 5Khz, full duty = 1000
0, //compare
1, //compare_postscale
0); //dead_time
set_power_pwm0_duty(1000);
set_power_pwm2_duty(1000);
set_power_pwm4_duty(1000);
output_high(pin_b0);
output_high(pin_b2);
output_high(pin_b5);
//RC servo
RC_duty=1500;
output_high(pin_c0);
//Timer0
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64);//old:64
set_timer0(0);//old:0
//TIMER 1 : behind all setup fucntions
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
set_timer1(65530); //0.1us
while(1)
{
}
}
I hope someone can help me to find error. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Nov 22, 2013 8:29 am |
|
|
1) Learn to use the code buttons....
2) Lumps are missing. ReadADC_Init?. RS232_Float();
3) Is ADC_CLOCK_ITERNAL legal at your clock rate?.
4) The approach is fundamentally flawed. The ADC takes 13 cycles of it's clock to perform a conversion, and requires the internal capacitor to be charged to the external voltage for quite a few uSec, before a conversion can be started. You _do not_ want to be doing this inside an interrupt. Use a state machine. Select the channel. Exit the interrupt. Next interrupt, start the conversion, exit the interrupt. Then on the next interrupt read the result. Let the hardware get on and do it's jobs in the time between interrupts, don't wait for this to happen inside the interrupt....
5) then the same applies in the next timer. I'm guessing that RS232_Float involves writing a float to the RS232?. If so, forget it. First float maths is appallingly slow. Then you don't want to be waiting for RS232 transmission to occur in the interrupt. Set a flag, and do these operations in the main code.
Repeat the mantra fifty times _keep interrupt handlers as quick as possible_. |
|
|
jemmyduc
Joined: 22 May 2013 Posts: 18
|
|
Posted: Fri Nov 22, 2013 9:51 am |
|
|
Thank you for your reply
ReadADC_Init() is a function to waiting for interrupt flag of ADC transfer and RS232_Float() is a function i wrote to send float data by RS232. And those work properly. But i think you right.
My main problem is INT_TIMER1
Code: |
#INT_TIMER1 HIGH
void interrupt_timer1()
{
set_timer1(65530);//1us
dem1++;
if (dem1==RC_duty)
{
output_low(pin_c0);
}
if (dem1==MAX_VALUE)
{
dem1=0;
output_high(pin_c0);
}
} |
This code don't work any more. I checked it.
I try to add the priority for interrupt timer1. But it still has not work. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Nov 22, 2013 1:48 pm |
|
|
Quote: | My main problem is INT_TIMER1
#INT_TIMER1 HIGH
void interrupt_timer1()
{
set_timer1(65530);//1us
dem1++;
if (dem1==RC_duty)
{
output_low(pin_c0);
}
if (dem1==MAX_VALUE)
{
dem1=0;
output_high(pin_c0);
}
} |
I assume you're running the PIC at 20 MHz. You can't get a 1 usec
interrupt rate. Your code inside the isr takes much longer than that
to run. The isr has hidden code to save registers before entering your
routine above, and to also restore registers after exiting your routine.
You need to think of a new program design that doesn't need a 1 usec
interrupt rate. |
|
|
jemmyduc
Joined: 22 May 2013 Posts: 18
|
|
Posted: Fri Nov 22, 2013 5:54 pm |
|
|
Thank PCM programer
I will change my code, You can guide me to set 1us, I cant use delay(). Because I want to control RC servo motor
Thank you so much again |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Nov 22, 2013 7:27 pm |
|
|
You want to control an RC servo. These units normally are given a
pulse between 1 and 2 ms, with 1.5ms pulse as the idle state.
Why do you think you need 1us resolution ?
There is some code in this thread for higher resolution (but not 1us).
It uses the CCP1 module in the PIC:
http://www.ccsinfo.com/forum/viewtopic.php?t=44328 |
|
|
jemmyduc
Joined: 22 May 2013 Posts: 18
|
|
Posted: Fri Nov 22, 2013 7:35 pm |
|
|
Because i want to have a controlling range from 100 to 200 with period is 20000.
Thank for your reply. i trying to do follow the link you give me |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Nov 22, 2013 7:41 pm |
|
|
I assume you mean 20000 is the 20000us (20ms) period for the pulses.
But where do you get the "100 to 200" from ? The pulse will be 1000us
to 2000us (1ms to 2ms) in duration. Not 100 to 200us.
Read this page here. It has a timing diagram of servo pulses:
http://www.helifreak.com/showthread.php?t=263175 |
|
|
jemmyduc
Joined: 22 May 2013 Posts: 18
|
|
Posted: Fri Nov 22, 2013 9:01 pm |
|
|
I got it and i make a correct control.
Thank you again. |
|
|
|