PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bits senden und erkennen



ShadowPhoenix
12.05.2004, 15:35
Hallo!
Ich brauche etwas Hilfestellung zu einem ATmega8.
Ich möchte folgendes tun:

Mit einem AVR möchte ich eine Bitfolge an einem Pin programmieren.
Also es sollen 24 einzelne Bits an einen Pin gesendet werden.
Diese schauen so aus:

00000001 11111110 00000011

Das erste Byte ist ein "Startsignal", das zweite Byte das eigentliche Kommando und das Dritte das "Endsignal".
Ich möchte mit diesem Prinzip eine IR Sendediode ansteuern und später dann einen Funksender.

Ok, ich denke das ist nicht so schwer:

Portd.0 = 0
waitms 10
Portd.0 = 1

So kann man doch schon mal 0 und 1 mit 10 Millisekunden an den Port senden , nicht?

Nur: Mir geht es darum, dass der zweite AVR, der am IR-Empfänger TSOP1736 hängt, dann nur das Kommando erkennt.
Also soll der zweite AVR nur 11111110 erkennen und auswerten.

Mein Prinzip: (BASCOM)
Der AVR erkennt das Byte 00000001 und startet somit die "Aufzeichnung", dann kommt auch schon das Kommando rein (11111110), und er wertet es aus. und das Byte 00000011 beendet die "Aufzeichnung" und der AVR wartet nun auf ein weiteres Startbyte.

NUr wie realisiere ich so etwas?
Wie kann ich einen Pin des AVR auslesen, und 0er und 1er -Folgen speichern und dann auslesen?
Für 11111110 soll zB Funktion1 starten, für 11111100 Funktion2.....

Man könnte die Bitfolgen doch in ein Array speichern und dann auslesen, oder?

Helft mir bitte!
MfG,
ShadowPhoenix

Gottfreak
12.05.2004, 16:48
Man könnte die Bitfolgen doch in ein Array speichern und dann auslesen, oder?

Ja, könnte man.
Was das Speichern angeht, kannst du über eine Zählvariable speichern, das wievielte Bit es ist und es jeweils an die entsprechende Stelle einer Byte-Variable schreiben (wenn der Zähler bei 8 ist, fängt das nächste Byte an.).
Dann musst du nurnoch den Anfang des Signals syncronisieren (also bei deinem Startbyte 15ms nach dem ersten Bit das zweite lesen und dann im 10ms-Takt weiter bis dein Stopbyte kommt oder einfach bis 8bit empfangen sind.).
Bei Signalen, die deutlich länger als 3 Byte sind, würde sich dann ein Interupt oder ein Pollen des Eingangspins mit höherer Frequenz anbieten, damit die Übertragung länger syncron bleibt.


Helft mir bitte!

Gern. Leider bin ich mir nicht ganz sicher, ob ich richtig verstanden habe, an welcher Stelle du ein Problem hast.

ShadowPhoenix
12.05.2004, 20:56
@Gottfreak

Okay, ich verstehe dein Prinzip, aber leider nicht alles.
Manches scheint mir etwas komplex.
Weisst du was? Ich wäre sehr sehr zufrieden, wenn du mir ein einfaches
Beispiel in BasCom erklären könntes.
Leider bin ich noch ziemlicher Anfänger.
Ich kann zwar AVR's programmieren, aber sobald neue Funktionen dazukommen, haperts bei mir ;) , du verstehst.

Mein eigentliches Problem ist:
Ich möchte wissen, wie ich in Bascom mit einem AVR je 3 Bytes senden kann, und dann an einem anderen AVR je diese 3 Bytes wieder verarbeiten kann.
Wie sollte der Code in Bascom zum senden ausschauen?
Und wie der Code zum Empfangen?

Würdest mir echt einen grossen Gefallen tun ;)

MfG,
ShadowPhoenix

Gottfreak
12.05.2004, 22:26
Hi
Du hast echt Glück, dass ich ohnehin nix besseres vorhatte.
Hier ist ein (hoffentlich ausreichend kommentiertes) Beispiel


$regfile = "2313def.dat" 'AT90S2313 natürlich muss hier die Definitionsdatei für deinen AVR hin
$crystal = 8000000 'Und hier deine Taktfrequenz

'Konstanten
Const Startbyte = 00000001
Const Stopbyte = 00000011

'Variablen
Dim Zaehl As Byte : Dim Fehler As Bit : Dim Temp As Byte
Dim Zaehl2 As Byte : Dim Temp2 As Byte 'Nur zum Zaehlen im Interrupt - nicht woanders benutzen, da es plötzlich auf 7 wechseln könnte. Temp2 ändert sich auch(höchstwahrscheinlich) bei jedem Interrupt
Dim Gelesen As Byte : Dim Zusenden As Byte 'In Gelesen steht nach dem Empfang (also automatisch, wenn ein Signal am Port anlag) der empfangene Wert. In Zusenden musst du vor dem Aufrufen der Senderoutine den Wert reinschreiben, den du senden willst.
Enable Int0
Config Int0 = Falling
On Int0 Onint0 Nosave
Enable Interrupts
Ddrb.0 = 0 'PortB.0 auf Eingang - Die Ports sind willkürlich gewählt
Ddrb.1 = 1 'PortB.1 auf Ausgang
Do
Zusenden = 54 'Sendet erstmal einfach jede Sekunde 54
Gosub Senden
Waitms 760 'Wartet den Rest der Sekunde, den das Senden nicht gedauert hat
Loop

Onint0: 'löst das erste mal aus, wenn das Startbyte vorbei ist(dafür würde auch ein Bit genügen. Ist schlecht für die Fehlerkorrektur.)
push SREG
Waitms 5 'jetzt sind wir in der Mitte des ersten Datenbits...
Gosub Bytelesen 'und lesen die anderen
Temp = Gelesen 'Hier sind wir in der Mitte des ersten Bit des Stopbytes...
Gosub Bytelesen ' ...und lesen es
If Gelesen <> Stopbyte Then Fehler = 1 Else Fehler = 0 'Für ein Minimun an Fehlererkennung kannst du in Fehler abfragen, ob das Stopbyte korrekt empfangen wurde
Gelesen = Temp 'In Gelesen steht jetzt der empfangene Wert
waitms 5 'Damit die fallende Flanke am Ende des Stopbytes nicht als Anfang eines neuen Bytes verstanden wird (da der Empfang während eines Interupts stattfindet, löst der so nicht nochmal aus).
pop SREG
Return

Bytelesen:
For Zaehl2 = 0 To 7
Gelesen.zaehl2 = Portb.1
Waitms 10
Next
Return

Senden:
Temp = Zusenden 'Zu sendendes Byte sichern, da die Variable Zusenden mehrfach benutzt wird
Zusenden = Startbyte
Gosub Bytesenden
Zusenden = Temp
Gosub Bytesenden
Zusenden = Stopbyte
Gosub Bytesenden
Return

Bytesenden:
For Zaehl = 0 To 7
Portb.0 = Zusenden.zaehl
Waitms 10
Next
End

Zu erwähnen wäre folgendes:
1. Ich hab's nicht getestet (zwei AVRs damit bespielen, verbinden und irgendwie ausprobieren, ob das richtige angekommen ist, war mir dann doch zu aufwändig). Im Prinzip sollte das halt gehen.
2. Ich hab' keine Ahnung, wie lange die einzelnen Bascom-Befehle brauchen. Zum Zeitbedarf der Warteschleifen kommt also noch der der Befehle hinzu(der Unterschied zwischen deren Zeitbedarf beim Senden und Empfangen ist hoffentlich bei einem Byte <5ms, sonst verpasst der ein Bit).
3. Senden und Empfangen "gleichzeitig"(also auf einem AVR) ist nicht ohne weiteres möglich, da die Empfangsroutine das Senden unterbricht (und so lange Pause macht, dass das Gesendete unverständlich wird). Dann müsstest du während dessen die Interrupts ausmachen und irgendwie dafür sorgen, dass die AVRs sich mit dem Zeitfenster abwechseln (oder statt Warteschleifen Timer nehmen, was aber erstens recht umständlich ist und zweitens wohl nur in ASM genau geht).
Die Routinen sind also nur zur Anschauung im gleichen Programm untergebracht.
4. Ich weis auch nicht, welche Register Bascom einfach so benutzt(für die Schleifen), die nicht gesichert werden(siehe nosave). Wenn der Rest deiner Programmausführung beim Empfangen nicht richtig geht, lass es weg(und wenn es dann zu lange dauert, mach die ersten "waitms 5" kürzer.).

Gottfreak
12.05.2004, 22:29
Ups
Da war wohl der eine oder andere Kommentar zu lang. Wenn du das ganze wieder in Bascom kopierst, verschwinden die hässlichen Zeilenumbrüche.

ShadowPhoenix
12.05.2004, 23:11
Ich danke dir vielmals für diesen Beispielcode.
Jedoch bin ich wiegesagt noch eher ein Anfänger in Bascom & Avr programmieren.
Mein Problem besteht nun darin, dass ich nicht verstehe, wie ich
den Code nun anwenden soll.

Ich weiß, es kann schwierig mit mir sein (:-O), aber auf jegliche Hilfe freue ich mich dafür umso mehr.
Leider weiß ich nun nicht, wo ich das Kommandobyte eingeben muss und wo das Kommandobyte dann empfangen wird.

Eines weiß ich:
Dieser Code ist zum Senden & Empfangen gleichzeitig, oder?
Man muss ihn nun irgendwie in zwei Hälften "trennen", einen Code zum Senden und einen Code zum Empfangen.
Dann kommt je ein Code auf einen AVR.
So stelle ich mir das vor. Könntest du mir noch diesen Gefallen machen, und den Code fachgemäß teilen?

Vielen Dank @Gottfreak für deine bisherige Hilfe, ich weiß das sehr zu schätzen :)

MfG,
ShadowPhoenix

Gottfreak
13.05.2004, 00:29
Hier nochmal in "zerhackstückselt" und mit Einrückungen
Immerhin sind mir noch sinnvolle Änderungen eingefallen (der Code ist nicht richtig kompatibel zu den Routinen oben).
Hier zum Senden. In der Hauptschleife, die jetzt die ganze Zeit das gleiche sendet, fügst du dann ein, was auch immer du dir als Anwendung überlegt hast.


$regfile = "2313def.dat" 'AT90S2313 natürlich muss hier die Definitionsdatei für deinen AVR hin
$crystal = 8000000 'Und hier deine Taktfrequenz

'Konstanten
Const Startbyte = 00000001
Const Stopbyte = 00000011

'Variablen
Dim Zaehl As Byte : Dim Temp As Byte
Dim Zusenden As Byte

Ports sind willkürlich gewählt
Ddrb.1 = 1 'PortB.1 auf Ausgang
Do
Zusenden = 54 'Sendet erstmal einfach jede Sekunde 54
Gosub Senden
Waitms 760 'Wartet den Rest der Sekunde, den das Senden nicht gedauert hat
Loop

Senden:
Temp = Zusenden 'Zu sendendes Byte sichern, da die Variable Zusenden mehrfach benutzt wird
Zusenden = Startbyte
Gosub Bytesenden
Zusenden = Temp
Gosub Bytesenden
Zusenden = Stopbyte
Gosub Bytesenden
Return

Bytesenden:
For Zaehl = 0 To 7
Portb.1 = Zusenden.zaehl
Waitms 10
Next
return
End

Und hier zum Empfangen (in der Hauptschleife kannst du wieder die gewünschte Auswertung einfügen.)


$regfile = "2313def.dat" 'AT90S2313 natürlich muss hier die Definitionsdatei für deinen AVR hin
$crystal = 8000000 'Und hier deine Taktfrequenz

'Konstanten
Const Stopbyte = 00000011

'Variablen
Dim Fehler As Bit
Dim Zaehl2 As Byte : Dim Temp As Byte 'Nur zum Zaehlen im Interrupt - nicht woanders benutzen, da es plötzlich auf 7 wechseln könnte. Temp ändert sich auch(höchstwahrscheinlich) bei jedem Interrupt
Dim Gelesen As Byte
Enable Int0
Config Int0 = Falling
On Int0 Onint0 Nosave
Enable Interrupts
Ddrd.2 = 0 'PortD.2 auf Eingang - Der Port sollte zu dem Interrupt gehören, über den empfangen wird
Do
If Gelesen = 4 Then Portb.5 = 1 Else Portb.5 = 0 'Hier kannst du den empfangenen Wert auswerten
Loop

Onint0: 'löst das erste mal aus, wenn das Startbyte vorbei ist(dafür würde auch ein Bit genügen. Ist schlecht für die Fehlerkorrektur...)
Waitms 5 'jetzt sind wir in der Mitte des ersten Datenbits...
Gosub Bytelesen 'und lesen die anderen
Temp = Gelesen 'Hier sind wir in der Mitte des ersten Bit des Stopbytes...
Gosub Bytelesen ' ...und lesen es
If Gelesen <> Stopbyte Then Fehler = 1 Else Fehler = 0 'Für ein Minimun an Fehlererkennung kannst du in Fehler abfragen, ob das Stopbyte korrekt empfangen wurde
Gelesen = Temp 'In Gelesen steht jetzt der empfangene Wert
Waitms 5
Return

Bytelesen:
For Zaehl2 = 0 To 7
Gelesen.zaehl2 = Portd.2
Waitms 10
Next
Return
End


PS: Deine Antwort kam so schnell, dass ich mir kaum vorstellen kann, dass du wirklich den ganzen Code durchgegangen bist und in der Hilfe alles nachgeschlagen hast, was nicht klar war.

ShadowPhoenix
13.05.2004, 00:46
Quote:
PS: Deine Antwort kam so schnell, dass ich mir kaum vorstellen kann, dass du wirklich den ganzen Code durchgegangen bist und in der Hilfe alles nachgeschlagen hast, was nicht klar war.

Hmm, ich habe mir den Code einmal angeschaut, da ich hier auf dem Laptop kein BasCom installiert habe, sondern in meiner Werkstätte am PC, hast du Recht; ich bin wirklich nicht alle Befehle durchgegangen :-/
Leider bin ich manchmal etwas ungeduldig oder begriffsstutzig *g*

Wow, ich danke dir trotzdem dafür, dass du dir so viel Mühe gemacht hast und mir den Code auch noch zerhackstückselt hast ;))

Wenn ich nur irgendetwas für dich tun könnte...,... :-o
MfG,
ShadowPhoenix

PS: Eins verstehe ich nicht, warum verwendest du "Ddrb.1" anstatt normal Portb.1 ?

Gottfreak
13.05.2004, 00:59
Eins verstehe ich nicht, warum verwendest du "Ddrb.1" anstatt normal Portb.1 ?

DDRB ist das Datenrichtungsregister von Portb.
Eine 0 an dieser Stelle heisst Eingang, eine 1 Ausgang (tatsächlich verwende ich in dem Code "normal Portb.1". Die Klarstellung ist für den Compiler wichtig, da es durchaus auch Sinn machen kann, einen Eingang zu setzen und einen Ausgang auszulesen.).

ShadowPhoenix
13.05.2004, 17:07
Okay!

So, ein großes Danke noch einmal!
Habe mir zufällig beim schlafen gehen noch Gedanken über die Fehlerkorrektur gemacht.
Nehmen wir an, das Signal wird durch irgendetwas gestört (Sei es eine Hochspannungsleitung oder eine Mikrowelle :-o).
Dann kommen doch die 3 Bytes nicht so an, wie sie sollten, oder?

Das könnte dann echt zu einem großen Problem ausarten, oder sehe ich das falsch bzw. ist in dem Code schon eine gewisse Fehlerkorrektur eingebaut?

MfG;
ShadowPhoenix

Gottfreak
13.05.2004, 17:33
Das könnte dann echt zu einem großen Problem ausarten, oder sehe ich das falsch bzw. ist in dem Code schon eine gewisse Fehlerkorrektur eingebaut?

Der Code hat (ist gut kommentiert, steht da alles bei) nur insofern eine Fehlerkorrektur als dass die empfangende Seite das bit "Fehler" setzt, wenn das Stopbit gestört ist.
Man könnte an das Datenbyte auch noch ein neuntes Bit anhängen, das angibt, ob die Summer der 8 Bits des Datenbytes gerade ist. Eine einzelne Störung würde damit zuverlässig erkannt (einfach in der Senderoutine eine Schleife, die die Bits aufaddiert und das letzte Bit der Summer sendet. Der Empfänger addiert auch alle Bits und vergleicht wieder die Summe mit dem 9ten Bit. Dann weis man zumindest, dass etwas schiefgegangen ist und kann das ignorieren oder nochmal abfragen.). Das Problem, sowas in Bascom zu machen, besteht darin, dass so genau nicht feststeht, wie lange die Rechnerei dauert(damit man das von den Wartezeiten abziehen könnte).
PS: Was spricht eigentlich gegen das UART, das die meisten AVRs schon eingebaut haben? Das macht im Prinzip das gleiche wie der Code da oben und ist dabei wesentlich schneller (und man kann auch gleich Parität einstellen, wenn man möchte.). Da es in Hardware implementiert ist, geht das auch nicht so auf die allgemeine Rechenleistung.
PPS: Das soll nicht heissen, dass es nicht manchmal interessant sein kann, das Rad neu zu erfinden.

ShadowPhoenix
13.05.2004, 17:39
Hallo Gottfreak!

Ich habe leider keine Ahnung, was "UART" bedeutet.
Aber würdest du so freundlich sein, und mir diese kleine Fehlerkorrektur mit dem 9. Bit und der geraden Summe schreiben?
Ich wiess, ich kann nerven, nur leider ist es so, dass ich selber dann nur wieder Mist bauen würde :-(

MfG,
ShadowPhoenix

Gottfreak
13.05.2004, 19:08
Ich habe leider keine Ahnung, was "UART" bedeutet.

Das ist die eingebaute serielle Schnittstelle(unter www.rowalt.de gibt's nen schönen allgemeines Bascom-Tutorial, wo das auch beschrieben ist.).


Ich wiess, ich kann nerven, nur leider ist es so, dass ich selber dann nur wieder Mist bauen würde

Einen Versuch wird das wohl wert sein... (von dem Programm oben abgesehen hab' ich in den letzten 20 Stunden basteln und coden NICHTS erzeugt, das läuft. Dafür hab' ich immerhin eine Vorstellung davon, wo der Fehler liegen KÖNNTE und besuche jetzt am Wochenende 'nen Kumpel, der ein Oszilloskop hab *g ). Gib dir doch mal Mühe. So schwer iss'es wirklich nicht, wenn du einfach von meinem Code mit den 8 bit abguckst.
Ich hätte ja Lust aber das wird frühestens nächste Woche was(zumindest hab' ich erst dann wieder Internet.).
Was versprichst du dir eigentlich genau davon? Hast du ein konkretes Produkt im Auge oder willst du was lernen?