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

is it necessary to get value from int_rda?
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

is it necessary to get value from int_rda?
PostPosted: Fri Jan 19, 2018 3:51 am     Reply with quote

Hello everyone,

I want to use the int_rda interrupt to get the code out from an endless loop. So i just want to change a value. is this ok?

Code:

byte surekli=1;
#int_RDA
void RDA_isr()
{
   disable_interrupts(INT_RDA);
   surekli = 0;
}


as i heard, the value that triggers interrupt is in buffer. should i use it? does it have any disadvantage?

thank you so much!
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Jan 19, 2018 6:00 am     Reply with quote

It should work fine, with two small changes
1) you can delete the
disable_interrupts(INT_RDA);
line of code as the CCS compiler already does that !
2) you need to actually read the UART data. this will clear the buffer.
3) also add 'errors' to the use rs232(...options...)

There may be a problem though. EVERY character coming into the PIC will trigger the ISR,so your variable will be reset EVERY time. It would be better to have a specific character(say 'P') to trigger the variable reset. That way you have control of the process.

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Fri Jan 19, 2018 9:16 am     Reply with quote

The point about reading the byte, is that the interrupt cannot be cleared until it has been read. So you _must_ read the byte, otherwise if you ever re-enable INT_RDA, the chip will immediately interrupt...
Code:

byte surekli=1;
#int_RDA
void RDA_isr()
{
   int8 dummy;
   dummy=getc(); //now allows the interrupt to be cleared
   //Do you really want to disable the interrupt?.
   //Why?.
   //Chip won't respond to another character if it is disabled.
   disable_interrupts(INT_RDA);
   surekli = 0;
} //The compiler will automatically clear the interrupt, but can't do so
//unless the character has been read.
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Fri Jan 19, 2018 10:39 am     Reply with quote

Hello everyone,

Thank you for your answers.

temtronic

1) you can delete the
disable_interrupts(INT_RDA);
line of code as the CCS compiler already does that ! (thank you, read this from an old book about ccs, updated it the way you said it)

2) you need to actually read the UART data. this will clear the buffer.

I added a variable for this.

3) also add 'errors' to the use rs232(...options...) i dont know what this does but i saw it on this forum so i am using it Smile

"There may be a problem though. EVERY character coming into the PIC will trigger the ISR,so your variable will be reset EVERY time. It would be better to have a specific character(say 'P') to trigger the variable reset. That way you have control of the process. "

I did not do that because i have read that using "if else" or loops in an interrupt routine is not good. as you suggested that i am assuming it is not that bad?

Ttelmah

Quote:
//Do you really want to disable the interrupt?. //Why?.


I use the code for a stepper motor driver module. Slave pic is 16f628 and master is 18f2550. The problem is i have to use 1 pin to communicate those 2 pics.

I want to be able to send a specific step number and also do a infinite go. But when the motor moves the infinite go function, i cannot stop it. I tried to use the interrupt to be able to stop the motors.

Why i want to disable? I dont want code to go isr on every comm attempt. Sorry for my english.

Thank you both for your answers
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Jan 19, 2018 11:15 am     Reply with quote

You should rethink your program 'flow'.
try this idea

main()
loopforever...
check for incoming serial data() function
step motor one pulse() function
...loopforever

end of main

the time it take check for an incoming character will not affect the stepping motors performance

there are several ways to accomplish this.
jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jan 19, 2018 4:29 pm     Reply with quote

temtronic wrote:

1) you can delete the
disable_interrupts(INT_RDA);
line of code as the CCS compiler already does that !

This is not correct. The compiler does not disable RDA interrupts.

The 18F2550 data sheet says:
Quote:

9.0 INTERRUPTS

When an interrupt is responded to, the global interrupt
enable bit is cleared to disable further interrupts.

This is done in hardware in the PIC's silicon. This affects the global
interrupt, not the RDA interrupt.


Below is the .LST file for the #int_rda routine. Notice that the compiler
does not clear the RCIE flag. The RCIE flag is the one that is disabled
when you use the line: disable_interrupts(INT_RDA).
Code:

.................... #int_rda
.................... void rda_isr(void)
.................... {
.................... char c;
.................... 
.................... c = getc();
00C6:  BRA    00AE
00C8:  MOVFF  01,c
00CC:  BCF    PIR1.RCIF
00CE:  GOTO   0060
.................... }

I'm not saying you need the disable_interrupts(INT_RDA) line.
Normally you don't need it. But I am saying that the compiler
doesn't automatically put that line in.
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Jan 19, 2018 4:53 pm     Reply with quote

hmm.. I was always under the impression the compiler did the 'housework'...to keep ISR 'neat and tidy'....
sigh, too many PICs, too little time
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sat Jan 20, 2018 1:59 am     Reply with quote

Yes, it does do the housework.

However 'since when' would disabling a receive data interrupt be part of this?. You want to receive data....

Very Happy

The hardware disables the global interrupt, when you enter the ISR, and re-enables it when you leave. The compiler clears the receive interrupt (if it can - the caveat about not reading the data). Only thing left is to read the data.

To doguhanpala

The point about 'ERRORS', is that the PIC USART has the 'feature', that if it overflows, it goes to a 'stalled' state, with 'overrun error' flagged. This stops further reception till cleared. 'ERRORS' adds the housekeeping, to automatically clear this if it happens. Smile
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Sat Jan 20, 2018 5:02 am     Reply with quote

Thank you all for your answers. I have another question.

This is the transmit code from 18f2550. It sends an 16 bit integer in 2 parts. After sending the bytes, the pin waits for high to understand if the process completed.

Code:
include <18F2550.h>
#DEVICE ADC=10
#fuses INTRC_IO,NOWDT,MCLR,NOPROTECT,NOLVP,NODEBUG,NOBROWNOUT,CPUDIV1,VREGEN
#use delay(clock=8000000)
#use rs232(baud=9600, UART1, ERRORS,stream = bt)
#use rs232(baud=9600, xmit=PIN_B1,stream = motormodul)

int16 step_sayisi=200;
int step_sayisi_l=0;
int step_sayisi_h=0;
int begin=0;

void main()
{
 
   while(true)
   {
      while(!kbhit(bt))
      delay_us(100);
     
     
      if(kbhit(bt))
      {
      begin=getc(bt);
      putc('b',bt);
      }
     
         while(begin=='a')
         {
                putc('c',bt);
                putc(1,motormodul);
                delay_ms(1);
                step_sayisi_l = make8(step_sayisi,0);
                step_sayisi_h = make8(step_sayisi,1);
                putc(step_sayisi_h,motormodul);
                delay_ms(1);
                putc(step_sayisi_l,motormodul);
                while(input_state(PIN_B1)!=0)
                delay_us(100);   
                putc('d',bt);
                break;
         }
   }
}


This is the receive code. I am not adding all functions they are very similiar. The code waits for step number high and low. It makes them 16 bit. After that i use that integer on for loops. When the loop is done, the code calls "bitir()" in order to inform 18f2550.

Code:
#include <16F628.h>
#DEVICE ADC=10
#fuses INTRC_IO,NOWDT,NOMCLR,NOPROTECT,NOLVP,NOBROWNOUT,
#use delay(clock=4000000)
#use rs232(baud=9600, rcv=PIN_B1)

#define motor1_pin1 PIN_A0
#define motor1_pin2 PIN_A1
#define motor1_pin3 PIN_A2
#define motor1_pin4 PIN_A3

#define motor2_pin1 PIN_B7
#define motor2_pin2 PIN_B6
#define motor2_pin3 PIN_B5
#define motor2_pin4 PIN_B4


void motor1_s1();
void motor1_s2();
void motor1_s3();
void motor1_s4();
void motor1_s5();
void motor1_s6();
void motor1_s7();
void motor1_s8();

void motor2_s1();
void motor2_s2();
void motor2_s3();
void motor2_s4();
void motor2_s5();
void motor2_s6();
void motor2_s7();
void motor2_s8();

void robot_ileri();
void robot_geri();
void robot_sol();
void robot_sag();
void motor1_ileri();
void motor1_geri();
void motor2_ileri();
void motor2_geri();
void durdur();

void bitir();
void komutal();

int16 step_sayisi = 0;
int8 step_sayisi_l=0;
int8 step_sayisi_h=0;
int16 sayac=0;

void main()
{
   durdur();
   while(true)
   komutal();
}

void bitir()
{
   output_high(PIN_B1);
   delay_ms(2);
   output_low(PIN_B1);
   delay_ms(2);
}

void komutal()
{
   int komut=0;
   while(!kbhit())
   delay_us(10);
   
   if(kbhit())
   {
   komut = getc();
   step_sayisi_h=getc();
   step_sayisi_l=getc();
   step_sayisi = make16(step_sayisi_h,step_sayisi_l);
      switch(komut)
      {
      case 1: 
               robot_ileri();
               durdur();
               bitir();               
      break; 
     
      case 2:
               robot_sol();
               durdur();
               bitir();
      break;
     
      case 3:
               robot_sag();
               durdur();
               bitir();
      break;
     
      case 4:
               robot_geri();
               durdur();
               bitir();
      break; 
     
      case 5:
               motor1_ileri();
               durdur();
               bitir();
      break;
     
      case 6: 
               motor2_ileri();
               durdur();
               bitir();
      break;
     
      case 7: 
               motor1_geri();
               durdur();
               bitir();
      break;
     
      case 8:
               motor2_geri();
               durdur();
               bitir();
      break;
      }
     
   }
}

void robot_ileri()
{
for(sayac=0;sayac<step_sayisi;sayac++)
   {
   motor1_s1();
   motor2_s1();
   delay_us(1000);
   motor1_s2();
   motor2_s2();
   delay_us(1000);
   motor1_s3();
   motor2_s3();
   delay_us(1000);
   motor1_s4();
   motor2_s4();
   delay_us(1000);
   motor1_s5();
   motor2_s5();
   delay_us(1000);
   motor1_s6();
   motor2_s6();
   delay_us(1000);
   motor1_s7();
   motor2_s7();
   delay_us(1000);
   motor1_s8();
   motor2_s8();
   delay_us(1000);   
   }
}


My question is, when i change the line
Code:
#use rs232(baud=9600, rcv=PIN_B1)


to this

Code:
#use rs232(baud=9600, UART1, ERRORS)


the 18f can't get the 2 ms high voltage, so it gets stuck at here
Code:

while(input_state(PIN_B1)!=0)
                delay_us(100);   
                putc('d',bt);
                break;



I don't see the char 'd'. Is there a way to make hardware uart pins act like IOs even if they are used as uart?
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sat Jan 20, 2018 11:46 am     Reply with quote

TTL serial, idles high. The line is permanently going to be high when the UART (soft or hard), is sitting not sending. You can't use this as an identifier.
Pulling the line low for 2mSec, sends two characters of 0.

Your approach is fundamentally flawed.

Simply send a character that is identified as a 'header' Something like a line feed or a '$' sign.

Follow this with your byte for 'what you want to do'. Now you seen to be relying on this being 1, 2, 3 etc.. You do understand the difference between a value of 1, and the character '1'. Which are you sending?.

Then send the value as hex, rather than as direct binary. Problem with direct binary is it makes it hard to identify other values.
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Sun Jan 21, 2018 6:20 am     Reply with quote

Ttelmah wrote:
TTL serial, idles high. The line is permanently going to be high when the UART (soft or hard), is sitting not sending. You can't use this as an identifier.
Pulling the line low for 2mSec, sends two characters of 0.

Your approach is fundamentally flawed.


Interestingly, the code works when i use software uart. When the motors do their job 16f sends low, and 18f gets it. after that i see the 'd' on screen. When i use hardware uart. It gets stuck on while loop.

Ttelmah wrote:
Simply send a character that is identified as a 'header' Something like a line feed or a '$' sign.


My problem is, i cannot understand the process on 16f is complete or not. I want to block the comm, if the process is not complete and motors are still moving. So i need to do something after the process.

Ttelmah wrote:
Follow this with your byte for 'what you want to do'. Now you seen to be relying on this being 1, 2, 3 etc.. You do understand the difference between a value of 1, and the character '1'. Which are you sending?.

Then send the value as hex, rather than as direct binary. Problem with direct binary is it makes it hard to identify other values.


I know the difference between value 1 and char '1'(this is 50 as i recall?). I chose to send value but not for a specific reason. I said, well send value man. Actually which one i send is not important to me, i can edit the code both sides(rcv and xmit) and send char. unfortunately it still does not solve my problem.

My guess, when i use software uart and call the function input state, the port starts to behave like io port? Sounds idiotic but my only guess Smile

Thank you for your aswer and explanation.
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sun Jan 21, 2018 9:41 am     Reply with quote

The problem is that because you rely on detecting values like 1, 2, 3. These can happen inside the data you are sending, since by sending 'raw' values any value is possible. The hardware UART will still be receiving the low as a character. Just because you have the interrupt disabled, does _not_ stop the UART from receiving. So it will have received a zero at this point, and will in fact have set it's error flags, since it will see a malformed character, and this has not been read, resulting in both a framing error and an overrun. The soft UART will not, since you are not actually calling it till after the line goes high again, and it does not have error checking.

If you just want to ignore data till a task is complete, then just set a flag.
Have your INT_RDA, simply throw any character received if the 'busy' flag is set. Once this goes off, start listening to the data again.

If you must use your current approach, then disable the UART (setup_uart(FALSE);), rather than disabling the interrupt.
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Mon Jan 22, 2018 7:36 am     Reply with quote

Ttelmah wrote:
The problem is that because you rely on detecting values like 1, 2, 3. These can happen inside the data you are sending, since by sending 'raw' values any value is possible. The hardware UART will still be receiving the low as a character. Just because you have the interrupt disabled, does _not_ stop the UART from receiving. So it will have received a zero at this point, and will in fact have set it's error flags, since it will see a malformed character, and this has not been read, resulting in both a framing error and an overrun. The soft UART will not, since you are not actually calling it till after the line goes high again, and it does not have error checking.


Thank you for suggestions Ttelmah. I edited the code to this. Used char instead of vaue itself.

Code:
#include <16F628.h>
#DEVICE ADC=10
#fuses INTRC_IO,NOWDT,NOMCLR,NOPROTECT,NOLVP,NOBROWNOUT,
#use delay(clock=4000000)
#use rs232(baud=9600, UART1, ERRORS)

#define motor1_pin1 PIN_A0
#define motor1_pin2 PIN_A1
#define motor1_pin3 PIN_A2
#define motor1_pin4 PIN_A3

#define motor2_pin1 PIN_B7
#define motor2_pin2 PIN_B6
#define motor2_pin3 PIN_B5
#define motor2_pin4 PIN_B4


void motor1_s1();
void motor1_s2();
void motor1_s3();
void motor1_s4();
void motor1_s5();
void motor1_s6();
void motor1_s7();
void motor1_s8();

void motor2_s1();
void motor2_s2();
void motor2_s3();
void motor2_s4();
void motor2_s5();
void motor2_s6();
void motor2_s7();
void motor2_s8();

void robot_ileri();
void robot_geri();
void robot_sol();
void robot_sag();
void motor1_ileri();
void motor1_geri();
void motor2_ileri();
void motor2_geri();
void durdur();

void bitir();
void komutal();

int16 step_sayisi = 0;
int8 step_sayisi_l=0;
int8 step_sayisi_h=0;
int16 sayac=0;

void main()
{
   durdur();
   while(true)
   komutal();
}

void bitir()
{
   output_high(PIN_B1);
   delay_ms(2);
   output_low(PIN_B1);
   delay_ms(2);
}

void komutal()
{
   setup_uart(true);
   int komut=0;
   while(!kbhit())
   delay_us(10);
   
   if(kbhit())
   {
   komut = getc();
   step_sayisi_h=getc();
   step_sayisi_l=getc();
   step_sayisi = make16(step_sayisi_h,step_sayisi_l);
   delay_ms(1);
   setup_uart(FALSE);
      switch(komut)
      {
      case '1': 
               robot_ileri();
               durdur();
               bitir();               
      break; 
     
      case '2':
               robot_sol();
               durdur();
               bitir();
      break;
     
      case '3':
               robot_sag();
               durdur();
               bitir();
      break;
     
      case '4':
               robot_geri();
               durdur();
               bitir();
      break; 
     
      case '5':
               motor1_ileri();
               durdur();
               bitir();
      break;
     
      case '6': 
               motor2_ileri();
               durdur();
               bitir();
      break;
     
      case '7': 
               motor1_geri();
               durdur();
               bitir();
      break;
     
      case '8':
               motor2_geri();
               durdur();
               bitir();
      break;
      }
     
   }
}

void robot_ileri()
{
for(sayac=0;sayac<step_sayisi;sayac++)
   {
   motor1_s1();
   motor2_s1();
   delay_us(1000);
   motor1_s2();
   motor2_s2();
   delay_us(1000);
   motor1_s3();
   motor2_s3();
   delay_us(1000);
   motor1_s4();
   motor2_s4();
   delay_us(1000);
   motor1_s5();
   motor2_s5();
   delay_us(1000);
   motor1_s6();
   motor2_s6();
   delay_us(1000);
   motor1_s7();
   motor2_s7();
   delay_us(1000);
   motor1_s8();
   motor2_s8();
   delay_us(1000);   
   }
}


Transmit code

Code:
#include <18F2550.h>
#DEVICE ADC=10
#fuses INTRC_IO,NOWDT,MCLR,NOPROTECT,NOLVP,NODEBUG,NOBROWNOUT,CPUDIV1,VREGEN
#use delay(clock=8000000)
#use rs232(baud=9600, UART1, ERRORS,stream = bt)
#use rs232(baud=9600, xmit=PIN_B1,stream = motormodul)

int16 step_sayisi=200;
int step_sayisi_l=0;
int step_sayisi_h=0;
int begin=0;
int yonler[8]={'1','2','3','4','5','6','7','8'};
void main()
{
 
   while(true)
   {
      while(!kbhit(bt))
      delay_us(100);
     
     
      if(kbhit(bt))
      {
      begin=getc(bt);
      putc('b',bt);
      }
     
         while(begin=='a')
         {
                putc('c',bt);
                putc(yonler[0],motormodul);
                delay_ms(1);
                step_sayisi_l = make8(step_sayisi,0);
                step_sayisi_h = make8(step_sayisi,1);
                putc(step_sayisi_h,motormodul);
                delay_ms(1);
                putc(step_sayisi_l,motormodul);
                while(input_state(PIN_B1)!=0)
                delay_us(100);   
                putc('d',bt);
                break;
         }
   }
}

this time the code works correctly '1' time. i send the values,see the 'abc' on screen. motors go, the transmit code waits for low and prints the 'd'. if i press 'a' again, i see the abcd on screen. the setup_uart(FALSE) does not work on second time.

Quote:

If you just want to ignore data till a task is complete, then just set a flag.
Have your INT_RDA, simply throw any character received if the 'busy' flag is set. Once this goes off, start listening to the data again.


I can block the receiver side from getting any data. The real problem is i want to block the transmit side from sending any data till the task is complete. so i tried the setup_uart approach.
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Mon Jan 22, 2018 8:02 am     Reply with quote

Code:

   delay_ms(1);
   setup_uart(FALSE)


What is going to happen if a character has already arrived in this mSec?.
You stop the UART which can already holding a character.

Then at the transmit, 'putc' for a hardware UART, returns as soon as a character is loader _to_ transmit. It hasn't actually been sent yet.

So, when sending, you need to wait for the transmit buffer to empty. On the receive switch off the UART as soon as you have read the characters you want.
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Thu Jan 25, 2018 5:57 am     Reply with quote

Ttelmah wrote:
Code:

   delay_ms(1);
   setup_uart(FALSE)


What is going to happen if a character has already arrived in this mSec?.
You stop the UART which can already holding a character.

Then at the transmit, 'putc' for a hardware UART, returns as soon as a character is loader _to_ transmit. It hasn't actually been sent yet.

So, when sending, you need to wait for the transmit buffer to empty. On the receive switch off the UART as soon as you have read the characters you want.


Hello Ttelmah

I tried to edit the code like this

Code:
void komutal()
{
   int komut=0;
   setup_uart(TRUE);
   while(!kbhit())
   delay_us(10);
   
   if(kbhit())
   {
   komut = getc();
   step_sayisi_h=getc();
   step_sayisi_l=getc();
   setup_uart(FALSE);
   step_sayisi = make16(step_sayisi_h,step_sayisi_l);
   


The problem still contuniues unfortunately. I thought maybe i can disable the rs232 from both sides.

So i changed the xmit code to this version.

Code:
 while(true)
   {
      setup_uart(TRUE,motormodul);
      while(!kbhit(bt))
      delay_us(100);
     
     
      if(kbhit(bt))
      {
      begin=getc(bt);
      putc('b',bt);
      }
     
         while(begin=='a')
         {
                putc('c',bt);
                putc(yonler[0],motormodul);
                delay_ms(1);
                step_sayisi_l = make8(step_sayisi,0);
                step_sayisi_h = make8(step_sayisi,1);
                putc(step_sayisi_h,motormodul);
                delay_ms(1);
                putc(step_sayisi_l,motormodul);
                delay_ms(1);
                setup_UART(FALSE,motormodul);
                while(input_state(PIN_B1)!=0)
                delay_us(100);   
                putc('d',bt);
                break;
         }
   }


This time problem got more interesting. I cannot see the 'd'. Also the pin B1 is still high. I disabled the comm from both sides, but could not solve the problem.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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