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 support@ccsinfo.com

Why this code does not work

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



Joined: 15 Sep 2003
Posts: 58

View user's profile Send private message

Why this code does not work
PostPosted: Fri Jan 02, 2004 10:48 am     Reply with quote

When I disable all the #ASM part the interupt is correct


#byte PCL = 0x0FF9


#int_TIMER1
Timer1_isr()
{
static char Toggle, Enc_Cur, Enc_Prev;

set_timer1(ROTORY_SCAN_TIME);

if(Toggle)
{
Toggle = 0;
output_low(RS485_ENABLE);
}
else
{
Toggle = 1;
output_high(RS485_ENABLE);
}


Enc_Cur = Port_B;
swap(Enc_Cur);
Enc_Cur &= 0x03;

if(bit_test(Enc_Prev,0))
bit_set(Enc_Cur, 2);

if(bit_test(Enc_Prev,1))
bit_set(Enc_Cur, 3);

Enc_Prev = Enc_Cur;


#ASM

movf Enc_Cur,w ; get combination of previous and new state
andlw 0x0F
addwf PCL,f ; bounce in jump table below

goto enc_done ; 00 -> 00 = no change
goto enc_inc ; 00 -> 01 = increment
goto enc_dec ; 00 -> 10 = decrement
goto enc_done ; 00 -> 11 = illegal, ignore
goto enc_dec ; 01 -> 00 = decrement
goto enc_done ; 01 -> 01 = no change
goto enc_done ; 01 -> 10 = illegal, ignore
goto enc_inc ; 01 -> 11 = increment
goto enc_inc ; 10 -> 00 = increment
goto enc_done ; 10 -> 01 = illegal, ignore
goto enc_done ; 10 -> 10 = no change
goto enc_dec ; 10 -> 11 = decrement
goto enc_done ; 11 -> 00 = illegal, ignore
goto enc_dec ; 11 -> 01 = decrement
goto enc_inc ; 11 -> 10 = increment
goto enc_done ; 11 -> 11 = no change


enc_dec:
bsf Decrement, 0
goto enc_done
enc_inc:
bsf Increment, 0;
goto enc_done

enc_done:
#ENDASM


Can some one help me with C code for a program jump?
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Re: Why this code does not work
PostPosted: Fri Jan 02, 2004 11:00 am     Reply with quote

Gerrit wrote:
When I disable all the #ASM part the interupt is correct


#byte PCL = 0x0FF9


#int_TIMER1
Timer1_isr()
{
static char Toggle, Enc_Cur, Enc_Prev;

set_timer1(ROTORY_SCAN_TIME);

if(Toggle)
{
Toggle = 0;
output_low(RS485_ENABLE);
}
else
{
Toggle = 1;
output_high(RS485_ENABLE);
}


Enc_Cur = Port_B;
swap(Enc_Cur);
Enc_Cur &= 0x03;

if(bit_test(Enc_Prev,0))
bit_set(Enc_Cur, 2);

if(bit_test(Enc_Prev,1))
bit_set(Enc_Cur, 3);

Enc_Prev = Enc_Cur;


#ASM

movf Enc_Cur,w ; get combination of previous and new state
andlw 0x0F
addwf PCL,f ; bounce in jump table below

goto enc_done ; 00 -> 00 = no change
goto enc_inc ; 00 -> 01 = increment
goto enc_dec ; 00 -> 10 = decrement
goto enc_done ; 00 -> 11 = illegal, ignore
goto enc_dec ; 01 -> 00 = decrement
goto enc_done ; 01 -> 01 = no change
goto enc_done ; 01 -> 10 = illegal, ignore
goto enc_inc ; 01 -> 11 = increment
goto enc_inc ; 10 -> 00 = increment
goto enc_done ; 10 -> 01 = illegal, ignore
goto enc_done ; 10 -> 10 = no change
goto enc_dec ; 10 -> 11 = decrement
goto enc_done ; 11 -> 00 = illegal, ignore
goto enc_dec ; 11 -> 01 = decrement
goto enc_inc ; 11 -> 10 = increment
goto enc_done ; 11 -> 11 = no change


enc_dec:
bsf Decrement, 0
goto enc_done
enc_inc:
bsf Increment, 0;
goto enc_done

enc_done:
#ENDASM


Can some one help me with C code for a program jump?


Try using a switch statement. When formated correctly it will compile as a jump table. There are many very detailed post you can read over. for example;
http://www.ccsinfo.com/forum/viewtopic.php?t=17868&highlight=jump+table
Ttelmah
Guest







Re: Why this code does not work
PostPosted: Fri Jan 02, 2004 11:46 am     Reply with quote

Gerrit wrote:
When I disable all the #ASM part the interupt is correct


#byte PCL = 0x0FF9


#int_TIMER1
Timer1_isr()
{
static char Toggle, Enc_Cur, Enc_Prev;

set_timer1(ROTORY_SCAN_TIME);

if(Toggle)
{
Toggle = 0;
output_low(RS485_ENABLE);
}
else
{
Toggle = 1;
output_high(RS485_ENABLE);
}


Enc_Cur = Port_B;
swap(Enc_Cur);
Enc_Cur &= 0x03;

if(bit_test(Enc_Prev,0))
bit_set(Enc_Cur, 2);

if(bit_test(Enc_Prev,1))
bit_set(Enc_Cur, 3);

Enc_Prev = Enc_Cur;


#ASM

movf Enc_Cur,w ; get combination of previous and new state
andlw 0x0F
addwf PCL,f ; bounce in jump table below

goto enc_done ; 00 -> 00 = no change
goto enc_inc ; 00 -> 01 = increment
goto enc_dec ; 00 -> 10 = decrement
goto enc_done ; 00 -> 11 = illegal, ignore
goto enc_dec ; 01 -> 00 = decrement
goto enc_done ; 01 -> 01 = no change
goto enc_done ; 01 -> 10 = illegal, ignore
goto enc_inc ; 01 -> 11 = increment
goto enc_inc ; 10 -> 00 = increment
goto enc_done ; 10 -> 01 = illegal, ignore
goto enc_done ; 10 -> 10 = no change
goto enc_dec ; 10 -> 11 = decrement
goto enc_done ; 11 -> 00 = illegal, ignore
goto enc_dec ; 11 -> 01 = decrement
goto enc_inc ; 11 -> 10 = increment
goto enc_done ; 11 -> 11 = no change


enc_dec:
bsf Decrement, 0
goto enc_done
enc_inc:
bsf Increment, 0;
goto enc_done

enc_done:
#ENDASM


Can some one help me with C code for a program jump?


You have to be very careful when doing a table jump like this, to ensure that the code isn't positioned in a block, so that the table 'wraps' over the end. If (for instance), the interrupt routine ends up at address 0x1d0, by the time you get to the jump table code, the address may be something like 0x1F8. Then the addition to PCL, of (say) 9, results in a jump to address 0x101. As has allready been stated, a switch will (if it has no 'default'), generate a jump table like this, and will automatically protect against the end of block problem. Alternatively, a couple of tests, can give very fast quadrature decoding. For instance:

Code:

void quad(void) {
   static int old;
   static int new;
   static int value;
   //Here I have an edge on one of the quadrature inputs
   new=portb;
   //Now I have to decode the quadrature changes. There are four possibilities:
   //I can have a rising or falling edge, on each of the two inputs. I have to
   //look at the state of the other bit, and increment/decrement according to
   //this.
   value=new^old;
   //'value', now has the bit set, which has changed
   if (value & 0x10) {
      //Here the low bit has changed
      if (new & 0x10) {
         //Here a rising edge on A
         if (new & 0x20) --position;
         else ++position;
      }
      else {
         //Here a falling edge on A
         if (new & 0x20) ++position;
         else --position;
      }
   }
   else {
      //Here the high bit (B) must have changed
      if (new & 0x20) {
         //Here a rising edge on B
         if (new & 0x10) ++position;
         else --position;
      }
      else {
         //Here a falling edge on B
         if (new & 0x10) --position;
         else ++position;
      }
   }
   old=new;
}



Works suprisingly efficiently to decode all four quadrature states. This has one XOR, followed by just three tests, whatever pattern of changes has taken place. It is also worth noting, that this code, can be executed as a completely 'standalone' interrupt handler, using just the 'fast' interrupt ability on 18F chips, and the RETFIE 1 return. This is because the functions used, all encode as standalone functions (making no use of other maths code), and no use is made of any 'table' registers etc.. Hence retfie 1 which restores the state of the status, W, and BSR registers, is sufficient to restore the machines state, allowing this entire routine to be executed in only a very few instructions, without the (normally massive) overhead of the global handler.

Best Wishes

Best Wishes
Gerrit



Joined: 15 Sep 2003
Posts: 58

View user's profile Send private message

PostPosted: Sat Jan 03, 2004 3:45 am     Reply with quote

I'm using a simple rotary switch with 20 detents.

When using the software from Ttelmah part it works

When I make 1 detent I get two pulses.

When I turn very slow (inbetween 2 detents) I get one puls
but when going to the detent position i get the next pulse.

How can I adjust the software for a rotary switch with detents
so that every detent just gives one puls, when the rotary switch
is turned with low or high speed (normal use to control audio equipment)

Thanks,

Gerrit
Ttelmah
Guest







PostPosted: Sat Jan 03, 2004 5:11 am     Reply with quote

Gerrit wrote:
I'm using a simple rotary switch with 20 detents.

When using the software from Ttelmah part it works

When I make 1 detent I get two pulses.

When I turn very slow (inbetween 2 detents) I get one puls
but when going to the detent position i get the next pulse.

How can I adjust the software for a rotary switch with detents
so that every detent just gives one puls, when the rotary switch
is turned with low or high speed (normal use to control audio equipment)

Thanks,

Gerrit

This is down to the possible 'decode' options on a quadrature encoder. The encoders produce two pulse 'trains', ninety degrees out of phase, with each train having a pulse for each 'line' on the decoder. The code I posted, decodes all four edges from the decoder, giving four edges for each 'line'. It sounds as if the 'detent' positions, correspond to the individual 'lines', on one pulse train. Hence you need only decode the edges from one train, rather than both sets of edges.
The existing code, can be changed, by just removing half the decoded states, as:

Code:

void quad(void) {
   static int old;
   static int new;
   static int value;
   //Here I have an edge on one of the quadrature inputs
   new=portb;
   //Now I have to decode the quadrature changes. Changing
   //to only decode two of the edges.
   value=new^old;
   //'value', now has the bit set, which has changed
   if (value & 0x10) {
      //Here the low bit has changed
      if (new & 0x10) {
         //Here a rising edge on A
         if (new & 0x20) --position;
         else ++position;
      }
      else {
         //Here a falling edge on A
         if (new & 0x20) ++position;
         else --position;
      }
   }
   //Simply removing the 'high bit' detection, to count only half
   //the states.
   old=new;
}


You could also potentially make slightly more efficient code (but more complex), by connecting just one of the quadrature signals to a 'level' interrupt, rather than a 'changed' interrupt, and when the interrupt occurs, 'toggle' the edge that this is set for. This will then get called for each 'edge', on just one of the two pulse trains, again givving the required behaviour.
It is really not worth doing though, since the frequency of a switch movement will be so low. (the code I posted, was from a quadrature decoder, which was typically moving at over 12000 pulses/second, while the switch will be lucky to reach a very few hundred).
You may find (depends on which detent changes in between the detents), that with the 'alternate edge' code, you get better results, by trying the pair of wires reversed (or reversing the '10', and '20' values in each line of the code). Ideally you want the count to change in the middle (between the detents), rather than at the detent position itself.

Best Wishes
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