Forum: Compiler & IDEs Programmierbare Relaiskarte - Konfigurationsdaten Lesen/Speichern/Übertragen


von Daniel S. (cyber)


Lesenswert?

Hallo,

ich sitze gerade an einem Projekt und steht vor dem Problem meine 
Konfiguration zu verwalten.

Bei dem Projekt handelt es sich um eine programmierbare Relaiskarte für 
meine Wohnzimmerwand.
Ich möchte mich hier ansich nicht über die Relaiskarte unterhalten 
sondern nur über die Software.


Es sind derzeit 8 Ausgänge die über eine Fernbedienung angesteuert 
werden. Hier sollen die Tasten aber programmiert werden ähnlich der 
Harmony von Logitech.

So kann ich also definieren wenn ich die Taste 1(DVD schauen) drücke das 
dann die ersten 3 Ausgänge geschaltet werden.

TV -> AN
AV -> AN
DVD -> AN

Der Rest der Ports soll entweder abgeschaltet oder unberücksichtigt 
bleiben.

Die Schaltung steht soweit, empfangen der IR-Signale und die UART 
(Senden/Empfangen) ebenfalls.

Das System wird am Computer angeschlossen. Nun kann ich eine neue Taste 
definieren. Drücke ich diese wird sie auf dem PC empfangen in Form von:
1
R:<Protokoll>:<Adresse>:<Command>;

Die Taste bekommt einen Namen geben wie oben geschrieben "DVD schauen" 
Dieser Name steht derzeit nur innerhalb der Konfiguration zur Verfügung. 
Später evtl. auch auf einem Display.

Jetzt kann ich noch definieren welchen Zustand die 8 Ausgänge einnehmen 
sollten:
1
0=OFF/1=ON/-=unberücksichtigt

Die Taste ist jetzt in der Konfigurationssoftware definiert und soll auf 
den Controller übertragen werden. Derzeit übertrage ich sie so:
1
C:<Name>:<Protokoll>:<Adresse>:<Command>:11100-00;

Die Zeilen haben immer eine Feste Länge.

Bis hier funktioniert es auch schon. Nun soll natürlich die 
Konfiguration auch irgendwie im Controller abgelegt werden. da würde 
sich ja nun der EEPROM anbieten. Aufgebaut ist es mit einem Mega8 also 
stehen mir 512Byte zur Verfügung. Eine Tastenzeile hat 40 Zeichen 
512/40=12 Somit könnte ich 12 Tasten speichern. Das ist mir eigentlich 
schon viel zu wenig. Denn Jeden Ausgang einzeln würde ja bedeuten das 
ich schon 8 von 12 belegt hätte und somit nur noch 4 für Kombinationen 
zur Verfügung hätte.


1. Die Frage ist erst einmal nach einer Möglichkeit genug Informationen 
speichern zu können. Ich könnte zwar die ":" weg lassen, da ich eine 
feste Länge habe aber das bringt mich ja auch nicht wirklich viel 
weiter.
Wäre es sinnvoll einen kleinen EEPROM anzusteuern mit mehr Speicher oder 
lieber eine Kleine SD-Karte? Eventuell ein ganz anderer Ansatz?
Dazu kommt das die Datenspeicherung natürlich kosten technisch nicht den 
Rest des Projektes übertreffen soll. Schaltung liegt derzeit bei rund 4€ 
ohne Relais.

2. So lange bin ich noch nicht bei den Mikrocontrollern, habe also noch 
ein wenig nachzuholen gerade in der Sprache C. Bin im Bereich 
Pascal/Delphi eher tätig.
Es wäre dann noch zu klären wie man es am ehesten umsetzt die Daten zur 
Laufzeit zu lesen. Ansatz aus meiner Erfahrung: Ich habe eine definierte 
Länge somit müsste ich den "Speicher" nach der Zeichenkette 
"<Protokoll>:<Adresse>:<Command>" durchsuchen und wenn diese passt die 
Zeile laden und die Ports setzen. Diese stehen ja auch immer an einer 
bestimmten Stelle vom Offset entfernt. Ich könnte es natürlich auch 
alles direkt im Programm definieren aber da geht mir echt die 
Flexibilität flöten die ich gerne hätte.
Mal eine Andere Konfiguration schnell ändern, die Fernbedienung 
austauschen, andere Tasten nutzen, es kommt ein Gerät hinzu, ein Gerät 
wird entfernt. Klar kommt das meiste eher selten vor aber es kann ja 
schon einmal vorkommen. Auch wenn für so etwas fürs Wohnzimmer mit 8 
Ports schon eine Menge ist, wäre es ja auch nicht auszuschließen das 
ganze über Schieberegister zu erweitern. Kleine Gimmicks mit 
irgendwelchen Lampen fürs Ambiente z.B. Oder ganz banal eine 
Urlaubssteuerung. Ich kenne heute noch Leute die irgendwelche 
Gerätschaften per Zeitsteuerung Schalten um den Schein zu erwecken als 
wären sie noch da…

Natürlich muss ich auch zugeben das ich mich eventuell ein wenig damit 
übernehme aber da muss ich nun durch :) Hoffe hier auch tatkräftige 
Unterstützung und Nachsicht wenn ich etwas nicht gleich kapiere oder es 
durch Delphi oder aber auch den PC anders gewohnt bin es umzusetzen.


Das Auslesen der gesamten Konfiguration wollte sich in einem Block 
setzen:
1
PC->µC: READ_CONF;
2
µC->PC: BEGIN_CONF;
3
        C:DVD Schauen:02:1234:0001:11100-00;
4
        C:TV         :02:1234:0002:10000-00;
5
        C:AV         :02:1234:0003:01000-00;
6
        C:Konsole    :02:1234:0002:00100-00;
7
        END_CONF;
Es soll zudem noch ein wenig Speicher über bleiben um eventuell später 
eine Uhr mit einzubauen, Sleep Timer, Display und nen WakeUp also 
Zeitgesteuert Ports schalten und USB…
Das ist aber nicht primär. Ggf. kommt dann noch ein größerer Controller 
ran. Erst sollte aber das Minimum funktionieren.


Kann mir jemand helfen hier eine akzeptable Lösung zu finden und hat 
evtl. auch noch etwas Nachsicht mit meinen C-Kenntnissen?

Gruß
Daniel

von Karl H. (kbuchegg)


Lesenswert?

> Wäre es sinnvoll einen kleinen EEPROM anzusteuern mit mehr Speicher
> oder lieber eine Kleine SD-Karte? Eventuell ein ganz anderer Ansatz?

Vielleicht hab ich das ja auch missverstanden. Aber du musst ja nicht 
deine Konfiguration im Klartext, so wie du sie vom PC bekommst 
speichern. Weder im EEPROM noch im Arbeitsspeicher, mit der der Mega 
dann im Endeffekt die Tasten auswertet.

Du hast 8 Ausgänge. Da bieten sich schon mal die 8 Bits eines Bytes als 
'Speicher' für jeweils einen Relais-Zustand an.

Genauso wie das hier
1
C:<Name>:<Protokoll>:<Adresse>:<Command>:11100-00;
Bis auf den Namen, reicht es doch, wenn der Mega aus der 
Tasteninformation eine Zahl von 0 bis n macht, mit dieser Zahl dann in 
ein Array geht und sich aus dem Array 2 Bytes rausholt, in denen 
bitmässig codiert ist, welches Relais zu setzen bzw. rückzusetzen sind 
und dann genau diese Ausgänge schaltet.

So ganz klar ist mir nicht, was da jetzt das Problem ist. Aber mir 
scheint du speicherst dir viel zu viele nutzlose Information auf dem 
Mega in Klartext-Form.

von Daniel (Gast)


Lesenswert?

Guten morgen,

naja bei den Ausgängen habe ich ja 3 Zustände OFF/ON/Status beibehalten.

Beispiel: Ich möchte DVD schauen und drücke die Taste 1. Ich habe vorher 
aber das Licht angeschaltet welches auf Port 5 und 6 liegt. Diese darf 
ich also nicht berühren. Wenn das Licht an ist, soll es an bleiben und 
wenn es ausgeschaltet ist dann soll es auch ausgeschaltet bleiben.

Ich glaube es ist ein Verständnisproblem.

Wenn ich die IR Daten im original Speicher werden 5 Bytes genutzt 
anstatt 10 aber selbst das bringt mich ja auch nicht so weit das ich n 
Möglichkeiten speichern kann.

Zudem wollte ich nicht den ganzen kram hin und her Konvertieren. Mag 
sein das ich da vielleicht noch defiziete habe weil ich mich um so etwas 
nie kümmern musste.

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:
> Guten morgen,
>
> naja bei den Ausgängen habe ich ja 3 Zustände OFF/ON/Status beibehalten.

Deswegen ja auch 2 Bytes.
ON_Byte: In dem Byte besagt ein 1 Bit, dass das zugehörige Relais auf 
ein zu schalten ist.
OFF_Byte: Im diesem Byte besagt ein 1 Bit, dass das zugehörige Relais 
auf aus zu schalten ist.

Ein 0 Bit in beiden Bytes besagt: lass dieses Relais in Ruhe.


Wenn du die 8 Relais an einem Port beisammen hast, dann geht das 
schalten aller 8 Relais in einem Aufwasch dann ganz einfach
1
   Relaisport = ( Relaisport | ON_Byte ) & ( ~ OFF_Byte );

fertig. Alle 8 Relais werden laut Vorgabe im ON_Byte bzw. OFF_Byte 
geschaltet.
Ist im ON_Byte ein 1 Bit wird der AUsgang auf 1 geschaltet. Ist im 
OFF_Byte ein 1 Bit, wird das Relais ausgeschaltet. Ist in beiden ein 0 
Bit dann verändert dieser eine Ausgang seinen Zustand nicht.

Wie du das ganze über die UART überträgst, ist damit ja nicht gesagt. 
Lass ruhig die Textübertragung. Dagagen hab ich sicher nichts 
einzuwenden. Aber speichern musst du das ganze nicht als Text, wenn du 
mit 2 Bytes dieselbe Information genausogut speichern kannst. Dann muss 
eben der Empfangscode, der das ganze dann im EEPOM speichert den Text 
auswerten und die beiden Bytes zurechtbasteln.
Darum gehts mir. Ich hatte in deinem Eröffnungsposting den Eindruck, 
dass dir dieser letzte Punkt nicht so recht klar ist.


> Zudem wollte ich nicht den ganzen kram hin und her Konvertieren
Ähm. Du musst diesen Text aber so und so irgendwann mal auswerten. Ob du 
den Text jetzt beim Drücken einer Taste auseinanderklamüserst um zu 
sehen, welches Relais wie zu schalten ist, oder ob du den prinzipiell 
identischen Code nach dem Erhalt des Konfigurationstextes über die UART 
laufen lässt und das Ergebnis davon in einer Form abspeicherst, so dass 
sie
a) weniger Platz braucht
b) beim Tastendruck dann trivial auszuwerten ist
ist doch gehupft wie gesprungen. Den Text analysieren bleibt dir so und 
so nicht erspart. Der einzige Unterschied besteht darin, wann genau 
diese Analyse stattfindet: Nachdem der Konfigurationsstring übertragen 
wurde ODER nachdem ein Tastendruck festgestellt wurde.

Und seien wir uns mal ehrlich. So kompliziert ist die Analyse eines 
Strings "11100-00" dann auch wieder nicht
1
void ConvertToOnOffByte( const char* str, uint8_t* InfoOn, uint8_t* InfoOff )
2
{
3
  uint8_t i;
4
5
  *InfoOn = 0;
6
  *InfoOff = 0;
7
8
  for( i = 0; i < 8; i++ )
9
  {
10
    if( *str == '1' )
11
      *InfoOn|= 0x01;
12
    else if( *str == '0' )
13
      *InfoOff |= 0x01;
14
15
    *InfoOn <<= 1;
16
    *InfoOff <<= 1;
17
    str++;
18
  }
19
}

Fertig. Das schreibt sich schneller als es sich textuell erklärt.

Für die Speicherung der Information zu einer Taste noch ein schönes 
struct gebaut
1
#define MAX_KEY_NAME_LEN 20
2
3
struct keyInfo_
4
{
5
  char    name[MAX_KEY_NAME_LEN];
6
  uint8_t keyCode;
7
  uint8_t infoOn;
8
  uint8_t infoOff;
9
};

daraus dann ein Array für alle Tasten, ein entsprechender Code, der aus 
den Informationen von der Fernsteuerung einen Tastencode errechnet und 
die ganze Sache ist soweit abgesteckt, dass man es erfolgversprechend 
zum laufen kriegt.

pro Taste 23 Byte, macht bei 512 Byte 22 Tasten. Wenn das zu wenig ist, 
dann bleibt nur noch die Namenslänge abzuspecken. Kommt man anstelle von 
19 Zeichen auch mit 9 Zeichen für den Namen aus, dann sind es schon 39 
Tasten, die ins 512-Byte EEPROM passen. Und das ist dann ja doch schon 
eine Menge Holz auf einer Fernbedienung. Wenn man es ein wenig geschickt 
anstellt, kann man den keyCode auch noch einsparen, indem man direkt aus 
den Informationen, die man von der Fernbedienung kriegt, einen 
Arrayindex errechnet, und wir sind bei 42 Tasten maximal.

von Daniel (Gast)


Lesenswert?

Jetzt hat es in meinem Hirn scheinbar auch klick gemacht.

Wenn ich das Obige Beispiel aufgreife, nur zum Verständnis:
11100-00 würde ON_Byte = E0 und OFF_Byte = 1B werden, so ist das doch 
gemeint oder?

Das würde bedeuten ich hätte pro Datensatz 6Byte gespart. Wenn ich nun 
vom IRMP das Protokoll(1Byte), Adresse(2Byte) und Command(2Byte) nutze 
habe ich wirklich einiges gespart. Also 7Byte für IR+Ports und dann ein 
paar für den Namen.
Wenn ich für den Namen dann 17 Zeichen lasse komme ich auf 21 
Datensätze.
Sind schon einmal 9 mehr aber irgendwie noch zu wenig. Wenn ich die 8 
Ports einzeln schalte bleiben noch 13. Eine Taste für Alles aus, bin ich 
bei 12.

Mein Kopf sagt mir das sollte bei weitem ausreichen. Mein Herz möchte 
gerne mehr, gerade wenn für Erweiterungen noch Platz sein soll, z.B. 
weitere 8 Ports für ein Licht Spiel... Ist aber denke ich erst einmal 
Nebensache.

Ich brauche also nun eine Funktion die mit aus den 8 Zeichen jeweils das 
On und das OFF-Byte erzeugt. Zudem eine weitere Funktion die Zeichen in 
uint8_t und uint16_t wandelt. Natürlich noch eine die mir einen 
Substring aus dem String herausholt.

Ich merke schon die Defizite wenn man es nur gewohnt ist auf einem PC zu 
programmieren. Das fällt einem wesentlich leichter, zumal C nicht gerade 
zu meinem Sprachgebrauch gehört. Hätte damals was anständiges lernen 
sollen ;)

Korrigiert mich wenn ich hier falsch denke, ist alles Neuland für mich.
Bleibt noch die Frage wie ich das am besten im EEPROM suche.
Eine Taste wird gedrückt. Es wird mit das Protokoll, Adresse und Command 
übergeben.
Protokoll ist 02; Adresse BF40; Command 0002.
Nun gehe ich an die erste Adresse + 17Bytes im EEPROM und prüfe die 
ersten 5Bytes. Passen diese lese ich die nachfolgenden 2Bytes aus zum 
setzen der Ports. Sollte das nicht passen gehe ich weitere 24Bytes 
weiter und Prüfe wieder 5Bytes bis ich etwas passendes gefunden habe 
oder ins leere laufe.
Ich habe gelesen das der Zugriff auf den EEPROM relativ langsam ist und 
eine Suche innerhalb auch nicht gerade das beste sein soll. Ist das 
überhaupt dann performant so vorzugehen?

Mein erstes Projekt war ein Belichtungstimer. der ist dagegen ja echt 
ein Kinderspiel...

von Daniel (Gast)


Lesenswert?

Da war ich wohl zu langsam und es beantwortet sich schon etwas.

Das mit dem KeyCode der Fernbedienung ist mir allerdings noch nicht so 
ganz klar. Ich nutze das IRMP. Protokoll könnte ich wohl raus lassen. 
Bisher haben alle meine Fernbedienungen das NEC Protokoll aber auf die 
Adresse würde ich schon gerne mit achten. Ich habe jetzt die Länge siehe 
oben vom Namen etwas kürzer aber dafür Protokoll, Adresse und Command 
mit drin.

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:
> Jetzt hat es in meinem Hirn scheinbar auch klick gemacht.
>
> Wenn ich das Obige Beispiel aufgreife, nur zum Verständnis:
> 11100-00 würde ON_Byte = E0 und OFF_Byte = 1B werden, so ist das doch
> gemeint oder?

Mal sehen. In 11100-00 ist codiert

On    11100000
Off   00011011

Also: 0xE0 bzw. 1B.  Jep. Stimmt.


> Das würde bedeuten ich hätte pro Datensatz 6Byte gespart. Wenn ich nun
> vom IRMP das Protokoll(1Byte),

Brauchst du das wirklich?
Wenn die Fernsteuerung erst mal steht, ändert sich diese Information ja 
nicht.
Eine Fernsteuerung sendet immer mit einem Protokoll. Und zwar immer mit 
derselben.
Eine Phillips Fernsteuerung benutz ein anderes Protokoll als eine von 
Samsung. Und die wieder ein anderes Protokoll als eine Fernsteuerung von 
NEC. Aber derselbe Klotz, den du in der Hand hältst benutzt immer das 
gleiche Protokoll.

> Adresse(2Byte) und Command(2Byte) nutze

Ach da würde ich mir mal ansehen, in welchem Zahlenbereich sich da die 
Werte bei deiner konkreten Fernbedienung bewegen. Da geht sicher was. 2 
Byte pro Teilbereich sind viel Holz. Adresse ist normalerweise das 
'Gerät'. Hast du wirklich 65535 unterschiedliche Geräte? Oder sind es 
konzeptionell dann doch eher maximal 4 (also 2 Bit anstelle von 2 Byte). 
Hast du wirklich 65536 unterschiedliche Kommandos oder bewegt sich diese 
Zahl dann doch eher im Zahlenraum 0 bis 127? Oder gar 0 bis 63, was 
vorteilhaft wäre, dann das wären dann nur 6 Bit. Zusammen mit den 2 BIt 
von der Geräteadresse macht das wieder 8 Bit und das wäre dann perfekt 
um in einem einzelnen uint8_t zusammengefasst zu werden. Konzeptionell 
maximal 4 Geräte mit jeweils 64 unterschiedlichen Kommandos - das sollte 
auch den verwöhntesten Ansprüchen der nächsten Jahre mehr als genügen. 
Zur Not muss man eben die einzelnen Bits eindeutig machen. Das kann man 
aber erst sagen, wenn man sich mal angesehen hat, was deine 
Fernbedienung eigentlich wirklich konkret liefert, wenn man eine Taste 
(jede Taste) mal drückt und sich ansieht, was da daher kommt.


> Mein Kopf sagt mir das sollte bei weitem ausreichen. Mein Herz möchte
> gerne mehr, gerade wenn für Erweiterungen noch Platz sein soll, z.B.
> weitere 8 Ports für ein Licht Spiel... Ist aber denke ich erst einmal
> Nebensache.

Es gibt ja immer noch Tastenkombinationen.
Denk an die alten Taschenrechner. Da gibt es eben eine Taste, die in die 
zweite Bedieneben schaltet. Aus der Tastenfunktion x^2 wird so mal ganz 
schnell sqrt(x). Und aus sin(x) wird dann sin-1(x), aus exp(x) wird ein 
ln(x), einfach indem man vorher die Taste INV drückt (oder wie auch 
immer die auf deinem Taschenrechner heißt). Spricht ja nichts dagegen, 
dass du eine Taste 'Lichtprogramm' hast, die du drückst, dann noch eine 
Zahlentaste 0 bis 9 hinterher und du hast aus 10 Lichtprogrammen eines 
ausgewählt, obwohl die Tasten 0 bis 9 eigentlich eine ganz andere 
Bedeutung haben (zb Einzelrelaisansteuerung)


Du denkst mir da zu eindimensional. Sieh dich in deiner Umgebung um. Man 
kann viel lernen, indem man beobachtet, wie andere Dinge machen. Und 
plötzlich geht einem dann oft sogar ein Licht auf, WARUM die das genau 
so gemacht haben.

von Karl H. (kbuchegg)


Lesenswert?

> Nun gehe ich an die erste Adresse + 17Bytes im EEPROM
> und prüfe die ersten 5Bytes. Passen diese lese ich die
> nachfolgenden 2Bytes aus zum setzen der Ports. Sollte das
> nicht passen gehe ich weitere 24Bytes weiter und Prüfe wieder
> 5Bytes bis ich etwas passendes gefunden habe oder ins leere laufe.

Machs doch nicht so komplizert.
Was interessieren dich da Bytezahlen?

Wenn ein Benutzer eine Taste drückt, reicht es, wenn die Schaltung ein 
paar Hunderstel Sekunden später reagiert. Du hast alle Zeit der Welt. 
Für einen Menschen ist das immer noch praktisch 'sofort'.

> Bleibt noch die Frage wie ich das am besten im EEPROM suche

Indem du dir einen Datensatz nach dem anderen ins SRAM holst (daher auch 
der struct) und dann vergleichst
1
uint8_t keyInfoSize EEMEM = 0;
2
struct  keyInfo_ eemem_KeyDesc[22] EEMEM;
3
4
5
uint8_t nrKeysInEEPROM;   // wieviele sind befüllt? (Wird bei Programmstart aus dem EEPROM geholt)
6
7
8
uint8_t searchKey( uint8_t code, struct keyInfo_* pFound )
9
{
10
  struct keyInfo_ keyDesc;
11
12
   for( uint8_t i = 0; i < nrKeysInEEPROM; i++ )
13
   {
14
     eeprom_read_block( &keyDesc, &eemem_KeyDesc[i], sizeof( keyDesc ) );
15
     if( keyDesc.keyCode == code )
16
     {
17
       *pFound = keyDesc;
18
       return TRUE;
19
     }
20
   }
21
22
   return FALSE;
23
}

von Daniel (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Du denkst mir da zu eindimensional. Sieh dich in deiner Umgebung um. Man
> kann viel lernen, indem man beobachtet, wie andere Dinge machen. Und
> plötzlich geht einem dann oft sogar ein Licht auf, WARUM die das genau
> so gemacht haben.

Das stimmt leider...

Zum Speichern der IR-Daten. Natürlich habe ich nicht so viele Commandos 
und auch nicht so viele Geräte. Ich habe aber daheim eine RGB LED Kette. 
Diese reagiert z.B. auf die Fernbedienung von sich selbst, auf die 
meines Verstärkers und die meines Receivers. Sie wird also sicher nur 
das Commando auswerten. Ich müsste also nun im Source Protokoll und 
Gerät festlegen. Oder aber auch im EEPROM damit ich mal die 
Fernbedienung tauschen kann. Das ist mir wichtig. Es werden hier 2 
Schaltungen gebaut. Eine für einen Kollegen und eine für mich. Ich würde 
him nun ungerne vorschreiben was er für eine Fernbedienung zu nutzen 
hat.

Dann wäre ich dafür damit ich da relativ flexibel bin diese Daten im 
EEPROM ebenfalls abzulegen. Einmal das Protokoll und das Gerät. Diese 
aber eben separat und nicht mit im Struct der IR-Codes. Damit habe ich 
da zumindest die Freiheit auch mal die Fernbedienung zu ändern.

Bin gerade auf der Arbeit und kann natürlich nicht nachsehen was diese 
Fernbedienung so alles aufgibt. es ist von meinem TV, die ich derzeit 
angeschlossen habe. Da soll natürlich mal eine eigene hin.

Der Ansatz mit der Doppelbelegung ist nicht schlecht aber dann muss ich 
natürlich hier am Source so abändern dass dann neben Den Ports auch eine 
Art Shift Funktion zur Verfügung steht. Die Fernbedienung die ich nutzen 
möchte später hat ca. 40 Tasten und ist von meinem alten AMP. Da brauch 
man nicht unbedingt eine Shift Funktion. Tasten wären zu genüge 
vorhanden.

Wäre allerdings noch das Auslesen auf dem EEPROM.

von Karl H. (kbuchegg)


Lesenswert?

> Ich habe gelesen das der Zugriff auf den EEPROM relativ langsam ist

Langsam ist relativ.
Für einen µC ist es langsam. Für einen Menschen ist es immer noch 
schnell.
Denn aus Sicht eines µC sind wir 
schnarch-langsame-super-zeitlupen-Säcke.

Und wenn es dann tatsächlich zu langsam ist, dann gibt es auch dann noch 
Mittel und Wege :-)
Zb mit einem Index im Speicher. zb. durch aufsteigendes Sortieren und 
binäre Suche. Zb durch Hashing. zb durch ....

Aber erst mal: implementier es so, dass es leicht zu lesen und zu 
verstehen ist. Und DANN siehst du dir an, ob es zu langsam im Gebrauch 
ist. Optimier nicht, solange nicht feststeht, dass du überhaupt 
optimieren musst. Erst mal ist es viel wichtiger ein korrektes Programm 
zu haben. Ein korrektes Programm welches zu langsam ist, ist immer noch 
nützlich. Ein schnelles Programm, welches nicht korrekt funktioniert ist 
hingegen zu gar nichts zu gebrauchen.

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:

> Wäre allerdings noch das Auslesen auf dem EEPROM.

Siehe den Post unmittelbar vor deinem :-)

von Daniel (Gast)


Lesenswert?

Du bist ja verdammt schnell, da komm ich mit den Fragestellungen ja gar 
nicht mehr nach und meist sind die dann schon beantwortet. :)

Die Hilfe ist mal echt klasse auch wenn ich mir dabei gerade sehr klein 
vorkomme.

Kann den Feierabend ja schon nicht mehr abwarten. :)

Werde das bis zum Feierabend auf mich wirken lassen und dann versuch ich 
es so umzusetzen.

Ich bedanke mich schon einmal vorab für die große Hilfe die du geleistet 
hast und auch die Geduld.

Klasse Forum :)

von Daniel (Gast)


Lesenswert?

Hab mir mal schnell in C das ganze kopiert und getestet.
In der Convert Funktion ist ein kleiner Fehler drin. Nachdem die 8 Ports 
gelesen sind wird erneut eine Bit Verschiebung gemacht wodurch das erste 
Bit weg fällt.
1
void ConvertToOnOffByte( const char* str, unsigned char* InfoOn, unsigned char* InfoOff )
2
{
3
  int i;
4
5
  *InfoOn = 0;
6
  *InfoOff = 0;
7
8
  for( i = 0; i < 8; i++ )
9
  {
10
    if( *str == '1' )
11
      *InfoOn |= 0x01;
12
    else if( *str == '0' )
13
      *InfoOff |= 0x01;
14
15
    if (i < 7)
16
    {
17
      *InfoOn <<= 1;
18
      *InfoOff <<= 1;
19
      str++;
20
    }
21
  }
22
}

Ist mit C darum kein uint8_t

Wo ich aber nun hänge ist es die Zeichenkette zu zerlegen. Ich tue mich 
verdammt schwer damit :(

Jetzt hat es geklappt nachdem ich die Terminierung weg gelassen habe am 
Anfang. Ich dachte ich könnte die Zeichenkette auf "" setzen
1
void ReadName(const char* str, char* strname)
2
{
3
  int i;
4
  //strname[0] = '\0';
5
  
6
  for (i = 2; i < 21; i++)
7
  {
8
    strname[i-2] = str[i];  
9
  }
10
  strname[i-2] = '\0';
11
}

Eine SubStr Funktion gibts ja so nicht. Ich müsste mir eine bauen. Bevor 
ich mich aber an so etwas setze, auch wenn sicher nur eine kleinigkeit 
ist, gehts auch schöner?

Jetzt kommt der Punkt an dem ich das Struct füllen muss... Graus...

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:
> Hab mir mal schnell in C das ganze kopiert und getestet.
> In der Convert Funktion ist ein kleiner Fehler drin. Nachdem die 8 Ports
> gelesen sind wird erneut eine Bit Verschiebung gemacht wodurch das erste
> Bit weg fällt.

Schreib es dem Umstand zu, dass ich direkt hier drinnen 'programmiere' 
:-)

Aber wenn schon, dann bitte so.
1
void ConvertToOnOffByte( const char* str, unsigned char* InfoOn, unsigned char* InfoOff )
2
{
3
  int i;
4
5
  *InfoOn = 0;
6
  *InfoOff = 0;
7
8
  for( i = 0; i < 8; i++ )
9
  {
10
    *InfoOn <<= 1;
11
    *InfoOff <<= 1;
12
13
    if( *str == '1' )
14
      *InfoOn |= 0x01;
15
    else if( *str == '0' )
16
      *InfoOff |= 0x01;
17
18
    str++;
19
  }
20
}


Da muss man jetzt keinen 'Sonderfall' draus konstruieren :-)

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:

> Eine SubStr Funktion gibts ja so nicht.

Na ja. Kann man schon machen.
Aber typischerweise 'zerlegt' man einen String nicht dadurch, dass man 
Teilstrings durch die Gegend kopiert, sondern indem man sich Pointer 
mitten in den String hinein merkt. Bei dir geht das sogar ganz 
wunderbar, weil dein Original da diese ':' als Trenner hat, die man 
durch \0 ersetzen kann und dann entsprechende Teilstrings hat.
Und das beste am ganzen :-) : genau da schlägt dann die Stunde von 
strtok()

von Daniel (Gast)


Lesenswert?

Tut mir leid, ich bin immer ein Sonderfall ;)
Habs aber begriffen.

War der Befehl nun ein Wink mit dem Zaunpfahl? :)

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:
> Tut mir leid, ich bin immer ein Sonderfall ;)
> Habs aber begriffen.
>
> War der Befehl nun ein Wink mit dem Zaunpfahl? :)

Der Zaunpfahl-Balken ist eigentlich:
Du solltest in Betracht ziehen erst mal ordentlich C zu lernen, ehe du 
dich an reale Projekte wagst. Das hat doch keinen Sinn, wenn du von den 
Möglichkeiten deiner Programmiersprache gerade mal 10% beherrscht.


:-)

Aber natürlich hab ich den Zaunpfahl auch ausgearbeitet :-)
Brauch halt auch ein wenig Zeit dafür.

> Aber typischerweise 'zerlegt' man einen String nicht dadurch, dass
> man Teilstrings durch die Gegend kopiert, sondern indem man sich
>  Pointer mitten in den String hinein merkt. Bei dir geht das sogar
> ganz wunderbar, weil dein Original da diese ':' als Trenner hat,
> die man durch \0 ersetzen kann und dann entsprechende Teilstrings
> hat.
> Und das beste am ganzen :-) : genau da schlägt dann die Stunde
> von strtok()


(ohne Fehlerbehandlung)
1
  char Answer[80] = "C:<Name>:<Protokoll>:<Adresse>:<Command>:11100-00;"
2
3
  char * Drive;
4
  char * Name;
5
  char * Protocoll;
6
  char * Address;
7
  char * Command;
8
  char * Bits;
9
10
11
  Drive     = strtok( Answer, ":" );
12
  Name      = strtok( NULL, ":" );
13
  Protocoll = strtok( NULL, ":" );
14
  Address   = strtok( NULL, ":" );
15
  Command   = strtok( NULL, ":" );
16
  Bits      = strtok( NULL, ";" );

das baut dir dann das hier auf
1
  Answer
2
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
3
  |C|0|<|N|a|m|e|>|0|<|P|r|o|t|o|k|o|l|l|>|0|<|A|d|r|e|s|s|e|>|0|<|...
4
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
5
   ^   ^               ^                     ^                   ^
6
   |   |               |                     |                   |
7
   |   |               |                     |                   |
8
 Drive |            Protocoll            Address              Command
9
      Name

(wobei die 0 in der Zeichnung als die C-String Nullterminierung \0 zu 
lesen ist)

jeder Pointer zeigt auf den Beginn eines 0-terminierten Strings.

Nichts wird stringmässig umkopiert. Lediglich ein paar ':' sind gegen 
'\0' ausgetauscht worden (und natürlich auch der ; zum Schluss, was in 
der Zeichnung nicht sichtbar ist).
Alles perfekt um die Funktion
1
     ConvertToOnOffByte( Bits, &On, &Off );
damit aufrufen zu können, bzw. den Namen in eine STruktur kopieren zu 
können
1
    ....
2
3
   struct keyInfo_ nextInfo;
4
5
 ...
6
   Drive     = strtok( Answer, ":" );
7
   Name      = strtok( NULL, ":" );
8
   Protocoll = strtok( NULL, ":" );
9
   Address   = strtok( NULL, ":" );
10
   Command   = strtok( NULL, ":" );
11
   Bits      = strtok( NULL, ";" );
12
 ...
13
14
   strcpy( nextInfo.name, Name );
15
   ConvertToOnOffByte( Bits, &nextInfo.infoOn, &nextInfo.infoOff );
16
  ...

von Daniel (Gast)


Lesenswert?

Verdammt so schnell kann ich mir die Funktion ja schon fast nicht mehr 
selber anschauen.

Wollte aber sagen, mein Beispiel funktioniert auch, auch wenn es nicht 
so spektakulär ist.
1
 char MyData[35] = "C:Name der Taste    1:0001:11100-00;";
2
  char * pch;
3
  pch = strtok (MyData,":");
4
  while (pch != NULL)
5
  {
6
    printf ("%s\n",pch);
7
    pch = strtok (NULL, ":");
8
  }
Verdammt so schnell kann ich mir die Funktion ja schon fast nicht mehr 
selber anschauen.

Wollte aber sagen, mein Beispiel funktioniert auch, auch wenn es nicht 
so spektakulär ist

von Karl H. (kbuchegg)


Lesenswert?

> Ist mit C darum kein uint8_t


Doch!

Du willst da einen uint8_t haben!
Brauchst doch nur stdint.h inkludieren und du hast diese Datentypen.

Und wenn nicht (weil dein Compiler zu alt ist), dann machst du dir eben 
welche
1
typedef unsigned char uint8_t;

von Daniel (Gast)


Lesenswert?

Cool danke. Habs nun drin.

Schade das mein Urlaub gerade vorbei ist.

von Daniel S. (cyber)


Lesenswert?

Dann will ich mal ein wenig meines Fortschritts zeigen.

Hab es mit dem EEPROM noch nicht drin, musste mich erst einmal richtig 
in den Source denken.
Die Zeile die ich mittels UART zum setzen der Konfiguration übergebe 
habe ich so angepasst das diese ins struct gesetzt wird und dann die 
Ports setzt. Das klappt auch wunderbar.

Hier wird das Struct, Protokoll und Adresse zugewiesen
1
void BuildStruct(char* Line, struct keyInfo_* pFound, uint8_t* Prt, uint16_t* Adr)
2
{
3
  struct keyInfo_ keyDesc;
4
  char * Comm;
5
  char * Name;
6
  char * Protocoll;
7
  char * Address;
8
  char * Command;
9
  char * Bits;
10
  uint8_t iProtocoll;
11
  uint16_t iAddress;
12
  uint16_t iCommand;
13
14
  Comm       = strtok( Line, ":" );
15
  Name       = strtok( NULL, ":" );
16
  Protocoll  = strtok( NULL, ":" );
17
  iProtocoll = strtol(Protocoll, NULL, 16);
18
  Address    = strtok( NULL, ":" );
19
  iAddress   = strtol(Address, NULL, 16);
20
  Command    = strtok( NULL, ":" );
21
  iCommand   = strtol(Command, NULL, 16);
22
  Bits       = strtok( NULL, ";" );
23
24
  strcpy(keyDesc.name, Name);
25
  memcpy(&keyDesc.keyCode, &iCommand, sizeof(uint16_t));
26
  ConvertToOnOffByte( Bits, &keyDesc.infoOn, &keyDesc.infoOff );
27
28
  *pFound = keyDesc;
29
  *Protocoll = iProtocoll;
30
  *Adr = iAddress;
31
}

Hier meine UART Empfangroutine:
1
  if (uart_data_received())
2
    {
3
  temp = uart_getc();
4
      
5
  if (temp == ';' || StringLen > 45) 
6
  {
7
    Line[StringLen] = '\0';
8
    uart_puts(Line);
9
    uart_puts("\r\n");
10
11
    if (Line[0] == 'P')
12
    {
13
       uart_puts("Received Dataset\n\r");
14
15
       char buf[5];
16
       uint8_t iProtocoll;
17
       uint16_t iAddress;
18
       struct keyInfo_ nextInfo;
19
       BuildStruct(Line, &nextInfo, &iProtocoll, &iAddress);
20
  
21
       uart_puts("Name: ");
22
       uart_puts(nextInfo.name);
23
       uart_puts("\r\n");
24
       uart_puts("Protokoll: ");
25
       itoa (iProtocoll, buf, 16);  
26
       uart_puts(buf);
27
       uart_puts("\r\n");
28
       uart_puts("Adresse: ");
29
       itoa (iAddress, buf, 16);
30
       uart_puts(buf);
31
       uart_puts("\r\n");
32
       uart_puts("Command: ");
33
       itoa (nextInfo.keyCode, buf, 16);
34
       uart_puts(buf);
35
       uart_puts("\r\n");
36
37
       OUT_PORT = ( OUT_PORT | nextInfo.infoOn ) & ( ~ nextInfo.infoOff );
38
    }
39
40
    StringLen = 0;
41
    Line[0] = '\0';
42
    uart_puts("CLEAR");
43
    uart_puts("\r\n");
44
45
  }
46
47
  if (temp != ';')
48
  {
49
    Line[StringLen] = (unsigned char)temp;
50
    StringLen++;
51
  }
52
}

Damit habe ich das Stuct, Protokoll und die Adresse.
Das setzen der Ausgänge funktioniert ebenfalls wenn ich die Line ändere.

Muss jetzt noch an dem Übertragungsprotokoll arbeiten um die ersten drei 
Bytes zu setzen im EEPROM für Protokoll und Gerät und dann das Auslesen 
und Speichern der Daten. Ein weiteres Byte für die Anzahl der 
Datensätze.

Ich danke dir für die Hilfe, bin Stolz das es mit deiner Hilfe bis hier 
hin so gut klappt. Ist spät und ich muss so langsam ins Bett, leider...


Ja mit C habe ich echt meine Probleme. Vieles von der Stringverarbeitung 
übernimmt die Pascal IDE bereits für mich. Wenn man allerdings sucht 
aber nicht die passenden Suchwörter findet läuft man leider leicht ins 
leere. Als nächstes steht ein vernünftiges C Buch auf meiner Liste.
Freue mich allerdings das mir dennoch so gut geholfen wird.

von Karl H. (kbuchegg)


Lesenswert?

Den Umweg über eine locale struct Variable kannst du dir sparen und den 
memcpy will ich jetzt erst mal nicht gesehen haben :-)

1
void BuildStruct(char* Line, struct keyInfo_* pFound, uint8_t* Prt, uint16_t* Adr)
2
{
3
  char * Comm;
4
  char * Name;
5
  char * Protocoll;
6
  char * Address;
7
  char * Command;
8
  char * Bits;
9
  uint8_t iProtocoll;
10
  uint16_t iAddress;
11
  uint16_t iCommand;
12
13
  Comm       = strtok( Line, ":" );
14
  Name       = strtok( NULL, ":" );
15
  Protocoll  = strtok( NULL, ":" );
16
  Address    = strtok( NULL, ":" );
17
  Command    = strtok( NULL, ":" );
18
  Bits       = strtok( NULL, ";" );
19
20
  *Prt       = strtol( Protocoll, NULL, 16 );
21
  *Adr       = strtol( Address, NULL, 16 );
22
23
  iCommand   = strtol( Command, NULL, 16 );
24
25
  strcpy( pFound->name, Name);
26
  pFound->keyCode = iCommand;
27
  ConvertToOnOffByte( Bits, &pFound->infoOn, &pFound->infoOff );
28
}

Die Pointer Variablen könnte man allesamt wegoptimieren, wenn man auf 
Fehlerbehandlung verzichtet, was bei einem maschinell erzeugtem String 
durchaus drinnen ist.
1
void BuildStruct(char* Line, struct keyInfo_* pFound, uint8_t* Prt, uint16_t* Adr)
2
{
3
  strtok( Line, ":" );
4
  strcpy( pFound->name, strtok( NULL, ":" ) );
5
  *Prt            = strtol( strtok( NULL, ":" ), NULL, 16 );
6
  *Adr            = strtol( strtok( NULL, ":" ), NULL, 16 );
7
  pFound->keyCode = strtol( strtok( NULL, ":" ), NULL, 16 );
8
  ConvertToOnOffByte( strtok( NULL, ";" ), &pFound->infoOn, &pFound->infoOff );
9
}

wird schon.


1
  if (temp == ';' || StringLen > 45)

wie ist Line definiert?
Ich hoffe mal für dich als
1
  char Line[47];
und nicht als Array der Länge 46 oder kleiner. Denn sonst greift deine 
Sicherheitsabfrage ins Leere um hier
1
    Line[StringLen] = '\0';
schlimmeres zu verhindern.

Solche magischen Zahlen mitten im Code sind schlecht. Entweder man macht 
sich ein entsprechendes #define mit einer konstanten Zahl dafür, oder 
man arbeitet gleich mit sizeof. Dann sucht sich der Compiler selbst die 
Größe des Arrays raus.
1
#define ARRAY_LEN(x) (sizeof(x) / sizeof(*x))

1
  if (temp == ';' || StringLen > ARRAY_LEN - 2 )
2
  {
3
    ...

von Daniel (Gast)


Lesenswert?

Guten morgen,

Warum müssen es 47 sein? Ich dachte die Terminierung ist nur ein 
Zeichen. 45 Zeichen + '\0' sollten dann doch 46 sein?
1
 Line[StringLen] = '\0';
Hier ist StringLen = 46.
Mit der Konstanten geb ich dir allerdings recht. Bisher ist das eben 
alles noch ein Versuchs Source. Wie gesagt ist eigentlich erst mein 
zweites Projekt abgesehen von LEDs blinken zu lassen und auf Tasten zu 
reagieren sowie ein paar Timer.
Als ich das Projekt angefangen habe, hatte ich die Ausmaße noch nicht im 
Kopf. Jetzt wird mir schon klar das es etwas umfangreicher ist. Anfangs 
sollten auch keine Keys über die Software programmiert werden.

von Daniel (Gast)


Lesenswert?

OK.. Ja verstanden... Mein Fehler Es sind 47

von Daniel S. (cyber)


Lesenswert?

Mir scheint mit dem EEPROM stehe ich echt auf Kriegsfuß...

Ich darf mir sicher gleich wieder etwas anhören aber da muss ich dann 
wohl durch...

Warum erwartet eeprom_write_byte als Adresse ein uint8_t aber 
eeprom_write_word ein uint16_t?
Block nen Void....

Ich kann ein Byte, Word und Stuct speichern/lesen aber schlau werde ich 
da nicht wirklich draus.
1
        if (strcmp(Line, "READ") == 0)
2
        {
3
          eeprom_read_block((void*)StringOfData, (const void*)12, 10);
4
          uart_puts("Line: ");
5
          uart_puts(Line);
6
          uart_puts("\r\n");
7
          uart_puts("READ from EEPROM: ");
8
          uart_puts(StringOfData);
9
          uart_puts("\r\n");
10
        }
11
12
        if (strcmp(Line, "WRITE") == 0)
13
        {
14
          char StringOfData[10] = "Test\0";
15
          eeprom_write_block((const void*)StringOfData, (void*)12, 10);
16
          uart_puts("Line: ");
17
          uart_puts(Line);
18
          uart_puts("\r\n");
19
          uart_puts("WRITE to EEPROM: ");
20
          uart_puts(StringOfData);
21
          uart_puts("\r\n");
22
        }
23
24
25
        if (strcmp(Line, "R") == 0)
26
        {
27
          uint8_t MyByte;
28
          char buf[10];
29
          MyByte = eeprom_read_byte((uint8_t*)0);
30
          //eeprom_read_block((void*)StringOfData, (const void*)12, 10);
31
          uart_puts("Line: ");
32
          uart_puts(Line);
33
          uart_puts("\r\n");
34
          uart_puts("READ from EEPROM: ");
35
          //uart_puts(StringOfData);
36
          sprintf(buf, "%x", MyByte);
37
          uart_puts(buf);
38
          uart_puts("\r\n");
39
        }
40
41
        if (strcmp(Line, "W") == 0)
42
        {
43
          uint8_t MyByte;
44
          char buf[10];
45
          //char StringOfData[10] = "Test\0";
46
          //eeprom_write_block((const void*)StringOfData, (void*)12, 10);
47
          MyByte = 0xEE;
48
          eeprom_write_byte((uint8_t*)0, MyByte);
49
          uart_puts("Line: ");
50
          uart_puts(Line);
51
          uart_puts("\r\n");
52
          uart_puts("WRITE to EEPROM: ");
53
          //uart_puts(StringOfData);
54
          sprintf(buf, "%x", MyByte);
55
          uart_puts(buf);
56
          uart_puts("\r\n");
57
        }

Bitte nicht auf das strcmp achten, das ist nur zum testen. In meinem C 
Programm habe ich das schon abgeändert. Dort hole ich mir den ersten 
Teilstring mit Hilfe vom Index des ':' und kopiere dann mit strncpy den 
Bereich heraus, damit ich nicht einen falschen Befehl interpretiere.

Im Programm soll es ja bisher so aussehen an der ersten Adresse steht 
das genutzte Protokoll gefolgt vom Gerät, danach folgt nrKeysInEEPROM. 
Damit sollten die ersten 5 Bytes beschrieben sein. Ab da also Adresse 4 
folgen dann die Tasten.

Die Adresse wäre dann doch eemem_KeyDesc[i] + mein Offset.
1
struct  keyInfo_ eemem_KeyDesc[22] EEMEM;

Die Zeile verstehe ich so das insgesamt 22 Adressen existieren die einen 
Abstand in der Größe des Structs haben.

Gibt es die Möglichkeit so etwas zu testen direkt in C bzw. ohne den 
EEPROM des Controllers zu belasten?

von Daniel (Gast)


Lesenswert?

Hallo,

bin leider gestern nicht zum Programmieren gekommen aber es steht ja nun 
das Wochenende an, dann gehts weiter.

Habe mir allerdings überlegt das es unsinnig ist den Tasten Namen zu 
geben. Selbst wenn ich irgendwann mal ein Display anschließen sollte 
sehe ich das von der Couch aus eh nicht. Ich gebe also den Ports Namen. 
Diese können dann auch kleiner ausfallen, da ja ein gerät dich eine 
recht kurze Bezeichnung hat.

1 Byte Protokoll
2 Byte Gerät
40-80 Byte pro Port
1 Byte geschriebene Datensätze

Das macht dann 43-83 Byte und habe dann 429 - 469 Byte frei für die 
Konfigurationsdaten.
Ein Datensatz besteht dann nur noch aus 4Byte(2 Byte Adresse und 2 Byte 
für On/Off Byte). Damit habe ich dann nun doch eine verdammt große Menge 
die ich abspeichern könnte.
Da hätte ich auch eher drauf können kommen...

von Daniel S. (cyber)


Lesenswert?

Guten Abend,

mittlerweile funktioniert schon ein wenig mehr.
Lesen / schreiben des IR-Systems
Lesen / schreiben der Portnamen inkl. Prüfung ob sie geschrieben sind
Lesen / schreiben Anzahl der Datensätze
 Auslesen aller Portnamen in einem durchlauf
die Struct wurde um ein Byte vergrößert für zusätzliche Informationen

Nun sitze ich gerade daran die Konfiguration in den EEPROM zu 
übertragen.

Auf Windows Seite existiert bisher ein recht einfaches Programm um die 
Informationen lesen und schreiben zu können.

Hier mal die Prozedur zum auslesen der Portnamen:
1
void CMD_Get_PortNames()
2
{
3
  uint8_t PortNum;
4
  uint16_t PortAddr = 0;
5
  char PortName[MAX_PORTNAME_LEN];
6
  char buf[6];  
7
8
  uart_puts("GET_PORTNAMES:BEGIN;\r\n");
9
  for (PortNum = 1; PortNum <= 8; PortNum++)
10
  {
11
    uart_puts("R:");
12
    itoa(PortNum, buf, 10);
13
    uart_puts(buf);
14
    uart_putc(':');
15
16
    PortAddr = CONF_PORTNAMES_START_ADDR + ((PortNum -1) * MAX_PORTNAME_LEN);
17
    PortName[0] = '\0';
18
    if (eeprom_read_byte((uint8_t*)PortAddr) != 0xFF)
19
    {
20
      eeprom_read_block((void*)PortName, (const void*)PortAddr, MAX_PORTNAME_LEN);
21
    }
22
    uart_puts(PortName);
23
    uart_puts(";\r\n");
24
  }
25
  uart_puts("GET_PORTNAMES:END;\r\n");
26
}

Hier noch ein kleiner Auszug aus meiner RS232 Empfangsroutine:
1
void WorkOnCommand()
2
{
3
  char temp;                                                              // Zeichen vom UART
4
  char Command[MAX_CMD_TOKEN_LEN];                                        // Befehlstoken
5
  uint8_t Index;                                                          // Index um den Befehlstoken zu identifizieren
6
7
  if (uart_data_received())                                                // Prüfen ob ein Zeichen empfangen wurde
8
  {
9
    temp = uart_getc();                                                    // Empfangenes Zeichen lesen
10
11
    if (temp == ';' || StringLen > MAX_COMMAND_LEN -2)                    // Wenn das Zeichen kein "Ende" ist oder die Länge überschreitet dann
12
    {
13
      Line[StringLen] = '\0';                                              // String terminieren 
14
      uart_puts("READ: "); uart_puts(Line); uart_puts("\r\n");            // Ausgabe der Empfangenen Befehlszeile
15
16
      Index = strcspn(Line, ":");                                          // Index des ersten Trenners suchen
17
      strncpy(Command, Line, Index);                                      // Aus der Zeile das Befehlstoken kopieren
18
      Command[Index] = '\0';                                              // string Terminieren
19
20
      if (strcmp(Command, "SET_PORTNAME") == 0)                            // Setzen des Portnamen
21
      {
22
        CMD_Set_PortName(Line);
23
      }
24
25
      if (strcmp(Command, "GET_PORTNAME") == 0)                            // Anzahl der Datensätze lese
26
      {
27
        CMD_Get_PortName(Line);
28
      }
29
30
      if (strcmp(Command, "GET_PORTNAMES") == 0)                          // Auslesen aller Portnamen
31
      {
32
        CMD_Get_PortNames();
33
      }
34
35
      if (strcmp(Command, "GET_CONFIG") == 0)                            // Auslesen der Konfiguration
36
      {
37
        CMD_Get_GetConfig();
38
      }
39
40
      StringLen = 0;
41
      Line[0] = '\0';
42
      uart_puts("\r\n");
43
    }
44
45
    if (temp != ';')
46
    {
47
      Line[StringLen] = (unsigned char)temp;
48
      StringLen++;
49
    }
50
  }
51
}

Natürlich habe ich mir mittlerweile auch 2 Bücher gekauft für C und die 
Programmierung der AVR-RISC Familie mit C.

von Daniel (Gast)


Lesenswert?

Guten morgen,

Gestern liefen die ersten Tests mit dem SOurce auf dem Controller bis 
zum setzen der Ports. Da wurde ich dann auf dem "Es funktioniert" Effekt 
raus gerissen da sich irgend etwas aufgehangen hat am Controller.

Das ist meine Main.
Zuerst werden die Ports 2-7 für 1.5 Sekunden auf On gesetzt und dann 
deaktiviert(ist noch auf dem Anfang). Dann wird die UART inizialisiert. 
Danach das IRMP initialisiert, Die Callback LED und die Routine gesetzt.
Init_IR(); liest aus dem EEPROM das Protokoll und die Geräteadresse der 
Fernbedienung. WorkOnCommand(); fragt die UART Schnittstelle ab.
1
int main (void)
2
{
3
  OUT_DDR |= ((1 << OUT_1) | (1 << OUT_2) | (1 << OUT_3) | (1 << OUT_4) | (1 << OUT_5) | (1 << OUT_6));
4
  OUT_PORT |= ((1 << OUT_1) | (1 << OUT_2) | (1 << OUT_3) | (1 << OUT_4) | (1 << OUT_5) | (1 << OUT_6));
5
  _delay_ms(1500);
6
  OUT_PORT &= ~((1 << OUT_1) | (1 << OUT_2) | (1 << OUT_3) | (1 << OUT_4) | (1 << OUT_5) | (1 << OUT_6));
7
8
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
9
  IRMP_DATA irmp_data;
10
11
  struct keyInfo_ nextInfo;
12
13
  irmp_init();                                                            // initialize irmp
14
  
15
  LED_DDR |= (1 << LED_PIN);                                              // LED pin to output
16
  LED_PORT |= (1 << LED_PIN);                                              // switch LED off (active low)
17
  irmp_set_callback_ptr (led_callback);
18
  
19
  timer1_init();                                                          // initialize timer1
20
  sei ();                                                                 // enable interrupts
21
22
  uart_puts("IR Demo Programm\r\n");
23
24
  Init_IR();
25
26
  for (;;)                                                                // Endlosschleife
27
  {
28
    WorkOnCommand();                                                      // Einlesen und verarbeiten der RS232 Befehle
29
30
    if (irmp_get_data(&irmp_data))
31
    {
32
33
      if (irmp_data.flags & IRMP_FLAG_REPETITION)
34
      {
35
        // Benutzer hält die Taste länger runter entweder:
36
        // ich ignoriere die (Wiederholungs-)Taste oder:
37
        // ich benutze diese Info, um einen Repeat-Effekt zu nutzen
38
      }
39
      else
40
      {
41
        // Es handelt sich um eine neue Taste
42
        if (irmp_data.protocol == IR_Protocol && irmp_data.address == IR_Address)            // Nur Befehle verarbeiten wenn das IR-System stimmt
43
        {
44
          WriteIRDataToUART(irmp_data);
45
46
          if (searchKey(irmp_data.command, &nextInfo) == TRUE)
47
          {
48
            OUT_PORT = ( OUT_PORT | nextInfo.infoOn ) & ( ~ nextInfo.infoOff );
49
            uart_puts("Set Ports done\r\n");
50
          }
51
          else
52
          {
53
            uart_puts("Key not found\r\n");
54
          }
55
        }
56
      }
57
    }
58
  }
59
}
Soweit klappt es auch. Ich kann die Keys in den EEPROM schreiben und 
auch wieder auslesen. Drücke ich nun eine Taste auf der Fernbedienung 
die nicht gespeichert ist meldet er auch 'Key not found'.
Drücke ich die Taste 'Power' die gespeichert ist mit '--000000' meldet 
er auch 'Set Ports done'.
Drücke ich die Taste '1' mit '--000001' so wird der letzte Port gesetzt. 
Wird nun die Taste 'Power' gedrückt geht der Port auch wieder aus.
Drücke ich die Taste 'OK' mit '--110011' so gehen auch die 
entsprechenden Ports an und meldet auch hier wieder 'Set Ports done'. 
Nun fangen die Probleme an. Es werden keine Tasten mehr erkannt.

UART funktioniert noch, ich kann die Konfiguration abrufen und auch 
setzen. die callback für die IR Aktivität verrichtet auch noch ihren 
Dienst. Sie blinkt wenn ich die Fernbedienung betätige. Es wird aber 
eben kein IR Signal mehr ausgegeben. IRMP ist unverändert es ist nur das 
NEC Protokoll aktiv.
Ich muss dazu sagen das es sich hier um den PORT C handelt und da 
natürlich auch UART genutzt wird. Darum sind hier die ersten beiden Bits 
immer mit '-' gesetzt. Da er allerdings meldet 'Set Ports done' sollte 
dort ja nicht das Problem liegen. Die Main läuft ja ebenfalls noch, 
sonst würde UART ja nicht mehr funktionieren.

Wo könnte hier noch das Problem liegen?

Gruß Daniel

von Daniel S. (cyber)


Lesenswert?

Wenn ich folgende Zeile auskommentiere gibt es keine Probleme:
1
OUT_PORT = ( OUT_PORT | nextInfo.infoOn ) & ( ~ nextInfo.infoOff );
Dabei hängt an diesem Port jedoch nicht der IR-Empfänger. UART läuft ja 
weiter und die Ports werden auch gesetzt.
1
#define OUT_PORT  PORTC
2
#define OUT_DDR    DDRC
3
#define OUT_1      PC0
4
#define OUT_2      PC1
5
#define OUT_3      PC2
6
#define OUT_4      PC3
7
#define OUT_5      PC4
8
#define OUT_6      PC5

Zum testen habe ich jetzt einmal eine Routine in die UART Verarbeitung 
eingebaut und setze die Ports direkt mittels UART.
1
void CMD_Set_Ports_Direct(char* Line)
2
{
3
  uint8_t infoOn, infoOff;
4
5
  strtok( Line, ":" );
6
  ConvertToOnOffByte( strtok( NULL, ";" ), &infoOn, &infoOff );
7
8
  OUT_PORT = ( OUT_PORT | infoOn ) & ( ~ infoOff );
9
}
Dann klappt die Zeile ohne Probleme. Nur sobald ich diese wieder in die 
IR Routine einsetze hängts.

Weiß hier jemand Rat?

von Daniel S. (cyber)


Lesenswert?

Ich weiß echt nicht weiter. Egal was ich anstelle es wird nicht mehr auf
1
if (irmp_get_data(&irmp_data))[c]reagiert.
2
3
[code]GET_CONFIG:BEGIN;
4
COUNT:3;
5
L:1:1:10101010:1001----;
6
L:2:2:10101010:10--11--;
7
L:3:3:10101010:000000--;
8
GET_CONFIG:END;[/code]
9
10
So schaut die Konfiguration derzeit aus. Diese liegt auch vollständig im EEPROM. Die letzten beiden Ports sind für UART reserviert, habe ja nur einen Mega8 gerade da.
11
Drücke ist Key1 so werden die Ports gesetzt. Drücke ich Key3 werden alle abgeschaltet. Drücke ich Key2 so werden auch diese gesetzt. Drücke ich wieder Key3 so werden sie auch wieder abgeschaltet. Drücke ich allerdings Key1, Key2, Key3 dann wird Key1 und Key2 ausgeführt. danach ist Ende...
12
13
Setze ich die Ports direkt über die UART so läuft es ohne Probleme. Lasse ich nur das setzen der Ports raus so läuft die IR-Routine ebenfalls ohne Probleme.
14
Die Main wird weiterhin ausgeführt UART funktioniert ja. IRMP ist nur auf NEC gesetzt und der IR Pin ist B0. F_INTERRUPTS ist auf 15000 gesetzt. Der ATMega8 läuft mit 16Mhz.
15
UART ist von Peter Fleury
16
17
[c]
18
void WriteMyPorts(uint8_t infoOn, uint8_t infoOff)
19
{
20
  uint8_t i, a = 7;
21
22
  for( i = 0; i < 8; i++ )
23
  {
24
    if ( (infoOn & (1 << i)) && !(infoOff & (1 << i)) )
25
    {
26
      OUT_PORT |= (1 << a);
27
    }
28
    else if ( !(infoOn & (1 << i)) && (infoOff & (1 << i)) )
29
    {
30
      OUT_PORT &= ~(1 << a);
31
    }
32
    else
33
    {
34
35
    }
36
    a--;
37
  }
38
}
39
40
41
void Init_IR()
42
{        
43
  IR_Protocol = eeprom_read_byte((uint8_t*)CONF_PROTOCOL_ADDR);            // Protokoll aus dem EEPROM lesen
44
  IR_Address = eeprom_read_word((uint16_t*)CONF_ADDRESS_ADDR);            // Adresse aus dem EEPROM lesen
45
}
46
47
uint8_t searchKey( uint8_t code, struct keyInfo_* pfound )
48
{
49
  struct keyInfo_ keyDesc;
50
  uint8_t NumDS = 0, CurrNumDS = 0;
51
  uint16_t Addr;
52
53
  CurrNumDS = eeprom_read_byte((uint8_t*)CONF_NUM_DATASETS);
54
  if (CurrNumDS == 0xFF)
55
  {
56
    CurrNumDS = 0;
57
  }
58
59
  for (NumDS = 1; NumDS <= CurrNumDS; NumDS++)
60
  {
61
    Addr = CONF_DATASETS_START_ADDR + ((NumDS -1) * sizeof(keyDesc));
62
    eeprom_read_block(&keyDesc, (void*)Addr, sizeof(keyDesc));
63
64
    if (keyDesc.keyCode == code)
65
    {
66
      *pfound = keyDesc;
67
      return TRUE;
68
    }
69
  }
70
  return FALSE;
71
}
72
73
74
void Handle_IR_Code(void)
75
{
76
  IRMP_DATA irmp_data;
77
78
  struct keyInfo_ nextInfo;
79
80
81
  if (Mode == NO_KEY)
82
  {
83
    if (irmp_get_data(&irmp_data))
84
    {
85
      Mode = KEY_RECEIVED; uart_puts("SET MODE = KEY_RECEIVED\r\n");
86
87
      if (irmp_data.flags & IRMP_FLAG_REPETITION)
88
      {
89
        // Benutzer hält die Taste länger runter entweder:
90
        // ich ignoriere die (Wiederholungs-)Taste oder:
91
        // ich benutze diese Info, um einen Repeat-Effekt zu nutzen
92
      }
93
      else
94
      {
95
        // Es handelt sich um eine neue Taste
96
        if (irmp_data.protocol == IR_Protocol && irmp_data.address == IR_Address)            // Nur Befehle vedrarbeiten wenn das IR-System stimmt
97
        {
98
          WriteIRDataToUART(irmp_data);
99
100
          if (searchKey(irmp_data.command, &nextInfo) == TRUE)
101
          {
102
            //OUT_PORT = ( OUT_PORT | nextInfo.infoOn ) & ( ~ nextInfo.infoOff );
103
            WriteMyPorts(nextInfo.infoOn, nextInfo.infoOff);
104
            //uart_puts("Set Ports done\r\n");
105
            Mode = NO_KEY; uart_puts("SET MODE = NO_KEY\r\n");
106
          }
107
          else
108
          {
109
            uart_puts("Key not found\r\n");
110
            Mode = NO_KEY; uart_puts("SET MODE = NO_KEY\r\n");
111
          }
112
        }
113
      }
114
    }
115
116
    /*  if (Mode == KEY_RECEIVED)
117
      {
118
        Mode = NO_KEY;
119
        WriteMyPorts(nextInfo.infoOn, nextInfo.infoOff);
120
        uart_puts("Set Ports done\r\n");
121
        memset(&nextInfo, 0, sizeof (nextInfo));
122
      } */
123
  }
124
}
125
126
127
int main (void)
128
{
129
  OUT_DDR |= ((1 << OUT_1) | (1 << OUT_2) | (1 << OUT_3) | (1 << OUT_4) | (1 << OUT_5) | (1 << OUT_6));
130
  OUT_PORT |= ((1 << OUT_1) | (1 << OUT_2) | (1 << OUT_3) | (1 << OUT_4) | (1 << OUT_5) | (1 << OUT_6));
131
  _delay_ms(1500);
132
  OUT_PORT &= ~((1 << OUT_1) | (1 << OUT_2) | (1 << OUT_3) | (1 << OUT_4) | (1 << OUT_5) | (1 << OUT_6));
133
134
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
135
136
137
  irmp_init();                                                            // initialize irmp
138
  
139
  LED_DDR |= (1 << LED_PIN);                                              // LED pin to output
140
  LED_PORT |= (1 << LED_PIN);                                              // switch LED off (active low)
141
  irmp_set_callback_ptr (led_callback);
142
  
143
  timer1_init();                                                          // initialize timer1
144
  sei ();                                                                 // enable interrupts
145
146
  uart_puts("IR Demo Program\r\n");
147
148
  Init_IR(); // Auslesen des IR-Systems aus dem EEPROM
149
150
  for (;;)                                                                // Endlosschleife
151
  {
152
    WorkOnCommand();                                                      // Einlesen und verarbeiten der RS232 Befehle
153
154
    Handle_IR_Code();
155
  }
156
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Daniel S. schrieb:

> Drücke ist Key1 so werden die Ports gesetzt. Drücke ich Key3 werden alle
> abgeschaltet. Drücke ich Key2 so werden auch diese gesetzt. Drücke ich
> wieder Key3 so werden sie auch wieder abgeschaltet. Drücke ich
> allerdings Key1, Key2, Key3 dann wird Key1 und Key2 ausgeführt. danach
> ist Ende...

"Ist Ende" heißt, dass irmp_get_data() niemals mehr TRUE zurückliefert?
Zeigt die Callback-LED weiterhin was an?
1
> void WriteMyPorts(uint8_t infoOn, uint8_t infoOff)
2
> {
3
>   uint8_t i, a = 7;
4
> 
5
>   for( i = 0; i < 8; i++ )
6
>   {
7
>     if ( (infoOn & (1 << i)) && !(infoOff & (1 << i)) )
8
>     {
9
>       OUT_PORT |= (1 << a);
10
>     }
11
>     else if ( !(infoOn & (1 << i)) && (infoOff & (1 << i)) )
12
>     {
13
>       OUT_PORT &= ~(1 << a);
14
>     }
15
>     else
16
>     {
17
> 
18
>     }
19
>     a--;
20
>   }
21
> }

Ein Tipp: Für einen AVR ist das Schieben von Bits über eine variable 
Anzahl ein Riesenaufwand. Aus den Befehlen 1<<i bzw. 1<<a wird richtig 
viel Maschinencode. Besser ist es hier, eine Maske durchzuschieben - 
immer um den konstanten Wert 1. Schau Dir oben mal an, wie das Karl 
Heinz es macht, z.B. in ConvertToOnOffByte().
1
>   for (NumDS = 1; NumDS <= CurrNumDS; NumDS++)
2
>   {
3
>     Addr = CONF_DATASETS_START_ADDR + ((NumDS -1) * sizeof(keyDesc));
4
>     eeprom_read_block(&keyDesc, (void*)Addr, sizeof(keyDesc));
5
> 
6
>     if (keyDesc.keyCode == code)
7
>     {
8
>       *pfound = keyDesc;
9
>       return TRUE;
10
>     }
11
>   }
12
>   return FALSE;
13
> }

NumDS würde ich von 0 bis < CurrNumDS laufen lassen, dann sparst Du den 
Abzug von 1 zwei Zeilen tiefer. Überhaupt solltest Du mehr von 0 und 
nicht von 1 an "denken" beim Programmieren ;-)

Wie ist eigentlich CONF_DATASETS_START_ADDR definiert? Eventuell muss da 
bei der Berechnung von Addr die C-Pointerarithmetik beachtet werden.

Einen Fehler kann ich direkt nicht sehen, aber ich vermute, dass Du 
entweder in einer Endlosschleife landest oder Dir irgendwas im RAM durch 
einen Programmierfehler kaputtschießt. Ich sehe nur nicht auf Anhieb, 
wo.

Aber Moment, was sehe ich denn da:

>   if (Mode == NO_KEY)
>   {
>     if (irmp_get_data(&irmp_data))

Kann es sein, dass Du vergisst, Mode wieder zurückzusetzen auf NO_KEY, 
wenn Du mal einen Frame mit gesetztem IRMP_FLAG_REPETITION Bit 
empfängst?

Wenn Mode auf KEY_RECEIVED bleibt, wird niemals mehr ein IR-Telegramm 
empfangen!

Statt
1
>       if (irmp_data.flags & IRMP_FLAG_REPETITION)
2
>       {
3
>         // Benutzer hält die Taste länger runter entweder:
4
>         // ich ignoriere die (Wiederholungs-)Taste oder:
5
>         // ich benutze diese Info, um einen Repeat-Effekt zu nutzen
6
>       }

solltest Du schreiben:
1
      if (irmp_data.flags & IRMP_FLAG_REPETITION)
2
      {
3
          Mode = NO_KEY; uart_puts("Repetition: SET MODE = NO_KEY\r\n");
4
      }

Das wird Deinen Fehler wohl beheben.

Gruß,

Frank

von Daniel (Gast)


Lesenswert?

Hallo und danke für die Antwort.

Die callback zeigt mir weiterhin an wenn ein IR Signal anliegt.

Die Prozedur WritePorts habe ich mir nur mal eben "schnell" sofern man 
das bei mir schnell nennen kann geschrieben um festzustellen ob es mit 
dem
{c]OUT_PORT = ( OUT_PORT | nextInfo.infoOn ) & ( ~ nextInfo.infoOff 
);[/c] ein Problem gibt. Zudem werden mir hier die Ports vertauscht. Hat 
ein wenig gebraucht bis mir das aufgefallen ist.

Wenn ich diese eben direkt über die UART setze gibt es weder mit 
WritePorts noch mit dem obigen Befehl Probleme.

Das mit dem von 0 anfangen werde ich beherzigen und nachher mal umsetzen 
wenn ich daheim bin.

Das hier ist die Definition:
1
#define CONF_PROTOCOL_ADDR         0                                      // Adresse im EEPROM um das Protokoll abzulegen (1Byte)
2
#define CONF_ADDRESS_ADDR           1                                      // Adresse im EEPROM um die Adresse abzulegen (2Byte)
3
#define CONF_PORTNAMES_START_ADDR   3                                      // Start Adresse für die Port Namen (8x10Byte)
4
#define CONF_NUM_DATASETS          84                                      // Adresse im EEPROM; Anzahl der Geschriebenen Datensätze
5
#define CONF_DATASETS_START_ADDR  85                                      // Startadresse der Tastendatensätze            
6
#define MAX_DATASETS              40                                      // Anzahl der Datensätze die möglich sind
7
#define MAX_COMMAND_LEN            47                                      // Maximale Länge des zu empfangen Befehls über RS232
8
#define MAX_PORTNAME_LEN          12                                      // Länge des Portnamen
9
#define MAX_CMD_TOKEN_LEN          20                                      // Größe des Befehlstoken
10
#define MAX_KEY_NAME_LEN          20                                      // Länge des Namens innerhalb eines IR Datensatzes
11
12
struct keyInfo_                                                            // IR Datensatz
13
{
14
  //char    name[MAX_KEY_NAME_LEN];                                        // Name der Taste
15
  uint16_t keyCode;                                                        // Taste auf der Fernbedienung
16
  uint8_t Options;                                                        // 1Byte für zusätzliche Informationen
17
  uint8_t infoOn;                                                          // On Byte: Hier stehen die On Bits des Ports drin
18
  uint8_t infoOff;                                                        // Off Byte: Hier stehen die Off Bits des Ports drin 
19
};
20
21
uint8_t StringLen = 0;                                                    // Anzahl empfangener Zeichen
22
char Line[MAX_COMMAND_LEN];                                                // die Befehlszeile
23
uint8_t IR_Protocol = 0xFF;                                                // Das verwendete Protokoll;
24
uint16_t IR_Address = 0xFFFF;                                              // Das verwendete Gerät;

Frank M. schrieb:
> Aber Moment, was sehe ich denn da:
>
>>   if (Mode == NO_KEY)
>>   {
>>     if (irmp_get_data(&irmp_data))
>
> Kann es sein, dass Du vergisst, Mode wieder zurückzusetzen auf NO_KEY,
> wenn Du mal einen Frame mit gesetztem IRMP_FLAG_REPETITION Bit
> empfängst?
>
> Wenn Mode auf KEY_RECEIVED bleibt, wird niemals mehr ein IR-Telegramm
> empfangen!

Hier muss ich zugeben das dies erst seit gestern Abend existiert. Ich 
wollte einmal sehen ob die Zeit hier nicht passt vom Ablauf her und die 
Prozedur eben nicht mehr aufgerufen wird solange die Ports nicht gesetzt 
sind. Also Zeittechnisch etwas nicht passt.

Hier hast aber recht, gab grad eine mit dem Brett vor den Kopf. Klar 
wenn IRMP_REPETITION_FLAG gesrtzt ist wird der Mode nicht zurück 
gesetzt. Kann ich aber mittels UART zurück setzen. :) Dies existierte 
vorher nicht und dennoch hing es sich weg. Ich habe die Routine
1
(irmp_get_data(&irmp_data))
 nicht weiter intern verfolgt. Das könnte ich noch prüfen.
Wie gesagt es hängt sich nur weg wenn ich die Ports setze, egal ob mit 
Write Ports oder direkt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Daniel schrieb:

> Hier hast aber recht, gab grad eine mit dem Brett vor den Kopf. Klar
> wenn IRMP_REPETITION_FLAG gesrtzt ist wird der Mode nicht zurück
> gesetzt. Kann ich aber mittels UART zurück setzen. :) Dies existierte
> vorher nicht und dennoch hing es sich weg. Ich habe die Routine
> (irmp_get_data(&irmp_data))nicht weiter intern verfolgt. Das
> könnte ich noch prüfen.

Brauchst Du nicht, ich kenne den IRMP-Source zufällig in- und auswendig 
:-)

Bitte korrigiere den Fehler, teste bitte, ob Du das Fehlverhalten 1:1 
mehrfach hintereinander reproduzieren kannst und dann hänge bitte den 
Source als Anhang an, insbesondere:

   main.c (oder wie immer das Modul heisst)
   irmpconfig.h

Eventuell noch weitere Header-Files, z.B. das, wo 
CONF_DATASETS_START_ADDR definiert ist.

Eine Ausgabe auf dem UART, ob irmp_get_data() überhaupt noch aufgerufen 
wird und was dessen Return-Code ist, wäre auch noch hilfreich.

Ich verstehe auch den Sinn der globalen(?) Variablen Mode nicht. Wo 
brauchst Du die noch außerhalb von Handle_IR_Code()? Wenn nirgendwo, 
kann die komplett weg und der Aufruf von irmp_get_data() kann unbedingt 
erfolgen.

Gruß,

Frank

von Daniel (Gast)


Lesenswert?

Wie gesagt ich hab dies gestern einfach mal eingebaut um zu prüfen was 
sich wie verhällt. diesen Source habe ich auch hier gesetzt. Vorher 
fehlte der Mode. In der Final soll er natürlich nicht mehr vorhanden 
sein.

Werde nachher den Source komplett anhängen. Das Mode nehme ich natürlich 
auch wieder raus.

von Daniel S. (cyber)


Angehängte Dateien:

Lesenswert?

µC ist ein ATMega8 mit 16Mhz. Board ist das Pollin Eval Board. Keine 
Ahnung ob es wichtig sein könnte aber ich erwähne es mal.

Habe Mode und DMode nun wieder vollständig entfernt. Bei den meisten 
Routinen habe ich nun auch 0 bis < als gesetzt. Bei den anderen muss ich 
erst mein Windows Source ändern und werde dann auch die Port Nummern mit 
0 beginnen. Musste natürlich bei der Ausgabe über UART wieder +1 nehmen 
sonst mag mein Windows Programm das nicht mehr.

WriteToPorts ist nun auch wieder draußen. Diese war nur zum testen 
aktiv.

Aktuelle Konfiguration
1
[2013-08-21 20:26:49]-> GET_CONFIG;
2
[2013-08-21 20:26:49]<- READ: GET_CONFIG
3
[2013-08-21 20:26:49]<- GET_CONFIG:BEGIN;
4
[2013-08-21 20:26:49]<- COUNT:3;
5
[2013-08-21 20:26:49]<- L:1:1:10101010:--110-11;
6
[2013-08-21 20:26:49]<- L:2:2:10101010:--1-0000;
7
[2013-08-21 20:26:49]<- L:3:3:10101010:--000000;
8
[2013-08-21 20:26:49]<- GET_CONFIG:END;

L:<DatensatzNr>:<IR-Taste>:<Options>:<Port>;

Die Definition des gesetzten Bit bedeutet '-' = alter Zustand bleibt, 
'0' = off und '1' = on.

Solange ich die Ports nicht setze läuft es alles reibungslos. Bei der 
gesetzten Konfiguration laufen Taste 2 und 3 ohne Probleme. Drücke ich 
aber die Taste 1 dann wird der Port noch gesetzt. Die UART meldet Ports 
sind gesetzt und von da an wird immer FALSE gemeldet.
1
irmp_get_data()
 wird weiterhin aufgerufen liefert aber ein FALSE zurück.
Das Fehlverhalten ist reproduzierbar. Ich versuche es ja schon einige 
male.

Im Anhang alle Dateien des Projekts. Derzeit ist alles in der IR-Demo.c 
enthalten. Das war ursprünglich mal die IR Demo vom IRMP. Bin noch in 
der Lernphase, ist mein zweites Projekt.

von Daniel S. (cyber)


Lesenswert?

Ich muß mich korrigieren habe eben bemerkt das ich die ganze Zeit von 
PortD als Ausgang gesprochen habe, dabei war es PortC. Habe das Programm 
nun auf PortD mal umgestellt aber leider hier auch keine Verbesserung.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Daniel S. schrieb:
> µC ist ein ATMega8 mit 16Mhz. Board ist das Pollin Eval Board.

Sind da irgendwelche Jumper gesetzt, d.h. bestimmte Pins vom ATmega mit 
irgendwelchen Komponenten auf dem Board verbunden?

> Im Anhang alle Dateien des Projekts. Derzeit ist alles in der IR-Demo.c
> enthalten. Das war ursprünglich mal die IR Demo vom IRMP. Bin noch in
> der Lernphase, ist mein zweites Projekt.

Ich kann auf Anhieb keinen Fehler erkennen. Das schließt aber nicht aus, 
dass da einer oder mehrere Fehler sind :-)

Folgende Sachen sind mir aufgefallen:

1. Du hast lange if-Ketten, die sich ungünstig auf die 
Bearbeitungs-Geschwindigkeit auswirken:
1
      if (strcmp(Command, "SET_IR_SYSTEM") == 0)                          // Setzen des IR-Systems in den EEPROM
2
      {
3
        CMD_Set_IR_System(Line);
4
      }
5
6
      if (strcmp(Command, "GET_IR_SYSTEM") == 0)                          // Liest das IR-System fom EEPROM
7
      {
8
        CMD_Get_IR_System();
9
      }
10
11
      if (strcmp(Command, "SET_NUM_DS") == 0)
12
                        ....

Hier wäre es sinnvoll, ab dem 2. if ein else davorzusetzen, also:
1
      if (strcmp(Command, "SET_IR_SYSTEM") == 0)                          // Setzen des IR-Systems in den EEPROM
2
      {
3
        CMD_Set_IR_System(Line);
4
      }
5
6
      else if (strcmp(Command, "GET_IR_SYSTEM") == 0)                          // Liest das IR-System fom EEPROM
7
      {
8
        CMD_Get_IR_System();
9
      }
10
11
      else if (strcmp(Command, "SET_NUM_DS") == 0)
12
                        ....

Grund: Der Prozessor kann mit dem Vergleichen aufhören, sobald eine 
Bedingung zutrifft, da die Bedingungen sich ausschließen.

Dann ist mir das noch aufgefallen:
1
      if (strcmp(Line, "SYS_SYNC") == 0)                                  // Synchronisieren des Datenstroms
2
      {
3
      }

Abgesehen davon, dass diese Zeilen null Effekt haben, muss da nicht auch 
Command statt Line stehen?

Was mir noch auffällt: Du hast sehr viele Stringkonstanten im Source, 
z.B. bei den obigen if-Statements. Diese werden beim Start des 
Prozessors alle ins RAM kopiert. Davon hast Du aber sehr sehr wenig! Was 
sagt denn das AVR-Studio zur Data-Größe am Ende des Compiliervorgangs?

Ich vermute, dass durch diese viele Stringkonstanten Dein Stack sehr 
knapp bemessen ist, dann irgendwann überläuft und das Programm fortan 
nicht mehr korrekt arbeiten kann.

Abhilfe ist sehr einfach:

Ersetze alle Vorkommnisse von

   strcmp (Variable, "abcdefgh")

durch

   strcmp_P (Variable, PSTR("abcdefgh"))

Dann bleiben die Stringkonstanten im Flash. Das Makro PSTR liefert eine 
Adresse aus dem Flash und nicht aus dem RAM zurück, strcmp_P() ist die 
äquivalente Form von strcmp, liest aber dann aus dem Flash.

Du musst dann noch am Anfang ein

#include <avr/pgmspace.h>

einfügen.

Das sollte viele Bytes im RAM einsparen, die Dir wahrscheinlich zur 
Laufzeit fehlen.

Gruß,

Frank

von Daniel (Gast)


Lesenswert?

Guten morgen,

Frank M. schrieb:
> Sind da irgendwelche Jumper gesetzt, d.h. bestimmte Pins vom ATmega mit
> irgendwelchen Komponenten auf dem Board verbunden?
Auf dem Eval Board sind keine Jumper gesetzt außer für UART, der Rest 
ist nicht weiter verbunden. Reset geht direkt auf den ISP und mit Taster 
gegen Masse. Auf dem Addon-Board ebenfalls nichts weiter angeschlossen.

Frank M. schrieb:
> Ich vermute, dass durch diese viele Stringkonstanten Dein Stack sehr
> knapp bemessen ist, dann irgendwann überläuft und das Programm fortan
> nicht mehr korrekt arbeiten kann.
Darüber habe ich mir ehrlich gesagt bisher keine Gedanken gemacht. Werde 
dies nachher mal umsetzen. So umzudenken vom PC auf µC fällt mir nicht 
einfach. Auf dem PC kann man schon mal verschwenderischer mit Ressourcen 
umgehen, hat man ja mehr von.

Auf dem PC hätte ich vermutlich auch If - Else genommen. Warum ich das 
hier nicht gemacht habe kann ich gerade nicht erklären. Werde das 
natürlich auch abändern.
1
if (strcmp(Line, "SYS_SYNC") == 0)
 Hier ist es egal an wo in dem String der Sub-String steht, es soll auf 
jeden Fall dieser Bereich ausgeführt werden.

Frank M. schrieb:
> Davon hast Du aber sehr sehr wenig! Was
> sagt denn das AVR-Studio zur Data-Größe am Ende des Compiliervorgangs?

Meinst du das hier?:
  Task "RunOutputFileVerifyTask"
        Program Memory Usage   :  6244 bytes   76,2 % Full
        Data Memory Usage     :  757 bytes   73,9 % Full
  Done executing task "RunOutputFileVerifyTask".

von Daniel S. (cyber)


Lesenswert?

Hallo,

Habe entsprechende Anpassungen gemacht aber sehr viel hat es nicht 
gebracht.

  Task "RunOutputFileVerifyTask"
        Program Memory Usage   :  6622 bytes   80,8 % Full
        Data Memory Usage     :  675 bytes   65,9 % Full
  Done executing task "RunOutputFileVerifyTask".

Dafür habe ich aber gerade festgestellt das er irgendwann wieder ein 
Signal durlässt. Gerade mehrfach getestet. Ich setze --100001 und direkt 
danach --000000 läuft ohne Probleme. Hier kann ich auch unbegrenzt hin 
und her schalten. Setze ich aber nun auf --111111 dann ist erst einmal 
Ende. Nach knapp über einer Minute reagiert er dann wieder mit einem 
IR-Signal.

Ich habe nun sehr viele Befehle auskommentiert die ich zum testen so 
nicht benötige. Nach dem Kompilieren hat sich der Wert für Data Memory 
Usage aber leider nicht geändert. Er steht immer noch auf 675Byte trotz 
7 entfernter Befehle. Leider ändert sich hier auch nichts an der 
Verarbeitung. Diesmal hat es fast 2 Minuten gedauert bis der nächste 
Datensatz angenommen wurde.

Es ist im übrigen egal ob ich den IR-Code auswerte oder direkt den Port 
Togle also sobald ein IR Signal ankommt und egal welches es ist ich 
togle alle 6 Bits. Selbst dann hängt er für eine Weile. Ob das bei der 
Fehlersche hilft weiß ich leider nicht.

von Daniel S. (cyber)


Lesenswert?

Ich habe jetzt noch einmal die Demo vom IRMP mit UART von P.F. auf den 
Controller gejagt und dabei nur folgendes eingesetzt.
1
if (irmp_get_data (&irmp_data))
2
{
3
  // ir signal decoded, do something here...
4
  // irmp_data.protocol is the protocol, see irmp.h
5
  // irmp_data.address is the address/manufacturer code of ir sender
6
  // irmp_data.command is the command code
7
  // irmp_protocol_names[irmp_data.protocol] is the protocol name (if enabled, see irmpconfig.h)
8
  itoa (irmp_data.protocol, buf, 10);   // protocol in decimal
9
  uart_puts (irmp_protocol_names[irmp_data.protocol]);
10
  uart_puts(" (");
11
  uart_puts(buf);
12
  uart_puts(") ");
13
  itoa (irmp_data.address, buf, 16);   // address in hex
14
  uart_puts (buf);
15
  uart_putc (' ');
16
  itoa (irmp_data.command, buf, 16);   // command in hex
17
  uart_puts (buf);
18
  uart_putc(' ');
19
  if (irmp_data.flags & IRMP_FLAG_REPETITION)
20
  {
21
    // Benutzer hält die Taste länger runter
22
    // entweder:
23
    //   ich ignoriere die (Wiederholungs-)Taste
24
    // oder:
25
    //   ich benutze diese Info, um einen Repeat-Effekt zu nutzen
26
    uart_puts("Wiederholung");
27
  }
28
  else
29
  {
30
    // Es handelt sich um eine neue Taste
31
    uart_puts("New Key");
32
  }
33
  uart_putc ('\r');
34
  uart_putc ('\n');
35
36
  // Test
37
  if (irmp_data.protocol == 2 && irmp_data.address == 0xBF40 && irmp_data.command == 0x01 && !(irmp_data.flags & IRMP_FLAG_REPETITION))
38
  {
39
    infoOn = 0xFC;
40
    OUT_PORT = infoOn;
41
  }
42
  else
43
  if (irmp_data.protocol == 2 && irmp_data.address == 0xBF40 && irmp_data.command == 0x03 && !(irmp_data.flags & IRMP_FLAG_REPETITION))
44
  {
45
    infoOn = 0x00;
46
    OUT_PORT = infoOn;
47
  }
48
}

Selbiges Problem irmp_get_data liefert FALSE. Die Callback wird aber 
noch aufgerufen, die LED reagiert bei eingehendem Signal.

Also bin ich noch einen Schritt weiter gegangen und habe die UART Lib 
von P.F. auch komplett entfernt. Hier ebenfalls ein Hänger.

an den Ports selbst kann es ja nicht liegen die setze ich ja für 1.5 
Sekunden beim Start.
1
if (irmp_data.protocol == 2 && irmp_data.address == 0xBF40 && irmp_data.command == 0x01 && !(irmp_data.flags & IRMP_FLAG_REPETITION))
2
{
3
  OUT_PORT |= ((1 << OUT_1) | (1 << OUT_2) | (1 << OUT_3) | (1 << OUT_4) | (1 << OUT_5) | (1 << OUT_6));
4
}
5
else
6
if (irmp_data.protocol == 2 && irmp_data.address == 0xBF40 && irmp_data.command == 0x03 && !(irmp_data.flags & IRMP_FLAG_REPETITION))
7
{
8
  OUT_PORT &= ~((1 << OUT_1) | (1 << OUT_2) | (1 << OUT_3) | (1 << OUT_4) | (1 << OUT_5) | (1 << OUT_6));
9
}

Selbst dieses funktioniert nicht. Da muß doch echt irgendwo der Wurm 
drin sein.

Auf dem Addon Board ist ein TSOP1136 verbaut selbst den habe ich nun 
extern wie im Artikel beschrieben angeschlossen. Ergebnis: keine 
Änderung. Nun habe ich ihn auf 8Mhz gesetzt aber selbst das bringt keine 
Änderung.

Jetzt bin ich ratlos.

von Daniel S. (cyber)


Lesenswert?

Ich habe das Programm nun mal auf einem Mega16 aufgespielt einmal mit 
8Mhz und einmal mit 16Mhz und hier läuft das Programm ohne Probleme.

Hier hat sich auch nicht viel geändert:
  Task "RunOutputFileVerifyTask"
        Program Memory Usage   :  5564 bytes   34,0 % Full
        Data Memory Usage     :  675 bytes   65,9 % Full
  Done executing task "RunOutputFileVerifyTask".

Ich frage mich nur warum es nicht auf dem Mega8 laufen will. Abgesehen 
davon das ich hier alle Pins des PortC nutzen kann und beim Mega8 hier 
noch UART drauf liegt hat sich nichts geändert.
Habe jediglich das Target geändert und die beidem Pins des PortC dazu 
genommen.

Hat hier jemand eventuell einen Ansatz warum dieses Problem auftritt 
oder sogar schon einmal ein gleiches Problem?

Was ich allerdings noch nicht versucht habe ist einfach mal einen 
frischen Mega8 zu nehmen. Habe gerade keinen hier liegen. :(

Würde schon gerne wissen warum der Mega8 diese Probleme macht.

von Daniel S. (cyber)


Lesenswert?

Guten Morgen,

ich habe noch einmal eine Frage bezüglich meines Sources.
1
          if (nextInfo.Options == 0x01)
2
          {
3
            NewSet = OUT_PORT;
4
            NewSet = ( OldSet | nextInfo.infoOn ) & ( ~ nextInfo.infoOff );
5
6
            if (OUT_PORT == NewSet)
7
            {
8
              OUT_PORT = ( OUT_PORT | nextInfo.infoOff ) & ( ~ nextInfo.infoOn );
9
            }
10
            else
11
            {
12
              OUT_PORT = ( OUT_PORT | nextInfo.infoOn ) & ( ~ nextInfo.infoOff );
13
            }
14
            
15
          }
16
          else
17
          {
18
            OUT_PORT = ( OUT_PORT | nextInfo.infoOn ) & ( ~ nextInfo.infoOff );
19
          }
Options = 0x01 bedeutet toggle. Gerade wenn eine Einzeltaste 
programmiert ist dann soll natürlich auch nur der Ausgang gesetzt bzw. 
zurück gesetzt werden. Bsp: Taste1 = TV - dementsprechend TV an oder aus 
wenn ich erneut die Taste betätige.
Es wird geprüft ob die aktuelle Maske der neuen entspricht, falls ja 
dann invertieren.

Ist dieses Konstrukt soweit ok?

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.