![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Gerrit
Joined: 15 Sep 2003 Posts: 58
|
Why this code does not work |
Posted: Fri Jan 02, 2004 10:48 am |
|
|
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? |
|
![](templates/subSilver/images/spacer.gif) |
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Why this code does not work |
Posted: Fri Jan 02, 2004 11:00 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
Re: Why this code does not work |
Posted: Fri Jan 02, 2004 11:46 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Gerrit
Joined: 15 Sep 2003 Posts: 58
|
|
Posted: Sat Jan 03, 2004 3:45 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Sat Jan 03, 2004 5:11 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|