PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega8 + MAX485



demmy
01.08.2011, 20:00
Hallo zusammen,

ich versuche seit ein paar Tagen einen Atmega8 mittels MAX485 in ein RS485 Halbduplex netzwerk ein zu binden.

Mein Problem ist, egal was ich den µC senden lasse ich bekomme immer einen Murx raus. Habe versucht per Tastendruck die Zahl 300 als Integer mit Printbin zu senden: Erhalten müsste ich ja etwas wie 00000001 00101100, tatsächlich erhalte ich aber 00000000 10000000. Ich habe die Crystal auf 8000000 und die Baud auf 19200 eingestellt. Das müsste dich so stimmen oder? Wo könnte mein Fehler liegen?

Hier is der Schaltplan des MAX485.

19499

Sauerbruch
02.08.2011, 07:35
Ich habe die Crystal auf 8000000 und die Baud auf 19200 eingestellt

...und die Fusebits sind auch so eingestellt, dass das Teil mit 8 MHz läuft? Verwendest Du einen Quarz, oder den internen RC-Oszillator?

demmy
02.08.2011, 08:38
Wie müsste denn die Einstellung der Fusebits aussehen für den Atmega8, dass er mit 8 MHz und 19200 Baud läuft?

Ich dachte das der Atmega8 einen internen Oszillator hat?

Wird eigentlich in Bascom die Einstellung in meinem Projekt gespeichert wenn ich was in den Fusebits ändere?

Sauerbruch
02.08.2011, 08:50
Klar, der Mega8 hat natürlich einen internen RC-Oszllator. Im Auslieferungszustand ist der aber auf eine Frequenz von 1 MHz eingestellt. Wenn Du also noch nichts an der Fuses geändert hast, wird er wohl noch mit dieser Taktfrequenz laufen.

Das kannst Du ganz einfach testen, indem Du eine LED in einem bestimmten Takt blinken lässt, z.B. einmal pro Sekunde ein und aus:


$regfile = mega8def.dat (oder so...)
$Crystal = 80000000

Config PortX.Y = output

Do
Toggle PortX.Y
Waitms 500
Loop


Wenn das Programm in "Zeitlupe" läuft, ist der tatsächliche Takt langsamer als der Wert bei $Crystal.

demmy
02.08.2011, 11:10
Mhh ok das heißt also ich muss den Internen Oszillator auch auf 8 MHZ einstellen um 19200 Baud zu erhalten?
Ich habe auch gelesen, dass man einstellen kann ob der interne oder ein externer Oszillator verwendet werden soll. Ich würde gerne den Internen nutzen.
Wie müssten denn die Einstellungen dann aussehen?

Sauerbruch
02.08.2011, 11:30
Mhh ok das heißt also ich muss den Internen Oszillator auch auf 8 MHZ einstellen um 19200 Baud zu erhalten?

Na ja - ob 19.200 Baud mit 1 MHz nicht vielleicht auch klappen könnten, müsste man mal schauen (dazu später mehr). Aber eins steht fest: Die Angabe bei $Crystal legt NICHT fest, mit welchem Takt der Controller läuft! Das kann man ausschließlich mit den Fusebits einstellen (die übrigens auch unverändert bleiben, wenn Du "normalen" Programm-Code in den Controller brennst).
Wenn aber der tatsächliche Takt (Fuses) und die Angabe bei $Crystal nicht übereinstimmen, sind alle zeitlichen Berechnungen falsch, die Bascom macht. Und dann kann´s mit einer koordinierten Übertragung via RS232 nicht klappen.

Also solltest Du vielleicht erstmal den internen Takt auf 8MHz stellen. Wie das in Bascom geht, weiß ich nicht, da ich meine Fusebits mit einem anderen Programm bearbeite. Aber das dürfte ja nicht allzuschwer herauszufinden sein. Vorsicht ist bei der Option "externer" Takt geboten: Wenn Du diese Option einmal gewählt hast, schaltet sich der interne Oszillator ab - und dann hast Du erst wieder Zugriff auf den Controller, wenn Du ihn mit einem externen Taktsignal versorgst (z.B. einem 1MHz-Rechteckgenerator).

Und zu den Baudraten muss man wissen, dass es zu jeder Taktfrequenz "passende" Baudraten gibt, d.h. Baudraten, die sich mit einer tolerablen Fehlerrate generieren lassen. Abweichungen von ein paar Prozent können schon nachhaltige Probleme bei der Datenübertragung verursachen. Deshalb wird auch oft empfohlen einen Quarz zu verwenden, wenn die UART-Schnittstelle benutzt werden soll. Schau im Netz einfach mal unter Baudraten-Rechner nach - da wirst Du einiges finden!

Richard
02.08.2011, 11:36
Mhh ok das heißt also ich muss den Internen Oszillator auch auf 8 MHZ einstellen um 19200 Baud zu erhalten?
Ich habe auch gelesen, dass man einstellen kann ob der interne oder ein externer Oszillator verwendet werden soll. Ich würde gerne den Internen nutzen.
Wie müssten denn die Einstellungen dann aussehen?

Das Problem bei internen Takt, der ist nicht besonders genau was dann zu fehlern in der Übertragung führt weil die Baudrate nicht ganz stimmt. :-( Mit 2400..4800 geht es noch ganz gut bei 19200 hmmmmm....Wenn Du noch keine Fuse verändert hast, stelle $Baut = 2400 ein und teste erst einmal ob die Übertagung an sich klappt. Wenn das der Fall ist kannst immer noch erhöhen. Denke daran...auf beiden Seiten 2400 Baut 8 N 1. Wie herum die AB TXRX angeschlossen werden müssen kannst Du mit dem Volt Meter messen die Pegel sollen + auf + / - auf- angeschlossen werden

Gruß Richard

Kampi
02.08.2011, 12:26
Das Problem bei internen Takt, der ist nicht besonders genau was dann zu fehlern in der Übertragung führt weil die Baudrate nicht ganz stimmt. :-( Mit 2400..4800 geht es noch ganz gut bei 19200 hmmmmm....Wenn Du noch keine Fuse verändert hast, stelle $Baut = 2400 ein und teste erst einmal ob die Übertagung an sich klappt. Wenn das der Fall ist kannst immer noch erhöhen. Denke daran...auf beiden Seiten 2400 Baut 8 N 1. Wie herum die AB TXRX angeschlossen werden müssen kannst Du mit dem Volt Meter messen die Pegel sollen + auf + / - auf- angeschlossen werden

Gruß Richard

Also ich hatte bisher beim internen Oszilator nie Probleme mit dem UART.....selbst 38400 waren kein Problem. Aber wichtig ist halt das die Taktfrequenz intern stimmt damit die Berechnungen die Bascom aufgrund deiner Taktangabe macht, auch richtig sind und funktionieren. Im Zweifelsfall einfach einen Quarz anklemmen. Ist meistens eh besser und kostet auch nicht viel ;). Es gibt auch Quarze mit speziellen Frequenzen die extra für genaue Baudraten ausgelegt sind.

demmy
02.08.2011, 16:46
So also ich habe jetzt versucht die Fusebits zu ändern, allerdings übernimmt er das irgendwie nicht??

Eingestellt war folgendes:

19529

Ich habe dann versucht, dass ein zu stellen:

19528

Wenn ich dann auf Fusebits schreiben klicke wird zwar etwas geschrieben, aber sobald der µC neu ausgelsesen wurde steht der alte Wert wieder drinne.

Ich Benutze einen ISP-Programmer falls das von interesse ist?

Anschließend ist mir aufgefallen dass im Programm folgende Zeile eingefügt wurde.

$prog &H00 , &H00 , &H00 , &H00 ' generated. Take care that the chip supports all fuse bytes.$PROG &H00,&H00,&H00,&H00' generated. Take care that the chip supports all fuse bytes.

Daraufhin habe ich versucht das Programm neu zu übertragen was er auch gemacht hat. Am Ende jedoch stand etwas mit Fuse-bits, was mit einer Fehlermeldung abgebrochen wurde.

Was mache ich falsch?

Richard
02.08.2011, 17:01
Ich habe noch mie versucht in Bascom Fusebit's zu setzen viel zu kompliziert. Für so etwas nehme ich das Studio 4, das klappt immer. :-)

Gruß Richard

Kampi
02.08.2011, 17:39
So also ich habe jetzt versucht die Fusebits zu ändern, allerdings übernimmt er das irgendwie nicht??

Eingestellt war folgendes:

19529

Ich habe dann versucht, dass ein zu stellen:

19528

Wenn ich dann auf Fusebits schreiben klicke wird zwar etwas geschrieben, aber sobald der µC neu ausgelsesen wurde steht der alte Wert wieder drinne.

Ich Benutze einen ISP-Programmer falls das von interesse ist?

Anschließend ist mir aufgefallen dass im Programm folgende Zeile eingefügt wurde.

$prog &H00 , &H00 , &H00 , &H00 ' generated. Take care that the chip supports all fuse bytes.$PROG &H00,&H00,&H00,&H00' generated. Take care that the chip supports all fuse bytes.

Daraufhin habe ich versucht das Programm neu zu übertragen was er auch gemacht hat. Am Ende jedoch stand etwas mit Fuse-bits, was mit einer Fehlermeldung abgebrochen wurde.

Was mache ich falsch?

Wenn diese Zeilen in deinem Code erscheinen:

$prog &H00 , &H00 , &H00 , &H00

heißt das die Fuse-Bits werden bei der Ausführung des Programmes geändert! Dann bist du auf den "Write PRG"-Button gekommen. Dadurch schreibst du die Fuses in dein Programm. Wenn du die aber ohne Programm setzen willst musst du die einstellen und dann glaub ich "Write LB" drücken.

demmy
02.08.2011, 19:44
ja das habe ich auch versucht, hat aber ebenfalls keinen Erfolg gehabt.

Ich habe es jetzt mit einem anderen Programm versucht, und siehe da es hat funktioniert. Das tool heißt AVRProgTool. Damit ging das Lesen und Schreiben der Fusebits problemlos.

Und jetzt empfange ich auch was über RS485.
Ich habe die zahl 300 in Binär übertragen. Ich habe nur noch ein kleines Problem. Der 1. Teil also das erste Byte der Zahl scheint korrekt zu sein nur im 2. Byte verhaspelt er sich wohl noch? was kann das jetzt noch sein? Liegt das nun daran, dass der Oszillator nicht 100% zur Baudrate passt?

Ich habe jetzt den Internen Oszillator so eingestellt:
Int. RC Osc. 8 MHz ; Start up Time : 6 CK + 64 ms

Was bedeuten denn die 64 ms??? es gibt auch noch kleinere Werte. Kann es daran liegen?

Kampi
02.08.2011, 19:58
Ich habe jetzt den Internen Oszillator so eingestellt:
Int. RC Osc. 8 MHz ; Start up Time : 6 CK + 64 ms

Was bedeuten denn die 64 ms??? es gibt auch noch kleinere Werte. Kann es daran liegen?

Die Startup Time sagt aus wie lange der Oszilator braucht um sich einzuschwingen. Also in dem Fall 64ms + 6 Clockzyklen glaub ich heißt das CK. Was heißt verhaspelt er sich? Was kommt da als Ergebniss raus?
Und diese 64ms haben nichts mit der Baudrate zu tun. Diese Zeit ist nur nach einem Reset wichtig.

demmy
02.08.2011, 20:04
Also 300 wäre ja 00000001 00101100:

ich empfange an : im 1. Byte 00101100
im 2. Byte 11000000

und im 2. Byte liegt der Fehler das müsste ja 00000001 sein!!
Oder?

demmy
02.08.2011, 22:25
Also ich versteh es aktuell nicht.
Ich habe jetzt mal noch ein paar Versuche gemacht. Zum einen habe ich 2 Byte mit jeweils einer 10 gesendet. Die erste 10 kommt sauber an. die 2. 10 ist irgend ein Mist. Egal was ich sende das 1. Byte passt und dann kommt nur noch Käse.

Ich habe auch mit den Baudraten etwas herumgespielt. Egal was ich einstelle immer das selbe Bild.
Woran könnte das noch liegen?

Könnte es an den Abschlusswiderständen des Busses liegen? Hatte nur 110 Ohm statt 120 Ohm.

Kampi
02.08.2011, 22:31
Nein die 10Ohm machen es nicht aus. Poste mal dein Code und eine komplette Verdrahtung.

demmy
02.08.2011, 22:59
Also die Schaltung sieht so aus:

19542

und das Programm:




$regfile = "m8def.dat"
$crystal = 8000000
'the internal oscillator of 8 Mhz was choosen in the fusebits
$baud = 19200
Osccal = &HAE
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 32 ' default use 32 for the SW stack
$framesize = 50 ' default use 50 for the frame space


'Ports Deklarieren
Relais1 Alias Portc.0
Config Relais = Output

Rs485dir Alias Portd.2
Config Rs485dir = Output
Rs485dir = 0 ' Empfangsmodus

Taster1 Alias Pinc.2
Config Taster1 = Input
Portc.2 = 1 'PullUp-Widerstand einschalten

Taster2 Alias Pinc.3
Config Taster2 = Input
Portc.3 = 1 'PullUp-Widerstand einschalten

Stromsensor Alias Pinc.4
Config Stromsensor = Input
Portc.4 = 1 'PullUp-Widerstand einschalten

$timeout = 100000

'System-Timer für periodische Encoder-Abfrage
Config Timer0 = Timer , Prescale = 256
On Timer0 Isr_timer0
Enable Timer0
Const Timer0_reload = 250

Config Debounce = 30

'Interrupt Daten wurden empfangen
'On Urxc Onrxd 'Interrupt-Routine setzen (Daten über Uart empfangen)
'Enable Urxc 'Interrupt URXC einschalten
'Interrupt Daten wurden gesendet
On Utxc Ontxd
Enable Utxc

Enable Interrupts 'Interrupts global zulassen


'Variablendeklaration

Dim Teilnehmeradresse As Byte
Teilnehmeradresse = 10


'MainLoop
Do

Loop

On_taster1:
Toggle relais

'SENDETEST
Rs485dir = 1
Waitms 50

Printbin Teilnehmeradresse ; Teilnehmeradresse;

Return

Ontxd:

Waitms 50
Rs485dir = 0

Return

'Timer 0

Isr_timer0:
Timer0 = Timer0_reload


Debounce Taster1 , 0 , On_taster1 , Sub


Return


End

Sauerbruch
03.08.2011, 11:11
Moin Demmy,

In der Sub on_taster1 wird etwas über die UART gesendet - und wenn die Sendung komplett ist, wird noch vor dem Return die ISR Ontxd ausgeführt. Ich weiß nicht, ob der TXC-Interrupt nicht schon bereits nach dem ersten gesendeten Byte ausgeführt wird. Wenn ja, könnte diese Unterbrechung vielleicht der Grund sein, weshalb beim 2. Byte Fehler entstehen.

Lass in einem ersten Schritt den TXC-Interrupt doch einfach mal weg - und setze die beiden Befehle aus der Ontxd-ISR einfach mal hinter den Printbin-Befehl in der Taster-Sub:



On_taster1:

Toggle relais
RS485dir = 1
waitms 50
Printbin Teilnehmeradresse ; Teilnehmeradresse ;
waitms 50
RS485dir = 0

Return




Wenn´s dann funktioniert, kannst Du sozusagen an der "B-Note" arbeiten:

Waitms-Befehle in ISRs sind nämlich etwas, was schnell mal problematisch werden kann. Die Hauptschleife wird nämlich ganz schön lange aufgehalten, und andere Interrupts könnten während einer laufenden ISR u.U. ignoriert werden.
In Deinem Code ist die Hauptschleife ja recht übersichtlich :-) und deshalb wirkt sich dieser Schönheitsfehler nicht besonders aus. In komplexeren Programmen sollte man in der ISR aber idealerweise nur ein Flag-Bit auf 1 setzen, das dann in der Hauptschleife regelmäßig abgefragt wird. Ist es 1, werden die Befehle ausgeführt, die zu dem Interrupt gehören, und das Bit anschließend auf 0 gesetzt.


Und noch was:

So wie ich das hier sehe, hast Du etwa 6000 (!) Timer0-Interrupts pro Sekunde. Das hält den Controller schon ganz schön in Schach, und ich könnte mir vorstellen, dass dieses Dauerfeuer an Interrupt-Routinen den Print-Befehl auch etwas stören könnte. Wenn Du damit nur den Taster1 abfragen möchtest, ginge das wesentlich leichter: Entweder direkt in der Hauptschleife, oder aber über einen der beiden externen Interrupt-Eingänge INT0 bzw. INT1.

demmy
03.08.2011, 11:56
Also das hört sich logisch an, ich werde das auf jeden Fall später mal testen.

Wegen der Timerproblematik: ich könnte doch den Const Timer0_reload = 250 heruntersetzen um die Anzahl der Aufrufe zu verringern oder?

Sauerbruch
03.08.2011, 12:10
Wegen der Timerproblematik: ich könnte doch den Const Timer0_reload = 250 heruntersetzen um die Anzahl der Aufrufe zu verringern oder?

Klar, aber wieso brauchst Du so etwas aufwendiges wie eine ISR, nur um den Taster abzufragen? Wenn Du den debounce-Befehl in die Hauptschleife packst, sparst Du dem Controller nicht nur eine Menge Arbeit in Form von tausenden von Interrupts - sondern der Taster wird auch noch viel häufiger abgefragt! Aber am elegantesten wäre es nach wie vor, mit dem Taster einen externen Interrupt auszulösen!

demmy
03.08.2011, 12:57
Ok da hast du recht, ich wollte den Debounce befehl auch zum entprellen des Tasters nutzen. Ich werde das alles heute Mittag mal testen und melde mich dann nochmal.
Vielen Dank soweit.

demmy
03.08.2011, 17:33
Juhuuu es funktioniert!!!! Er sendet und empfängt wie er soll! :-)
Ursache war folgende Zeile in meinem Code:
Osccal = &HAE
Ich habe die Zeile entfernt und alles war ok. Wie ich nun herausfinden konnte Kalibriert man den Ozillator mit diesem Befehl, und scheinbar war der Wert nicht korrekt und hat somit irgendwas durcheinander gewürfelt. Dummerweise hatte ich den Kopf des Programmes aus einer Vorlage übernommen. Naja wie auch immer, ich werde auf jeden Fall noch einige hier angesprochene Punkte im Programm ändern.

Also Vielen Dank nochmals an Alle die mir geholfen haben!