Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Arduino ILI9341 TFT Display Pitanja
#21
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
Reply
#22
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.
Reply
#23
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
Reply
#24
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....
Reply
#25
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
Reply
#26
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 Smile

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 ...
Reply
#27
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...
Reply
#28
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 .... Smile
Reply
#29
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
Reply
#30
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.
Reply
#31
(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!
Reply
#32
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.
Reply
#33
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...
Reply
#34
Da, to je STM32F103, on ima QEI na tajmer modulu.
Reply
#35
(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.
Reply
#36
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_PININPUT_PULLUP);  //channel A
 
 pinMode(QEI_B_PININPUT_PULLUP);  //channel B
 
 pinMode(QEI_Z_PININPUT_PULLUP);  //channel Z

 
 // Set up the built-in LED pin as an output and button:
 
 pinMode(BOARD_LED_PINOUTPUT);

 
 //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(0func); //channel doesn't mean much here either.
 
 timer.refresh(); //! important

 
 attachInterrupt(QEI_Z_PINz_idx_funcRISING);

}


//-----------------------------------------
//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));

Reply
#37
(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.
Reply
#38
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
Reply
#39
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.
Reply
#40
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 ...
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)