CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

INT_RB problem...

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
HOHOHAHA



Joined: 13 Apr 2007
Posts: 24

View user's profile Send private message AIM Address

INT_RB problem...
PostPosted: Tue Jan 15, 2008 3:40 am     Reply with quote

I am trying to make an obstacle avoidance robo, using stepper (unipolar) motor ,,, and IR for the detection...I have connected the output of and LM324 (opamp) to the interrupt pins... the IR receiver are connected to the opamp , I have checked the hardware using LEDs ... when the objects detected by a specific IR the Leds go low ( leds connected to the output of the opamp. Now I have removed the LEDs and connected the 4 outputs of the opamps to the interrupt pins(RB4-RB7) ... but the interrupt seem not to work ...

I am using PIC16F877A ... and v4 CCS ...
What is the problem with my code... please help the newbie...

Thanks in Advance...

Code:

#include <16F877A.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES PUT                      //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES WRT_50%                  //Lower half of Program Memory is Write Protected

#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#define T 20

byte last_b, port_b;
#int_rb

void rb_isr() {

    byte changes;
    byte port_b_Temp;
    port_b_Temp==input_b();
    port_b=(port_b_Temp & 0b11110000) ;

    changes = last_b ^ port_b;

    last_b = port_b;

    if (bit_test(changes,4 )&& !bit_test(last_b,4)){

         //b4 went low
         printf("\nB4 Went low");
        // enable_interrupts(INT_RB);
        // enable_interrupts(GLOBAL);     
         return ;

    }

    if (bit_test(changes,5)&& !bit_test (last_b,5)){

        //b5 went low 
      printf("\nB5 Went low");
     // enable_interrupts(INT_RB);
     // enable_interrupts(GLOBAL);
       return ;
    }

    if (bit_test(changes,6 )&& !bit_test(last_b,6)){

         //b6 went low
         printf("\nB6 Went low");
       //  enable_interrupts(INT_RB);
       //  enable_interrupts(GLOBAL);
          return ;

    }
    if (bit_test(changes,7 )&& !bit_test(last_b,7)){

         //b4 went low
         printf("\nB7 Went low");
       //  enable_interrupts(INT_RB);
       //  enable_interrupts(GLOBAL);
          return ;

    }
   // enable_interrupts(INT_RB);
   // enable_interrupts(GLOBAL);
}

void Move(void)
{
int16 i;
for(i=0;i<=24;i++)  // turns 180
{
   output_d(0b11001100);
   delay_ms(T);
   output_d(0b01100110);
   delay_ms(T);
   output_d(0b00110011);
   delay_ms(T);
   output_d(0b10011001);
    delay_ms(T);
 }
}

void main()
{
   byte last_b_Temp;
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DIV_BY_1,131,1);
   setup_ccp1(CCP_PWM);
   set_pwm1_duty(264);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   
   
   // TODO: USER CODE!!
   set_tris_a(0x00);
   output_a(0x00);
   set_tris_b(0xff);
   //port_b_pullups (FALSE);
   last_b_Temp=input_b();
   last_b=last_b_Temp & 0b11110000;
   set_tris_d(0x00);
   clear_interrupt(INT_RB);
   enable_interrupts(INT_RB);
   
   enable_interrupts(GLOBAL);

   printf("\n hello world");
   while(1)
   {
   
  //  scan();
   Move();
   //delay_ms(15);
   //output_d(0b00000000);
   //delay_ms(15);
   Right_Ninety();
   //delay_ms(15);
  // Back();
   //Back();
   //Left_Ninety();
 

   }
   


}




I tried a lot of options but ..the ISR seem not to work ... why ? I am really frustrated...
D-Kens



Joined: 09 May 2005
Posts: 35
Location: Toulouse (France)

View user's profile Send private message MSN Messenger

PostPosted: Tue Jan 15, 2008 3:51 am     Reply with quote

In the beginning of your interrupt routine, you wrote :
Code:
port_b_Temp==input_b();

where you meant
Code:
port_b_Temp=input_b();

Else, try just to increase a counter in your interrupt, for example, and print it on hyperterminal in your main(), just to check if you enter the interrupt or not... Depending on your answer, I'll look again at your code. Cool

Regards,
Christophe.
HOHOHAHA



Joined: 13 Apr 2007
Posts: 24

View user's profile Send private message AIM Address

PostPosted: Tue Jan 15, 2008 4:13 am     Reply with quote

Thanks .. I really overlooked it ...but the interrupt is still not working
HOHOHAHA



Joined: 13 Apr 2007
Posts: 24

View user's profile Send private message AIM Address

PostPosted: Tue Jan 15, 2008 4:23 am     Reply with quote

Basically it works but not properly....though RB4 RB5 works fine but RB6 and RB7 give ambiguous results
Ttelmah
Guest







PostPosted: Tue Jan 15, 2008 4:24 am     Reply with quote

First, get rid of the 'enable_interrupts(GLOBAL)' lines in the ISR. Don't just REM them out, but remove them completely, and repeat after me _ on the PIC, you must never enable the global interrupt flag in the ISR_. This is a 'sure' way to make the code not work. One of the great 'never do' lines for the PIC. You had remmed the lines out, but remove them from existing completely!...

Now, the next stage, is to test what your hardware is actually doing. Verify that your processor can send a simple text message to the serial.

Then run a simple 'main' like:
Code:

   int8 last_b, new_b;
   last_b=new_b=input_b();
   while (true) {
      new_b=input_b();
      if ((new_b^last_b) & 0b11110000) {
         last_b=new_b;
         printf("%2x/n/r",new_b);
      }
   }

My 'guess', is that you are going to find this does not work. The problem then is not the ISR, but almost certainly, that the signal levels being fed into the PIC, are not reaching the voltages needed to be detected reliably in one direction or the other. The PortB inputs, need the signal to get to below 0.8v, to be seen as a '0', and above 2v, to be seen as a '1' (assuming you are running off 5v). The LM324, should do this happily (should pull up to 3.5v, on a 5v supply, and down to only a few mV from the 0v rail), but (obviously), what it actually swings depends on the input circuit, and I'd suspect that it is nt swinginh far enough in one direction...

Best Wishes
D-Kens



Joined: 09 May 2005
Posts: 35
Location: Toulouse (France)

View user's profile Send private message MSN Messenger

PostPosted: Tue Jan 15, 2008 4:28 am     Reply with quote

Well, you set the B4 to B7 pins to inputs, and you enable interrupts, so you should enter the routine. Did you try, as I said, to do something more simple ? Something like that :
Code:
long test=0 ;

#int_rb
void rb_isr() {
    test++;
}

void main() {
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DIV_BY_1,131,1);
   setup_ccp1(CCP_PWM);
   set_pwm1_duty(264);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   
   set_tris_b(0xff);
   clear_interrupt(INT_RB);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);

   while(1)  { printf("Counter : %ld", test) ;
                   delay_ms(5000) ;
   }
}

As I said, just to check if you enter the routine and that your problem is inside the routine, or if it is elsewhere.

Then, you should consider a debouncing solution for your inputs, else your counter will probably increase much more than expected at any change on the inputs. Confused
HOHOHAHA



Joined: 13 Apr 2007
Posts: 24

View user's profile Send private message AIM Address

PostPosted: Tue Jan 15, 2008 9:35 am     Reply with quote

D-Kens wrote:
Well, you set the B4 to B7 pins to inputs, and you enable interrupts, so you should enter the routine. Did you try, as I said, to do something more simple ? Something like that :
Code:
long test=0 ;

#int_rb
void rb_isr() {
    test++;
}

void main() {
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DIV_BY_1,131,1);
   setup_ccp1(CCP_PWM);
   set_pwm1_duty(264);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   
   set_tris_b(0xff);
   clear_interrupt(INT_RB);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);

   while(1)  { printf("Counter : %ld", test) ;
                   delay_ms(5000) ;
   }
}

As I said, just to check if you enter the routine and that your problem is inside the routine, or if it is elsewhere.

Then, you should consider a debouncing solution for your inputs, else your counter will probably increase much more than expected at any change on the inputs. Confused


Yes I am having debouncing problem... no solution for hardware .. the input is given by LM324... what should be the software solution ?
Ttelmah
Guest







PostPosted: Tue Jan 15, 2008 10:20 am     Reply with quote

Software solution, is to use one of the timers.
In the INT_RB routine, program this to trigger in perhaps 1mSec, enable this interrupt, disable int_rb, and exit the routine.
Then have an interrupt handler for the timer. In this, read the input again, and only if it still has the required 'change', then execute the required movement code. Disable the ter, and re-nable int_rb, before exiting.
This way, when an edge changes, it sets up the timer, and stops further changes triggering the interrupt. Then when the timer triggers, if the signal is still in the 'new' state, you respond to this, and go back to looking for further changes.

Best Wishes
HOHOHAHA



Joined: 13 Apr 2007
Posts: 24

View user's profile Send private message AIM Address

PostPosted: Tue Jan 15, 2008 10:41 am     Reply with quote

I can't call a delay_ms() in isr... right ?? Can I call a function which will in turn call a delay ?? ... How can I exit from an isr without executing the later part of the code in isr... ? Your solution is nice but a bit tough for me to implement ... I am just a newbie..
Ttelmah
Guest







PostPosted: Tue Jan 15, 2008 3:40 pm     Reply with quote

You can call a delay in an interrupt, but there are caveats.
If you add a separate #use delay statement in front of the interrupt declaration, then _separate_ timing code will be generated for the interrupt routine. This will prevent delays in the 'main' routines, from all having the interrupts disabled, which otherwise will cause massive response problems for all interrupts.
However, even with this done, remember that time spent in the interrupt handler, is time when nothing ese can basically occur. It may cause problems with serial reception, timing loops in the other code, etc. etc..
Basically, it is much nicer to always keep interrupts short. The delays needed for good keyboard debouncing, are so long, that they are likely to cause problems latter, if done in software inside the ISR...
As a further comment though, consider approaching everything differently. If you have a 'tick' interrupt from a timer, at something like (say) 50* per second, this can be used to provide basic timekeeping throughout the code, and if it checks the key bits (rather than using an interrupt to do this), and then if the keys are _still_ pressed on the next interrupt, 'records' the new key value, this provides debounce as well. This type of 'heartbeat' approach can be a much better approach to a lot of things...

Best Wishes
HOHOHAHA



Joined: 13 Apr 2007
Posts: 24

View user's profile Send private message AIM Address

PostPosted: Thu Jan 17, 2008 10:22 am     Reply with quote

Ttelmah wrote:
Software solution, is to use one of the timers.
In the INT_RB routine, program this to trigger in perhaps 1mSec, enable this interrupt, disable int_rb, and exit the routine.
Then have an interrupt handler for the timer. In this, read the input again, and only if it still has the required 'change', then execute the required movement code. Disable the ter, and re-nable int_rb, before exiting.
This way, when an edge changes, it sets up the timer, and stops further changes triggering the interrupt. Then when the timer triggers, if the signal is still in the 'new' state, you respond to this, and go back to looking for further changes.

Best Wishes


Can you please provide a working codeof the above concept ... delay in functions of ISR in not working properly ... if you ask I can put up my code here .. but it will be real pain for you to go through it ... I just messed it up...
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group