Hejsa
Som man nok kan se af nogle af mine tidligere indlæg, sidder jeg og
roder med lidt AVR ind imellem. Jeg er nu løbet ind i et problem med
følgende program:
#asm
.equ __lcd_port=0x15
#endasm
#include <skjult.h>
#include <io.h>
#include <lcd.h>
#include <stdio.h>
#include <delay.h>
#include <mega8515.h>
// Krystalfrekvens [Hz]
#define XTAL 4000000
// PINC0..3 will be row inputs
#define KEYIN PIND
// PORTC4..7 will be column outputs
#define KEYOUT PORTD
// used for TIMER1 count initialization
#define INIT_TIMER1 TCNT1 = 0x10000-(XTAL/1024/500);
//TCNT0=0x100L-XTAL/64L/543L
#define FIRST_COLUMN 0x80
#define LAST_COLUMN 0x10
#define GIMSK GICR
typedef unsigned char byte;
// store here every key state as a bit,
// bit 0 will be KEY0, bit 1 KEY1,...
unsigned keys;
unsigned char n_spor;
// LCD display buffer
char buf[33];
eeprom unsigned k = 0xaa;
//Timer 0 overflow ISR
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
static unsigned int timecount = 0; //global time counter
//unsigned int programmeringsmode = 0;
TCNT0 = 0x06; // start med at tælle fra 6; Tæl til 250
if(++timecount == 400)
{
PORTB = PORTB ^ 0x10; // Toggle bit 7 på PortA
timecount = 0; // Clear for de næste 500 us
}
}
//Timer 1 interrupt hver 2ms
interrupt [TIM1_OVF] void timer1_ovf_int(void)
{
static byte key_pressed_counter=20;
static byte key_released_counter,column=FIRST_COLUMN;
static unsigned row_data,crt_key;
// reinitialize TIMER1
INIT_TIMER1;
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)
{
if (k=keys) keys=0;
return k;
}
void write_to_LEDs(unsigned char ch)
{
switch(ch)
{
case 1: PORTA = 0b11100001;
break;
case 2: PORTA = 0b11010001;
break;
case 3: PORTA = 0b10110001;
break;
case 4: PORTA = 0b01110001;
break;
case 5: PORTA = 0b11100010;
break;
case 6: PORTA = 0b11010010;
break;
case 7: PORTA = 0b10110010;
break;
case 8: PORTA = 0b01110010;
break;
case 9: PORTA = 0b11100100;
break;
case 10:PORTA = 0b11010100;
break;
case 11:PORTA = 0b10110100;
break;
case 12:PORTA = 0b01110100;
break;
case 13:PORTA = 0b11101000;
break;
case 14:PORTA = 0b11011000;
break;
case 15:PORTA = 0b10111000;
break;
case 16:PORTA = 0b01111000;
break;
default:PORTA = 0b11111111;
}
}
// Omregning af 2^n værdi af læst knap
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 */
}
void initialize(void)
{
unsigned char i;
DDRA = 0xff; // Port A
output
DDRB = 0x10; // Port B -
bit 4 Output, rest Input
DDRD = 0x00; // Port D
input
n_spor = 16;
/*n_spor = (PINB & 0x0f)+1;
lcd_gotoxy(0,1);
sprintf(buf,"Antal spor=%d",n_spor);
lcd_puts(buf);
delay_ms(500);*/
for (i = 1; i <= n_spor; i++) // Check
forbindelse af LEDs OK
{
write_to_LEDs(i);
delay_ms(60);
PORTB = PORTB ^ 0x10; // Toggle bit 5 på PortB
}
for (i = n_spor-1; i >= 1; i--) // Check
forbindelse af LEDs OK
{
write_to_LEDs(i);
delay_ms(60);
PORTB = PORTB ^ 0x10; // Toggle bit 5 på PortB
}
write_to_LEDs(0); // Sluk LEDs
igen
PORTB.4 = 1; // Test
}
void init_keypad(void)
{
DDRC = 0x0f; // Port C 0-3 output, 4-7
input
INIT_TIMER1;
TCCR1A = 0; // Disconnect Timer1 fra OC1,
ingen PWM
TCCR1B = 0x05; // Sæt Timer1 til clock/1024
som clock input
TIFR=0; // Clear alle Timer1 interrupt
flag
TIMSK = 0x82; // Enable Timer0 (0x02) og
Timer1 (0x80) overflow interrupt
GIMSK=0; // Alle andre interruptkilder
er disablet. Husk Timer0 senere
// Global aktivering af interrupts
#asm("sei")
}
main() {
initialize();
init_keypad();
while (1)
{
if(PINB.5 == 0 && PINB.6 == 0)
TCCR0 = 0x03;
else
TCCR0 = 0x00;
lcd_gotoxy(0,1);
if (k=inkey())
{
k = invpow(k)+1;
//sprintf(buf,"Key code=%d",k);
write_to_LEDs(k);
//lcd_puts(buf);
}
//else lcd_putsf("NO KEY ");
delay_ms(500);
}
}
Beskrivelse:
På Port A sidder 16 LEDs, der skrives til vha. funktionen
Write_to_LEDs(). Under initialiseringen testes alle LEDs via to
for-løkker.
På Port C sidder der et 4x4 keypad, som læses vha. interrupt af
Timer1.
På Port B, bit 0-3 sidder 4 jumpere, hvis binære værdi læses ind i
værdien n_spor under initialiseringen. Denne værdi skal benyttes til
at bestemme, hvor mange taster keypad'en og dermed LED's der er
forbundet til controlleren.
På Port B sidder der også 2 taster (PINB.5 og PINB.6). Når de begge
holdes nede i ca. 3 sek., skal PINB.4 gå høj. Aktiverer man atter
PINB.5 og PINB.6 skal den atter gå lav.
Jeg kan sagtens læse værdien ind af de 4 jumpere under
initialiseringen, men så kører testløkken af LED'ene ikke. Deaktiveres
jumperindlæsningen, som den er i koden nu, virker det dog fint.
Hvorfor ved jeg dog ikke.
Et andet problem: Som SW'en er nu, skal man efter initialiseringsfasen
er overstået kunne aktivere en af tasterne på keypad'en og så tænde
den respektive LED, der svarer til tastnummeret. Jeg har haft
programmet til at køre som enkelt funktion i et simpelt program, men
når jeg har lagt funktionerne sammen som vist her ovenfor, fungerer
læsningen af tasterne ikke.
Et sidste problem: Værdien 'k' har jeg defineret som skulle ligge i
eeprom'en, da den gerne skal huske, hvilken tast, der sidst blev
påvirket efter der har været slukket for boardet, men det gør den
desværre ikke. Mangler jeg en opsætning af eeprom'en for at kunne gøre
dette?
Håber, der er en der kan hjælpe, da jeg er lidt uforstående overfor,
hvad der er galt.
--
På forhånd tak
Tomas
|