Yes I see 150Hz limitation. But as said above, I'd like to test idea first, if it is working at all.
Yes I see 150Hz limitation. But as said above, I'd like to test idea first, if it is working at all.
I couldn't help myself, had to see what I could do with just some simple, basic (no pun intended) coding. No interrupts, no hardware assist, no inline assembly language, just 33 line loop of straight PBP.
On an 18F4520 running at 20MHz it's seems solid as a rock at 20kHz. Above 20kHz it misses the odd count when subjected to long bursts. This is with a function generetor generating bursts of "perfect" signals with 50% dutycyle so in real life it might be a little less.
Connecting an optical encoder works fine but a mechanical one does not due to contact bounce. Using a 16bit WORD for the position counter and simple 1x decoding, pissing away 3/4 of the resoultion but that was what was asked for.
It bit-bangs SPI data to an AD9833 but there's no math to calculate actual frequency.
The LCD code is there for my debug purposes but I left it there just in case.
Code:DEFINE LOADER_USED 1 DEFINE OSC 20 DEFINE LCD_DREG PORTD 'LCD data port DEFINE LCD_DBIT 0 'LCD data starting bit 0 or 4 DEFINE LCD_RSREG PORTA 'LCD register select port DEFINE LCD_RSBIT 3 'LCD register select bit DEFINE LCD_EREG PORTA 'LCD enable port DEFINE LCD_EBIT 1 'LCD enable bit DEFINE LCD_RWREG PORTA 'LCD read/write port DEFINE LCD_RWBIT 2 'LCD read/write bit DEFINE LCD_BITS 8 'LCD bus size 4 or 8 DEFINE LCD_LINES 2 'Number lines on LCD DEFINE LCD_COMMANDUS 3000 'Command delay time in us DEFINE LCD_DATAUS 40 'Data delay time in us FSYNC VAR LATB.3 SCLK VAR LATB.4 SDATA VAR LATB.5 Ch_A VAR PortB.6 Ch_B VAR PortB.7 Position VAR WORD ' Encoder position Frequency VAR WORD ' AD9833 VAR WORD[5] ' Array for data to be sent to the AD9833 BitsToSend VAR BYTE ' Number of bits -1 to send to the AD9833 (max 127) Ch_A_Old VAR BIT ' Memory bit for edge-detection '------------------------------------------------------------- '------------------------- Init ------------------------------ '------------------------------------------------------------- CMCON = 7 ADCON1 = %00001111 ' No analog inputs. TRISB = %11000001 Frequency = 0 Position = 0 BitsToSend = 255 PAUSE 1000 LCDOUT $FE, 1, "AD9833..." ' Initialize the AD9833 as per example in AN-1070. ' Just to verify that we're good to go. ' This should make it output 400Hz with a 25MHz base clock AD9833[4] = $2100 AD9833[3] = $50C7 AD9833[2] = $4000 AD9833[1] = $C000 AD9833[0] = $2000 FSYNC = 0 For BitsToSend = 79 to 0 Step -1 SDATA = AD9833.0[BitsToSend] SCLK = 0 PAUSEUS 20 SCLK = 1 PAUSEUS 20 NEXT FSYNC = 1 Main: '------------------------------------------------------------- '--------------Poll encoder and keep count ------------------- '------------------------------------------------------------- IF Ch_A = 1 THEN IF Ch_A_Old = 0 THEN IF Ch_B = 1 THEN Position = Position + 1 ELSE Position = Position - 1 ENDIF Ch_A_Old = 1 ENDIF ELSE Ch_A_Old = 0 ENDIF '------------------------------------------------------------- '------------------------------------------------------------- '------------- If needed, prepare to update DDS -------------- '------------------------------------------------------------- IF Position <> Frequency THEN ' Has the count changed since last update of the DDS? IF BitsToSend.7 THEN ' Are we free to update? Frequency = Position ' See datasheet for AD9833, this is just for basic testing. AD9833[2] = %0010000000000000 AD9833[1] = %0100000000000111 AD9833[0] = Frequency AD9833.0[15] = 0 AD9833.0[14] = 1 BitsToSend = 47 ' 3*16 = 48 but we're using this variable to index the bits so minus 1 ENDIF ENDIF '------------------------------------------------------------- '------------------------------------------------------------- '---If DDS is to be updated, do it one bit per loop iteration---- '------------------------------------------------------------- IF NOT BitsToSend.7 THEN ' Still bits left to send ? FSYNC = 0 ' Chip select SDATA = AD9833.0[BitsToSend] ' Setup data SCLK = 0 ' Clock low BitsToSend = BitsToSend - 1 ' Index next bit SCLK = 1 ' Clock high ELSE SCLK = 1 FSYNC = 1 ' Chip select ENDIF ' This is for debugging purposes. ' If button is pressed and LCD updated while the encoder is moved ' counts will obviously be missed. IF PortB.0 = 0 THEN LCDOUT $FE, 1, DEC Position, " ", DEC Frequency, " ", DEC BitsToSend ENDIF Goto Main
Excellent job Henrik.
At the expense of a little slower response, a couple of 100nF will help a lot debouncing mechanical encoders. I used that as I did not want to make a software debouncing at that time.
Ioannis
IF A=1 or B=1 AND A<>B
Is this proper replacement for XOR statement?
You could always write a little program to test your supposition and find out , you never know you may learn something
Code:TOUCH var byte A VAR TOUCH.0 B VAR TOUCH.1 RES var byte touch = 4 Debug 9,"XOR TRUTH TABLE" Debug ,13 ,10,"A",9,"B",9,"A^B",9,"CUT",13 ,10 while touch touch=touch-1 touch=~touch ;CODE UNDER TEST IF A = 1 or B = 1 AND A <> B THEN RES=1 ELSE RES=0 ENDIF DEBUG #A,9,#B,9," ",#A^B ,9," ",#RES ,13 ,10 touch=~touch WEND
Last edited by richard; - 6th June 2020 at 07:46. Reason: white space
Warning I'm not a teacher
And although the little debug program of Richard's might not give you a clue, the keyword is "priority".
Machines do not follow your thoughts. Need more detailed explanations, so parenthesis will help. See page 87 of the manual to understand why your expression is way out of what you intended to.
Ioannis
If not pissing away 3/4 of the encoder resolution is something worth doing here's a replacement routine that does 4x decoding. It might not be the most optimized or elegant way but is works. Surprisingly (to me) it seems to work fine up to around 8kHz which means it does 32000 counts per second when being fed "perfect" quadrature signals my function gen.
Code:' Added variables: Encoder VAR BYTE Old_Enc VAR BYTE Test VAR BYTE Dir VAR WORD ' Must be same size as Position variable '------------------------------------------------------------- '--------------Poll encoder and keep count ------------------- '-------------Alternative routine with 4x decoding------------ '------------------------------------------------------------- Encoder.0 = Ch_A Encoder.1 = Ch_B Test = Encoder ^ Old_Enc Dir = 0 If Test = 1 THEN If Old_Enc = 0 THEN Dir = 1 IF Old_Enc = 1 THEN DIR = -1 IF Old_Enc = 2 THEN Dir = -1 If Old_Enc = 3 Then Dir = 1 ENDIF IF Test = 2 THEN IF Old_Enc = 0 THEN DIR = -1 IF Old_Enc = 1 THEN Dir = 1 IF Old_Enc = 2 THEN Dir = 1 IF Old_Enc = 3 THEN Dir = -1 ENDIF Position = Position + Dir Old_Enc = Encoder
Bookmarks