Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega16 Rechtecksignal ausgabe!!!
wistudent
08.01.2007, 04:34
Hallo zusammen!
Ich muss ein Programmentwickeln, das auf dem Ausgabepin C0 ein Rechtecksignal ausgibt,
dessen Periodendauer in Millisekunden über den am 8–Bit–Eingabekanal PortA anstehenden
Wert festgelegt werden kann: Liegt dort z.B. der Wert 0000 0101 entsprechend
dezimal 5 an, so soll die Periodendauer ca. 5 msec betragen. ¨Anderungen am Eingabekanal
sollen sich ohne Neustart des Programms direkt auswirken.
ach ja und dann noch ein Unterprogramm, das eine Zeitverzögerung von exakt 1msec erzeugt.
Die Ausführungszeiten der benoetigten CALL und RETURN Befehle sollen dabei mit
berücksichtigt werden.
Kann mir hier vielleicht einer helfen, leider komm ich damit garnicht weiter...
muss in assembler programmieren,und leider bin in noch ganz frisch in diesem thema :(
Also ich würd das mit dem Rechtecksignal mit einem Comparematch Interrupt mit dem Timer1 machen.
Wenn Du die Taktfrequenz geschickt auswählst Ich würd vermutlich 8 MHz nehmen kommst Du auf deine gewünschte Periodendauer.
In das Comparematch Vergleichsregister trägst du je nach gewünschter Periodendauer den Vergleichswert ein (Tabelle oder den Controller rechnen lassen). Der Vergleichswert sollte der halben Periodendauer entsprechen, weoil Du ja eine positive und eine negative Halbwelle brauchst.
Wenn dann der Timer diesen Wert erreicht hat löst er einen Comparematch Interrupt aus. Der interne Timer wird wieder auf 0 gesetzt, was man auch durch setzen eines Bits machen kann.
In der gleichen Routine wird dann dein Port C0 von 0 nach eins bzw. von 1 nach 0 gesetzt.
Die Abfrage von deinem Eingangsport PortA sowie die Neubeschreibung der Comparematchwerte würd ich auch in dieser Interrupt Routine machen um Überholeffekte zu vermeiden.
Ob Du die Abfrage von PortA, sowie die Berechnung des Comparematchwertes in den Interrupt reinkriegst ist vor allem ein Timingproblem. Vor allem wenn eine Periodendauer von 1mS = 0,5mS für eine halbe Periode gefordert wird.
Während des Schreibens der Comparematchwerte in ein Hilfsregister, das dann später in der Comparematch Routine abgefragt wird würd ich mit "CLI" eine Interruptausführung kurz unterbinden um zu Vermeiden, das zwischen dem Schreiben der beiden Bytes ein Interrupt auftreten kann.
Wie genau diese Routine arbeitet ist hauptsächlich davon abhängig wieviele andere Interrupts auch noch aktiv sind, weil ein aktiver Interrupt die Ausführung eines weiteren verhindert.
Ausserdem solltest Du die Abschaltung von Interrupts mit "CLI" im Hauptprogramm möglichst vermeiden und die Befehle bis zum "SEI" auf ein minimum beschränken, da es sonst zu einem kleinen Phasenjitter kommen kann.
Ein weiterer Punkt ist im Tastverhältnis versteckt.
Wenn ein Tastverhältnis von genau 50% gefordert ist musst Du dafür sorgen, das in diesem Comparmatchinterrupt genau gleich viele Taktzyklen fur das Ausschalten, sowie für das Einschalten des Ports C0 gebraucht werden.
Eine möglichkeit wäre den PORTC0 in ein Register einzulesen, mit EOR 0b00000001 das letzte Bit umzukehren und den Registerwert wieder in den PORTC zurückzuschreiben.
Da dabei immer die gleiche Befahlsanzahl durchlaufen wird, sollte auch das Tastverhältnis genau 50% betragen.
Versuchs mal es ist eigentlich einfacher als man denkt.
Die 1ms Zeitschleife würd ich einfach mal ins Blaue (so ungefähr)programmieren und mit dem Simulator (AVR STudio 4) die genauen Zeiten austesten.
Normalerweise zählt man dazu einfach irgendwelche vorbelegten Registerwerte runter bis die 0 erreichen und springt dann aus der Routine wieder raus. Wenn während der Zählschleife natürlich Interrups auftreten braucht die Zeitroutine natürlich für die Abarbeitung mehr als 1ms.
Wenn Du natürlich einen mathematischen Weg für sowas brauchst musst Du halt ein wenig rechnen.
MartinFunk
08.01.2007, 14:24
Hi,
kann der ausgang des rechtecksignals auch an PORTD 4 ausgegeben werden?
Dann könntest du nämlich PWM verwenden und den wert von PORTA ins Output Compare Register schreiben.
MfG Martin
wistudent
08.01.2007, 14:50
Hallo, danke für deine Hilfe wkrug...
Aber leider komme ich immer noch nicht mit der Assembler programmierung klar, wie ich das alles zusammen schreibe!
:(
Und leider benötige ich das schon für morgen!
Ich bin schon die ganze zeit am arbeiten,habs aber leider noch nicht hinbekommen...
Mfg
Aber die Aufgabe hast Du sicher nicht erst seit gestern, oder?
Wenn Du bis jetzt nicht die Befehle "zusammengeschrieben" bekommst, solltest Du lieber um Aufschub bitten anstatt zu hoffen, dass Du durch ein Wunder die Assemblerprogrammierung, die Funktionsregister und die Timer des AVR verstehst. Und wenn Du einen neuen Zeitrahmen hast, dann noch mal detailliert und von anfang an das Problem beschreiben und vor allem: wie weit Du eigentlich schon bist.
na Du bist witzig, so mal über Nacht ....
wichtige Infos fehlen:
Welcher Controller in welcher Sprache zu programmieren?
Sonstige Funktionen?
in Bascom währen das so auf die Schnelle,
wenn der Controller nix anderes machen soll
irgendwas um die 6-7 Codezeilen, das währ in
5 Minuten machbar
(Mainloop mit Pinabfrage und waitms und toggle portd.4 oder wars portc.0?
ist ja auch wurscht welcher)
... in ASM ists natürlich ne andere
Geschichte, sprich n paar Zeilen mehr.
Muss der Ausgabepin unbedingt PortC,0 sein ?
Wenn du den PortD,4 oder PortD,5 verwenden könntest würde deine Frequenzausgabe ohne weiteres zutun laufen. Stichwort OC1A OC1B pin.
Du müsstest dann halt nur die Comparematch Register OCR1AH und OCR1AL mit den richtigen Daten füttern.
Die nötigen Informationen über den Timer 1 findest Du im Datenblatt des ATMEGA 16 auf Seite 87...115.
Die allgemeine Timer Beschreibung ist für den Prescaler (Vorteiler) wichtig.
Mit ein bischen Assemblerkenntissen und ein wenig Mühe sollte sich sowas innerhalb von 5..6 Stunden proggen lassen (inkl. Datenblatt lesen).
Übrigens solltest Du während einer Interruptroutine alle benutzten Register inklusive Statusregister auf dem Stack sichern un später auch wieder runterholen.
bsp:
tim1cmp_int:
PUSH r16
IN r16,SREG
PUSH r16
PUSH r17
; Dein Interrupthandlerprogramm welches r16 und r17 benutzen will.
POP r17; Werte in umgekehrter Reihenfolge vom Stack holen
POP r16
OUT SREG,r16
POP r16
RETI ; Der Aussprung aus einer Interruptroutine ist immer RETI !
Damit das auch so klappt musst Du am Anfang deines normalen Programmes den Stack initialisieren.
LDI r16,low(RAMEND)
LDI r17,high(RAMEND)
OUT SPL,r16
OUT SPH,r17
Die Interruptvektortabelle muss natürlich auch stimmen, aber das ist im Datenblatt auf Seite 43 bestens beschrieben.
Nicht benutzte Interrupts solltest du mit dem Befehl RETI belegen, damit dein Controller keinen Blödsinn macht.
Beispiel:
.CSEG
.org 0
jmp RESET ; Reset Handler
RETI ; IRQ0 Handler
RETI ; IRQ1 Handler
RETI ; Timer2 Compare Handler
RETI ; Timer2 Overflow Handler
RETI ; Timer1 Capture Handler
jmp TIM1_COMPA ; Timer1 CompareA Handler
jmp TIM1_COMPB ; Timer1 CompareB Handler
RETI ; Timer1 Overflow Handler
jmp TIM0_OVF ; Timer0 Overflow Handler
jmp SPI_STC ; SPI Transfer Complete Handler
jmp USART_RXC ; USART RX Complete Handler
jmp USART_UDRE ; UDR Empty Handler
jmp USART_TXC ; USART TX Complete Handler
jmp ADCC ; ADC Conversion Complete Handler
jmp EE_RDY ; EEPROM Ready Handler
jmp ANA_COMP ; Analog Comparator Handler
jmp TWSI ; Two-wire Serial Interface Handler
jmp EXT_INT2 ; IRQ2 Handler
jmp TIM0_COMP ; Timer0 Compare Handler
jmp SPM_RDY ; Store Program Memory Ready Handler
Ich hoffe die Informationen haben Dir weitergeholfen.
Schreiben solltest Du dein Prog schon selber.
Hi Vitis:
Controller: Atmega16 (Threadtitel)
Sprache: Assembler ("muss in assembler programmieren")
Sonstige Aufgaben wird er wohl nicht haben, sonst hätte er danach gefragt ;)
Gruß, CowZ
ok, ASM bin ich nicht bewandert, aber im Prinzip kannstes ja
recht einfach realisieren, sprich Timer weglassen und ne
Warteschleife.
Wenn ich so auf die Schnelle was in ASM bräucht würd ich folgendes
machen.
Ich würds in Hochsprache Coden und mir die Kompilierte Geschichte
dann straffen. Die Hex von Bascom oder GCC kannste im AVR-Studio
ja decompilieren.
Ich würds in Hochsprache Coden und mir die Kompilierte Geschichte
dann straffen
So Einfach gehts dann doch nicht, weil eine Hochsprache erstmal eine ganze menge "Müll" definiert bevor der eigentliche Code losgeht.
Mein Codevision löscht erstmal das ganze RAM und schreibt eine eigene Datei für die Interruptvektortabelle.
BASCOM sichert bei einem Interruptaufruf z.B. immer (kann man aber abschalten) den kompletten Registersatz.
Da sieht man auf den ersten Blick, das das von nem Compiler produziert wurde.
Ausserdem fehlen die ganzen Kommentare sowie teilweise die Variablenzuweisungen.
Um vernünftig in ASM zu proggen braucht man ohne Vorkenntisse fast ein Jahr, mit Vorkenntnissen gehts auch in 1 bis 2 Monaten.
Was nicht geht ist sowas über Nacht zu lernen (ohne wistudent entmutigen zu wollen).
wistudent
08.01.2007, 21:48
Hey leute danke sehr für eure Hilfen ...
Hab es grad eben noch hinbekommen,
war doch nicht so schwer zuprogrammieren, mir haben nur paar Grunddaten gefehlt ;)
Aber soviel war garnicht gefragt, ich setze einfach die Ausgabe PINC0 auf low und auf high, und dabei lass ich immer dazwischen eine Zeitschleife laufen, somit bekomme ich mein Rechtecksignal.
Zeitschleife beträgt 1m/sec. Und mit der eingabe in PINA kann man wählen wie lange die Zeitschleife laufen soll.
Nur ein Problem habe ich da noch, undzwar wenn ich für PINA nichts eingebe,
sollte er normal garnicht im Loop arbeiten und auf ret gehen,
aber er fängt von FF an runterzuzählen.
Ab der eingabe 1 in PINA macht der das nicht mehr...
Danke nochmal vielmals
MFG
wistudent
08.01.2007, 21:51
wartms:
; warte 3999 Zyklen:
in r17, PinA
LOOP: ldi r18, $1F
LOOP0: ldi r19, $1A
LOOP1: dec r19
brne LOOP1
dec r18
brne LOOP0
dec r17
brne LOOP
; warte 1 Zyklus:
reti
hier zum besseren Verständnis!
Mach doch eine Abfrageroutine vor deiner Zeitschleife rein
IN r17,PINA
TST r17
BRNE weiter
CBI PORTC,0
JMP ENDEROUTINE
weiter:
hier geht dein ASM PROG weiter.
Durch Deine Art der Ausgabeprogrammierung kann dein ATMEGA 16 aber keine anderen Aufgaben mehr ausführen als ein Rechtecksignal zu erzeugen, weil sonst deine Zeitschleife unterbrochen wird und die Frequenz somit nicht mehr stimmt.
Für nen Test mag das ja OK sein im richtigen Leben wäre sowas aber Käse.
Na also, so schlecht wie zunächst dargestellt können Deine ASM-Kenntnisse also kaum sein. Was Dein FF statt 0-Problem angeht: wie legst Du denn den Wert an PortA an? Bzw.: ist PortA offen, wenn nichts angelegt ist? Das würde dann ja das FF bei aktiven Pullups erklären. Oder hab ich jetzt was übersehen?
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.