Ich habe vor einiger Zeit mal ein kleines Wochenend-Projekt gemacht: Einen Reaktionstester.
Im Kern steckt ein ATmega8, welcher eine LED, Sieben-Segment-Anzeigen und einen Tester ansteuert. Sobald der Taster gedrückt wird, werden zwei Balken angezeigt. Sobald die LED angeht (pseudozufällig verzögert), muss der Taster schnellstmöglich gedrückt werden. Macht man dies, dann zeigt die Sieben-Segment-Anzeige die benötigte Reaktions-Zeit in Millisekunden an. Drückt man zu früh den Taster wird “FAIL” ausgegeben. Der Taster ist als Öffner ausgeführt war ursprünglich als Öffner geplant, damit das Ergebnis genauer ist.
Die Schaltung wird von einem 5V-Steckernetzteil gespeist. Die ISP-Schnittstelle ist nicht verbunden, der AVR wurde extern programmiert. Die vier Transistoren werden für das Multiplexing der Segmentanzeigen benötigt. Die Vorwiderstände weiß ich leider nicht mehr auswendig, aber es sollte kein Hexenwerk sein diese zu berechnen. Als Taktgeber wird der interne Oszillator genutzt. Der reicht voll und ganz aus.
Interessant ist die display.c. Diese kümmert sich um die Kodierung von Zahlenwerten auf das Display. set_number() setzt die angebenen Segmentanzeige auf den angegebenen Wert. Mit set_display_number() kann ein Wert zwischen 0 und 9999 auf ausgegeben werden. Die anderen Funktionen dienen Spezialausgaben (z.B. “FAIL”).
display.c
#include <avr/io.h>
#include "multiplex.h"
#include "sbit.h"
void set_number(int nr, int display) {
if(nr==0) {
FB[display] = 0b00111111+(SBIT(FB[display],7)<<7);
} else if(nr==1) {
FB[display] = 0b00000110+(SBIT(FB[display],7)<<7);
} else if(nr==2) {
FB[display] = 0b01011011+(SBIT(FB[display],7)<<7);
} else if(nr==3) {
FB[display] = 0b01001111+(SBIT(FB[display],7)<<7);
} else if(nr==4) {
FB[display] = 0b01100110+(SBIT(FB[display],7)<<7);
} else if(nr==5) {
FB[display] = 0b01101101+(SBIT(FB[display],7)<<7);
} else if(nr==6) {
FB[display] = 0b01111101+(SBIT(FB[display],7)<<7);
} else if(nr==7) {
FB[display] = 0b00000111+(SBIT(FB[display],7)<<7);
} else if(nr==8) {
FB[display] = 0b01111111+(SBIT(FB[display],7)<<7);
} else if(nr==9) {
FB[display] = 0b01101111+(SBIT(FB[display],7)<<7);
}
}
void set_display_number(uint16_t nr) {
uint8_t n0, n1, n2, n3;
if(nr<10) {
n3=nr;
set_number(0,0);
set_number(0,1);
set_number(0,2);
set_number(n3,3);
} else if(nr<100) {
n3=nr%10;
n2=(nr-(n3))/10;
set_number(0,0);
set_number(0,1);
set_number(n2,2);
set_number(n3,3);
} else if(nr<1000) {
n3=nr%10;
n2=((nr-(n3))/10)%10;
n1=((nr-(n2*10)-n3)/100);
set_number(0,0);
set_number(n1,1);
set_number(n2,2);
set_number(n3,3);
} else if(nr<10000) {
n3=nr%10;
n2=((nr-(n3))/10)%10;
n1=((nr-(n2*10)-n3)/100)%10;
n0=((nr-(n1*100)-(n2*10)-n3)/1000);
set_number(n0,0);
set_number(n1,1);
set_number(n2,2);
set_number(n3,3);
}
}
void set_fail(void) {
FB[0] = 0b01110001;
FB[1] = 0b01110111;
FB[2] = 0b00000110;
FB[3] = 0b00111000;
}
void set_blank(void) {
FB[0] = 0b00000000;
FB[1] = 0b00000000;
FB[2] = 0b00000000;
FB[3] = 0b00000000;
}
void set_wait(void) {
FB[0] = 0b00110000;
FB[1] = 0b00000000;
FB[2] = 0b00000000;
FB[3] = 0b00000110;
}
Die multiplex.c enthält eine Funktion, welche vom timer0-Interrupt aufgerufen wird und sich um das Multiplexen kümmert.
multiplex.c
#include <avr/io.h>
#include "sbit.h"
#include "io_label.h"
uint8_t FB[4];
uint8_t ct=0;
void seg_multiplex(void) {
SEG_0=false;
SEG_1=false;
SEG_2=false;
SEG_3=false;
SEG_A=SBIT(FB[ct],0);
SEG_B=SBIT(FB[ct],1);
SEG_C=SBIT(FB[ct],2);
SEG_D=SBIT(FB[ct],3);
SEG_E=SBIT(FB[ct],4);
SEG_F=SBIT(FB[ct],5);
SEG_G=SBIT(FB[ct],6);
SEG_DP=SBIT(FB[ct],7);
if(ct==0) {
SEG_0=true;
} else if(ct==1) {
SEG_1=true;
} else if(ct==2) {
SEG_2=true;
} else if(ct==3) {
SEG_3=true;
}
if(ct<3) {
ct++;
} else {
ct=0;
}
}
In der main.c gibt es eine Schrittkette, welche sich um den Hauptprogrammablauf kümmert.
Schritt Null wartet auf den Taster. Schritt Eins Wartet eine Pseudozufällige Zeit und fragt ab, ob der Button zu früh gedrückt wurde. Schritt Zwei wartetet darauf, dass man den Taster drückt (oder die Maximalzeit abgelaufen ist und gibt den Wert (bzw. Fehler) aus.
main.c
#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>
#include "sbit.h"
#include "io_label.h"
#include "timer0.h"
#include "timer1.h"
#include "display.h"
int main(void)
{
SEG_DDR = 0b11111111;
SEL_DDR = 0b00101111;
BUT1_PULL = true;
timer0_init();
timer1_init();
timer1_var_enabled = false;
set_blank();
uint8_t step=0;
while(1)
{
if(step==0) {
timer1_var=0;
while(!BUT1);
_delay_ms(300);
while(BUT1);
set_wait();
_delay_ms(300);
step=1;
}
if(step==1) {
uint16_t ms;
ms=0;
while ((ms<(uint16_t)((timer1_rand*70L)+300L))&&(step!=0)) {
_delay_ms(10);
if(BUT1) {
set_fail();
_delay_ms(500);
step=0;
}
ms++;
}
if(step!=0) step=2;
}
if(step==2) {
LED1 = true;
timer1_var_enabled = true;
while((!BUT1)&&(!(timer1_var>9999)));
timer1_var_enabled = false;
if(timer1_var>9999) {
set_fail();
} else {
set_display_number(timer1_var);
}
LED1 = false;
_delay_ms(500);
step=0;
}
}
}