Posts: 670
Threads: 40
Joined: Jul 2015
Reputation:
400
Ja mislim da ide prvo RST pin na displayu na LOW dok se setuje pa onda na HIGH. Znaci moras pin sa Arduina (bez level siftera) sa 1k na RST pin displeja a jedan PullDown od 1k8 na GND. Taj divider 1k i 1k8 sa 5V treba da daju cca 3.3V
Posts: 2.481
Threads: 85
Joined: Feb 2013
Reputation:
1.440
Odlično....sada radi problem je bio taj divider, ima prvo LOW pa onda HIGH i tako ga drzi sada i radi kod paljenja...hvala YuMERA.
Posts: 670
Threads: 40
Joined: Jul 2015
Reputation:
400
04-12-2019, 06:26 PM
(This post was last modified: 04-12-2019, 06:55 PM by me[R]a.)
Ovom kombinacijom taj pin Arduina ti je konstantno opterecen strujom od oko 2mA ako ti je to puno onda napravi divider sa 5k1 i 10k
Posts: 2.481
Threads: 85
Joined: Feb 2013
Reputation:
1.440
04-12-2019, 09:02 PM
(This post was last modified: 04-12-2019, 09:05 PM by ronovar.)
Code: // include library
#include <LiquidCrystal.h>
#include <Encoder.h>
// LCD interface pins
int RS = A4, EN = A5, D4 = A3, D5 = A2, D6 = A1, D7 = A0;
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);
// ROTARY encoder pins
int switchPin = 0; // button pin
int switchState = HIGH; // button value
int pinA = 2; // rotary encoder PinA
int pinB = 3; // rotary encoder PinB
int tempSet = 0; // temperature set value
void setup() {
// Enable the switchPin as input with a PULLUP resistor
pinMode(switchPin, INPUT_PULLUP);
// Set PinA and PinB as input
pinMode(pinA, INPUT_PULLUP); // turn on pull-up resistor
pinMode(pinB, INPUT_PULLUP); // turn on pull-up resistor
// Attach a CHANGE interrupt to PinB and execute the doEncoder function when this change occurs
attachInterrupt(digitalPinToInterrupt(pinB), doEncoder, FALLING);
// LCD number of columns and rows
lcd.begin(16, 2);
lcd.clear();
lcd.print("Hello, World!");
}
void loop() {
// Read the digital value of the switch (LOW/HIGH)
switchState = bitRead(PIND, switchPin);
// If the switch is pressed (LOW), execute MENU function
if (switchState == LOW) {
lcd.clear();
lcd.print("SWITCH PRESSED...");
}
}
// Rotary Encoder - increase/decrease temp by 5°C
void doEncoder() {
// If there is a minimal movement of 1 step
if (bitRead(PIND, pinA) == bitRead(PIND, pinB)) {
// Increase set temperature by 5°C
tempSet = tempSet + 5;
} else {
// Decrease set temperature by 5°C
tempSet = tempSet - 5;
}
lcd.clear();
lcd.print(tempSet);
}
Navedeni gore kod treba da na LCD ispisuje brojku od 0 do npr 450 (to cu kasnije staviti MAX i MIN brojača tempSet).
Rotary Encoder je spojeni na arduino pro mini na pinove 2 i 3 (A(INT0) i B(INT1)) i switch button na pin0.
Zadatak je da kad se okreće lijevo enkoder da tempSet se smanjuje za 5 a kad se okreće desno da se povećava do 5 i ispisuje vrijednost na LCD-u.
Kod mene se događa da kada idem polako okretat desno nekad trebam okrenuti dva puta, nekad jednom(dakle to je OK), nekad tri puta da se poveca varijabla za 5. Isto vrijedi i za lijevo samo tamo se smanjuje za 5, ali nekada se smanji za jedan okretaj(sto je OK), nekad za dva a nekad za tri.
Radim preko FALLING edge što po googlu kazu da je najsigurniji način...no kod mene su bugovi...
Čak mi se događa da mi se brojač kad lovi iz prvog okretaja polako povećava za 10 a trebao bi za 5....pa me zanima gdje griješim gore u kodu? Čitao sam google primjere i library ali očito sam nešto propustio....
Posts: 670
Threads: 40
Joined: Jul 2015
Reputation:
400
04-12-2019, 11:27 PM
(This post was last modified: 04-12-2019, 11:28 PM by me[R]a.)
Probaj ovo da zamenis :
Code: // Rotary Encoder - increase/decrease temp by 5°C
void doEncoder() {
// If there is a minimal movement of 1 step
if (bitRead(PIND, pinA) == bitRead(PIND, pinB)) {
// Increase set temperature by 5°C
tempSet = tempSet + 5;
} else {
// Decrease set temperature by 5°C
tempSet = tempSet - 5;
}
Sa ovim :
Code: // Rotary Encoder - increase/decrease temp by 5°C
void doEncoder() {
cli(); //stop interrupts
// If there is a minimal movement of 1 step
if (bitRead(PIND, pinA) == bitRead(PIND, pinB)) {
// Increase set temperature by 5°C
tempSet = tempSet + 5;
} else {
// Decrease set temperature by 5°C
tempSet = tempSet - 5;
sei(); //restart interrupts
}
I probaj taj attachInterrupt da vozis sa RISING
Posts: 8.814
Threads: 138
Joined: Apr 2013
Reputation:
3.678
Ako pricamo o ratacionim enkoderima (umesto potenciometra), ne "pravi opticki enkoder", oni su iskreno "igracke", ako od 100 razlicitih na trzistu nadjes 1 koji radi kako treba javi mi
Oni previse problema imaju jer pocnu da im "krckaju" kontakti posle 3 dana upotrebe, signal je previse prljav i MCU to na razlicite nacine tumaci, hoce jedan korak da prutumaci kao vise, neke ce da preskoci i tako dalje ...
Izmislili ljudi mnogo pismeniju stvar za to, bezkontaktni magnetni ugaoni enkoder sa razlicitim opcijama izlaza:
https://ams.com/angle-position-on-axis
Dakle jedan magnet koji je ustvari "dugme" i taj IC koji direktno salje poziciju (ne mora da se preracunavaju koraci) i to vam je to ...
Posts: 2.481
Threads: 85
Joined: Feb 2013
Reputation:
1.440
04-13-2019, 08:02 AM
(This post was last modified: 04-13-2019, 08:07 AM by ronovar.)
Stavio sam kod:
Code: // Attach a CHANGE interrupt to PinB and execute the doEncoder function when this change occurs
attachInterrupt(digitalPinToInterrupt(pinB), doEncoder, RISING);
I ovaj:
Code: // Rotary Encoder - increase/decrease temp by 5°C
void doEncoder() {
// If there is a minimal movement of 1 step
if (bitRead(PIND, pinA) == bitRead(PIND, pinB)) {
// Increase set temperature by 5°C
tempSet = tempSet + 5;
} else {
// Decrease set temperature by 5°C
tempSet = tempSet - 5;
// Restart interrupts
sei();
}
lcd.clear();
lcd.print(tempSet);
}
Ali isto se događa i postavljam video kada se jedan po jedan korak okreće udesno rotary enkoder, dakle nekad treba tri koraka da se okrene da bi registrirao jedan, a nekad se varijablja poveća za 10 a treba da je uvijek za 5. A i nekad se varijabla umjesto da se poveća za 5 ona smanji, a namjerno sam u video uratku išao samo desno da se to vidi (jer lijevo nema smisla da kompliciramo stvari, pa sada se fokusiramo samo na desno okretanje rotary enkodera).
Također sam gornji kod sei() probao staviti iznad lcd.clear(); jer bi tako bilo logično ali je isto.
Ima se još kakva ideja?
https://streamable.com/x5fgg
Inače kupio sam ove:
https://www.ebay.com/itm/2Pcs-KY-040-Rot...2553258460
Moguce da pošto su jeftini da su neprecizni? Ako da koje preporučujete da je rotary encoder na modulu, pa da narucim sa ebaya pošto bih htio solziti OLED Soldering Station, a vec sam zapeo sa nekvalitetnim rotary encoderom....
EDIT:
Gledam baš ovaj:
https://www.ebay.com/itm/DC-5V-360-Degre...3394525143
Kvalitetno mi izgleda jel bi bio OK? Ili me slika vara...
Posts: 8.814
Threads: 138
Joined: Apr 2013
Reputation:
3.678
04-13-2019, 08:48 AM
(This post was last modified: 04-13-2019, 09:07 AM by mikikg.)
Vara te slika, dok ne vidis osciloskopom signale i dok u interapt rutini ne stavis jedan togle za debug signal i vidis koliko je puta usao u interapt za taj jedan korak ne mozes tacno da sagledas sta se tu desava.
Svaki mehanicki kontakt ima svoje poznate probleme, ovde se radi o vise kontakta koji moraju da budu jako dobro upareni i odradjeni da bi davali ciste signale koje MCU moze jako brzo da detektuje, u pitanju su MHz brzine kada se to lepo upotrebi, ali problem je i dalje mehanicki kontakt, mnogo brljavi, mora da se ozbiljno filtrira da bi to radilo nekako dobro, perfektno ne moze, ne moze ni na mom Rigol, bacio bih ga u kantu kad mi "prokliza" jedan od 15 enkodera takvih koje ima na sebi, svaki je sklon da po neki put prokliza, maaaa ....
Posts: 8.814
Threads: 138
Joined: Apr 2013
Reputation:
3.678
Resenje je STM32 i AMS magnetni rotacioni enkoder!
Drugari, to da poterate, to je sam vrh mehatronike, dovoljno je jeftino da se igramo sa tim a dovoljno mocno da moze da upravlja servo motorom!
Imaju bas aplikacije "zamena potenciometra", mnogo lepo odradjeno!
https://ams.com/angle-position-on-axis
Posts: 2.481
Threads: 85
Joined: Feb 2013
Reputation:
1.440
Naravno ovo gore je profi, ali meni ne treba nešto takvo...ovo za filtraciju je odlična ideja, gledao sam na PCB rotary encodera veze i vidio da ima na sebi spojeno:
A <=> 10k <=> +5V
B <=> 10k <=> +5V
SWITCH <=> +5V
I gledam na netu sheme i vidim da je na svaku pullup otpornik dodan 100nF kondenzator, i ja dodam ovako:
GND <=> 100nF <=> A <=> 10k <=> +5V
GND <=> 100nF <=> B <=> 10k <=> +5V
SWITCH <=> +5V
I sada je točno na LCD-u povecanje ili smanjenje za 5, ovisno o tome dali lijevo i desno okrecem, znači na ovim jeftinim kineskim modulima su stavili samo 2x10k otpornike za pullup bez kondezatora i time nistu napravili filtraciju, zato je brljavilo signale....no filtracija očito nije kako treba...jer mi nakon nekog vremena na LCD-u se pojavljuju hyeroglifi (loša filtracija pa MCU brljavi)...dok bez tih filterskih kondenzatora nema hyeroglifa na LCD-u ali je netočno očitanje.
Što predlažete za filtraciju? Tj kako da se to sad kako je donekle dovede do red, jer ne tražim ultra precizno očitavanje, nego samo da očita 1korak i poveca/smanji za 5 na LCD-u.
Posts: 8.814
Threads: 138
Joined: Apr 2013
Reputation:
3.678
(04-13-2019, 09:13 AM)ronovar Wrote: Što predlažete za filtraciju?
Pa STM32, on ima integrisane filtere i kvadraturni enkoder interfejs u sebi : )
Najozbiljnije, on ima tacno predvidjene registre gde se kaze koliko "clock" impulsta mora da bude aktivno stanje na 1. i 2. ulazu da bi inkrementovao ili dekrementovao interni brojac, dakle NEZAVISNO interni modul to sve obraduje, tvoj program samo procita trenutno stanje kad mu treba i za vise krugova imas samo da hendlujes jedan interapt ne preterano kritican i to je sve sto treba.
To radi jako dobro na bilo kom enkoderu kada se lepo podesi, na optickom enkodeui to radi na par MHz bez jednog izgubljenog impulsa!
Posts: 1.159
Threads: 27
Joined: Oct 2014
Reputation:
313
U doEncoder() funkciji samo treba da uvećavaš ili umanjuješ brojač. Ispis na LCD pomeri u loop.
doEncoder je funkcija koja obrađuje prekid i treba da bude što kraća. Sve ostalo ide u loop.
Posts: 2.481
Threads: 85
Joined: Feb 2013
Reputation:
1.440
OK, imam doma samo ovaj:
https://wiki.stm32duino.com/index.php?title=Maple_Mini
Jel taj ima te integrirane filtere pa da probam na breadboardu...
Posts: 8.814
Threads: 138
Joined: Apr 2013
Reputation:
3.678
Da, to je STM32F103, on ima QEI na tajmer modulu.
Posts: 2.481
Threads: 85
Joined: Feb 2013
Reputation:
1.440
(04-13-2019, 09:28 AM)gorankg Wrote: U doEncoder() funkciji samo treba da uvećavaš ili umanjuješ brojač. Ispis na LCD pomeri u loop.
doEncoder je funkcija koja obrađuje prekid i treba da bude što kraća. Sve ostalo ide u loop.
Pomjerio sam ga u loop i sada je to OK sa delayem od 100ms da se vidi osvjezavanje brojaca, ali i dalje brljavi enkoder, i primjetio sam da sam sa tim 100nF sporio ocitanje enkodera i sada treba dva okretaja/stepa da se promjeni brojac...i pocne da brljavi...smanji sam sa 100nF na 10nF i sada nema brljavljenja ali je neprecizam...idem probam sa STM32 pa cemo vidjet dal ce se situacija poboljsati.
Posts: 8.814
Threads: 138
Joined: Apr 2013
Reputation:
3.678
Evo jedan konkretan programcic za Arduino i opticki enkoder, moze pomoci.
PHP Code: /* Hardware Timer as an Encoder interface.
The STM32 Timers have the possibility of being used as an encoder interface. This can be both a quadrature encoder (mode 3) or pulse encoder with a signal to give direction (modes 1 and 2). The default behavior is for quadrature encoder.
To avoid overflowing the encoder (which may or may not happen (although with 16 bits, it's likely), the following code will interrupt every time the number of pulses that each revolution gives to increment/decrement a variable (ints).
This means that the total number of pulses given by the encoder will be (ints * PPR) + timer.getCount()
Attached is also a bit of code to simulate a quadrature encoder. To test this library, make the connections as below:
TIMER2 inputs -> Digital Pins used to simulate. D2 -> D4 D3 -> D5
COUNTING DIRECTION: 0 means that it is upcounting, meaning that Channel A is leading Channel B
EDGE COUNTING:
mode 1 - only counts pulses on channel B mode 2 - only counts pulses on Channel A mode 3 - counts on both channels.
*/ #include "HardwareTimer.h"
#define MySer Serial2 //koji seriski port koristimo za komunikaciju (Serial=USB, Serial2=HW port 2) #define BOARD_LED_PIN PC13 #define QEI_A_PIN PA0 #define QEI_B_PIN PA1 #define QEI_Z_PIN PA2 #define PPR 2000 //Pulses per revolution
HardwareTimer timer(2);
unsigned long time = 0; //time variable for millis() unsigned long ints = 0; unsigned long interval = 0; //variable for status updates... char received = 0; unsigned long cnt = 0;
//----------------------------------------- //overflaw interpat //----------------------------------------- void func() { if (timer.getDirection()) { ints--; } else { ints++; } }
void z_idx_func() { // toggleLED(); //timer.setCount(0);
TIM1->CNT = 0;
//if (timer.getDirection()) { // ints--; //} else { // ints++; //} }
//----------------------------------------- //setup //----------------------------------------- void setup() {
MySer.begin(115200); MySer.println("Encoder APP started ...");
//define the Timer channels as inputs. pinMode(QEI_A_PIN, INPUT_PULLUP); //channel A pinMode(QEI_B_PIN, INPUT_PULLUP); //channel B pinMode(QEI_Z_PIN, INPUT_PULLUP); //channel Z
// Set up the built-in LED pin as an output and button: pinMode(BOARD_LED_PIN, OUTPUT);
//configure timer as encoder //timer.setMode(0, TIMER_ENCODER); //set mode, the channel is not used when in this mode. timer.pause(); //stop... timer.setPrescaleFactor(4); //normal for encoder to have the lowest or no prescaler. timer.setOverflow(PPR); //use this to match the number of pulse per revolution of the encoder. Most industrial use 1024 single channel steps. timer.setCount(0); //reset the counter. timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER3); //or TIMER_SMCR_SMS_ENCODER1 or TIMER_SMCR_SMS_ENCODER2. This uses both channels to count and ascertain direction. timer.resume(); //start the encoder... timer.attachInterrupt(0, func); //channel doesn't mean much here either. timer.refresh(); //! important
attachInterrupt(QEI_Z_PIN, z_idx_func, RISING);
}
//----------------------------------------- //LOOP //----------------------------------------- void loop() {
cnt = timer.getCount();
//encoder code if (millis() - interval >= 200) { MySer.print(cnt); MySer.print(" counts"); //MySer.print("direction "); //MySer.println(timer.getDirection()); MySer.print(" Full Revs: "); MySer.println(ints); interval = millis(); //update interval for user. }
if (cnt > (PPR - 20) || cnt < 20) { //tu smo +/- 50 count oko nule, upali led // digitalWrite(BOARD_LED_PIN, 0); } else { //ugasi led // digitalWrite(BOARD_LED_PIN, 1); }
/* Protocol...
if received r - reset counter. if received 1 - Mode 1 (Channel B counts) if received 2 - Mode 2 (Channel A counts) if received 3 - Mode 3 (Counts on both channels) if received 4 - Change prescaler to 4 if received 0 - change prescaler to 1 if received - - Increase Speed if received + - Decrease Speed */
//take care of comms...
if (MySer.available() > 0) {
received = MySer.read();
if (received == 'r') { timer.setCount(0); //reset the counter. ints = 0; } if (received == '1') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER1); //count only the pulses from input 1 if (received == '2') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER2); //count only the pulses from input 2 if (received == '3') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER3); //count on both channels (default of the lib). if (received == '4') timer.setPrescaleFactor(4); //only updates on overflow, so you need to wait for an overflow. Not really used... if (received == '0') timer.setPrescaleFactor(1); //only updates on overflow, so you need to wait for an overflow.
}
}
//----------------------------------------- //togle LED on board //----------------------------------------- void toggleLED() { digitalWrite(BOARD_LED_PIN, !digitalRead(BOARD_LED_PIN)); }
Posts: 1.159
Threads: 27
Joined: Oct 2014
Reputation:
313
(04-13-2019, 09:58 AM)ronovar Wrote: (04-13-2019, 09:28 AM)gorankg Wrote: U doEncoder() funkciji samo treba da uvećavaš ili umanjuješ brojač. Ispis na LCD pomeri u loop.
doEncoder je funkcija koja obrađuje prekid i treba da bude što kraća. Sve ostalo ide u loop.
Pomjerio sam ga u loop i sada je to OK sa delayem od 100ms da se vidi osvjezavanje brojaca, ali i dalje brljavi enkoder, i primjetio sam da sam sa tim 100nF sporio ocitanje enkodera i sada treba dva okretaja/stepa da se promjeni brojac...i pocne da brljavi...smanji sam sa 100nF na 10nF i sada nema brljavljenja ali je neprecizam...idem probam sa STM32 pa cemo vidjet dal ce se situacija poboljsati.
Osvežavanje radiš kad se nešto promeni. Nema potrebe stalno da zoveš LCD.
Posts: 8.814
Threads: 138
Joined: Apr 2013
Reputation:
3.678
U Reference Manual-u RM0008 od stranice 392 imas opisano sve oko enkoder interfejsa, na stranici 407 imas registre i vrednosti za filtere.
https://www.st.com/content/ccc/resource/...171190.pdf
Posts: 2.481
Threads: 85
Joined: Feb 2013
Reputation:
1.440
Stavio sam isti kod na STM32 preko Arduino IDE i isto problemi se javljaju...dakle nije do ATmega ni STM32..nego do nekvalitetnog enkodera.
Tako da cu naruciti STEC12E08 i odlemiti sa ovog modula ovaj kineski enkoder zalemiti ovaj ALPS staviti na PCB 2komada 100nF SMD kondenzatora i to bude to. Tako da projekt ide na mirovanje dok ne stigne ALPS. I cijena mu je cca 8$ dok sam ja ova dva kineska enkodera dobio za $0.89 tako da vjerujem da je ALPS jako kvaliteta za ono sto mi treba.
Do onde ce da stigne i OLED pa ce biti zamjenjen LCD sa njime.
Posts: 8.814
Threads: 138
Joined: Apr 2013
Reputation:
3.678
Cek, kako isti code, ovaj code sto sam ja postavio koristi QEI, ti si sve radio softwerski, probaj QEI, to mora malo bolje da radi ...
|