Microcontrollerprobleme; Assembler

Guten Tag an Alle!
Also ich habe letztenz versucht einen PIC12F629 zu programmieren, aber der PIC tut absolut gar nichts.

Das Programm ist eigentlich ganz einfach:

  1. Als erstes wird der PIC konfiguriert
  2. werden die Register vergeben
  3. das programm wartet für 2s in abständen von 0,125s auf ein high von GPIO, 4
  4. wenn ja springt das programm zur entscheidungspause, damit man sich nicht vertippen kann, und wartet dann wieder für 2s auf ein high von GPIO, 4 und würde auf ein weiteres high zu programm3 wechseln, wenn kein high da ist wird gewechselt zu programm2
    4a.wenn nein,bezogen auf 3., dann wird gewechselt zu programm1
    5.Das jeweilige Programm wartet jetzt die Zeitschleifen ab und macht währendessen eine LED an
  5. ist die Zeit abgelaufen, so wird die Zündug aktiviert also GP1 high geschaltet
  6. zuletzt kommt der PIC in eine endlos schleife solange bis er abgeschaltet wird oder er keinen Saft mehr hat.

Das Programm hat den Sinn, wie eine Art Countdown zu funktionieren.
Quellcode:
http://bitshare.de/download.php?file=651189

Errorlog:
http://bitshare.de/download.php?file=407957

Habe ich ein falsches Programm geschrieben oder es nur falsch rein gebrannt oder sonst einen Fehler gemacht???
Ich bin da noch voll der Anfänger.

Vielen Dank für eure Antworten

Hallo Fragewurm,

Vorab: Mit den PIUCs habe ich noch nicht gearbeitet.

Ich sehe aber zwei Fehler welche du begangen hast.

  1. Wenn der Linker Errors bringt, wir dein Programm nicht funktionieren, also ist brennen zwecklos.

  2. Alle CPUs müssen nach einem Reset „irgendwo“ mit der Programmabarbeitung anfangen. Damit dieses „irgendwo“ reproduzierbar ist ist es in der Hardware fest eingebaut.

a) Entweder beginnt eine CPU an einer ganz bestimmten Adresse damit den ersten Befehl zu laden. Das bedingt, dass das Programm auch an dieser Stelle abgelegt wird, wofür der Programmierer verantwortlich ist.

b) Meist arbetet man aber mit einem Reset-Vektor. Dies ist eine in der Hardware festgelegte Speicheradresse, aus welcher sich die CPU nach einem Reset die Adresse ausliest unter welcher dann der erste Befehl abgelegt ist. AUch hier ist der Programmierer verantwortlich, dass die Daten und der Code richtig im Speicher abgelegt werden.

In deinem Code kann ich diese Adressen nicht finden.

MfG Peter(TOO)

Hi,

Das Programm ist eigentlich ganz einfach:

Du hast erstmal nicht die Assembler Direktive .org vergeben. Damit werden Programmadressen festgelegt.
Die ersten 5 Programmadressen sind reserviert, 0 ist für den Resetvektor, 4 ist für den Interrupt. Schau mal ins Datenbuch. Bei 0 steht der Resetvektor. Dorthin gehört der Sprung zum Beginn des Hautprogrammes.

Als Idee, wenn du keinen Interrupt benutzt:

.org 0
goto Haupt

.org 5
Haupt:

Dann mußt du noch aufpassen, in welcher Bank welche Register zu finden sind. Da tun sich gewaltige Fettnäpfchen auf.

mfg Ulrich

Fehlerliste / Programmbeispiel
Hallo Beahr,

bitte sei mir nicht böse, aber wenn ich mir Deinen Quelltext ansehe, kommt mir das Grausen weil er so unübersichtlich und wirr ist.

Nun, ich habe folgende Fehler in Deinem Quellcode gefunden:
1.) wie andere schon festgestellt haben, musst Du da, wo Dein Hauptprogramm beginnt ein „org 0x00“ hinsetzen. Gleich danach schreibst Du: „goto init“, wobei Du unter dem Label „init“ alle erforderlichen Special-Funktion-Register mit den gewünschten Startwerten initialisierst.
2.) Im Register „CMCON“ setzt Du Bits, ohne dass Du es zuvor unter „Register benennen“ deklariert hast.
3.) unter „internen Taktgenerator kalibrieren“ rufst Du mit „call“ einen hex-Wert auf. Mit „call“ kannst Du nur ein Unterprogramm aufrufen. Um einen Wert (Konstante) in den Akku zu laden, verwendet man den Befehl „movlw 0xFF“. Du verstehst aber besser was Du tust, wenn Du statt eines Hex-Wertes einen Dezimalwert oder eine 8 Bit-Konstante in den Akku lädst:
a) Dezimalwert (100) in Akku laden: movlw d’100’
b) Die Zahl „7“ als Binärwert in Akku laden: movlw b’00000111’
4.) Das OSCCAL-Register hast Du auch nicht deklariert.
5.) Die Variable „Zähler4“ hast Du in einem nicht vorhandenen RAM-Bereich (4fh) deklariert.
6.) Um einem Register einen selbstgewählten Namen zu geben, musst Du die „#Define“-Anweisung verwenden, und nicht die equ-Anweisung.
Beispiel: #Define Tris_Reg trisio ;mit dieser Anweisung erhält das Register „trisio“ den Namen „Tris_Reg“. Zuvor muss aber das „trisio“-Register deklariert werden mit „trisio equ 0x85“.
7.) Du löscht das Trisio-Register im Deklarationsteil: das geht nicht!
Prozessorbefehle kannst Du nur im Hauptprogramm ausführen, d. h. nach der Startadresse des RESET-Vektors „org 0x00“. Wie oben erwähnt gehst Du nach der Anweisung „org“ erst einmal zur Initialisierung (Label: „init“), um dann dort jedem deklarierten Register den gewünschten Startwert zu geben. Beachte, dass Du vor dem Label „init“ schreibst: org 0x06!
8.)Du möchtest den Pin 3 (GP4) als Eingang deklarieren, verwendest aber einen Befehl mit dem Du ihn als Ausgang setzt. Richtig muss es heissen: „bsf Tris_Reg,4“
9.) Im Hauptprogramm lädst Du die Zahl „24“ in den Akku, wobei weder Du noch der Prozessor erkennt, welches Zahlenformat Du dieser Zahl gegeben hast. Wenn Du eine Dezimalzahl meinst, verwende den Befehl: „movlw d’24’“.
10.) Die Unterprogramme setzt man in der Regel oberhalb des Hauptprogramms weil dies der besseren Übersicht dient.

Hier ein Beispiel für einen übersichtlichen Programmkopf:
;----------------------------------------------------
; Projektname: LED-Zeitschalter
; Datum : 22.10.2006 Name:_ _ _ _ _ _ _
; Prozessor: PIC12F629-I/SN
;----------------------------------------------------

;--------- Konstanten-Deklarationen -----------------
#Define Millisek d’10’ ;Dezimalwert für 1ms
#Define _1_Sek d’100’ ;Dezimalwert für 1 Sek

;--------- Portregister-Initialisierungs-Konstanten -
#Define TrisA_init b’11101100’ ;
#Define TrisB_init b’11000000’ ;
#Define PortA_init b’00010000’ ;
#Define PortB_init b’00000000’ ;

;--------- Tris-Deklarationen -----------------------
#Define Tr_LED_1 TrisA,0 ;
#Define Tr_Eingang TrisB,1 ;
#Define Tr_LED_rot TrisC,1 ;

;--------- Port-Deklarationen -----------------------
#Define LED_1 PortA,0 ;Alles OK-LED
#Define Eingang PortA,1 :stuck_out_tongue_winking_eye:rüfeingang
#Define LED_rot PortA,2 ;Fehler-LED

;--------- Port-Register ----------------------------
PortA equ 0x05 ;B0
PortB equ 0x06 ;B0
PortC equ 0x07 ;B0

;--------- Tris-Register ----------------------------
TrisA equ 0x85 ;B1 (Bank_1)
TrisB equ 0x86 ;B1
TrisC equ 0x87 ;B1

;--------- SPECIAL-Function-Register ----------------
status equ 0x03 ;B0/B1 Status-Register
option_reg equ 0x81 ;B1 Option Register
wpub equ 0x95 ;B1 Weak-Pull-up-Register
osccon equ 0x8F ;B1 Oszillator Steuerregister
cmcon equ 0x19 ;B0 int. Comparator

;--------- Timer-Register ---------------------------
tmr0 equ 0x01 ;B0 Timer0-Register
t1con equ 0x10 ;B0 Timer 1
tmr1_L equ 0x0E ;B0 Timer1 LOW -BYTE
tmr1_H equ 0x0F ;B0 Timer1 HIGH-BYTE

;--------- RAM - Variablen --------------------------
zähler_1 equ 0x20 ;Zählvariable für 1 Millisek
zähler_2 equ 0x21 ;Zähler für 1 Minute
zähler_3 equ 0x22 ;Zähler für 1 Stunde

;----------------------------------------------------
;Unterprogramme
;----------------------------------------------------
;UP 1: LED1_on (LED1 einschalten)
;-----------------------------
LED1: bsf GPIO, 0
return

;-----------------------------
;UP 2: LED1_off (LED1 ausschalten)
;-----------------------------
LED1: bcf GPIO, 0
return

;-----------------------------

;XXXXXXXXXXXXXXXXX Hauptprogramm XXXXXXXXXXXXXXXXXXX

reset: org 00 :stuck_out_tongue_winking_eye:osition des Reset-Vektors
goto init
org 06 ;Start Programmcode

;----------------------------------------------------------
;initialisiere Register und Variablen mit Startwerten
init: bsf status,5 ;Bank_1
movlw TrisA_init ;lade Init-Wert in Akku
movwf TrisA ;schreibe in TRIS-Register
movlw b’00000111’ ;lade Bitmaske für CMCON
bcf status,5 ;Bank_0
movwf cmcon ;deaktiviere internen Comparator

movlw PortA_init ;lade Init-Wert in Akku
movwf PortA ;schreibe Anfangswerte in Port A

clrf zähler_1 ;lösche Zähler_1
clrf zähler_2 ;lösche Zähler_2
movlw Millisek ;lade INIT-Wert für Zähler_3
movwf zähler_3 ;schreibe Startwert in Zähler_3

goto start ;Initialisierung fertig --> geh zum HP
;----------------------------------------------------------

;frage PIN3 in Abständen von 0,125 Sek. ab
start: btfss Eingang ;prüfe ob Eingang = HIGH
goto weiter ;Eingang ist LOW --> mach weiter
call LED_1_an ;Eingang ist HIGH --> LED_1 einschalten
goto pause_1 ;LED wurde eingeschaltet --> mach Pause

weiter: decfsz Zähler_3 ;warte 1 Millisekunde
goto weiter ;1ms noch nicht vorbei --> dec zähl_3
call LED_1_aus ;Zeit abgelaufen --> schalte LED_1 aus
goto start ;wiederhole Hauptschleife

pause_1:nop ;warte
nop ;
nop ;
goto start ;geh zurück zu Hauptschleife

end :stuck_out_tongue_winking_eye:rogrammende

So, dies mal als kleines Beispiel dazu was Übersicht bedeutet.
Ich hoffe Du kommst mit diesen Tips etwas weiter.

Gruß, Alexander

Assemblerprobleme
Hallo.
Ich habe ein Problem. Der Assembler zeigt mir beim assemblieren einen ERROR an und zwar das:
Error[118] Overwriting previous address contents

Was soll ich überschrieben haben?
Hat jemand diesen Fehler schon mal gehabt?
Was macht man dagegen?

Danke für allle Antworten

Hallo,

Ich habe ein Problem. Der Assembler zeigt mir beim
assemblieren einen ERROR an und zwar das:
Error[118] Overwriting previous address contents

Mein Auto zeigt mir einen Fehler an. Was kostet die Reparatur?

Offensichtlich ist das eine Frage, die man nicht ohne weitere Infromationen beantworten kann. Genauso verhält es sich mit Deiner Frage hier. Wenn man den Quelltext nicht kennt und keine Ahnung hat, in welcher Zeile des Quelltextes der Fehler gemeldet wird, kann man Dir keine sinnvolle Antwort geben.

Wie wäre es denn, wenn Du mal in ein Wörterbuch schaust, was die Fehlermeldung übersetzt heißt? Und danach ins Handbuch des Assemblers, was über diese Fehlernummer gesagt wird? Und dann schaust Du in die Zeile des Quelltextes, was dort passieren soll und was abweichend davon tatsächlich passiert.

Ich bin mir noch nicht darüber im Klaren, was Du eigentlich vorhast: Möchtest Du gern Programmieren lernen, ist dieses Programm eine Haus- oder Diplomarbeit, geht es um ein konkretes Projekt? Ist das Programmieren eher lästiges Beiwerk, Hauptsache das Ding funktioniert?

Gruß
loderunner

Quelltext:
http://z06.zupload.com/download.php?file=getfile&fil…

Errorlog:
http://z06.zupload.com/download.php?file=getfile&fil…

Hallo,

http://z06.zupload.com/download.php?file=getfile&fil…

Hast Du Dir mal angeschaut, was genau die einzelnen Zeilen dieser Datei anzeigen?
Zuerst kommt jeweils die Meldung ‚Error‘ oder ‚Warning‘. Darauf folgt in eckigen Klammern die Nummer der meldung (die auch im Handbuch dann nachzulesen ist). Es folgt der Name der Datei, auf die sich die Meldung bezieht. Die Nummer dahinter ist die Zeilennummer, in der der Fehler bemerkt wurde (das muss nicht immer die Zeile sein, in der sich der Fehler befindet - er kann sich auch darüber befinden, aber niemals darunter). Und schließlich folgt noch die Bezeichnung des Fehlers im Klartext, ggf. mit einem zusätzlichen Hinweis in Klammern.

Wenn man mal in die von Dir verlinkte Datei schaut, steht da schonmal in Zeile1 , dass eine Datei nicht gefunden wurde. Bei dieser Datei handelt es sich (schließe ich aus dem Dateinamen) um Definitionen für den verwendeten Prozessor. Schau mal ins handbuch, wo die Datei stehen sollte oder wie der Pfad zur Datei angegeben werden muss.

In Zeile2 kommt eine Warnung (und die folgt dann noch endlos oft auf andere Quelltextzeilen bezogen), dass Du ein Label nicht wie vorgeschrieben in der ersten Spalte definiert hast. Grund ist: Du beginnst jede Zeile mit einem Leerzeichen. Lass das weg, das sieht schön aus, hat aber in einem Assemblerquelltext nichts zu suchen.

Dann kommt ein Error113, weil Du ein vorher nicht definiertes Label vwerwendest. Auf die gleiche Quelltextzeile (57) bweziehen sich auch die beiden folgenden Error118. Schau Dir die Zeile im Quelltext doch mal an: was hat der Befehl bsf… denn dort verloren?

Es folgen wieder endlose Warnings.

Du solltest Dir wirklich mal anschauen, wie ein Assemblerquelltext auszusehen hat. Man kann für Assembler nicht einfach alles so hinschreiben, dass es schön aussieht, hier haben Leerzeichen eine Bedeutung. Nimm Dir mal die mitgelieferten Beispiele vor und schau Dir an, wie es dort gemacht wird. Und dann beseitigst Du alle Fehler und Warnings, beginnend in der ersten Zeile der Errordatei. Es hat keine Zweck, das Programm in den PIC zu brennen, solange auch nur eine Warning existiert, deren Inhalt Dir nicht klar ist.

Brauchst Du einen Link zu einer Einführung in die PIC-Programmierung? Wie gut sind Deine Englischkenntnisse?

Gruß
loderunner

1 „Gefällt mir“

Hilfe ist da - wenn sie nur genutzt würde
Lieber Baehr,

ich habe mir die Mühe gemacht, Dir in einem vorhergehenden Posting ein Beispielprogramm zusammenzustellen. Anhand dieses sehr übersichtlichen Beispiels sollte Dir einiges in Punkto Aufbau eines Assemblerprogramms für PIC-Prozessoren klar geworden sein, sofern Du mal einen Blick darauf geworfen hast. Nach Deinem erneuten Hilferuf scheint es, dass Du diese Hilfe bislang nicht in Anspruch genommen hast - schade.

Ich habe Dir außerdem gestern per Mail ein PIC-Tutorial (3,6MB) geschickt, das ebenso übervoll mit Beispielprogrammen und Erklärungen ist. Je öfter Du da reinschaust, desto mehr Antworten wirst Du Dir selber geben können.

Nun zu Deinem Fehler:
was mir auf den ersten Blick aufällt ist, dass Du nach der Anweisung „org 00“ versuchst, Register (STATUS, CMCON) zu deklarieren - das ist grober Unfug! Nach der Anweisung „org xxxx“ dürfen nur noch Prozessorbefehle, Labels, UP-Aufrufe und dergleichen stehen, aber keine Deklarierungen mehr!

Also nochmal meine Bitte: studiere mein Beispielprogramm und gewöhne Dir dieses Übersichts-Chaos in Deinen PIC-Programmen ab - Du wirst Dir damit selbst den größten Gefallen tun.

Gruß, Alexander

Hallo
Also ich habe nun einen neuen Code geschrieben und bekamm keinen einzigen Error/Warning.
http://z06.zupload.com/download.php?file=getfile&fil…

Ist dieser Code jezt Korrekt?

Hallo

Also ich habe nun einen neuen Code geschrieben und bekamm
keinen einzigen Error/Warning.

Das hört sich doch erstmal gut an.

Ist dieser Code jezt Korrekt?

Wenn Du damit meinst, ob er seiner Form nach korrekt ist: offensichtlich schon, sonst hätte der Assembler gemeckert.
Wenn Du damit meinst, ob das Programm so funktioniert: das weiß niemand.

Gruß
loderunner

schnell gelernt
Hi Baehr,

so, jetzt sieht Dein Programm schon viel besser aus - so schön kann mehr Ordnung und Übersicht sein, und schon funktioniert alles besser *smile*.

Die Entwicklungsumgebung von der Herstellerfirma der PIC-Prozessoren MICROCHIP (siehe www.microchip.com) bietet nicht nur einen komfortablen Programm-Editor, sondern auch einen Programm-Simulator, mit dem man sein Programm probemäßig Befehl für Befehl abarbeiten lassen kann. All diese Funktionen kannst Du nutzen, wenn Du Dir die kostenlose Entwicklungsumgebung „MPLAB“ von der microchip-Homepage herunterlädst und auf Deinem Rechner installierst.

Der Simulator bietet natürlich die Möglichkeit, die Zustände (LOW oder HIGH) sämtlicher Ports und sämtlicher Register zu überwachen, bzw. zu kontrollieren. Damit kannst Du herausfinden, ob Dein Programm auch das tut was Du von ihm erwartest. Außerdem kannst Du jederzeit Ports (Eingänge) mit HIGH oder LOW belegen, und dann beobachten, ob Dein Programm auf diese Ereignisse richtig reagiert.

Nun zu Deinem neuen Quelltext:
1.) direkt nach der Anweisung „org 0x00“ solltest Du einen Sprungbefehl (goto-Anweisung) setzen, vor dem Du abermals die Anweisung „org 0x06“ setzt. Dies ist sinnvoll, weil an der Programmadresse „0x04“ der Interrupt-Vektor steht, sprich, immer wenn ein Interrupt auftritt, springt der Prozessor an die Adresse 0x04 und führt alle Befehle aus, die nach dieser Adresse stehen. Wenn Du keine Interrupt-Routine benötigst, schreibe auf Adresse 0x05 den Befehl „retfie“, was soviel bedeutet wie „steige aus der Interrupt-Routine aus“ und springe dort hin, von wo Du hergekommen bist. Weil kein Code zwischen Adresse 0x04 und 0x05 steht, wird der Prozessor im Falle eines Interrupts auch keine Befehle ausführen und pfuscht Dir damit nicht in Deinen Programmablauf hinein. Jeder (unerwünschte oder zufällig auftretende) Interrupt wird somit unschädlich gemacht.

Das soeben beschriebene muss also so aussehen:

reset: org 0x00 ;hier beginnt der Prozessor nach jedem Reset
goto init

org 0x04 ;Interrupt-Vektor Startadresse
retfie

init: clrf TRISIO ;mach alle Ports zu Ausgängen
bsf TRISIO,2 ;mach Port 2 zu Eingang
.
.
.
und so weiter
goto Hauptprog ;Initialisierung fertig --> geh zu HP

2.) wenn Du dem Register TRISIO die Registeradresse 0x85 zugewiesen hast (mittels "TRISIO equ 0x85), kannst Du im Programmtext den Namen TRISIO anstelle des HEX-Wertes verwenden, was Dein Programm übersichtlicher macht.

Beispiel (unübersichtlich):
TRISIO equ 0x85 ;deklariere TRISIO-Register
clrf 0x85 ;mach alle Ports zu Ausgängen

Beispiel (sehr gut):
TRISIO equ 0x85 ;deklariere TRISIO-Register
clrf TRISIO ;mach alle Ports zu Ausgängen

natürlich darf der clrf -Befehl nicht im Deklarationsteil stehen, sondern muss sich im Initialisierungs-Abschnitt befinden.

Okay, soviel für heute. Ich möchte Dir nun sagen, dass ich ab jetzt nicht mehr für Nachhilfe in Sachen Assembler-Code zur Verfügung stehen werde. Arbeite das PIC-Tutorial durch, welches ich Dir per Mail geschickt hatte und Du wirst ganz gut allein zurecht kommen.

Gruß, Alexander

Hallo Fragewurm,

Ich bin gerade über diese Seite gestolpert:
http://www.sprut.de/electronic/pic/index.htm

MfG Peter(TOO)