cblock 0x70
W_TEMP
STATUS_TEMP
endc
ok..thanksCould you change a few things to make it more readable please?
Anything like:
movf var, 0
to
movf var, F or movf var, W
anything like
btfss STATUS, 0
to
btfss STATUS, C or btfss STATUS, Z
It might not fix anything but more people will look at it.
Also you should move W_TEMP and STATUS_TEMP into the memory which is available to all banks: 0x70 to 0x7F
Just put:
after the first cblock (and remove them from the first one).Rich (BB code):cblock 0x70 W_TEMP STATUS_TEMP endc
LIST p=16F628A ;tell assembler what chip we are using
include "P16F628A.inc" ;include the defaults for the chip
__config _INTOSC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRTE_OFF & _BOREN_OFF & _MCLRE_OFF
cblock 0x20 ;start of general purpose registers
tmp ;20
tmp2 ;21
Old ;22
New ;23
RCounter ;24
FRotation;25
dataL;26
endc
cblock 0x70
W_TEMP;70
STATUS_TEMP;71
ENDC
org 0x0000 ;org sets the origin, 0x0000 for the 16F628,this is where the program starts running
goto main
org 0x0004
movwf W_TEMP ; push W
swapf STATUS,W ; push Status without affecting flags. The saved value is swapped
movwf STATUS_TEMP
BTFSS INTCON,T0IF
goto exitint
Call Encoder
exitint
BCF STATUS,RP0
movlw 0xF0
movwf TMR0
swapf STATUS_TEMP,W ; swap back status to W
movwf STATUS ; pop original value to status
swapf W_TEMP,F ; swap back W value
swapf W_TEMP,W ; pop W
bcf INTCON,T0IF ;clear int flag
retfie
main
movlw 0x07
movwf CMCON ;turn comparators off and enable pins for I/O functions
bsf STATUS, RP0 ;select bank 1
movlw 0xff ;set PortB all inputs
movwf TRISB
movlw 0x00
movwf TRISA ;set PortA all outputs
MOVLW B'10000000' ; Set TMR0 prescaler to 2
MOVWF OPTION_REG
bcf STATUS,RP0 ;select bank 0
movlw 1
movwf RCounter
CLRF INTCON
bsf INTCON,GIE
BCF INTCON,T0IF
bsf INTCON,T0IE
Loop
movf FRotation,W
movwf PORTA
goto Loop
Encoder
movf PORTB,W ; read port B to W
andlw 0x30 ; Keep only the first bits 5,4
movwf tmp ; keep it to tmp
rrf tmp,F
rrf tmp,F
rrf tmp,F
rrf tmp,F
movf New,W ; mov the previous "New" value
movwf Old ; to OLD file register
movf tmp,W ; then move the new value
movwf New ; to "New" file register
Clrf STATUS
xorwf Old,W ; xor old and new
btfss STATUS,2 ;if it is zero then bit 2 of status reg is set. if so call
return
Call EncoderStatus ; else call encoderstatus
Return
EncoderStatus
movf Old,W ; move the right
andlw 0x01 ; bit of the OLD value to tmp2
movwf tmp2
movf tmp,W
andlw 0x02 ; move the left bit of the
movwf tmp ; new value to tmp
rrf tmp,0; rotate one bit tmp
Clrf STATUS
xorwf tmp2,W ; xor them. if it is zero decrease else increase
btfss STATUS,2
Goto INCRC
Goto DECRC
INCRC
INCF RCounter
Clrf STATUS
movf RCounter,W
xorlw d'201'
btfsc STATUS,2
Goto IFROT
Return
IFROT
INCF FRotation
movlw 0x01
movwf RCounter
return
DECRC
Decf RCounter
Clrf STATUS
movf RCounter,W
xorlw d'0'
btfsc STATUS,2
Goto DFROT
return
DFROT
DECF FRotation
movlw d'200'
movwf RCounter
return
end
end
Not at all. i am currently working on increasing and decreasing a 32bit value so feel free to share your work here.Well congratulations on getting this to work!
I spent some time yesterday morning getting interrupt driven code to do this, with built in on the fly deglitching. It seems to sim well, is completely tolerant of any glitch or either input and will keep a 32 bit variable updated as to total rotation.
However, I shall not steal your thread to post. (If anyone is interested, PM me and I will start a new thread.)
// Sample code for rotary encoder decoding
// PIC16F628A running at 4MHz
// Encoder connected as A->RB6, B->RB7
// BoostC compiler (License type: free) under MPLAB
// http://www.sourceboost.com
#include <system.h>
#pragma CLOCK_FREQ 400000 // let compiler know our 4 Mhz clock frequency
#pragma DATA _CONFIG, _BOREN_OFF & _CP_OFF & _DATA_CP_OFF & _PWRTE_OFF &
_WDT_OFF & _LVP_OFF & _MCLRE_OFF & _INTOSC_OSC_NOCLKOUT
char LastInState; // last valid state of encoder outputs
char CurrentState; // holds current reading
// (to prevent multiple read of port)
char LastChange = 0; // last input to change
char CurrentChange; // current input changing
long _Rotation = 0; // current valid rotation counts
long Rotation = 0; // internal copy of current rotation counts
volatile bit Rotation_Flag = 0; // flag to guard reading _Rotation variable
// clear this flag,then copy Rotation variable
// if flag now set, clear flag & repeat
volatile bit NewData_Flag = 0; // flag to notify we have a new Rotation value
#define ENCODER_MASK 0x30 // Keep only the first bits 5,4
#define ENCODER_A 4 // encoder A pin
#define ENCODER_B 5 // encoder B pin
#define A_CHANGE 1
#define B_CHANGE 2
void main(void)
{
// init PIC
LastInState = portb & ENCODER_MASK;
intcon = 0b10001000; // enable PORTB IOC
while (1)
{
// while we wait for an interupt
// let's get a copy of the rotation counnts
do
{
NewData_Flag = Rotation_Flag; // copy in case there is a pernding update
Rotation_Flag = 0; // reset flag
Rotation = _Rotation; // copy value to safe place
if (Rotation_Flag == 1) // flag set when we have corrupt data
NewData_Flag = 1; // flag we have new data
} while (Rotation_Flag ==1); // flag set if copy corrupted, so try again
// see if this is new data and do something interesting with it
while (NewData_Flag == 1)
{
// we have new data to process
// add code to handle new value here
NewData_Flag = 0; // clear flag for the new data
}
}
}
void interrupt(void)
{
if (intcon.RBIF == 1)
{
// we have our encoder interupt
CurrentState = portb & ENCODER_MASK; // get current pins
if (CurrentState != LastInState)
{
// we had an input change!
// is this the same change we saw last time?
if (CurrentState.ENCODER_A == LastInState.ENCODER_A)
CurrentChange = B_CHANGE; // if old A == new A then B changed
else
CurrentChange = A_CHANGE; // if old A != new A then A changed
if (LastChange != CurrentChange) //is this a new change?
{
// we got a new valid input change
LastChange = CurrentChange; // preserve change
LastInState = CurrentState; // preserve state
Rotation_Flag = 1; // set change flag
if (CurrentState.ENCODER_A == CurrentState.ENCODER_B)
if (CurrentChange == A_CHANGE)
_Rotation--;
else
_Rotation++;
else
if (CurrentChange == A_CHANGE)
_Rotation++;
else
_Rotation--;
}
}
intcon.RBIF = 0; // ready to exit, clear our IOC flag
}
// handle other int sources here
}
Sure, as long as you can guarantee a sample rate faster then the data change rate all should be well with a polling method. It would work just fine and there is no need to beat that dead horse.I claim that glitches, no matter how fast, can't cause inaccuracy with a program that checks the encoder on a timer basis.
Go ahead and replace "might" with "will sooner or later." PIC hardware and the code above would handle this as the port mismatch condition that fires the interrupt is set on a port read statement and the port is only read once. That means if another change occurs during the ISR (after the one and only port read) then the flag gets set and the return from interrupt just generates another interrupt, thus nothing "steady state" is missed. It may miss some very fast glitches but that is the whole point of a deglitcher, isn't it?.On the other hand, if you use the interrupt-on-change approach, the first change might still be getting processed when the second one occurs. It's possible to write code to deal with this, but it's also possible to fail to deal with it.
bsf INTCON,RBIF ; 'force' the IOC interrupt. (assembly version)
INTCON.RBIF = 1; // 'force' the IOC interrupt. (C version)
I owe you an apology ErnieM! Having re-read my words, they do indeed sound "inhospitable" and furthermore sound downright arrogant. I'm sorry. It was not my intention to be either of those things, it was a social clumsyness on my part where I typed in a hurry and was trying to express a genuine question of why you would use that particular pin testing procedure instead of one that was already posted and much smaller and (to me) cleaner. You have put in a lot of effort in to this thread providing long informative posts to help the OP and it was wrong of me to criticise your work in such an arrogant sounding manner....
Finally, why would I post this technique? Mostly the OP asked me to do so. It is my understanding this board is to share ideas, maybe to learn something, maybe to teach something. I would hope to find a more hospitable atmosphere here in the future.