Forum: Mikrocontroller und Digitale Elektronik Hilfe mit dem Code (C#)


von Tobias N. (silberkristall)


Lesenswert?

Hallo,

ich habe mir eine Schaltung zusammen gebaut und diese mit dem folgenden 
Code geflasht.

http://nopaste.info/d182180668.html

Der Käfer ist ein ATMega8. So weit läuft auch alles, der Fototransistor 
etc. alles klappt, allerdings habe ich ein problem ab Zeile 101.

Das ganze sollte folgendermassen laufen:

Wenn auf BLI (PC3) GND anliegt schalte den Transistor an BLO (PC1).
Liegt nach einer Sekunde immernoch GND an BLI dann schalte nicht mehr.
Liegt nach einer Sekunde kein GND mehr an Schalte BLO noch für 2 sek und 
schalte dann ab.

Das klappt auch soweit mit dem Code, allerdings brauche ich eine Lösung 
er kennt ob GND gehalten wird, und wenn ja, dann warte solange bis kein 
GND mehr anliegt, allerdings tue auch solange nicht.

Also, wird BLI kurz auf Masse gezogen schalte transistor für 3 sek. Wird 
BLI auf Masse gehalten tue nichts, auch wenn masse wieder abfällt nicht. 
Sondern erst wenn wieder auf Masse gezogen wird.

Ich hoffe das ist verständlich und jemand kann mit dabei weiter helfen.

von Karl H. (kbuchegg)


Lesenswert?

Wenn man sich maximal unbeliebt machen will, dann verstreut man die 
Bestandteile seines Projekts auf möglichst vielen Web-Seiten, damit es 
für die Forenteilnehmer möglichst kompliziert wird, sich die Einzelteile 
anzusehen, zu studieren und mit deiner Beschreibung in Einklang zu 
bringen. Das gilt für Photos. Und in noch größerem Masse gilt es für 
Code
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
 
4
#define LICHT    PC0    // Licht port
5
#define BLO      PC1    // Blinker links ausgangsport
6
#define BRO     PC2    // Bliner rechts ausgangsport
7
#define BLI      PC3    // Blinker links eingangsport
8
#define BRI      PC4    // Blinker rechts eingangsport
9
#define FOTOTR     PC5    // Fototransistor
10
#define STRPORT PORTC
11
#define STRDDR  DDRC
12
 
13
// Variablen
14
int timerstat = 0;
15
int lichtsek = 3;
16
int lichtstat = 0;
17
int blinkerlinkson = 0;
18
int blt = 10;    // Blinkerlinkstimerzeit
19
int brt = 10;    // Blinkerrechtstimerzeit
20
//Variable für die Zeit des Timers
21
volatile unsigned int sekunde;
22
 
23
// Timer ISR
24
ISR(TIMER1_OVF_vect) {       
25
    TCNT1 = 49911;      // Zaehlregister mit Vorladewert vorladen
26
    sekunde++;            // Variable hochzählen
27
    blt++;
28
    brt++;
29
}
30
 
31
 
32
/* ADC initialisieren */
33
void ADC_Init(void) {
34
 
35
  uint16_t result;
36
 
37
  // interne Referenzspannung als Refernz für den ADC wählen:
38
  ADMUX = (1<<REFS1) | (1<<REFS0);
39
 
40
  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
41
  // schon auf 0, also single conversion
42
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
43
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
44
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
45
    also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
46
 
47
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung
48
  while (ADCSRA & (1<<ADSC) ) {        // auf Abschluss der Konvertierung warten
49
  }
50
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
51
    Wandlung nicht übernommen. */
52
  result = ADCW;
53
}
54
 
55
/* ADC Einzelmessung */
56
uint16_t ADC_Read( uint8_t channel )
57
{
58
  // Kanal waehlen, ohne andere Bits zu beeinflußen
59
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
60
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
61
  while (ADCSRA & (1<<ADSC) ) {  // auf Abschluss der Konvertierung warten
62
  }
63
  return ADCW;                    // ADC auslesen und zurückgeben
64
}
65
 
66
int main (void) {
67
 
68
// Setze Portausgänge
69
    STRDDR |= (1 << LICHT);    // Licht
70
    STRDDR |= (1 << BLO);         // Blinker Links
71
    STRDDR |= (1 << BRO);         // Blinker Rechts
72
    
73
// Setze Porteingänge
74
    STRDDR &= ~(1 << BLI);        // Blinker Links
75
    STRDDR &= ~(1 << BRI);     // Blinker Rechts
76
    STRDDR &= ~(1 << FOTOTR);     // Fototransistor
77
// Timer
78
  // Global Interrupts aktivieren
79
  sei();
80
     
81
    TIMSK |= (1<<TOIE1);
82
    TCCR1B |= (1<<CS11) |  (1<<CS10);    //Prescaler = 64
83
    TCNT1 = 0xFFFF;        //Zaehlregister vorladen mit FFFF zum Sofortstart
84
uint16_t adcval;
85
ADC_Init();
86
 
87
// Hauptcode
88
  while(1)
89
  {
90
 
91
    // Lichtsensor
92
    adcval = ADC_Read(5);  // Kanal 5
93
    if (adcval > 400) { STRPORT &= ~(1 << LICHT); } else { STRPORT |= (1 << LICHT); }
94
    
95
    // Blinker Links
96
   
97
    if (blt == 1)
98
        {
99
            if (!(PINC & 1<< BLI)) // Taster pressed
100
                {
101
                    blt = 10;
102
                    blinkerlinkson = 0;
103
                }
104
        }
105
        else
106
        {
107
            if (!(PINC & 1<< BLI)) // Taster pressed
108
                {
109
                    blt = 0;
110
                    blinkerlinkson = 1;
111
                }
112
        }
113
    if (blt == 3)
114
        {
115
            blinkerlinkson = 0;
116
        }
117
        
118
    if (blinkerlinkson == 1)
119
        {
120
            STRPORT |= (1 << BLO);
121
        }
122
        
123
    if (blinkerlinkson == 0)
124
        {
125
            STRPORT &= ~(1 << BLO);
126
        }
127
  }
128
}

von Tobias N. (silberkristall)


Lesenswert?

sorry, ich bin es grundsätzlich gewöhnt ein pastebin zu nutzen. z.b. in 
einem chat (irc) kommt es nicht so gut wenn man einen ganzen code 
postet. zumal in einem pastebin der code auch editierbar dargestellt 
wird. aber ok, ich werde es mir merken den code direkt zu posten.

von Karl H. (kbuchegg)


Lesenswert?

Tobias N. schrieb:

> Also, wird BLI kurz auf Masse gezogen schalte transistor für 3 sek. Wird
> BLI auf Masse gehalten tue nichts, auch wenn masse wieder abfällt nicht.
> Sondern erst wenn wieder auf Masse gezogen wird.
>
> Ich hoffe das ist verständlich und jemand kann mit dabei weiter helfen.

die Lösung deines Problems liegt darin, dass du weg musst von 'Ist eine 
Taste gedrückt' und hin musst zu 'Hat sich der Zustand des Eingangs 
verändert (im Vergleich zum letzten mal als nachgesehen wurde) und wenn 
ja, wie hat er sich verändert'. Du brauchst eine Flankenerkennung.


Im Prinzip kann das zb so aussehen
1
   ...
2
3
   oldLinks = jetziger Pin Status;
4
5
   while( 1 )    // Hauptschleife
6
   {
7
     newLinks = jetziger Pin Status;
8
9
     if( oldLinks != newLinks )    // Hoppla, am Pin hat sich was getan!
10
     {
11
       if( newLinks == Zustand Low )    // der Pin ist von 1 auf 0 gewechsel
12
       {
13
         mach was für den Fall einer fallenden Flanke
14
       }
15
16
       else                             // der Pin ist von 0 auf 1 gewechselt
17
       {
18
         mach was für den Fall einer steigenden Flanke
19
       }
20
     }
21
   }


Und in diese Flankenerkennung bettest du jetzt deine Zeitsteuerung ein.
Die im Prinzip so aussieht, dass du dir bei der fallenden Flanke den 
Wert einer vom Timer hochzählenden Variablen merkst und bei der 
steigenden Flanke mit dem dann aktuellen Wert vergleichst. Wenn die 
Differenz klein genug ist, dann war auch der Puls kurz genug und du 
machst dein Ding und startest die LED. Ist er aber größer als dein 
Grenzwert, dann machst du gar nichts.

Wobei ich das 'Nachleuchten' der LED so realisieren würde, dass in der 
Timer ISR (die auch auf weniger als 1 Sekunde einstelle), ein Zähler 
heruntergezählt wird, der im Prinzip eine Eieruhr realisiert und der bei 
erreichen von 0 dann die LED abschaltet.
1
volatile uint8 LEDLinks;
2
3
ISR( ... )
4
{
5
  if( LEDLinks > 0 )
6
  {
7
    LEDLinks--;
8
    if( LEDLinks == 0 )
9
      schalte Linke LED ab
10
  }
11
12
  ....
13
}

Im Hauptprogramm muss man dann nur noch die LED einschalten, den Zähler 
LEDLinks auf einen vernünftigen Wert setzen (hängt davon ab, wie oft die 
ISR aufgerufen wird), und nach Ablauf der mit diesem Wert verknüpften 
Zeit, schaltet die ISR die LED wieder ab.


Das sind so die Einzelteile, von denen ich denke, dass sie dir 
weiterhelfen. Vorausgesetzt ich hab deine Problembeschreibung richtig 
verstanden.

von Tobias N. (silberkristall)


Lesenswert?

also das ganze soll halt erkennen ob eine taste gedrückt oder gehalten 
wird. also wird die taste nur einmal gedrückt schalte den transistor 3 
sek, danach schalte ab. wird die taste gehalten dann tue nichts, selbst 
wenn die taste wieder losgelassen wird. also reagiere auf tippen und 
nicht auf halten, wird gehalten dann tue solange nichts bis die taste 
wieder getippt wird.

also, wird der blinker links nur angetippt, blinke 3mal (etwa 3sek) wird 
der blinker aber komplett geschaltet (an einer ampel z.b. beim abbiegen) 
dann tue, selbst wenn der blinker nach der kurve von alleine ausgeht 
nichts, also tue nur was wenn der hebel angetippt wird.

das soll halt werden: 1x tippen, 3 x blinken

derzeigt erkennt man code zwar 1x tippen, 3 x blinken aber wenn man den 
hält und dann z.b. 10sek später den blinker ausmacht, dann schaltet der 
code 1sek später den blinker nochmal für 3 sek. und das muss ich 
irgendwie erkennen und "abschalten".

von Karl H. (kbuchegg)


Lesenswert?

Tobias N. schrieb:
> also das ganze soll halt erkennen ob eine taste gedrückt oder gehalten
> wird. also wird die taste nur einmal gedrückt schalte den transistor 3
> sek, danach schalte ab. wird die taste gehalten dann tue nichts, selbst
> wenn die taste wieder losgelassen wird. also reagiere auf tippen und
> nicht auf halten, wird gehalten dann tue solange nichts bis die taste
> wieder getippt wird.

Ja.
Und da dein µC genausowenig wie du ein Hellseher ist, läuft es darauf 
hinaus, auszumessen wie lange die Taste gedrückt wurde. Wird die Taste 
niedergedrückt, dann startet eine Stoppuhr, wird sie losgelassen, dann 
stoppt die Stoppuhr. Und erst dann kannst du entscheiden ob das ein 
kurzes Antippen oder langes Halten war.

Und genau so läuft das dann auch im Code
Beim Niederdrücken die aktuelle 'Uhrzeit' merken. Beim Loslassen die 
dann aktuelle "Uhrzeit" holen, beide vergleichen und aus der Differenz 
der beiden die weiteren Schlüsse ziehen. 'Uhrzeit' ist nichts anderes 
als ein Zähler, der zb Timergesteuert alle 0.01 Sekunden um 1 hochzählt.

Aber der springende Punkt ist, dass du erst beim Loslassen der Taste 
diese Unterscheidung treffen kannst, wobei du zu kurze Tastendrücke als 
Tastenprellen gleich mit verwirfst.

von Karl H. (kbuchegg)


Lesenswert?

Ich weiß schon, dass du von deinem Code retten willst, was zu retten 
ist.
Aber erstens ist das nicht viel Code und zweitens denke ich, dass du mit 
diesem Code nicht vernünftig weiter kommst. Du stehst fast am Ende in 
einer Sackgasse und die einzige Chance ist es umzudrehen und an den 
Anfang zurückzufahren.
So aufwändig ist das ganze ja nicht. Die paar Codezeilen hast du gleich.

von Tobias N. (silberkristall)


Lesenswert?

ja, wie du schon sagst, viel is es nicht. und naja das bisschen kann ich 
wirklich neu machen. mir hing es da nur ein wenig an der umsetzung, nach 
deiner erklärung nun ist es für mich auch jetzt klarer geworden.

wurde taste gedrücke zähle solange taste gedrückt wird.
 danach werte aus, wurde taste länger als 1sek (ist ja dann veränderbar) 
gedrückt tue garnichts, ansonsten schalte den transistor 3 sek.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.