Forum: Mikrocontroller und Digitale Elektronik Microcontroller über Windows Applikation anpassen. Aber wie?


von Nino K. (lnino)


Lesenswert?

Hi an alle.

Ich habe einen ATmega168 mit 4 LEDs(rot, blau, grün und gelb).

Die LEDs zum leuchten oder blinken zu bringen stellt nicht die 
Schwierigkeit dar. Mich stört nur ein wenig, dass der Code immer fix im 
Microcontroller "eingebrannt" ist. Wenn man die Reihenfolge der 
blinkenden LEDs ändern möchte, dann muss man wieder in den Quelltext und 
das anpassen.

Bei so einem kleinen Projekt ist das ja nicht weiter tragisch, aber bei 
größeren kam mir der Gedanke, dass es durchaus praktisch wäre, wenn ich 
den Micrcontroller(mit Platine, Quarz, etc.) per USB an den PC hänge und 
dort über eine selbst geschriebene Anwendung in C# in der GUI anklicke, 
welche LEDs leuchten sollen. Dann sollen die Einstellung welche vom User 
getroffen wurden auf den MCU geschrieben werden.

Die Anwendung soll somit jeder bedienen können der von Microcontroller 
Programmierung keine Ahnung hat. Also reiner End-Anwender.

Leider habe ich keine Ahnung wie man das umsetzen kann.

Kann mir hier jemand dies etwas näher erklären oder mich an ein Tutorial 
weiter leiten, welches mir zeigt wie ich diese Schnitstelle herstellen 
kann und welche zusätzlichen Komponenten ich eventuell dazu brauche um 
es zu realisieren.

Danke schon mal für die Hilfe.

von Coder (Gast)


Lesenswert?

Das ist bei uC mit Flash-Programmspeicher so. Du kannst Parameter ins 
eeprom ablegen, die dein Programm auswertet.

von EGS_TI (Gast)


Lesenswert?

Du könntest z.B. einfach per PC Befehle an den Controller schicken, der 
die dann logischerweise auswertet und somit weiß, welche LEDs leuchten 
sollen...

Was ist daran so schwierig?

von Nino K. (lnino)


Lesenswert?

Ich weiß nicht so recht wie es umzusetzen ist.
Habe so etwas noch nie gemacht.

Habt ihr vielleicht ein Codebeispiel in welcher zum Beispiel eine LED 
leuchten soll?

Danke für die Hilfe.

von Coder (Gast)


Lesenswert?

El Nino schrieb:
> Ich weiß nicht so recht wie es umzusetzen ist.
> Habe so etwas noch nie gemacht.
>
> Habt ihr vielleicht ein Codebeispiel in welcher zum Beispiel eine LED
> leuchten soll?
>
> Danke für die Hilfe.

Na schau Dir doch mal die AVR Tutorials an.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Blink/Leucht-Code über UART an den µC übermitteln.
Ein Speichern der Standard-Einstellungen im EEPROM (512 Bytes sind 
vorhanden im Mega168) ist auch möglich.

Ein Teil des Codes muß dann natürlich Anfragen über UART auswerten.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Wenn die LEDs zur Laufzeit stetig verändert werden sollen, muss der PC 
über beispielsweise einen COM-PORT, an dem ein FT232R sitzt, an dem der 
Mega168 über UART angeschaltet ist, lediglich ein Byte versenden, 
welches im RAM des Mega168 landet. In diesem Byte ist das jeweilige Bit 
für die jeweilige LED gesetzt. Der Mega braucht dann diese Bits nur noch 
auf den LED-Port zu kopieren. Ich würde mal sagen 30 Befehle in ASM :-)

von Nino K. (lnino)


Lesenswert?

Knut Ballhause schrieb:
> Wenn die LEDs zur Laufzeit stetig verändert werden sollen, muss der PC
> über beispielsweise einen COM-PORT, an dem ein FT232R sitzt, an dem der
> Mega168 über UART angeschaltet ist, lediglich ein Byte versenden,
> welches im RAM des Mega168 landet. In diesem Byte ist das jeweilige Bit
> für die jeweilige LED gesetzt. Der Mega braucht dann diese Bits nur noch
> auf den LED-Port zu kopieren. Ich würde mal sagen 30 Befehle in ASM :-)

Danke für die Rückmeldung. Ich sehe UART klingt nach dem richtigen 
Stichwort. Da werde ich mich ein wenig einlesen.

Die Hauptfunktion die ich möchte ich folgende:

Ich baue eine kleine Platine(ATmega, Quarz, Capacitor, 4 LEDS und 
Batterie)
Es wird ein Code in den ATmega geschrieben, welche nur die blaue LED 
leuchten lässt.

Nun gebe ich diese Platine an einen einfachen Anwender welcher von 
Programmierung keine Ahnung hat. Nun möchte ich es so lösen, dass er/sie 
das Gerät per USB an den Computer anschließt und ein C# Programm 
startet.

In dem Programm kann er/sie dann anklicken welche der 4 LEDs leuchten 
sollen(z.b.: alle 4). Das Programm soll dann diese Information an den 
MCU schicken und "reinbrennen".

Wenn das Gerät vom PC getrennt wird, muss die letzte Konfiguration aktiv 
sein. In diesem Fall müssen alle 4 LEDs brennen. Auch wenn die Batterie 
getrennt wurde und wieder neu angesteckt wird muss die letzte 
Konfiguration durch die Software noch vorhanden sein.

Lässt dich das realsieren und was brauche ich noch für diese Umsetzung?
Bausteine?

von Karl H. (kbuchegg)


Lesenswert?

El Nino schrieb:

> Lässt dich das realsieren und was brauche ich noch für diese Umsetzung?
> Bausteine?

Ich bin mir nicht sicher, ob du das Prinzip schon verstanden hast oder 
nicht. Teilweise klingt es richtig und dann verwendest du wieder eine 
Wortwahl, die mich das Gegenteil vermuten lässt.

Das Prinzip ist folgendes:
Das Programm wird nicht so geschrieben, dass es fix verdrahtet zb die 
blaue LED brennen lässt.
Das Programm holt sich aus dem EEPROM 1 Byte, in welchem codiert ist, 
welche LED einzuschalten sind und welche nicht. Und genau das macht das 
Programm: Aufgrund der 'ANweisungen', die in diesem Byte stecken 
schaltet es die betreffende LED.

Wie kommt diese 'Anweisung' in das EEPROM?
Indem ein anderer Teil des Programms ständig auf der UART mithört, ob 
vom PC etwas kommt. Wenn ja, dann wertet es das als Steuerbyte und 
schreibt dieses Byte an die entsprechende Stelle im EEPROM (und sorgt 
auch gleichzeitig dafür, dass die LED entsprechend geschaltet werden).

Warum UART?
  weil du vom PC aus eine Möglichkeit brauchst, um ein Kommando an den
  µC zu schicken

Warum EEPROM?
  Weil der EEPROM seinen Inhalt auch dann nicht verliert, wenn der
  Strom abgedreht wird.

D.h. du veränderst nicht das Programm an sich. Das Programm bleibt immer 
gleich. Aber das Programm ist so gebaut, dass es von Daten gesteuert 
wird. Daten die im EEPROM vorliegen, und die sich das Programm von dort 
holt, bzw. die das Programm von der UART dorthin schreibt.

von Nino K. (lnino)


Lesenswert?

Karl Heinz Buchegger schrieb:
> D.h. du veränderst nicht das Programm an sich. Das Programm bleibt immer
> gleich. Aber das Programm ist so gebaut, dass es von Daten gesteuert
> wird. Daten die im EEPROM vorliegen, und die sich das Programm von dort
> holt, bzw. die das Programm von der UART dorthin schreibt.

Danke vielmals für deine ausführliche Erklärung. Das war sehr 
verständlich und spitzenmäßig erklärt. Ich glaube nun habe ich es 
verstanden.

1) Das heißt meine nächsten Schritte werden sein, dass ich es schaffe 
"etwas" über UART in den EEPROM zu schreiben.

2) Wenn das mal geglückt ist, kann ich schauen das ich etwas sinnvolles 
über UART in den EEPROM schreibe.

3) Dann schreib ich mein Programm so, dass es Informationen aus dem 
EEPROM(ich nehme an das ist ein Register) ausliest und anhand dieser 
dann das tut was ich möchte. Dies sollte dann eigentlich gleich 
funktionieren wie die Übergabe einer Variable in eine Funktion, oder?

// Pseudocode

inhalt_eeprom = abcd();

void blink_led (inhalt_eeprom)
{

switch (inhalt_eeprom)
{
case xxx:
// LED blau

case yyy:
// LED grün

case zzz:
// LED rot
}

}
Habe ich das richtig interprätiert?

von Karl H. (kbuchegg)


Lesenswert?

El Nino schrieb:
> 3) Dann schreib ich mein Programm so, dass es Informationen aus dem
> EEPROM(ich nehme an das ist ein Register)

Bitte studier das AVR-GCC-Tutorial

Nein. Das EEPROM ist kein Register. Dein µC hat 3 Arten von Speicher

* Flash
    In diesem Speicher liegt dein Programm.
    Es wird beim Brennen des Programms beschrieben.

* SRAM
    Dort legt das Programm seine Variablen an. Es wird zur Laufzeit
    gelesen und beschrieben

* EEPROM
    Auch dieser Speicher wird zur Laufzeit gelesen und beschrieben.
    Aber: Das geht langsamer als beim SRAM. Dafür hält dieser Speicher
    anders als das SRAM seinen Inhalt auch dann, wenn der Strom
    abgeschaltet wird.

> Habe ich das richtig interprätiert?

So ungefähr.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Der EEPROM wird als Stromausfallsicherung benutzt und am Anfang z.B. in 
den RAM geladen, von wo aus dann dein "Programm" durch das AVR-Programm 
im Flash interpretiert wird z.B.

Im EEPROM hätten dann 512 Bytes interpretierbarer Code platz.

Byte 0 Rot an mit Level 128
Byte 1 Warte 1 sekunde
Byte 2 Grün an mit Level 128
....


Es ist deiner Fanatasie überlassen wie das Flash-Programm dann den 
EEPROM interpretiert.

Zusätzlich dazu wäre es von Vorteil, wenn dein Flash-Programm dem PC per 
UART anbietet das EEPROM-Programm anzuhalten und z.B. umzuschreiben.

Mit Level nehme ich mal die Möglichkeit von PWM vorweg.
Dein Controller hat nicht wirklich viel zu tun und SoftPWM bietet sich 
dann an.

Der Flash-Code im Controller wäre dann nur einmal zu Programmieren.
Änderungen werden dann per UART befehligt und im EEPROM gespeichert.

von Thomas (Gast)


Lesenswert?

Warum bietet sich SoftPWM an?
Der ATmega168 hat 6 PWM Kanäle.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Thomas schrieb:
> Warum bietet sich SoftPWM an?
> Der ATmega168 hat 6 PWM Kanäle.

Minimum bietet sich SoftPWM an.
Wenn die LED's jetzt nicht zufällig schon an den passenden I/O-Pins 
hängen.
Pins wären (OC[0,1,2][A,B])

von Nino K. (lnino)


Lesenswert?

Danke für die super Antworten. So langsam kapier ichs. :-)

Das Lesen aus dem EEPROM und das Schreiben denke ich nun verstanden zu 
habe:

Aus dem AVR GCC Tuorial hat mich das "&eeFooByte" im Befehl:
myByte = eeprom_read_byte (&eeFooByte);
etwas verwirrt. Ich konnte nichts damit anfangen.

Habe dann noch etwas im Netz gesucht und denke ich habe das &eeFooByte 
richtig interprätiert. Hoffe ich zumindest. Das soll die ByteStelle im 
EEPROM darstellen. Ist das korrekt?


uint8_t num;
num = eeprom_read_byte((uint8_t*)46)

// Der Inhalt an Stelle 46 des EEPROM wird in der Variable num 
gespeichert.

eeprom_write_byte ((uint8_t*) 46, 8);

// Mit diesem Befehl wird eine 8 an die Stelle 46 des EEPROM 
geschrieben.

Sollte mit #include <avr/eeprom.h> korrekt funktionieren.

Ist das so korrekt?

Heißt das nun, dass ich an die Stellen 0-511(512 Stellen) wegen des 
vorhandenen 512 Byte EEPROM Speichers schreiben kann?

Wie viel wird beim Schreiben eines Wortes belegt?
Pro Buchstabe ein Bit?

Demnach müsste es möglich sein an die Stelle 46 das Wort rot zu 
schreiben, da dieses nur 3 der vorhandenen 8 Plätze(1Byte) an Stelle 46 
belegt.

Habe ich das richtig verstanden?

eeprom_write_word ((uint8_t*)46, rot);

von Karl H. (kbuchegg)


Lesenswert?

El Nino schrieb:
> Danke für die super Antworten. So langsam kapier ichs. :-)
>
> Das Lesen aus dem EEPROM und das Schreiben denke ich nun verstanden zu
> habe:
>
> Aus dem AVR GCC Tuorial hat mich das "&eeFooByte" im Befehl:
> myByte = eeprom_read_byte (&eeFooByte);
> etwas verwirrt. Ich konnte nichts damit anfangen.

Im Abschnitt drüber
1
uint8_t eeFooByte EEMEM = 123;

eeFooByte ist eine Variable vom Typ uint8_t. Das EEMEM markiert diese 
Variable als "liegt im EEPROM".

(Du wirst das natürlich nicht eeFooByte nennen sondern deiner Verwendung 
entsprechend
1
#include <avr/eeprom.h>
2
3
uint8_t ledStatEeprom EEMEM;   // gesicherter Wert im EEPROM
4
uint8_t ledStat;               // Arbeitsversion
5
6
int main()
7
{
8
  ....
9
10
  // den LED Status aus dem EEPROM lesen
11
  ledStat = eeprom_read_byte( &ledStatEeprom );
12
13
  // mit ledStat weiterarbeiten
14
15
  ....
16
  while( 1 ) {
17
    ....
18
19
    // beim UART Empfang kriegt ledStat einen neuen Wert
20
    // den wieder zurück ins EEPROM schreiben, damit er
21
    // beim nächsten Programmstart wieder zur Verfügung steht
22
    eeprom_write_byte( &ledStatEeprom, ledStat );
23
  }
24
}

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Da gibt es aber ein grundlegendes Unverständnis.

> Demnach müsste es möglich sein an die Stelle 46 das Wort rot zu
> schreiben, da dieses nur 3 der vorhandenen 8 Plätze(1Byte) an Stelle 46
> belegt.

1 Byte = 8 Bit
Das Wort "Rot" wäre dann ein String von mindestens 3 Byte im Ascii-Code.

Schreiben kann man an jedes der 512 Bytes im EEPROM.
Pro Byte kann man aber getrost 10 mSec Schreibzeit einrechnen.

Lesen geht mit maximaler Geschwindigkeit.

von Karl H. (kbuchegg)


Lesenswert?

El Nino schrieb:


> Heißt das nun, dass ich an die Stellen 0-511(512 Stellen) wegen des
> vorhandenen 512 Byte EEPROM Speichers schreiben kann?
>
> Wie viel wird beim Schreiben eines Wortes belegt?
> Pro Buchstabe ein Bit?

In einem Bit kann man keinen Buchstaben ablegen.
1 Buchstabe <==> 1 Byte

genauso wie es auch im Speicher ist.


> Demnach müsste es möglich sein an die Stelle 46 das Wort rot zu
> schreiben

Kann man.
Aber wozu willst du da einen String reinschreiben.
Ist nur Aufwand für nichts.
Du kannst ja auch Codezahlen benutzen, bzw. Kombinationen davon.
Die sind viel einfacher per UART zu übertragen, zu speichern und auch 
auszuwerten.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Ein Byte kann einen Wert von 0 - 255 darstellen.

Du selbst kann ja dann die Interpretierung im Flash-Code übernehmen.

while(1)
{
 eeprombyte=eeprom_read_byte(PC);

 switch(eeprombyte)
 {
   case 0: //restart
    PC=0;break;
   case 1:
    red=on;break;

  .........

 }
}

Der Fantasie sind nur die Grenzen des EEPROMs gesetzt.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Wenn du dich für interpretierte Programme aus dem EEPROM entscheidest, 
solltest du dir erstmal Gedanken machen, was denn so alles passieren 
soll.
Die Definition der Opcodes der State-Maschine also.

z.B.
- Farbkanal X mit Helligkeit ... einschalten.
- Farbkanal X ausschalten.
- MilliSekunden warten bis zum nächsten Programmschritt
- Goto/Reset-Befehl für Programmcounter (PC)

etc.

von Karl H. (kbuchegg)


Lesenswert?

Hmm.
Wenn ich so revü passieren lasse, dann denke ich, du solltest erst mal 
dein normales Blinkprogramm so anpassen, dass da nicht eine Abfolge von 
Port-Operationen mit zwischengestreuten _delay_ms steht, sondern du dir 
überlegst, wie du die Abfolge der LED erst mal durch ein Array 
ausdrücken kannst. Ich schätze dann wird dir vieles klarer.
Der Schritt zu dem, was dir vorschwebt, dürfte für dich noch viel zu 
groß sein.
1
// in jedem Sequence Element steckt die Information, welche LED leuchten
2
// soll. zb durch die Bits.
3
//  Bit 0    rote LED einschalten
4
//  Bit 1    grüne LED einschalten
5
//  Bit 2    blaue LED einschalten
6
//  Bit 3    gelbe LED einschalten
7
8
#define KEINE  0x00
9
#define ROT    0x01
10
#define GRUEN  0x02
11
#define BLAU   0x04
12
#define GELB   0x08
13
14
uint8_t Sequence[] =
15
{
16
  ROT,
17
  GELB,
18
  GRUEN,
19
  BLAU,
20
  KEINE,
21
  ROT | GELB,
22
  GRUEN | BLAU,
23
  KEINE
24
  GRUEN,
25
  KEINE,
26
  BLAU
27
];
28
29
uint8_t lenSequence = sizeof( Sequence ) / sizeof( *Sequence );
30
uint8_t nextNr;
31
uint8_t command;
32
33
int main()
34
{
35
  LED Portpins auf Ausgang stellen
36
37
38
  nextNr = 0;
39
40
  while( 1 )
41
  {
42
    command = Sequence[nextNr];
43
    nextNr++;
44
    if( nextNr == lenSequence )
45
      nextNr = 0;
46
47
    alle LED ausschalten
48
49
    if( command & ROT )
50
      Rote LED einschalten
51
52
    if( command & GRUEN )
53
      Gruene LED einschalten
54
55
    if( command & BLAU )
56
      blaue LED einschalten
57
58
    if( command & GELB )
59
      gelbe LED einschalten
60
61
    _delay_ms( 100 );
62
  }
63
}

Die Abfolge der LED ist NICHT im Programmcode selber, sondern im Array 
Sequence abgelegt. Das Programm arbeitet datengesteuert. Durch Verändern 
der Werte im Array kannst du das Leuchtmuster verändern.
(Und die Details für die LED An-/Abschaltung musst du selbst ins 
Programm einsetzen)

So könnte zb dein erstes Zwischenziel aussehen.
Dein nächstes Ziel könnte es zb sein, die Werte in Sequence per UART zu 
übertragen bzw. zu verändern.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Wie sehen denn deine ersten Ausflüge in die C-programmierung und dein 
Projekt aus ?

von Nino K. (lnino)


Lesenswert?

Danke für deine Rückmeldung Karl Heinz.

Nun bin ich aber vollends verwirrt. :-) Ich steh echt total auf der 
Leitung.

Könntest du mir eventuell deinen Code erklären bzw. kommentieren?
Spitze wären noch ein bis zwei Schleifendurchläufe, damit ich verstehe 
welche Werte ich in jedem Durchlauf bekomme.

Ich versuche zu erklären wie ich deinen Code interprätiere. Ist aber 
sicher falsch sonst würde ich nicht fragen. Aber dann weißt du wo das 
Problem liegt.


Habe ich das Array richtig verstanden?

Nehmen wir an im Array stehen nur 4 Inhalte folgendes:
1
uint8_t Sequence[] =
2
{
3
  ROT,
4
  GELB,
5
  GRUEN,
6
  BLAU,
7
}
Gehe ich nun richtig in der Annahme, dass durch das #define der Farben 
zu Beginn
1
#define KEINE  0x00
2
#define ROT    0x01
3
#define GRUEN  0x02
4
#define BLAU   0x04
5
#define GELB   0x08
nun folgendes im Array steht: 1,8,2,4 ?
1
command = Sequence[nextNr];           // nextNr beginnt bei 0
2
    nextNr++;
Nun steht beim ersten Durchlauf -> command = Sequence[1] also GELB, bzw. 
8
Beim zweiten Durchlauf -> command = Sequence[2] also GRUEN, bzw. 2
Beim dritten Durchlauf -> command = Sequence[3] also BLAU, bzw. 4


Die If Bedingung "if( command & ROT )" verstehe ich nicht recht.
1. Warum vergleiche ich generell command mit Rot?
2. Die Syntax mit dem einzelnen & ist mit nicht geläufig:
     Ich kenne es nur mit if( command == 1 && ROT == 1)
3. Welche Werte werden hier verglichen?


Eigentlich könnte ich ja eine Funktion schreiben welche die 4 LEDs 
leuchten lässt und diese im Code aufrufen.
1
void test()
2
{
3
  PORTB |= (1<<PB2); 
4
  // ...
5
}


======

Kann ich mit UART direkt das string Array im Code verändern?
Ich dachte per UART kann Daten im EEPROM lesen und schreiben, aber nicht 
direkt im Quelltext.

von Fabian O. (xfr)


Lesenswert?

Die Zustände der LEDs sind bitweise kodiert.
1
#define ROT    0x01 = 0b00000001
2
#define GRUEN  0x02 = 0b00000010
3
#define BLAU   0x04 = 0b00000100
4
#define GELB   0x08 = 0b00001000

Das hat den Vorteil, dass Du per bitweisem Oder in einem Zustand auch 
mehrere LEDs gleichzeitig leuchten lassen kannst:
1
ROT | GELB = 0x01 | 0x08 = 0b00000001 | 0b00001000 = 0b00001001

Der Vergleich
1
if (command & ROT)
ist eine kürzere Schreibweise für:
1
if ((command & ROT) != 0)

Der &-Operator ist ein logisches Und. Wenn also command = ROT | GELB = 
0b00001001 ist, steht da:
1
if ((0b00001001 & 0b00000001) != 0)

0b00001001 & 0b00000001 ergibt 0b00000001. Das ist ungleich Null und 
damit wird die LED eingeschaltet. Die Bedingung prüft also, ob das Bit 
für die rote LED gesetzt ist.

von Fabian O. (xfr)


Lesenswert?

El Nino schrieb:
> Kann ich mit UART direkt das string Array im Code verändern?
> Ich dachte per UART kann Daten im EEPROM lesen und schreiben, aber nicht
> direkt im Quelltext.

Nein, natürlich nicht. Im Quelltext stehen nur die initialen Werte, die 
in den Speicher geladen werden sollen, wenn das Programm startet (also 
wenn Du den Mikrocontroller mit Strom versorgst). Den Inhalt des 
Speichers kannst Du ändern, während das Programm läuft. Zum Beispiel, 
wenn per UART Daten empfangen werden:
1
uint8_t c = uart_getc();
2
...
3
Sequence[x] = c;

Damit hast Du die den Ablauf der LEDs verändert.

Wenn das Array Sequence im SRAM ist, wird es bei jedem Start des 
Mikrocontrollers wieder mit den Werten initialisiert, die im Quelltext 
stehen. Wenn die Werte erhalten bleiben sollen, wenn der Mikrocontroller 
keinen Strom mehr hat, musst das Array statt im SRAM im EEPROM liegen. 
Dann bleiben die Werte, die Du zuletzt per UART empfangen und im EEPROM 
gespeichert hast beim nächsten Start bestehen. Was als Initialisierung 
im Quelltext stand spielt dann keine Rolle mehr.

von Nino K. (lnino)


Lesenswert?

Ich habe nun den Code in meinen ATmega168 übertragen, aber irgendwie 
scheine ich da noch was falsch zu haben. Es leuchtet keine LED. Alles 
dunkel.
1
// test.c
2
3
#define F_CPU 14745600
4
5
#define KEINE  0x00
6
#define ROT    0x01
7
#define GRUEN  0x02
8
#define BLAU   0x04
9
#define GELB   0x08
10
11
#include <avr/io.h>
12
#include <inttypes.h>
13
#include <util/delay.h>
14
#include <string.h>
15
16
17
// PIN DEFINITIONS:
18
19
// ### Other LEDs ###
20
// ------------------
21
// PC1 -- LED Green
22
// PC2 -- LED Yellow
23
// PC3 -- LED Blue
24
// PC4 -- LED Red
25
26
27
uint8_t Sequence[] =
28
{
29
  ROT,
30
  GELB,
31
  GRUEN,
32
  BLAU,
33
  KEINE,
34
  ROT | GELB,
35
  GRUEN | BLAU,
36
  KEINE,
37
  GRUEN,
38
  KEINE,
39
  BLAU
40
};
41
42
uint8_t lenSequence = sizeof( Sequence ) / sizeof( *Sequence );
43
uint8_t nextNr;
44
uint8_t command;
45
46
47
48
int main(void) {
49
50
  DDRC  = 0b00011110; // Pinc.1,2,3,4 as Output, the Rest as Input
51
  
52
  nextNr = 0;
53
  
54
  while(1) {
55
56
    
57
    command = Sequence[nextNr];
58
    nextNr++;
59
    
60
  if( nextNr == lenSequence )
61
  {
62
    nextNr = 0;
63
64
    PORTC &= ~(1<<PC1);
65
    PORTC &= ~(1<<PC2);
66
    PORTC &= ~(1<<PC3);
67
    PORTC &= ~(1<<PC4);
68
  }
69
  
70
    if( command & ROT )
71
  {
72
      PORTC |= (1<<PC4);        // Turn On Red LED
73
  }
74
75
    if( command & GRUEN )
76
  {
77
      PORTC |= (1<<PC1);        // Turn On Green LED  
78
  }
79
    
80
  if( command & BLAU )
81
  {
82
      PORTC |= (1<<PC3);        // Turn On Blue LED  
83
  }
84
    
85
  if( command & GELB )
86
  {
87
      PORTC |= (1<<PC2);        // Turn On Yellow LED  
88
  }
89
    
90
  _delay_ms( 100 );
91
  
92
  }
93
  return 0;
94
}

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Erster Fehler


....

  if( nextNr == lenSequence )
  {
    nextNr = 0;

    PORTC &= ~(1<<PC1);
    PORTC &= ~(1<<PC2);
    PORTC &= ~(1<<PC3);
    PORTC &= ~(1<<PC4);
  }

....


da deine Folgenden IF's nur einschalten dürfte nach wenigen durchläufen 
alles an sein und nichts wirklich interessantes mehr passieren.

schreibs doch so:


  if( nextNr == lenSequence )
  {
    nextNr = 0;
  }

  PORTC &= ~(1<<PC1);
  PORTC &= ~(1<<PC2);
  PORTC &= ~(1<<PC3);
  PORTC &= ~(1<<PC4);

Alle LED's aus, als Anfangsbedingung jedes Schrittes.

von Nino K. (lnino)


Lesenswert?

Dennis Heynlein schrieb:
> schreibs doch so:
>
>
>   if( nextNr == lenSequence )
>   {
>     nextNr = 0;
>   }
>
>   PORTC &= ~(1<<PC1);
>   PORTC &= ~(1<<PC2);
>   PORTC &= ~(1<<PC3);
>   PORTC &= ~(1<<PC4);

Danke nun rühren sich die LEDs. :-)

Nun müsste doch die Abfolge vom Quellcode ausgegeben werden, oder?
1
uint8_t Sequence[] =
2
{
3
  ROT,
4
  GELB,
5
  GRUEN,
6
  BLAU,
7
  KEINE,
8
  ROT | GELB,
9
  GRUEN | BLAU,
10
  KEINE,
11
  GRUEN,
12
  KEINE,
13
  BLAU
14
};

Aber bei mir wird folgendes ca. 18 Mal ausgegeben und anschließend eine 
andere Folge. ??

ROT (Eine LED leuchtet)
ROT GRUEN (2 LEDs leuchten)
ROT GRUEN BLAU (3 LEDs leuchten)
ROT GRUEN BLAU GELB (4 LEDs leuchten)

Ist das so korrekt?

Und wie bekomme ich nun das Sequence Array in den EEPROM?
Muss ich nun eine Applikation beispielsweise in C# schreiben um mittels 
UART diesen zu beschreiben? Falls ja, hat hier jemand ein Codebeispiel?

Danke für die tolle Unterstützung.

von Joerg W. (joergwolfram)


Angehängte Dateien:

Lesenswert?

Um nochmal auf die Ausgangsfrage zurückzukommen, möglich ist es schon 
aber meiner Meinung nach alles andere als trivial. Als Anhang mal ein 
Screenshot von meinem aktuellen Projekt (allerdings für Linux und in C), 
mit dem das Erstellen von solchen (Ablauf-)Programmen sozusagen zum 
"Kinderspiel" wird.
Mit der Schaltfläche "Schreiben" wird ein Hexfile bestehend aus einem 
Interpreter und dem dazugehörigen Datenblock erzeugt und mittels 
anpassbarem Script automatisch in den Controller programmiert.

Jörg

von Karl H. (kbuchegg)


Lesenswert?

Joerg Wolfram schrieb:

> Mit der Schaltfläche "Schreiben" wird ein Hexfile bestehend aus einem
> Interpreter und dem dazugehörigen Datenblock erzeugt und mittels
> anpassbarem Script automatisch in den Controller programmiert.

Fang jetzt bitte keine 2.te Baustelle an.

Er soll jetzt erst mal grundlegend Programmieren lernen.
Danach 1 Byte per UART übertragen (SEnder ist zb hTerm)
Danach mehrere Bytes.
Dann ein Protokoll mit welchem er eine Bytesequenz ins SRAM übertragen 
kann.
Dann meinetwegen erst mal ein PC-Programm mit einer GUI, das ihm erlaubt 
die Steuersequenz zusammenzustellen.
Dann das ganze ins EEPROM und beim Programmstart aus dem EEPROM holen.

Alleine damit dürfte er gut und gerne ein halbes Jahr beschäftigt sein.

von Karl H. (kbuchegg)


Lesenswert?

Nino K. schrieb:

> Aber bei mir wird folgendes ca. 18 Mal ausgegeben und anschließend eine
> andere Folge. ??
>
> ROT (Eine LED leuchtet)
> ROT GRUEN (2 LEDs leuchten)
> ROT GRUEN BLAU (3 LEDs leuchten)
> ROT GRUEN BLAU GELB (4 LEDs leuchten)
>
> Ist das so korrekt?

Nein. Ist nicht korrekt. Sieh dir die Abfolge im Array an. Die ist 
komplett anders.

> Und wie bekomme ich nun das Sequence Array in den EEPROM?

Eines nach dem anderen.
Das Schlechteste was du jetzt tun kannst, ist weitere Baustellen 
aufzumachen. Bring erst mal das was du hast zum Laufen.

Fang halt erst mal mit einer einfacheren Sequenz an.
1
uint8_t Sequence[] =
2
{
3
  ROT
4
};
klappt die?
Wenn nein, warum nicht?

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Haste mal nen Schaltplan ?
Nicht das es bei dir Invers läuft.

Pin(Out) ---|<|--- [VCC]
Pin(Out) ---|<|--- [GND]
Pin(Out) ---|>|--- [VCC]
Pin(Out) ---|>|--- [GND]

sind so die ersten Möglichkeiten.

von Nino K. (lnino)


Lesenswert?

Habe mich nun ausführlich mit meinem Programm beschäftigt deswegen komme 
ich erst jetzt zum Schreiben. Habe mir ein Display an den ATmega168 
rangehängt um ein paar Werte zu kontrollieren, da ich keinen JTAG zum 
debuggen habe. Damit konnte ich schon mal etwas Fehlersuchen.

Ich habe nun das Programm zum Laufen bekommen. Aber nur teilweise.
Vielleicht kann mir jemand helfen, das gewollte umzusetzen.

Ich musste das Array in die Main Funktion holen, sonst leuchten einfach 
alle LEDs permanent. Wenn ich im Array noch einen Wert hinzufüge, dann 
leuchten wieder alle LEDs permanent. Mit 4 Werten im Array läuft die 
eingestellte Blinkfolge ROT,GELB,GRUEN,BLAU wie gewünscht in einer 
Endlosschleife. Aber ein größeres Array geht nicht. 
(z.b.:ROT,GELB,GRUEN,BLAU,GELB)

Hier der Code welcher mit einem 4er Array super funktioniert:
1
#define KEINE  0x00
2
#define ROT    0x01
3
#define GRUEN  0x02
4
#define BLAU   0x04
5
#define GELB   0x08
6
7
#define F_CPU 14745600
8
9
#include <stdio.h>
10
#include <math.h>
11
12
#include <avr/io.h>
13
#include <avr/interrupt.h>
14
#include <avr/pgmspace.h>
15
#include <inttypes.h>
16
#include <util/delay.h>
17
18
19
// PIN DEFINITIONS:
20
21
// ### Other LEDs ###
22
// ------------------
23
// PC1 -- LED Green
24
// PC2 -- LED Yellow
25
// PC3 -- LED Blue
26
// PC4 -- LED Red
27
28
// Global Variables
29
30
uint8_t nextNr;
31
uint8_t command;
32
33
34
int main(void) {
35
36
  // start up the LCD
37
  lcd_init();
38
  lcd_home();
39
40
  DDRC  = 0b00011110; // Pinc.1,2,3,4 as Output, the Rest as Input
41
  
42
  uint8_t Sequence[] =
43
  {
44
    ROT,
45
    GELB,
46
    GRUEN,
47
    BLAU,
48
  };
49
50
  uint8_t lenSequence = sizeof( Sequence ) / sizeof( *Sequence );
51
  
52
53
  while(1) {
54
  
55
    command = Sequence[nextNr];
56
    nextNr++;
57
    
58
    if( nextNr == lenSequence )
59
    {
60
    nextNr = 0;
61
    }
62
63
    PORTC &= ~(1<<PC1);
64
    PORTC &= ~(1<<PC2);
65
    PORTC &= ~(1<<PC3);
66
    PORTC &= ~(1<<PC4);
67
    
68
    if( command & ROT )
69
    {
70
      PORTC |= (1<<PC4);        // Turn On Red LED
71
    }
72
73
    if( command & GRUEN )
74
    {
75
      PORTC |= (1<<PC1);        // Turn On Green LED  
76
    }
77
    
78
    if( command & BLAU )
79
    {
80
      PORTC |= (1<<PC3);        // Turn On Blue LED  
81
    }
82
    
83
    if( command & GELB )
84
    {
85
      PORTC |= (1<<PC2);        // Turn On Yellow LED  
86
    }
87
      
88
    _delay_ms( 500 );
89
  }
90
  
91
  return 0;
92
}

Habe ich da noch einen Fehler?

von Fabian O. (xfr)


Lesenswert?

Das Array gehört nicht in die main-Funktion. Wenn es nur so geht, hast 
Du ein tiefergehendes Problem. Probier mal folgendes (außerhalb der 
main):
1
static uint8_t nextNr;
2
static uint8_t command;
3
4
static uint8_t Sequence[] =
5
{
6
  ROT,
7
  GELB,
8
  GRUEN,
9
  BLAU,
10
};
11
12
#define LEN_SEQUENCE (sizeof(Sequence) / sizeof(*Sequence))

Lass außerdem alle Includes weg, die Du nicht brauchst: math.h, 
interrupt.h und pgmspace.h werden im Code nicht gebraucht. Dafür fehlt 
vermutlich eine lcd.h oder ähnliches. Am besten lässt Du die 
LCD-Routinen erstmal weg.

Dein F_CPU sieht auch nicht ganz koscher aus. Da muss die tatsächliche 
Taktfrequenz des Mikrocontrollers stehen.

Und schalte die Compilerwarnungen an (-Wall) bzw. beachte sie!

von Fabian O. (xfr)


Lesenswert?

Wenn alle LEDs am gleichen Port hängen lässt sich das Programm übrigens 
noch deutlich verkürzen:
1
#define F_CPU 14745600
2
3
#include <stdint.h>
4
#include <avr/io.h>
5
#include <util/delay.h>
6
7
#define LED_KEINE  0x00
8
#define LED_GRUEN  (1<<PC1)
9
#define LED_GELB   (1<<PC2)
10
#define LED_BLAU   (1<<PC3)
11
#define LED_ROT    (1<<PC4)
12
#define LED_MASK   (LED_ROT | LED_GRUEN | LED_BLAU | LED_GELB)
13
14
static uint8_t Sequence[] = {
15
  LED_ROT,
16
  LED_GELB,
17
  LED_GRUEN,
18
  LED_BLAU,
19
};
20
#define LEN_SEQUENCE (sizeof(Sequence) / sizeof(*Sequence))
21
22
int main(void)
23
{
24
  uint8_t nextNr = 0;
25
  
26
  DDRC = LED_MASK;
27
  
28
  while (1) {
29
    nextNr++;
30
    if (nextNr == LEN_SEQUENCE) {
31
      nextNr = 0;
32
    }
33
  
34
    PORTC = (PORTC & (~LED_MASK)) | Sequence[nextNr];
35
    _delay_ms(500);
36
  }
37
}

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.