/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
Bech_bb 500
kyllekylle 500
jdjespers.. 500
gibson 300
scootergr.. 300
molokyle 287
10  strarup 270
Læsning af 4x4 keypad med AVR
Fra : Tomas .


Dato : 05-01-08 18:06

Hejsa

Jeg sidder og roder med et projekt med en AVR controller. Til dette
anvender jeg CodeVision.
Heri er der et kodeeksempel til læsning af et 4x4 keypad, som så læser
den trykkede tast ud på et LCD-display. Jeg smider lige koden ind
herunder:

/*
4x4 Keypad Demo

CodeVisionAVR C Compiler
(C) 2000-2002 HP InfoTech S.R.L.
www.hpinfotech.ro

Chip: AT90S8515
Connect the keypad matrix as follows:

[STK500 PORTD HEADER] [KEYS] R1
1 PD0 -----0----1----2----3----~~~~~---o+5V
| | | | R2 |
2 PD1 -----4----5----6----7----~~~~~-
| | | | R3 |
3 PD2 -----8----9----10---11---~~~~~-
| | | | R4 |
4 PD3 -----12---13---14---15---~~~~~-
D1 | | | |
5 PD4 -|<|- | | |
D2 | | |
6 PD5 -|<|------ | |
D3 | |
7 PD6 -|<|----------- | R1..R4=10k..47k
D4 |
8 PD7 -|<|---------------- D1..D4=1N4148

Use an 2x16 alphanumeric LCD connected
to PORTC as follows:

[LCD] [STK500 PORTC HEADER]
1 GND- 9 GND
2 +5V- 10 VCC
3 VLC- LCD contrast control voltage 0..1V
4 RS - 1 PC0
5 RD - 2 PC1
6 EN - 3 PC2
11 D4 - 5 PC4
12 D5 - 6 PC5
13 D6 - 7 PC6
14 D7 - 8 PC7
*/

#asm
.equ __lcd_port=0x15
#endasm

#include <lcd.h>
#include <stdio.h>
#include <delay.h>
#include <90s8515.h>

// quartz crystal frequency [Hz]
#define F_XTAL 3686400L
// PIND0..3 will be row inputs
#define KEYIN PIND
// PORTD4..7 will be column outputs
#define KEYOUT PORTD
// used for TIMER0 count initialization
#define INIT_TIMER0 TCNT0=0x100L-F_XTAL/64L/500L
#define FIRST_COLUMN 0x80
#define LAST_COLUMN 0x10

typedef unsigned char byte;
// store here every key state as a bit,
// bit 0 will be KEY0, bit 1 KEY1,...
unsigned keys;
// LCD display buffer
char buf[33];

// TIMER 0 interrupt at every 2 ms
interrupt [TIM0_OVF] void timer0_int(void)
{
static byte key_pressed_counter=20;
static byte key_released_counter,column=FIRST_COLUMN;
static unsigned row_data,crt_key;
// reinitialize TIMER0
INIT_TIMER0;
row_data<<=4;
// get a group of 4 keys in in row_data
row_data|=~KEYIN&0xf;
column>>=1;
if (column==(LAST_COLUMN>>1))
{
column=FIRST_COLUMN;
if (row_data==0) goto new_key;
if (key_released_counter) --key_released_counter;
else
{
if (--key_pressed_counter==9) crt_key=row_data;
else
{
if (row_data!=crt_key)
{
new_key:
key_pressed_counter=10;
key_released_counter=0;
goto end_key;
};
if (!key_pressed_counter)
{
keys=row_data;
key_released_counter=20;
};
};
};
end_key:;
row_data=0;
};
// select next column, inputs will be with pull-up
KEYOUT=~column;
}

// test if a key was pressed
unsigned inkey(void)
{
unsigned k;
if (k=keys) keys=0;
return k;
}

void init_keypad(void)
{
DDRD=0xf0;
INIT_TIMER0;
TCCR0=3;
TIMSK=2;
#asm("sei")
}

main() {
unsigned k;
init_keypad();
lcd_init(24);
lcd_putsf("CVAVR Keypad");
// read keys and display key code
while (1)
{
lcd_gotoxy(0,1);
if (k=inkey())
{
sprintf(buf,"Key code=%d",k);
lcd_puts(buf);
}
else lcd_putsf("NO KEY ");
delay_ms(500);
}
}


Koden fungere således, af der, sålænge man ikke trykker på nogen tast,
skrives: "NO KEY" i displayet. Taster man i stedet på en vilkårlig
tast, skrives der: "Key code= ", og så den trykkede tast ca 1 sek,
hvorefter der atter skrives: "NO KEY". Dette er også, hvad jeg gerne
vil. Problemet er dog, at den pågældende tast skrives som 2^n, hvor
´n´ så er den pågældende tast, så tast 1, skrives som ´1´, 2 som ´2´,
men 3 som ´4´, 4 som ´8´ osv. op til 16, der så skrives som
32768´(2^15). Jeg kan dog ikke lige se i koden, hvorfor dette sker, så
jeg håber, der er en herinde, som måske kan gennemskue koden og rette
mig, så tast 16 faktisk skriver ´16´ i displayet.

Håber nogen kan hjælpe mig.

På forhånd tak

Tomas





 
 
Bertel Brander (05-01-2008)
Kommentar
Fra : Bertel Brander


Dato : 05-01-08 20:00

Tomas . skrev:
> Hejsa
>
> Jeg sidder og roder med et projekt med en AVR controller. Til dette
> anvender jeg CodeVision.
> Heri er der et kodeeksempel til læsning af et 4x4 keypad, som så læser
> den trykkede tast ud på et LCD-display. Jeg smider lige koden ind
> herunder:

[KODE SNIP]

> Koden fungere således, af der, sålænge man ikke trykker på nogen tast,
> skrives: "NO KEY" i displayet. Taster man i stedet på en vilkårlig
> tast, skrives der: "Key code= ", og så den trykkede tast ca 1 sek,
> hvorefter der atter skrives: "NO KEY". Dette er også, hvad jeg gerne
> vil. Problemet er dog, at den pågældende tast skrives som 2^n, hvor
> ´n´ så er den pågældende tast, så tast 1, skrives som ´1´, 2 som ´2´,
> men 3 som ´4´, 4 som ´8´ osv. op til 16, der så skrives som
> 32768´(2^15). Jeg kan dog ikke lige se i koden, hvorfor dette sker, så
> jeg håber, der er en herinde, som måske kan gennemskue koden og rette
> mig, så tast 16 faktisk skriver ´16´ i displayet.

Det letteste er nok at lave en funktion:
unsigned int invpow(unsigned int In)
{
unsigned int i;
for(i = 0; i < sizeof(unsigned int)*8; i++)
if(In & (1 << i))
return i;
return 32; /* No key */
}

og kalde den med tallet som 2^n, så vil den returnere n


Tomas . (06-01-2008)
Kommentar
Fra : Tomas .


Dato : 06-01-08 13:08

Bertel Brander <bertel@post4.tele.dk> skrev:
>Tomas . skrev:
>> Hejsa
>>
>> Jeg sidder og roder med et
>>projekt med en AVR controller. Til dette
>> anvender jeg CodeVision.
>> Heri er der et kodeeksempel til
>>læsning af et 4x4 keypad, som så læser
>> den trykkede tast ud på et
>>LCD-display. Jeg smider lige koden ind
>> herunder:
>
>[KODE SNIP]
>
>> Koden fungere således, af der,
>>sålænge man ikke trykker på nogen tast,
>> skrives: "NO KEY" i displayet.
>>Taster man i stedet på en vilkårlig
>> tast, skrives der: "Key code= ",
>>og så den trykkede tast ca 1 sek,
>> hvorefter der atter skrives: "NO
>>KEY". Dette er også, hvad jeg gerne
>> vil. Problemet er dog, at den
>>pågældende tast skrives som 2^n, hvor
>> ´n´ så er den pågældende tast, så
>>tast 1, skrives som ´1´, 2 som ´2´,
>> men 3 som ´4´, 4 som ´8´ osv. op
>>til 16, der så skrives som
>> 32768´(2^15). Jeg kan dog ikke
>>lige se i koden, hvorfor dette sker, så
>> jeg håber, der er en herinde, som
>>måske kan gennemskue koden og rette
>> mig, så tast 16 faktisk skriver
>>´16´ i displayet.
>
>Det letteste er nok at lave en funktion:
>unsigned int invpow(unsigned int In)
>{
> unsigned int i;
> for(i = 0; i < sizeof(unsigned
>int)*8; i++)
> if(In & (1 << i))
> return i;
> return 32; /* No key */
>}
>
>og kalde den med tallet som 2^n, så
>vil den returnere n

Kanon Bertel

Super fedt, du lige kunne løse mit problem. Jeg indsatte blot: k
= invpow(k)+1; i min kode, så kørte det som ønsket!

Takker mange gange

De bedste hilsener

Tomas


Tomas . (06-01-2008)
Kommentar
Fra : Tomas .


Dato : 06-01-08 15:17

Nu er jeg jo så kommet til en ny milesten.

Da jeg nu har koden med læsning af 4x4 keypaden til at virke, har jeg
fået problemer med
Timer0, der i den omtalte kode benyttes til at give SW-interrupt, når
en tast påvirkes. Jeg
har dog brug for timerfunktionen andre steder, hvor Timer0 anvendes
til at teste, om 2 knapper
holdes nede i 5 sek. Denne funktion vil jeg så have over på Timer1 i
stedet. Til at teste
Timer1, tager jeg udgangspunkt i dette lille kodeeksempel:

#include <mega8515.h>

//Timer 0 overflow ISR
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
static unsigned int timecount = 0; //global time counter

TCNT0 = 0x06; // start med at tælle
fra 6; Tæl til 250

if(++timecount == 1000)
{
PORTA = PORTA ^ 0x80; // Toggle bit 7 på
PortA
timecount = 0; // Clear for de næste
500 us
}
}

void main(void)
{
// Timer 0 interrupt initialisering
TIMSK = 0x02; // Afmask Timer 0
overflow interrupt
DDRA = 0x80; // Port A bit 7 er
output
TCCR0 = 0x02; // Sæt Timer0 til
clock/8 som clock input

// Global aktivering af interrupts
#asm("sei")

while(1)
;
}

Denne blinker fint med bit7 på PortA med 1 Hz. Dette forsøger jeg så
at ændre til Timer1,
således:

#include <mega8515.h>

//Timer 1 overflow ISR
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
static unsigned int timecount = 0; //global time counter

TCNT1 = 0xFF05; // start med at tælle
fra 65285; Tæl til 250

if(++timecount == 1000)
{
PORTA = PORTA ^ 0x80; // Toggle bit 7 på
PortA
timecount = 0; // Clear for de næste
500 us
}
}

void main(void)
{
// Timer 0 interrupt initialisering
TIMSK = 0x02; // Afmask Timer 0
overflow interrupt
DDRA = 0x80; // Port A bit 7 er
output
TCCR1B = 0x02; // Sæt Timer1 til
clock/8 som clock input

// Global aktivering af interrupts
#asm("sei")

while(1)
;
}


Hvilket desværre blot for bit 7 til at lyse konstant - Har ikke lige
en scop, så jeg kan
teste, om det blot er en høj frekvens.
Hvad gør jeg galt?

--
Mvh.

Tomas


Bertel Brander (06-01-2008)
Kommentar
Fra : Bertel Brander


Dato : 06-01-08 20:24

Tomas . skrev:
> Nu er jeg jo så kommet til en ny milesten.
>
> Da jeg nu har koden med læsning af 4x4 keypaden til at virke, har jeg
> fået problemer med
> Timer0, der i den omtalte kode benyttes til at give SW-interrupt, når
> en tast påvirkes. Jeg
> har dog brug for timerfunktionen andre steder, hvor Timer0 anvendes
> til at teste, om 2 knapper
> holdes nede i 5 sek. Denne funktion vil jeg så have over på Timer1 i
> stedet. Til at teste
> Timer1, tager jeg udgangspunkt i dette lille kodeeksempel:
>
> #include <mega8515.h>
>
> //Timer 0 overflow ISR
> interrupt [TIM0_OVF] void timer0_ovf_isr(void)
> {
> static unsigned int timecount = 0; //global time counter
>
> TCNT0 = 0x06; // start med at tælle
> fra 6; Tæl til 250
>
> if(++timecount == 1000)
> {
> PORTA = PORTA ^ 0x80; // Toggle bit 7 på
> PortA
> timecount = 0; // Clear for de næste
> 500 us
> }
> }
>
> void main(void)
> {
> // Timer 0 interrupt initialisering
> TIMSK = 0x02; // Afmask Timer 0
> overflow interrupt
> DDRA = 0x80; // Port A bit 7 er
> output
> TCCR0 = 0x02; // Sæt Timer0 til
> clock/8 som clock input
>
> // Global aktivering af interrupts
> #asm("sei")
>
> while(1)
> ;
> }
>
> Denne blinker fint med bit7 på PortA med 1 Hz. Dette forsøger jeg så
> at ændre til Timer1,
> således:
>
> #include <mega8515.h>
>
> //Timer 1 overflow ISR
> interrupt [TIM1_OVF] void timer1_ovf_isr(void)
> {
> static unsigned int timecount = 0; //global time counter
>
> TCNT1 = 0xFF05; // start med at tælle
> fra 65285; Tæl til 250
>
> if(++timecount == 1000)
> {
> PORTA = PORTA ^ 0x80; // Toggle bit 7 på
> PortA
> timecount = 0; // Clear for de næste
> 500 us
> }
> }
>
> void main(void)
> {
> // Timer 0 interrupt initialisering
> TIMSK = 0x02; // Afmask Timer 0
> overflow interrupt

Jeg kender ikke AVR, og ved ikke hvordan de virker,
jeg undrer mig dog over at linjen med TIMSK ikke er
ændret fra det først til dette eksempel.

Tomas . (06-01-2008)
Kommentar
Fra : Tomas .


Dato : 06-01-08 22:21

>Jeg kender ikke AVR, og ved ikke
>hvordan de virker,
>jeg undrer mig dog over at linjen
>med TIMSK ikke er
>ændret fra det først til dette eksempel.

Ærgeligt.
TIMSK står for Timer Interrupt MaSK Register

--
Mvh.

Tomas


Bertel Brander (06-01-2008)
Kommentar
Fra : Bertel Brander


Dato : 06-01-08 22:57

Tomas . skrev:
>> Jeg kender ikke AVR, og ved ikke
>> hvordan de virker,
>> jeg undrer mig dog over at linjen
>> med TIMSK ikke er
>> ændret fra det først til dette eksempel.
>
> Ærgeligt.
> TIMSK står for Timer Interrupt MaSK Register

Skal du ikke sætte et andet bit i TIMSK når du bruger
timer 1 i stedet for timer 0?


Jesper Vium Kalms (07-01-2008)
Kommentar
Fra : Jesper Vium Kalms


Dato : 07-01-08 07:07

Hej,
Er du sikker på du har initialiseret timer interrupt 1 rigtigt? Det lyder
umiddelbart som om interruptet bliver kaldt 1 gang (eller meget hurtigt som
du selv skriver). Jeg kan ikke lige se ud af din initialisering om interrupt
1 er rigtigt opsat. Umiddelbart synes jeg ikke du bruger det samme register
til timer 1 som til 0 (TCCR0 ved 0 og TCCR1B ved 1 - er det som det skal
være?).

Du opsætter heller ikke timer 1overflow masken (du bruger TIMSK ved 0) -
skal dette ikke også gøres ved 1'eren?

Tjeck manuallen for microprocessoren, så kan du se hvordan timer interrupt 1
skal initialiseres.

/Jesper

----- Original Message -----
From: "Tomas ." <huttelbuttel@hotmail.com>
Newsgroups: dk.edb.programmering.c
Sent: Sunday, January 06, 2008 3:17 PM
Subject: Flytte kode fra Timer0 til Timer1 på AVR


> Nu er jeg jo så kommet til en ny milesten.
>
> Da jeg nu har koden med læsning af 4x4 keypaden til at virke, har jeg
> fået problemer med
> Timer0, der i den omtalte kode benyttes til at give SW-interrupt, når
> en tast påvirkes. Jeg
> har dog brug for timerfunktionen andre steder, hvor Timer0 anvendes
> til at teste, om 2 knapper
> holdes nede i 5 sek. Denne funktion vil jeg så have over på Timer1 i
> stedet. Til at teste
> Timer1, tager jeg udgangspunkt i dette lille kodeeksempel:
>
> #include <mega8515.h>
>
> //Timer 0 overflow ISR
> interrupt [TIM0_OVF] void timer0_ovf_isr(void)
> {
> static unsigned int timecount = 0; //global time counter
>
> TCNT0 = 0x06; // start med at tælle
> fra 6; Tæl til 250
>
> if(++timecount == 1000)
> {
> PORTA = PORTA ^ 0x80; // Toggle bit 7 på
> PortA
> timecount = 0; // Clear for de næste
> 500 us
> }
> }
>
> void main(void)
> {
> // Timer 0 interrupt initialisering
> TIMSK = 0x02; // Afmask Timer 0
> overflow interrupt
> DDRA = 0x80; // Port A bit 7 er
> output
> TCCR0 = 0x02; // Sæt Timer0 til
> clock/8 som clock input
>
> // Global aktivering af interrupts
> #asm("sei")
>
> while(1)
> ;
> }
>
> Denne blinker fint med bit7 på PortA med 1 Hz. Dette forsøger jeg så
> at ændre til Timer1,
> således:
>
> #include <mega8515.h>
>
> //Timer 1 overflow ISR
> interrupt [TIM1_OVF] void timer1_ovf_isr(void)
> {
> static unsigned int timecount = 0; //global time counter
>
> TCNT1 = 0xFF05; // start med at tælle
> fra 65285; Tæl til 250
>
> if(++timecount == 1000)
> {
> PORTA = PORTA ^ 0x80; // Toggle bit 7 på
> PortA
> timecount = 0; // Clear for de næste
> 500 us
> }
> }
>
> void main(void)
> {
> // Timer 0 interrupt initialisering
> TIMSK = 0x02; // Afmask Timer 0
> overflow interrupt
> DDRA = 0x80; // Port A bit 7 er
> output
> TCCR1B = 0x02; // Sæt Timer1 til
> clock/8 som clock input
>
> // Global aktivering af interrupts
> #asm("sei")
>
> while(1)
> ;
> }
>
>
> Hvilket desværre blot for bit 7 til at lyse konstant - Har ikke lige
> en scop, så jeg kan
> teste, om det blot er en høj frekvens.
> Hvad gør jeg galt?
>
> --
> Mvh.
>
> Tomas
>


Søg
Reklame
Statistik
Spørgsmål : 177419
Tips : 31962
Nyheder : 719565
Indlæg : 6407871
Brugere : 218876

Månedens bedste
Årets bedste
Sidste års bedste