Atmega8515 programmieren?

Hallo Dirk!

Ich habe es mal schnell ausprobiert (Morgen früh klingelt der Wecker wieder so erbahmungslos).

Test 1 : Bestanden
Test 2 : Bestanden

Beide durchlaufen allerdings noch die 0 wenn von 80 weiter gezählt wird.
Die LED blinkt auch bei Test1, bei Test2 (Mainloop) bleibt der ganze Port Lo .

Das ist jetzt schon so viel Code, da werd ich wohk nie durch finden :eek:

Ich werde mich morgen mal weiter vertiefen, vielleicht kann ich dem ganzen ja folgen ?!

Vielen Dank und schönen Abend noch,

Michael
 
Hallo Michael,

such mal in der Software folgende Zeilen:
Code:
.equ MAX_DisplayNumber  = 80   ; Hier den Maximalwert und den Minimalwert für
.equ MIN_DisplayNumber  = 0    ; DisplayNumber definieren
Hier kannst Du Obergrenze und Untergrenze vorgeben. MIN_DisplayNumber = 1 setzen.
Alle Signale von PortC sind low, da nichts die PortC-Register verändert und PortC in der Routine InitPorts als Ausgang / low eingestellt wird.

Nimm einfach erst mal die Routinen TaskManager und KeyboardManager als gegeben und lass dich nicht dadurch irritieren.

Dein Mainloop sieht im Moment folgerndermaßen aus:
Mainloop:
wdr

rcall Task5ms
rcall Task20ms
rcall Task250ms

rcall ChangeDisplayNumber
; hier weitere Funktionen einfügen, die grundsätzlich ausgeführt werden sollen
rjmp mainloop
In den Routinen Task5ms, Task20ms und Task250ms kannst du Routinen in den entsprechenden Zeitintervallen aufrufen. Der KeyboardManager wird zum Beispiel in der Routine Task20ms aufgerufen, also alle 20ms (50 mal in der Sekunde).

Code:
Task5ms:
   sbrs Flags1, SIGNAL_Event5ms
   ret
   cbr Flags1, 1<<SIGNAL_Event5ms

  ; hier weitere Routinen die alle 5ms aufgerufen werden sollen

ret

Task20ms:
   sbrs Flags1, SIGNAL_Event20ms
   ret
   cbr Flags1, 1<<SIGNAL_Event20ms


   rcall KeyboardManager              ; keyboard controller

   ; hier weitere Routinen die alle 20ms aufgerufen werden sollen

ret


Task250ms:
   sbrs Flags1, SIGNAL_Event250ms
   ret
   cbr Flags1, 1<<SIGNAL_Event250ms

   ; hier weitere Routinen die alle 250ms aufgerufen werden sollen

ret
Du könntest die neuen Routinen InitTaskManager, TaskManager, InitKeyboardManager und KeyboardManager, mit denen du ja nicht arbeiten musst, in ein Include-File packen und am Programmende mit .include "MeinIncludeFile.inc" einfügen, dann wird dein Programm übersichtlicher.

In der Routine ChangeDisplayNumber könntest du nun die Werte für den PLL updaten lassen:
Code:
   ; Inkrementieren
   rcall IncDisplayNumber
   rcall LEDDisplay
   [COLOR=DarkRed]lds RegA, DisplayNumber
   rcall DecodePLLValue[/COLOR]
und
Code:
   ; Dekrementieren
   rcall DecDisplayNumber
   rcall LEDDisplay
   [COLOR=DarkRed]lds RegA, DisplayNumber
   rcall DecodePLLValue[/COLOR]
Gruss
Dirk
 
Ja, die Übersicht habe ich schon verloren *lach
Ist aber eine gute Idee Programmteile in Include-Dateien auszulagern!


Folgende Fehlermeldung wir mir aber noch ausgespuckt :
C:\assembler\proggy7.asm(357): error: Invalid number
C:\assembler\proggy7.asm(369): error: Invalid number

Das ist jeweils der Befehl : "lds RegA, displaynumber".
Selbes passiert dauch bei "lds RegA, r25"
Nur wenn ich regA einen Wert zuweise (zB 01) kommt keine Fehlermeldung ?!

Muss demnach ja was "falsches" in DisplayNumber stecken ???
 
Ups, mein Fehler.
DisplayNumber ist eine Registervariable und keine SRAM-Variable. Den Inhalt der Variable also folgendermaßen in RegA (Register) kopieren:
Code:
mov RegA, DisplayNumber
 
Oki, der Fehler wird nun nicht mehr angezeigt.

Eigenartig ist, dass nach dem einschalten (Reset) nichts angezeigt wird, erst wenn ich eine der Tasten betätigt habe. Am Anfang habe ich schon mit "ldi displaynumer, x" experimentiert. Wird aber erst nach einem Tastendruck aktiviert.

An Port C kommt auch noch nichts raus, steht immer auf 0, egal welche ziffer
ich anwähle.

Könnte es sein dass wir bei "DecodePllValue" garkeinen Ausgabe befehl eingebaut haben, oder habe ich jetzt was übersehen?
 
Hallo Michael,

Eigenartig ist, dass nach dem einschalten (Reset) nichts angezeigt wird, erst wenn ich eine der Tasten betätigt habe.
Ja, das ist richtig. Wir müssen bei Programmstart DisplayNumber initialisieren und dann LED-Display und PLL-Port aktualisieren. Das kann man so machen:
Code:
SystemInit:
   ; ...
   rcall InitKeyboardControl   
   sei                      ; Set EnablaInterrupts Bit

   [COLOR=DarkRed]ldi DisplayNumber, 20   ; Der Kanal, mit dem immer gestartet werden soll   
   rcall LEDDisplay
   rcall DecodePLLValue[/COLOR]
An Port C kommt auch noch nichts raus, steht immer auf 0, egal welche ziffer
ich anwähle.

Könnte es sein dass wir bei "DecodePllValue" garkeinen Ausgabe befehl eingebaut haben
Ja, das stimmt auch. Hier einmal die komplette Routine. Ich habe gleich DisplayNumber "eingebaut", so dass du vor dem Aufruf der Routine DisplayNumber nicht nach RegA kopieren musst (das ist oben schon berücksichtigt)
Code:
LED_DecodeDigit1:
   [COLOR=DarkRed]mov RegA, DisplayNumber[/COLOR]
   cpi RegA, 10
   brlo leddecdig1_start
   ldi RegA, 0xFF            ; alles aus, digit unterdrücken
   ret

leddecdig1_start:
   ldi r30, LOW(2*LEDSegmentTable1) 
   ldi r31, HIGH(2*LEDSegmentTable1)

   add r30, RegA             ; hier den Offset bilden
   clr RegA
   adc r31, RegA

   lpm                       ; load program memory (Byte aus Flash lesen, 
                             ; lpm nimmt die Adresse im z-Register (r30, r31)
   mov RegA, r0              ; Ergebnis ist im Register r0
  [COLOR=DarkRed] out PortC, RegA[/COLOR]

ret
 
Puhhhhhh Dirk, ich habe nun schon garkeinen Überblick mehr :eek:

Nach den Änderungen erscheint auf der LED-Anzeige sturr die 88,
PortC gibt berharrlich 0 aus
und die Tasten verweigern jegliche Arbeit :(

Ich hatte vorher schon versucht die ganze Geschichte übersichtlicher zu gestalten, also in include zu packen usw, mit dem selben Ergebnis.

Irgendwie kommt das Proggy ins schleudern wenn es ums Daten auslesen des PLL-Table geht?!

Ich packe hier noch mal den "ungepackten" und verbesserten Code dran.


Viele Grüße vom jetzt schon total verwirrtem Michael :D
 

Anhänge

  • proggy1310.zip
    6,2 KB · Aufrufe: 2
Ich finde in dem Programm direkt keinen Fehler, der Tastaturabfrage oder Display-Ausgabe durcheinander bringen könnte.

Die Routine DecodePLLValue erwartet als Argument RegA, es muss zuvor RegA mit dem Inhalt von DisplayNumber geladen werden, auch wird noch keine Ausgabe des Ergebnisses der Routine an PortC gemacht.

Beides habe ich im angehängten Programm korrigiert.

Ansonsten ist das angehängte Programm test0915.asm identisch mit test0910.asm vom letzten mal. Du hattest ja geschrieben, das Programm hat funktioniert, bis auf die PLL-Wert-Ausgabe? Wichtig ist erst einmal, daß die Taster-Abfrage und die Display-Ausgabe funktioniert.

Kannst Du das Programm test0915.asm einmal prüfen...
 

Anhänge

  • test0915.zip
    6,1 KB · Aufrufe: 3
Hallo Dirk!

Nun läuft es so wie es soll! Vielen Dank für die Hilfe, besser gesagt dass du es programmiert hast :)

Weiter gehts mit einer Scan-funktion und dass der letzt geschaltete Kanal nach dein Ausschalten wieder da ist.

Mit der Scan-Funktion habe ich schon meine Ideen, ob das so klappt wie ich mir das Vorstelle wird sich noch zeigen.
Mit dem "letzten Kanal merken" : Kann ich das mit einer BackupBatterie bewerkstelligen? Oder wäre es eine gute Idee die Daten im Eeprom abzulegen?
Im Eeprom wäre das Problem(?) das ständig geschrieben wird.

Michael
 
Hallo Michael,

um sich den zuletzt eingestellten Kanal zu merken, würde ich das EEPROM verwenden. Man könnte natürlich bei jeder Änderung des Kanals diesen sofort im EEPROM speichern, man darf eine EEPROM-Speicherstelle jedoch nur 100.000mal beschreiben, danach kann es zu Fehlern kommen.

Mir fallen zwei Möglichkeiten ein, dies eleganter zu lösen:
  • Eine Memo-Taste spendieren (ok, nicht elegant, aber schützt das EEPROM ;))
  • Den Komparatoreingang des AVRs verwenden. Zwei Widerstände in Reihe (5V ... GND), noch zwei Widerstände in Reihe (Ub ... GND). Jeweis den Mittelabgriff eines Spannungsteilers an invertierenden und nicht-invertierenden Komparatoreingang. Schaltest du aus, bricht Ub zusammen, 5V nach dem Spannungsregler bleiben noch einige Zeit stabil. Es wird ein Komparatorinterrupt ausgelöst, in dessen Interruptroutine man den aktuellen Kanal im EEPROM speichert. (Werte der Widerstände sind abhängig von den Betriebsspannungen) Wichtig ist nur, dass die 5V wenigstens so um 20ms nach Ausschalten stabil bleiben, da Speichern ins EEPROM etwas dauert.
Bin mal gespannt, wie du das mit dem "scannen" machen möchtest.

Dirk
 
Tja, wie möchte ich das machen ?!
Einen weiteren PinD mit einem Taster verbinden, verwzeigt zu einem Zähler ....
Eine Spannung aus dem Empfänger abzwacken, wenn diese Spannung eine bestimmte Größe hat, wird ein weiterer PinD Low gelegt und springt aus dem Zähler ...

Was passiert überhaupt mit PortE? Der hat ja nur 3 Anschlüsse, lässt sich aber mit allen 8Bits ansprechen, ohne dass es eine Fehlermeldung gibt.
Wird das bei PortE wirklich einfach so ignoriert, oder passieren da dann andere Dinge?
 
Ich hab mal wieder eine Frage:

Betrifft:
.equ MAX_DisplayNumber = 80 ; Hier den Maximalwert und den Minimalwert für
.equ MIN_DisplayNumber = 0 ; DisplayNumber definieren

".equ" kann man wohl hinschreiben wo man will, es wird immer gelesen?

Wenn ich jetzt eine 2. Kanalliste (in meinem Fall die englischen Kanäle), müsste ich den MaxWert auf 40 setzen (weil nur 40 Kanäle sind).

Ich wollte eine Verzweigung so machen :
...
sbis PortD,Pin2
.equ max=40
.equ max=80
...

Geht aber nicht ?! Warum geht das nicht, und was muss ich machen damit es geht?

Genau so wollte ich mit "sbis" zum anderen PLL-Table verzweigen, bin ich da denn so falsch mit?
 
Alles was mit "." beginnt (z.B. .org, .equ, .cseg usw.) sind Assemblerdirektiven, also Anweisungen an den Assembler, die der Assembler während der Assemblierung abarbeitet.

Wenn du zum Beispiel ".equ Maximalwert = 100" schreibst, wird überall in deinem Programm "100" eingesetzt, wo "Maximalwert" steht.

Um in deinem Fall unterschiedliche Maximalwerte zu setzen, könntest du eine neue Variable einführen. Definierst du zum Beisspiel im SRAM die Variable "Maximalwert: .byte 1", so könntest du den Maximalwert folgendermaßen umschalten:
Code:
ldi RegA, 80
sbis PIND, PIND2     ; PinD nicht PortD !
ldi RegA, 40
sts Maximalwert, RegA
Die Routinen IncDisplayNumber und DecDisplayNumber müsstest du dann ändern, Beispiel:
Code:
IncDisplayNumber:
   lds RegA, Maximalwert
   cpc DisplayNumber, RegA
   brsh incdn_setmin

   inc DisplayNumber
   ret

incdn_setmin:
   ldi DisplayNumber, MIN_DisplayNumber

ret

DecDisplayNumber:

   cpi DisplayNumber, MIN_DisplayNumber
   breq decdn_setmax
   
   dec DisplayNumber
   ret   
   
decdn_setmax:
   lds DisplayNumber, Maximalwert
ret
Wenn du allerdings gerade Kanal 60 eingestellt hast und schaltest um auf englische Kanäle, wird solange 60 angezeigt, bis du Plus oder Minus drückst. Das ist aber durch ein bisschen Code lösbar.
 
OhJehh, nicht mal der Anfang gelingt mir (Variable zuweisen).

Unter ".dseg" habe ich eingefügt:
MAX_DisplayNumber: .byte 1

Vor dem "Mainloop" habe ich eingefügt:
ldi RegA, 40
sts MAX_DisplayNumber, RegA

Ausgegeben wird mir:
C:\assembler\uk-2.asm(392): error: Operand(s) out of range in 'cpi r25,0x100'
C:\assembler\uk-2.asm(412): error: Operand(s) out of range in 'ldi r25,0x100'
C:\assembler\uk-2.asm(817): warning: .cseg .db misalignment - padding zero byte


Kommt davon wenn ich immer alles nur abschreibe *grins* , aber ich finde den Grund für die Fehlermeldung nicht?
 
Kannst du mir den aktuellen Stand des Programms einmal mailen oder hier als Anhang posten, ich kuck mir das auf meinem Rechner an.

Gruß
Dirk
 
Hallo Dirk!

Die Datei habe ich mal angehängt ....

Während dessen habe ich noch ein wenig weiter (andere Dinge) probiert, und bin doch schon wieder auf ein Problem gestossen :

Wird PortD,Pin2 auf Masse gelegt, soll am PortC das ausgegeben Byte den Wert 1 weniger ausgeben:


DecodePLLValue:

mov RegA, DisplayNumber

ldi r30, LOW(2*PLLTable) ; Anfangsadresse der Tabelle in das z-Register
ldi r31, HIGH(2*PLLTable)

add r30, RegA ; hier den Offset addieren, also
clr RegA ; z = z + RegA
adc r31, RegA ; jetzt zeigt z auf den Eintrag mit dem Offset RegA

lpm ; load program memory (Byte aus Flash mit Adresse z lesen)

mov RegA, r0 ; Ergebnis ist im Register r0, r0 nach RegA kopieren (muss
; man nicht, aber es ist besser wenn man immer mit bestimmten
; Registern arbeitet, um eine Struktur in seine Software zu bekommen)

ldi rege,1
sbic portd,pd2
sub rega,rege ;


out PortC, RegA

ret

Sinn der Sache soll sein, dass wenn man einen Schalter betätigt, das Gerät 10Khz höher schaltet.
Ich habe das direkt in die Ausgabe für PortC gebaut, würde also eigentlich nur funktionieren, wenn ich nach dem drücken des Schalters einen Kanalwechsel vornehme. (Blöd, aber für den Versuch würd das ja reichen).
Funktioniert allerdings nicht. Sobald ich "sbic" bzw "sbis" entferne, gehts :confused:
 

Anhänge

  • uk-2.zip
    5,7 KB · Aufrufe: 3
Ich sehe mir das Programm morgen mal genauer an, heute komme ich nicht mehr dazu.

Was mir aufgefallen ist:
Code:
[COLOR=Red]   [COLOR=black]ldi rege,1       
[COLOR=DarkRed][B]    sbic portd,pd2 [/B][/COLOR]
   sub rega,rege ; [/COLOR][/COLOR]
   
   out PortC, RegA
Wenn du Portpins abfragst, musst du das Register PIND, nicht PORTD ansprechen, also

Code:
sbic PinD, PD2
 
:eek: Das war der Fehler :eek:

Danke dir, mein Abend ist erstmal gerettet.
Dir auch einen schönen Abend noch...


Wenn du Morgen (oder demnächst) in den Code rein schaust, verrat mir doch mal wo ich die Scan-Funktion einfügen kann.
Überlegung ist im Mainloop Pind,pd3 abzufragen, verzweigt nach "Scan:"
Scan:

inc Displaynumber
rcall LEDDisplay
rcall DecodePLLValue

ret

Eigenartigerweise führt das Proggy ein Reset durch sobald ich PD3 low lege.

Ist Mainloop: nicht der richtige Ort um Pin`s abzufragen, oder liegt der Fehler wieder ganz wo anders?
 
Hallo Michael.

Eigenartigerweise führt das Proggy ein Reset durch sobald ich PD3 low lege.
Wahrscheinlich springst du mit einem rjmp zu Scan, ich kann das aus deinem letzten Programm nicht ersehen, da dort die Scan-Routine noch nicht enthalten ist. Du beendest Scan mit einem ret. Bei ret wird die Adresse vom Stack in den Program Counter (PC) geladen, die zuvor durch z.B. rcall auf den Stack gelegt wurde. Wenn du mit rjmp zu Scan springst, wird keine Adresse auf den Stack gelegt. Wird die Routine Scan mit ret beendet, so befindet sich eine falsche Adresse auf dem Stack, das wird entweder zum Absturz oder in deinem Fall zu einem Reset führen.

Ist Mainloop: nicht der richtige Ort um Pin`s abzufragen, oder liegt der Fehler wieder ganz wo anders?
Du kannst überall im Programmverlauf Portpins abfragen, es gibt hier keine Einschrängungen.

Interessant wäre noch zu wissen, was du genau vorhast, ich könnte dir da vielleicht noch ein bisschen Code schreiben und dabei gleich in die "richtige Richtung" programmieren. So wie ich das bis jetzt verstanden habe ...
  • 2 Kanalbereiche (Kanal 0 bis 80, Kanal englisch 0 bis 40), mit einer Taste umschaltbar?
  • 10kHz hochschalten wenn eine Taste gedrückt wird (Taste zum an/abschalten der Funktion). An dem Anzeigewert ändert sich hierbei nichts? Eventuell signalisieren der 10kHz Funktion über LED? Es wird hier einfach nur der Wert für PLL geändert (ein konstanter Wert addiert)?
  • Scan-Routine wird durch Taster ausgelöst? Kanäle einfach durchlaufen und auf Pegel an einem Pin reagieren (stoppen)? Oder soll der PLL-Wert feiner geändert werden? Wie schnell darf der PLL-Wert geändert werden, bzw. wie schnell ist neue Frequenz im Receiver eingestellt und Senderpegel stabil? Ist der Pegel analog oder digital?
Gruss
Dirk


 
Hallo Dirk.

Ja, ich springe mit rjmp zum Scan: ! Richtig wäre rcall, ja ?!

Bei dem Programm finde ich durch die ganze "Springerei" gar nicht mehr durch, was ganz und gar durcheinander wirft ist die Reihenfolge des Ablaufs.
Daher habe ich noch das Problem, dass ich nicht weiß wo ich welche Variablen "abzwacken" kann oder andere Funktionen einfügen kann. Der Ablauf bis eine Taste gedrückt wird, habe ich noch nicht richtig geblickt.

Vorhaben tu ich :

1. 2 Bänder, einmal 80, einmal 40 Kanäle (jeweils auch andere Werte an PortC), zu schalten über ein Pin (high=80, low=40)

2. Ein Pin auf Low geschaltet = +10 Khz, also den Wert an PortC um Eins erhöhen, Kanalanzeige soll allerdings gleichbleiben. Schlecht wär nicht wenn dann der DezimalPunkt von der Anzeige an PortA dann leuchtet.

3. Scannen: wird ein Pin kurzzeitigt Low getastet werden die Kanäle aufwärts durch geschaltet. Verzögerung schwer zu sagen, vielleicht 250mS?!
Wird nun zusätzlich ein weiterer Pin auf Low gelegt (gesteuert über die Regelspannung des Empfängers), geht die Scanfunktion aus und wartet wieder auf Eingabe. Eine Digitale Auswertung des Signals reicht also vollkommen aus.
Möglich sollte ein Beenden des Scanns auch sein, in dem zB der Pin für scan noch mals, oder Up/down betätigt wird.


Puhh, das ist ne ganze Menge.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)