ATmega8: Ovládanie maticovej klávesnice - príklad programu

Ahoj viete mi poradiť.
chcem si skúsiť ovladať maticovú klávesnicu.
A nedarí sa mi nájsť nejaký príklad.

Mám zatial len toto no tam sa sice ukáže stlačené tlačidlo no na displeji ho vypisuje donekonečna ja chcem aby to napisalo len raz a ďalčie hneď vedla napr (1.2.3.atď) Dakujem za radu.

[code]#define F_CPU 4000000UL

#include <avr/io.h>
#include <stdlib.h>
#include <avr/delay.h>
#include “lcd.h”

char text = 255;

int main()
{

DDRB = 0xff;
DDRD = 0;
PORTD = 0xff;

lcd_init(LCD_DISP_ON); // inycializacia disp.
lcd_gotoxy(0,0);

while(1)
{
PORTB = 0xfb;
{
if (bit_is_clear(PIND,0)) text =3;
if (bit_is_clear(PIND,1)) text =6;
if (bit_is_clear(PIND,2)) text =9;
if (bit_is_clear(PIND,3)) text =12;
}
PORTB = 0xfd;
{
if (bit_is_clear(PIND,0)) text =2;
if (bit_is_clear(PIND,1)) text =5;
if (bit_is_clear(PIND,2)) text =8;
if (bit_is_clear(PIND,3)) text =0;
}
PORTB = 0xfe;
{
if (bit_is_clear(PIND,0)) text =1;
if (bit_is_clear(PIND,1)) text =4;
if (bit_is_clear(PIND,2)) text =7;
if (bit_is_clear(PIND,3)) text =11;
}
PORTB = 0x0;

if(text == 0) lcd_puts("0");
if(text == 1) lcd_puts("1");
if(text == 2) lcd_puts("2");
if(text == 3) lcd_puts("3");
if(text == 4) lcd_puts("4");
if(text == 5) lcd_puts("5");
if(text == 6) lcd_puts("6");
if(text == 7) lcd_puts("7");
if(text == 8) lcd_puts("8");
if(text == 9) lcd_puts("9");
if(text == 11) lcd_puts("*");
if(text == 12) lcd_puts("#");
text = 255;

// cakanie na ziadnu stlacenu klavesu
while (PIND & 0x0f != 0x0f) {}

}
}[/code]

:arrow_right: administrator: přejmenováno z "Atmega 8 a klávesnica"

Tak si tam vloz podmienku, ze zobrazi sa kod klavesy len ked je nejaky bit nastaveny na definovany stav a zaroven je stlacena nejaka klavesa. Zaroven si hned po zobrazeni kodu tento stav zmen na opacny. Stav pomocnej premennej zase zmen az ked nie je nic stlacene. A je to :slight_smile:

Místo

while (PIND & 0x0f != 0x0f)

napiš tohle

while ((PIND & 0x0f) != 0x0f)

Takový zlatý pravidlo :
Pokud si nejsi jistý, jak překladač výraz pochopí, použij závorky.

Překladač nejdříve vyhodnotí 0x0f != 0x0f. Tato podmínka nikdy není splněna. Pak může být PIND jakýkoliv a podmínka splněná nebude. Optimalizace pak dokonce celý prázdný while cyklus může zahodit.

Zdar, když chtěl zprovoznit klávesnici, tak mě nejvíc pomohla tato stránka tutorial.cytron.com.my/2012/08/15/project-17-%E2%80%93-interface-with-4x4-keypad-and-2x16-lcd/ je to sice pro pic, ale to nevadí :wink: jde to dobře pochopit a udělat pro atmegy :wink:. Hlavně bacha na vstupy a výstupy u piců je to přesně obráceně než u atmeg 0 je výstup a jednička vstup :wink:.

No tak s tímto to ako tak funguje len nejak pomaly číta klávesnicu ked stlačim napriklad 5 tak ju musim aj niekolko x stlačiť kým ju načíta. Niekedy to zas hned zobere.

Je vôbec tento spôsob vhodný na ovládanie klávesnice?

TO: pepikas poyrem aj tú stránku len škoda že je anglicky.

Nebo takhle:


//==============================================================================
#include "gpio.h"
#include "ioports.h"
#include "keyboard.h"
//==============================================================================
//==============================================================================
//==============================================================================
volatile u8 keyboard_Key=0;
//==============================================================================
//==============================================================================
//==============================================================================
void keyboard_Refresh(void)
{
u8 scan=0;
static u8 state=0;
static u8 time=0;

switch(state)
    {
    case 0: if(gpio_TestPort(CANP2)==0) scan=KEY_1;
            if(gpio_TestPort(CANP7)==0) scan=KEY_4;
            if(gpio_TestPort(CANP8)==0) scan=KEY_7;
            if(gpio_TestPort(CANP3)==0) scan=KEY_DEL;
            gpio_ClrPort(CANP15);
            gpio_SetPort(CANP14);
            state=1;
            break;

    case 1: if(gpio_TestPort(CANP2)==0) scan=KEY_2;
            if(gpio_TestPort(CANP7)==0) scan=KEY_5;
            if(gpio_TestPort(CANP8)==0) scan=KEY_8;
            if(gpio_TestPort(CANP3)==0) scan=KEY_0;
            gpio_ClrPort(CANP14);
            gpio_SetPort(CANP13);
            state=2;
            break;

    case 2: if(gpio_TestPort(CANP2)==0) scan=KEY_3;
            if(gpio_TestPort(CANP7)==0) scan=KEY_6;
            if(gpio_TestPort(CANP8)==0) scan=KEY_9;
            if(gpio_TestPort(CANP3)==0) scan=KEY_E;
            gpio_ClrPort(CANP13);
            gpio_SetPort(CANP12);
            state=3;
            break;

    case 3: if(gpio_TestPort(CANP2)==0) scan=KEY_C;
            if(gpio_TestPort(CANP7)==0) scan=KEY_B;
            if(gpio_TestPort(CANP8)==0) scan=KEY_A;
            if(gpio_TestPort(CANP3)==0) scan=KEY_D;
            gpio_ClrPort(CANP12);
            gpio_SetPort(CANP10);
            state=4;
            break;

    case 4: if(gpio_TestPort(CANP2)==0) scan=KEY_RIGHT;
            if(gpio_TestPort(CANP7)==0) scan=KEY_DOWN;
            if(gpio_TestPort(CANP8)==0) scan=KEY_UP;
            if(gpio_TestPort(CANP3)==0) scan=KEY_LEFT;
            gpio_ClrPort(CANP10);
            gpio_SetPort(CANP15);
            state=0;
            break;

    default: state=0; break;
    }

if(time>0)
    {
    if(scan>0) time=KEYTIME; else time--;
    }
    else
    {
    if(scan>0)
        {
        time=KEYTIME;
        keyboard_Key=scan;
        gpio_SetPort(LEDY);
        }
        else
        {
        gpio_ClrPort(LEDY);        
        }
    }
}
//==============================================================================
//==============================================================================
//==============================================================================

CANPx jsou řádky a sloupce klavesnicové matice.
keyboard_Key obsahuje co si zmacknul - po použití vynuluješ.
keyboard_Refresh() voláš periodicky z přerušení.

To je tím, že do čekání na uvolnění klávesy vstupuješ pokaždé. Stane se tedy, že projedeš test klávesnice a klávesu stiskneš v okamžiku, než vstoupíš do čekání na uvolnění. Program v tu chvíli sice klávesu nezaregistroval, protože během skenu klávesnice ještě nebyla stisknutá, ale v okamžiku vstupu do čekání na uvolnění už stisknutá byla. Uprav to takhle :

Původní kód :

    text = 255;

    // cakanie na ziadnu stlacenu klavesu
    while ((PIND & 0x0f) != 0x0f) {}

upravený kód :

    if (text!=255)
    {
      text = 255;

      // cakanie na ziadnu stlacenu klavesu
      while ((PIND & 0x0f) != 0x0f) {}
    }

Balů ďakujem už to funguje tak ako som chcel. Možem skúšať ďalšie veci. Chcem skúsiť uplne primitívny zámok a určite budem ešte otravovať. :wink:

Tak skúšam ten zámok z napevno uložením heslom ele nejak sa mi nedarí.

Heslo ma 4 znaky ak zadám viac čísel napíše DLHE HESLO. Po tadeto to funguje, ale nedarí sa mi porovnávať uložené heslo zo zadaným po stlačení #. Nejaka rada?

[code]#define F_CPU 4000000UL

#include <avr/io.h>
#include <stdlib.h>
#include <avr/delay.h>
#include “lcd.h”

char password[4]; // pole na ulozenie hesla zadavaneho z klavesnice
char password_[4] = {‘1’,‘2’,‘3’,‘4’}; // heslo ulozene na pevno v pamati
char i=0;

char text = 255;

int main()
{

DDRB = 0xff;
DDRD = 0;
PORTD = 0xff;

lcd_init(LCD_DISP_ON); // inycializacia disp.
lcd_clrscr();
lcd_gotoxy(0,0);
lcd_puts(" Zadaj heslo: ");
lcd_gotoxy(6,1);

while(1)
{

  if (bit_is_clear(PIND,3)) 
 {
 if(password* == password_*)

{
lcd_puts(“spravne heslo”);
}
}

PORTB = 0xfb; 
{ 
  if (bit_is_clear(PIND,0)) text =3; 
  if (bit_is_clear(PIND,1)) text =6; 
  if (bit_is_clear(PIND,2)) text =9; 

}
PORTB = 0xfd;
{
  if (bit_is_clear(PIND,0)) text =2;
  if (bit_is_clear(PIND,1)) text =5;
  if (bit_is_clear(PIND,2)) text =8;
  if (bit_is_clear(PIND,3)) text =0; 
}
PORTB = 0xfe;
{
  if (bit_is_clear(PIND,0)) text =1;
  if (bit_is_clear(PIND,1)) text =4;
  if (bit_is_clear(PIND,2)) text =7;
  if (bit_is_clear(PIND,3)) text =11;
}

PORTB = 0x0;
{
if(text == 0) lcd_puts("0"); 
if(text == 1) lcd_puts("1"); 
if(text == 2) lcd_puts("2"); 
if(text == 3) lcd_puts("3"); 
if(text == 4) lcd_puts("4"); 
if(text == 5) lcd_puts("5"); 
if(text == 6) lcd_puts("6"); 
if(text == 7) lcd_puts("7"); 
if(text == 8) lcd_puts("8"); 
if(text == 9) lcd_puts("9"); 
if(text == 11) lcd_puts("*"); 
if(text == 12) lcd_puts("#");
}

if (text!=255) 
{ 
  text = 255; 

  while ((PIND & 0x0f) != 0x0f) {} 		// cakanie na ziadnu stlacenu klavesu 

if(i <= 3)								// ulozenie hesla 
{
password* = text;
i++;
}else{
lcd_gotoxy(0,0);
lcd_puts("   Dlhe heslo!  ");
_delay_ms(1000);
i=0;
return main();
}

}
}
}
[/code]***

Měl bys v programu reagovat jen na obsah proměné “text” a né na několika místech duplikovat snímání klavesnice.

Napiš si funkci která Ti bude vracet stisknutopu klavesnici (uvedl jsem ti funkci kod ktery jen lehce zmodifikujes)

Tu budes pravidelne volat a podle toho pobezi tvuj dalsi program.

Tahle konstrukce neřeší porovnání celeho hesla.
" if(password* == password_*) "

Tady si nulujes co si sejmul z klavesnice aniž bys to někam uložil…

if (text!=255)
{
text = 255;**

Nazdar po dlhom čase sa vraciam k mojej klavesnici a displeju.

Skúšam začať úplne odznova. Zatial som napísal niečo taketo neni to kompletné ale zauima ma či je to zatial OK

PS: skúšal som to dat preložit a píše mi to chybu čo to znamena?

../kodzam.c:57: error: lvalue required as left operand of assignment atd atd atd to iste 16x

[code]#define F_CPU 4000000UL

#include <avr/io.h>
#include <stdlib.h>
#include “lcd.h”
#include <avr/interrupt.h> //Knihovna přerušení
#include <util/delay.h>

/****** klavesnica 4x3 ********/

#define KL_R1 PC0 //riadok1
#define KL_R2 PC1 //riadok2
#define KL_R3 PC2 //riadok3
#define KL_R4 PC3 //riadok4

#define KL_S1 PD0 //stlpec1
#define KL_S2 PD1 //stlpec2
#define KL_S3 PD2 //stlpec3

/******************************/

unsigned char kl_citaj (void)
{
KL_R1 = 1; //citaj 1, 2, 3

KL_R2 = 0;		
KL_R3 = 0;		
KL_R4 = 0;
_delay_us (30);
if	(KL_S1 == 1) 	  lcd_puts("1");
if	(KL_S2 == 1) 	  lcd_puts("2");
if	(KL_S3 == 1) 	  lcd_puts("3");

KL_R1 = 0;		//citaj 4, 5, 6

KL_R2 = 1;		
KL_R3 = 0;		
KL_R4 = 0;
_delay_us (30);
if	(KL_S1 == 1) 	  lcd_puts("3");
if	(KL_S2 == 1) 	  lcd_puts("4");
if	(KL_S3 == 1) 	  lcd_puts("5");

KL_R1 = 0;		//citaj 7, 8, 9

KL_R2 = 0;		
KL_R3 = 1;		
KL_R4 = 0;
_delay_us (30);
if	(KL_S1 == 1) 	  lcd_puts("7");
if	(KL_S2 == 1) 	  lcd_puts("8");
if	(KL_S3 == 1) 	  lcd_puts("9");

KL_R1 = 0;		//citaj *, 0, #

KL_R2 = 0;		
KL_R3 = 0;		
KL_R4 = 1;
_delay_us (30);
if	(KL_S1 == 1) 	  lcd_puts("*");
if	(KL_S2 == 1) 	  lcd_puts("0");
if	(KL_S3 == 1) 	  lcd_puts("#");

}
[/code][/code]

Myslím si, že to bude tím, že PC0, PC1 … jsou definované jako čísla. A číslu nemůžeš přiřadit hodnotu…

takže je to celé zle ? takto? :cry: :cry:

nerozumiem ako bi to malo vyzerať?

Prostuduj si jak se u AVR pracuje se vstupama/vystupama a pak to dej dohromady s tim co se da pouzit v jazyce C.

:arrow_right: administrator: příspěvek byl upraven
Předchozí příspěvky se necitují.

Dal som to takto a vyzerá že to pojde …dúfam že postupujem správne.

[code]KLAV_PORT|=(1<<KL_R1); //citaj 1, 2, 3

KLAV_PORT&=(~(1<<KL_R2));		
KLAV_PORT&=(~(1<<KL_R3));		
KLAV_PORT&=(~(1<<KL_R4));
_delay_us (30);
if	(KL_S1 == 1) 	  lcd_puts("1");
if	(KL_S2 == 1) 	  lcd_puts("2");
if	(KL_S3 == 1) 	  lcd_puts("3");[/code]

/*
Klávesnice 3x4:

     COL1 COL2 COL3 

ROW1  1    2    3

ROW2  4    5    6

ROW3  7    8    9

ROW4  10   0   12

*/

#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include “lcd.h”
#define F_CPU 4000000UL
//--------------------------------------------------

#define setbit(port,bit) ((port) |= (1<<bit)) //nastav bit
#define clearbit(port,bit) ((port) &= ~(1<<bit)) //nuluj bit

// zapojení klávesnice
#define ROWPORT PORTD // port na kterém jsou připojeny řádky
#define ROWDDR DDRD

#define COLPORT PORTD // port na kterém jsou připojeny sloupce
#define COLDDR DDRD

#define ROW1 0 // ROW1 na ROWPORT.0
#define ROW2 1
#define ROW3 2
#define ROW4 3

#define COL1 4 // COL1 na COLPORT.4
#define COL2 5
#define COL3 6

#define DELKA_HESLA 8 // heslo má 8 znaků

//--------------------------------------------------
void kbd_init(void)
{
COLDDR |= (1<<COL1)|(1<<COL2)|(1<<COL3); // nastav sloupce jako výstupy
ROWDDR &= ~((1<<ROW1)|(1<<ROW2)|(1<<ROW3)|(1<<ROW4)); // řádky jako vstupy

ROWPORT |= (1<<ROW1)|(1<<ROW2)|(1<<ROW3)|(1<<ROW4); // pull-up na vstupech
}

//--------------------------------------------------
// Funkce get_kbd() vrací hodnotu stisknutého tlačítka.
// Pokud není stisknuto žádné tlačítko, vrací 0xff(255).
unsigned char get_kbd(void)
{
COLPORT |= (1<<COL1)|(1<<COL2)|(1<<COL3); // nastav všechny sloupce na hodnotu “1”
clearbit(COLPORT,COL1); // nastav první sloupec na “0”
_delay_us(1);
if(bit_is_clear(ROWPORT,ROW1)) return 1;
if(bit_is_clear(ROWPORT,ROW2)) return 4;
if(bit_is_clear(ROWPORT,ROW3)) return 7;
if(bit_is_clear(ROWPORT,ROW4)) return 10;

COLPORT |= (1<<COL1)|(1<<COL2)|(1<<COL3);
clearbit(COLPORT,COL2);
_delay_us(1);
if(bit_is_clear(ROWPORT,ROW1)) return 2;
if(bit_is_clear(ROWPORT,ROW2)) return 5;
if(bit_is_clear(ROWPORT,ROW3)) return 8;
if(bit_is_clear(ROWPORT,ROW4)) return 0;

COLPORT |= (1<<COL1)|(1<<COL2)|(1<<COL3);
clearbit(COLPORT,COL3);
_delay_us(1);
if(bit_is_clear(ROWPORT,ROW1)) return 3;
if(bit_is_clear(ROWPORT,ROW2)) return 6;
if(bit_is_clear(ROWPORT,ROW3)) return 9;
if(bit_is_clear(ROWPORT,ROW4)) return 12;

return 255; // žádné tlačítko nestisknuto
}

//--------------------------------------------------

char heslo] = “12345678”; // platné heslo
char string[15]; // zadané heslo
unsigned char temp, i;

//----------------------------- MAIN -----------------------------------------

int main()
{
lcd_init(LCD_DISP_ON);
kbd_init();
lcd_gotoxy(0,0);
lcd_puts(“zadej heslo: \r\n”);

while(1)
{
temp = get_kbd(); // čti klávesnici

  //-------------------------- 
  if(temp != 255)                // pokud je stisknuto některé tlačítko
  {
     _delay_ms(50);              // debounce
     while(get_kbd() != 255) {}  // čekej na uvolnění tlačítka
     _delay_ms(50);              // debounce
  }

  //-------------------------- 
  if(temp < 10)                  // zadáno číslo 0-9
  {
     string* = temp + '0';     // ulož zadané číslo jako ascii znak 
     i++;

     if(i > DELKA_HESLA - 1)     // příliš dlouhé heslo
     {
        i = 0;
        continue;                // jdi na začátek while(1)
     }
  }
  
  //-------------------------- 
  if(temp == 12)                 // zadáno tlačítko "12", potvrzení hesla
  {
     string* = 0;              // zakonči string nulou
     
     // porovnej zadaný kód s heslem
     if(strcmp(string, heslo) == 0) lcd_puts("spravne heslo \r\n");
     else                           lcd_puts("spatne heslo \r\n");
     i = 0; 
  }

}//while
}**