yo6pir Postat Septembrie 14, 2015 Partajează Postat Septembrie 14, 2015 Va salut baieti, Vreau sa dau si eu un sfat aici, din perspectiva celui care a folosit BASCOM-ul in toate proiectele si a întâmpinat aceleasi greutati la codul pentru Encoder. 1. Ca sa implementezi o functie encoder este aproape imperios necesar sa folosesti o intrerupere de system, sau in cel mai rau caz un TIMER; de preferinta TIMER0. Asta ca sa beneficiezi de functia "debounce" pe care o castigi in acest mod si nu-numai. Se citesc terminalele encoderuli numai cand se produce takt-ul respectiv (intrerupere) sau numai intr-un anumit interval de timp dat (Timer). Totodata combinând doua timere (TIMER0 si TIMER1) se poate face usor si functia FAST-ENCODER. 2. Citirea celor doua contacte ale encoderului se face cu functia "SAU-EXCLUSIV" pentru a pre-întâmpina citiri eronate exact ceea ce nu se vrea. Daca se respecata aceste doua puncte, se va putea citi excellent orice encoder oricât de prost ar fi ( bine-nteles pana la o anumita limita!). Va spun astea din proprie experienta si am sa caut niste bucati de cod-sursa ca sa exemplific cele expuse anterior coduri implementate deja de mine in diferite proiecte care merg fara cusur. Pana atunci, success la compilat programe! Link spre comentariu
yo6pir Postat Septembrie 17, 2015 Partajează Postat Septembrie 17, 2015 Iata o rutina de citire a encoderului folosita de mine care a dat rezultate foarte bune si stabile cu diferite encodere mecanice. Partea slaba a acestui cod este ca foloseste trei pini pentru a comanda encoderul doi dintre ei (INT0-INT1) conectati impreuna; partea buna este simplitatea si eficienta: '(Rutina de citire Encoder cu intreruperi de sistem INT0-INT1Se utilizeaza ambele intrari de INT ale unui mcu Attiny3213conectate impreuna si legate la un pin al encoderului EncACelalalt pin al Encoderului este conectat la un port oarecare al mcu.')$regfile = "attiny2313.dat"$crystal = 8000000'FUSEBITS ON: [SUT0,CKSEL3,CKSEL1,CKSEL0] restul...OFF$hwstack = 40$swstack = 16$framesize = 32'===================================================================Mcucr = &B00001011 'set interrupt edges on mcuConfig Int0 = Rising 'configurare INT0 front crescatorConfig Int1 = Falling 'config.INT1 pe front descrescatorOn Int0 Phase_a_edge 'executa rutina la INT0On Int1 Phase_a_edge 'executa rutina la INT1Enable Int0 'activeaza INT0Enable Int1 'activeaza INT1Config Portd.3 = Input 'input encoderA INT1Config Portd.2 = Input 'input encoderA INT0Phase_a Alias Pind.2 'pinul A al encoderuluiConfig Portd.4 = Input 'input EncoderBPhase_b Alias Pind.4 'pinul B al encoderuluiSet Portd.4 'pull-up EncoderBSet Portd.2 'pull-up EncoderAdim valoare_raw as byte 'Valoarea care se modifica in functie de encoderenable interrupts 'activeaza intreruperile de sistem'======================================================================do'aici se executa altceva in bucla principala de program loop'=======================================================================' Rutina pentru citire Encoder A-BPhase_a_edge:If Phase_b <> Phase_a Then 'daca encoderul s-a miscat... Decr Valoare_raw 'decrementeaza valoareaElse Incr Valoare_raw 'incrementeaza valoareaEnd IfReturn'=========================================================================end 1 Link spre comentariu
yo6pir Postat Septembrie 20, 2015 Partajează Postat Septembrie 20, 2015 (editat) Am revenit cu un cod de comanda pentru encodere conectate la mcu care au functia "pin-change-interrupt"; din aceasta categorie sunt procesoarele Atmega; deasemenea se foloseste in acest caz o functie suplimentara de multiplicare a numarului de impulsuri citite la rotirea rapida a butonului encoder, adica functia FAST-ENCODER. Aceasta metoda o utilizez actualmente la ultimul meu transceiver. '(Rutina de citire encoder cu intreruperi de systemSe utilizeaza encoder pe pini cu intrerupere activati hardwareTIMER0 se foloseste pentru functia FAST-ENCODER (optional)Se foloseste procesor M324P dar se poate adapta la orice procesor care suporta"Pin-change-interrupt" function')$regfile = "m324pdef.dat"$crystal = 20000000$hwstack = 64$swstack = 48$framesize = 48'=====[ Enable Pin change interrupt pt.pini encoder]============================Pcmsk3 = &B00000011 ' Set mask pentru pinii PORTD.0 si PORTD.1Pcicr.3 = 1 ' PCICR register (Enable Pin Change Interrupt Enable 3)On Pcint3 Int_isr ' Set interrupt vector for PCMSK3'------------------------------- FAST ENCODER SETTINGS -------------------------'Configurare Timer0 pentru citire FAST ENCODER'Timer0 basculeaza odata la (20000000/1024)*256 = 13,1 msConfig Timer0 = Timer , Prescale = 1024On Ovf0 , Tim0_isrEnable Ovf0Start Timer0 'start TIMER0dim b as byte 'variabila de multiplicare fast-encoderdim Fast_encoder as byte 'Variabila Fast-Encoderdim coder as byte 'variabila de integrare stare encoderdim coder_old as byte 'variabila de memorare stare encoderdim rotary_encoder as byte 'variabila encoderdim Mx as byte 'variabila de multiplicareEnable Interrupts 'activare all interrupts.do'se executa altceva aici...loopend'==============================================================================='Rutina Encoder ISRInt_isr: Incr Fast_encoder 'incrementeaza variabila F-E (optional) Ddrd.0 = 0 'set PortD.0=input Ddrd.1 = 0 'set PortD.1=input Coder = Pind 'encoderul este conectat la PortD(0-1) Coder = Coder And &B00000011 'citeste doar PIND.0 SI PIND.1If Coder.1 < Coder_old.1 Then 'daca se roteste encoderul... If Coder.0 = 1 Then 'rotire inainte 'rutina ENCODER inainte: Rotary_encoder = Rotary_encoder + 1 'incrementeaza variabila encoder '------------rutina fast-encoder (optionala) --------------------------- If Fast_encoder > 10 Then Rotary_encoder = Rotary_encoder + Mx 'la 10 impulsuri numarate F-E '---------------------------- End If If Coder.0 = 0 Then 'rotire inapoi Rotary_encoder = Rotary_encoder - 1 'decrementeaza var.encoder '------------rutina fast-encoder (optionala) --------------------------- If Fast_encoder > 10 Then Rotary_encoder = Rotary_encoder - Mx 'la 10 impulsuri numarate FE - '----------------------------------------------------------------------- End IfEnd IfCoder_old = Coder 'memoreaza starea actuala a encoderului Pcifr = 8 're-activeaza intreruperileReturn'===============[ Rutina de Intrerupere pentru fast-encoder ]===================Tim0_isr:Incr B 'INCR variabila de inmultire TMR0If B > 4 Then 'TMR0 x 4 = 13,1 x 4 = 52msec Fast_encoder = 0 'reseteaza fast-encoder odata la 52ms B = 0 'reset variabila de inmultire Tmr0End IfReturn Pentru cei care nu detin un mcu cu functie "pin-change -interrupt" se poate utiliza o versiune simplificata folosind doar intreruperea generata de TIMER0. Pentru un cristal de 4MHz se seteaza rutina de intrerupere Timer0 astfel: 'Timer0 basculeaza odata la (4000000/64)/256 => 4 msConfig Timer0 = Timer , Prescale = 64On Ovf0 , Tim0_isrEnable Ovf0Start Timer0 Codul corespunzator citirii encoderului ramane neschimbat si se plaseaza in interiorul rutinei de intrerupere TIMER0 (Tim0_isr). Atentie la setarea perioadei de intrerupere pentru TIMER0 ca sa nu fie prea lenesa la citirea variatiilor rapide ale axului encoder! Editat Septembrie 20, 2015 de yo6pir Link spre comentariu
nickrvl Postat Septembrie 20, 2015 Partajează Postat Septembrie 20, 2015 Am incercat in jumatae de ora urmatorul cod deocamdata fara rezultat: '( Rutina de citire encoder cu intreruperi de system Se utilizeaza encoder pe pini cu intrerupere activati hardware TIMER0 se foloseste pentru functia FAST-ENCODER (optional) Se foloseste procesor M324P dar se poate adapta la orice procesor care suporta "Pin-change-interrupt" function ') $regfile = "m8def.dat" Config Lcd = 16 * 2 Config Lcdpin = Pin , Db7 = Portb.7 , Db6 = Portb.6 , Db5 = Portb.5 , Db4 = Portb.4 , E = Portb.3 , Rs = Portb.0 Cursor Off Cls '=====[ Enable Pin change interrupt pt.pini encoder]============================ 'Pcmsk3 = &B00000011 ' Set mask pentru pinii PORTD.0 si PORTD.1 'Pcicr.3 = 1 ' PCICR register (Enable Pin Change Interrupt Enable 3) 'On Pcint3 Int_isr ' Set interrupt vector for PCMSK3 '------------------------------- FAST ENCODER SETTINGS ------------------------- 'Configurare Timer0 pentru citire FAST ENCODER 'Timer0 basculeaza odata la (4000000/64)/256 => 4 ms Config Timer0 = Timer , Prescale = 64 On Ovf0 , Int_isr: 'Tim0_isr Enable Ovf0 Start Timer0 dim b as byte 'variabila de multiplicare fast-encoder dim Fast_encoder as byte 'Variabila Fast-Encoder dim coder as byte 'variabila de integrare stare encoder dim coder_old as byte 'variabila de memorare stare encoder dim rotary_encoder as byte 'variabila encoder dim Mx as byte 'variabila de multiplicare 'Ddrd.6 = 0 'set PortD.6=input 'Ddrd.7 = 0 'set PortD.7=input 'Coder = Pind 'encoderul este conectat la PortD(0-1) 'Coder = Coder And &B11000000 'citeste doar PIND.6 SI PIND.7Config Portd.6 = InputConfig Portd.7 = InputPortd.6 = 1Portd.7 = 1Coder = Pind 'encoderul este conectat la PortD(6-7)Coder = Coder And &B11000000 'citeste doar PIND.6 SI PIND.7 Enable Interrupts 'activare all interrupts. do Locate 2 , 1 Lcd "Test " loop end '=============================================================================== Int_isr: If Coder < Coder_old Then 'daca se roteste encoderul... If Coder.6 = 1 Then 'rotire inainte 'rutina ENCODER inainte: Rotary_encoder = Rotary_encoder + 1 'incrementeaza variabila encoder End If If Coder.6 = 0 Then 'rotire inapoi Rotary_encoder = Rotary_encoder - 1 'decrementeaza var.encoder End If End If Coder_old = Coder 'memoreaza starea actuala a encoderului Gosub Afis Return Afis: Locate 1 , 1 Lcd Rotary_encoder ; " " Return Mc-ul este Atmega8 setat intern la 4Mhz cu pinii D6,7 activati . Intreruperea functioneaza, am testat separat, insa nu reusesc sa "citesc" (cred) rotirea encoderului, pe LCD am afisat doar "0" Link spre comentariu
yo6pir Postat Septembrie 21, 2015 Partajează Postat Septembrie 21, 2015 (editat) Eu asa as fi scris aceasta bucata de cod: '( Rutina de citire encoder cu intreruperi de system Se utilizeaza encoder pe pini cu intrerupere activati hardware TIMER0 se foloseste pentru functia FAST-ENCODER (optional) Se foloseste procesor M324P dar se poate adapta la orice procesor care suporta "Pin-change-interrupt" function ')$Regfile = "m8adef.dat"$Crystal = 4000000$hwstack = 40$swstack = 16$framesize = 32 Config Lcd = 16 * 2 Config Lcdpin = Pin , Db7 = Portb.7 , Db6 = Portb.6 , Db5 = Portb.5 , Db4 = Portb.4 , E = Portb.3 , Rs = Portb.0 Cursor Off Cls 'Timer0 basculeaza odata la (4000000/64)/256 => 4 ms Config Timer0 = Timer , Prescale = 64 On Ovf0 , Int_isr 'Tim0_isr Enable Ovf0 Start Timer0 dim b as byte 'variabila de multiplicare fast-encoder dim Fast_encoder as byte 'Variabila Fast-Encoder dim coder as byte 'variabila de integrare stare encoder dim coder_old as byte 'variabila de memorare stare encoder dim rotary_encoder as byte 'variabila encoder dim Mx as byte 'variabila de multiplicareConfig Portd.6 = InputConfig Portd.7 = InputPortd.6 = 1Portd.7 = 1 Enable Interrupts 'activare all interrupts.Rotary_encoder = 0 'initiere variabila encoder do Locate 2 , 1 Lcd "Test " ; Rotary_encoder loop end '=============================================================================== Int_isr: '================================================ 'Aici trebuie sa fie aceste doua linii de cod! Coder = Pind 'encoderul este conectat la PortD(6-7) Coder = Coder And &B11000000 'citeste doar PIND.6 SI PIND.7 '================================================= 'Atentie la conditia de mai jos! se refera la unul din pinii encoderuli[pin 7] If Coder.7 < Coder_old.7 Then 'daca se roteste encoderul... If Coder.6 = 1 Then 'rotire inainte 'rutina ENCODER inainte: Rotary_encoder = Rotary_encoder + 1 'incrementeaza variabila encoder End If If Coder.6 = 0 Then 'rotire inapoi Rotary_encoder = Rotary_encoder - 1 'decrementeaza var.encoder End If End If Coder_old = Coder 'memoreaza starea actuala a encoderului 'Aici nu mai trebuie adaugata instructiunea gosub ca sa nu intarzie degeaba bucla de temporizare TIMER0 ' Gosub Afis Return '( Afis: Locate 1 , 1 Lcd Rotary_encoder ; " " Return') Editat Septembrie 21, 2015 de yo6pir Link spre comentariu
nickrvl Postat Septembrie 21, 2015 Partajează Postat Septembrie 21, 2015 (editat) Diseara o sa incerc negresit, ce am postat mai sus era doar ca idee si doar sa-mi afiseze ceva pe LCD dupa care il "slefuiam", am incercat (vorbesc din memorie) si conditia "If Coder.7 < Coder_old.7 Then " insa i-mi dadea eroare la compilare (probabil am scris-o incorect) oricum multumesc pentru implicare si o sa vad precis diseara, sint tare curios de cum o sa raspunda astfel programul la comenzile encoderului, daca sare pasi, daca e destul de rapid etc etc Editat Septembrie 21, 2015 de nickrvl Link spre comentariu
nickrvl Postat Septembrie 21, 2015 Partajează Postat Septembrie 21, 2015 (editat) "yo6pir" stima, nu degeaba se spune ca o imagine face cit o mie de cuvinte, exemplul dat este perfect functional, fara rateuri sau bilbiieli din partea encoderului, deabia acum am priceput cum poate fi implement un encoder cu ajutorul functiei "Timer", mai departe repostez varianta usor slefuita, testata si perfect functionala: $regfile = "m8def.dat" $crystal = 4000000 $hwstack = 40 $swstack = 16 $framesize = 32 Config Lcd = 16 * 2 Config Lcdpin = Pin , Db7 = Portb.7 , Db6 = Portb.6 , Db5 = Portb.5 , Db4 = Portb.4 , E = Portb.3 , Rs = Portb.0 Cursor Off Cls 'Timer0 basculeaza odata la (4000000/64)/256 => 4 ms Config Timer0 = Timer , Prescale = 64 On Ovf0 , Int_isr Enable Ovf0 Start Timer0 Dim Coder As Byte 'variabila de integrare stare encoder Dim Coder_old As Byte 'variabila de memorare stare encoder Dim Rotary_encoder As Byte 'variabila encoder Config Portd.6 = Input Config Portd.7 = Input Portd.6 = 1 Portd.7 = 1 Enable Interrupts 'activare all interrupts. Rotary_encoder = 0 'initiere variabila encoder do Locate 2 , 1 Lcd "Test " ; Rotary_encoder ; " " loop End '=============================================================================== Int_isr: '================================================ 'Aici trebuie sa fie aceste doua linii de cod! Coder = Pind 'encoderul este conectat la PortD(6-7) Coder = Coder And &B11000000 'citeste doar PIND.6 SI PIND.7 '================================================= 'Atentie la conditia de mai jos! se refera la unul din pinii encoderuli[pin 7] If Coder.7 < Coder_old.7 Then 'daca se roteste encoderul... If Coder.6 = 0 Then 'rotire inainte Incr Rotary_encoder 'incrementeaza variabila encoder End If If Coder.6 = 1 Then 'rotire inapoi Decr Rotary_encoder 'decrementeaza var.encoder End If End If Coder_old = Coder 'memoreaza starea actuala a encoderului Return L.E. Atmega8 are functia "pin-change-interrupt"? intreb deoarece codul pentru asta postat mai sus nu il pot compila, nu-mi recunoaste functiile "Pcmsk" , "Pcicr", tind sa cred ca pentru "fast encoder" trebuie folosit inca un Timer.... Editat Septembrie 21, 2015 de nickrvl Link spre comentariu
nico_2010 Postat Septembrie 22, 2015 Partajează Postat Septembrie 22, 2015 @nickrvl: ATmega8 nu are PCINT.Incearca cu ATmega88 Link spre comentariu
nickrvl Postat Septembrie 22, 2015 Partajează Postat Septembrie 22, 2015 Am inteles, termenii i-mi sint necunoscuti si de acea intrebam despre Atmega8, o sa vad cu timpul daca o sa trec la 88. Link spre comentariu
yo6pir Postat Septembrie 22, 2015 Partajează Postat Septembrie 22, 2015 Ma bucur ca ti-a reusit, felicitari pentru perseverenta! Pentru Atmega8 cu intrerupere se poate folosi prima varianta de cod cea cu trei pini folositi pentru encoder. Si in completare se poate folosi TIMER0 pentru FAST-ENCODER. Dez-avantajul este ca se utilizeaza 3 pini pentru encoder. dar nu deranjeaza daca ai destui liberi ca sa-i folosesti la altceva. SUCCES! Link spre comentariu
yo6pir Postat Septembrie 23, 2015 Partajează Postat Septembrie 23, 2015 Aceasta varianta de citire a encoderului este aplicata de catre mine atat pe AVR cat si pe PIC cu folosirea TIMER0 ca baza de intrerupere: '(Varianta De Citire Encoder Cu Timer0 Pe Doi Pini Ai Unui PortEncoderul conectat la PortD oricare doi pini alaturati.Se Fac Setari Pentru Timer0 Ca Sa Basculeze Odata La 4msFrecventa de ceas 4MHz, prescaler=64(4000000/64)/256 => 4ms')Config Timer0 = Timer , Prescale = 64Start Timer0On Ofv0 , Tim0_isrEnable Ovf0Config Portd = Input 'seteaza portD intrariPortd = 255 'Pull-Up portDDim Old As Byte 'variabila encoder memorata temporarDim New As Byte 'variabila encoder actualaDim Encoder_raw As Byte 'variabila de integrare encoderDim Direction As Bit 'BIT care arata directia de rotire a encoderuluiEnable Interrupts'===============================================================================DoLoopEnd'===============================================================================Tim0_isr:Old = New 'vechea valoare este memorata'se citeste noua stare a encoderuluiNew = Pind And &B00000011 'encoderul este conectat la PinD(0-1)If New <> Old Then 'daca se misca encoderul..'decodifica directia in care se roteste cu functia "SAU-EXCLUSIV" Direction = New.1 Xor Old.0 If Direction = 1 Then 'rotire inainte Encoder_raw = Encoder_raw + 1 'incrementeaza valoarea Else 'rotire inapoi Encoder_raw = Encoder_raw - 1 'decrementeaza valoarea End IfEnd IfReturn Link spre comentariu
nickrvl Postat Septembrie 23, 2015 Partajează Postat Septembrie 23, 2015 (editat) Pentru varianta cu INT0, INT1 la Atmega8 inseamna ca pinii se conecteaza astfel? B-ul la orice pin d.... Editat Septembrie 23, 2015 de nickrvl Link spre comentariu
yo6pir Postat Septembrie 24, 2015 Partajează Postat Septembrie 24, 2015 Da, asa se conecteaza encoderul; la pinii INT0-INT1 impreuna. Link spre comentariu
ratza Postat Septembrie 24, 2015 Partajează Postat Septembrie 24, 2015 Eu folosesc un pin la INT0 şi celălalt la INT1. Link spre comentariu
nickrvl Postat Septembrie 24, 2015 Partajează Postat Septembrie 24, 2015 Cu acelasi cod dat exemplu mai sus de "yo6pir"? Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum