Archiv verlassen und diese Seite im Standarddesign anzeigen : Kein Rücksprung aus Unterprogammen zurücl in die Main
Moin moin zusammen,
vielen Dank für die Begrüßung in den Tipp eines neuen Threads. Daher hier nochmal den Gleichen Text meines Problems zzgl. meines Quelltextes. Ich denke auch, dass es entweder ein C-Problem ist bzw. mit der Speicherverwaltung zusammenhängt... Aber erstmal zum Problem:
Im Studium wurde ich kürzlichst mit der uC-Programmierung konfrontriert und habe glatt so viel gefallen daran gefunden, dass ich mir einen RP6 zugelegt habe.
In anhlehnung an mein Studium, wo ich den Infineon XC161 kennenlernte, möchte ich den RP6 nun von Grund auf neu programmieren.
Hier kurz die Rahmendaten:
- RP6 mit ATMEGA32L + RP6-Control mit ATMEGA32
- nutze AVR Studio 4
- und mitgelieferte GCC
Die ersten Schritte waren bisher mühsam aber gelangen. Wobei mir noch immer nicht so ganz klar ist, wie ich bei einem neuen Projekt für diese Prozessoren die Speichereinstellungen vornehmen muss?
Im weiteren habe ich bisher ein einfaches Init-Unterprogramm geschrieben, mit dem ich die auf dem RP6 vorhandenen LEDs initialisiere. Aus diesem Unterprogramm kommt der Programmablauf auch korrekt zurück.
Arbeite ich - wofür auch immer / hier z.B. um gezielt einzelne LEDs zu schalten - mit einem weiteren Unterprogramm, bleibt der Programmablauf sowohl in der Simulation, als auch in der Hardware am Ende des Unterprogramms stehen. Steppe ich durch die Simulation, schaltet der Simulator dann an der Stelle wo ich den Rücksprung in die Main erwarte auf Running.
Ein weiteres Problem, was ich gerne ansprechen möchte ist folgendes:
Wieso kann ich ausser in der MAIN keine lokalen Variablen anlegen? Hierbei kommt es dann bereits zu einem Fehler beim Übersetzen. Hängt das mit der womöglich noch nicht korrekt angelegten "Speicherverwaltung" in den Einstellungen des Projektes zusammen?
Schonmal vorab vielen Dank für die Hilfe,
MfG,
Oppi
Quelltext:
int main(void)
{
RP6_init_LEDs();
setLeds(leds);
while(1){
if(MAX_COUNT == i){
leds = leds << 1;
if(0x40>leds)
leds = 0x1;
i=0;
}
}
return 1;
}
Hier der Text zum besagten Unterprogramm:
#include "RP6_First_Action.h"
unsigned char portB = 0, portC = 0, actLeds;
void RP6_init_LEDs(void)
{
PORTB &= ~0x83;
DDRB = 0x83;
PORTC &= ~0x70;
DDRC = 0x70;
actLeds = ((PINC & (SL4|SL5|SL6)) >> 3) | (PINB7 >> 4) | (PINB1 << 4) | (PINB0 << 5);
}
void setLeds(unsigned char leds)
{
portB = 0;
portC = 0;
portC = ((leds & 0x7) << 4); // SL1-SL3
portB = ((leds & SL4) << 4); // SL4
portB |= ((leds & SL5) >> 3); // SL5
portB |= ((leds & SL6) >> 5); // SL6
if( (actLeds & 0x7) != (leds & 0x7) ) // Setzen der LEDs SL1-SL3
PORTC = (PORTC & 0xF8) | portC;
if( (actLeds & 0x38) != (leds & 0x38) )
PORTB = (PORTB & 0xF8) | portB;
nop();
}
SprinterSB
01.01.2009, 23:22
Dein Text wird auch gelesen, wenn er nicht in Fett schwimmt ;-)
Generell schwierig zu sagen, was schiefgeht, weil viele Makros im Code sind bzw. nicht der ganze Quellcode zu sehen ist. In main() fällt i zum Beispiel vom Himmel -- ne globale Variable namens i? Gleiches gilt für RP6_init_LEDs et al.: wo sind die Prototypen?
Was meinst du mit "Speichereinstellungen". AVR sind recht kleine µC, für die es idR keine komplizierte Memorymodelle braucht. Zudem hat AVR keine zerfrickelte Speicherarchitektur qua Segmentierung wie XC16x. Segmentierung hat man für AVR während der Entwicklungsphase zum Glück wieder ausgebaut.
Wenn du Probleme beim Debuggen hast, hilft es evtl. den Optimierungsgrad runterzudrehen oder vor der kritischen Stelle in die ASM-Ansicht zu wechseln und in Einzelschritt durchzugehen. Du bist erfahren in µC-Proggen, also sollte es dir einigermassen leicht fallen, die asm-Instruktonen den jeweiligen C-Anweisungen zuzuordnen und den Bösewicht zufinden. Oder beisst dir der Wachhund (WDT) ins Bein?
Vielen Dank für die Blumen. Dabei beruht mein Können beim Programmieren im wesentlichen auf das, was ich im letzten Quartal im Studium gemacht habe.
Die mitgelieferten Bibliotheken habe ich bewusst nicht verwendet, da genau das mein Bestreben ist, dass ich den RP6 von grundauf selbst mit Leben füttern möchte.
Grundsätzlich habe ich mir angewöhnt, Funktionsprototypen in einer Headerdatei zu sammeln und Funktionen in andere Dateien auszulagern. Entsprechend sind die Varaiablen alle vorhanden. Ich werde gleich nochmal alles aufführen. Ich dachte nur, dass ich Teile weglasse die meiner Ansicht nach nicht die Ursache darstellen.
Mit Speicherverwaltung meine ich die Memory Settings, welche man in den Projektoptionen vornehmen kann. Dort kann man im AVR Studio ja sagen, bei welcher Adresse welcher Speicher beginnt bzw. ab welcher Adresse der Speicher eingeblendet wird. Oder muss ich beim AVR dort keine Einstellungen vornehmen? (Flash, EEPROM und SRAM)
Ok, lokale Variablen akzeptiert der nun, nachdem ich den Optimierungsgrad reduziert habe.
Hier nochmal die Inhalte der drei Dateien. Zunächst die, welche auch die Main enthält. Diesmal vollständig (c; Hier möchte ich zunächst nur aus Testzwecken die Sechs LEDs auf dem RP6 durchlaufen lassen.
#include "RP6_First_Action.h"
#define MAX_COUNT 500000
int i=0;
unsigned char leds = 0x3F;
int main(void)
{
RP6_init_LEDs();
setLeds(leds);
while(1){
if(MAX_COUNT == i){
leds = leds << 1;
if(0x40>leds)
leds = 0x1;
i=0;
}
}
return 1;
}
Hier der Inhalt meiner Headerdatei. Die Funktionsprototypen, zu denen die eigentliche Fubktion noch nicht steht, habe ich noch auskommentiert.
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <stdio.h>
#include <stdlib.h>
#define ON 1
#define OFF 0
#define SL1 0x01
#define SL2 0x02
#define SL3 0x04
#define SL4 0x08
#define SL5 0x10
#define SL6 0x20
#define nop() asm volatile("nop\n\t")
extern void RP6_init_LEDs(void);
extern void setLeds(unsigned char leds);
//extern void RP6_init_Bumpers(void);
Hier nochmal die komplette Datei mit meinen ausgelagerten Funktionen. Hierzu sei erwähnt, dass es keinen Unterschied macht, ob die Funktion in der gleichen Datei wie die Main liegt oder extern ist. Das habe ich probiert. Mich irritiert schon, dass ich beim AVR Studio die Main mit einer return beenden muss. Ich lernte, solche Dinge aus Speicherplatz gründen zu lassen, auch wenn ich es für "ordentlicher" erachte.
#include "RP6_First_Action.h"
unsigned char actLeds;
void RP6_init_LEDs(void)
{
PORTB &= ~0x83;
DDRB = 0x83;
PORTC &= ~0x70;
DDRC = 0x70;
actLeds = ((PINC & (SL4|SL5|SL6)) >> 3) | (PINB7 >> 4) | (PINB1 << 4) | (PINB0 << 5);
}
void setLeds(unsigned char leds)
{
unsigned char portB = 0, portC = 0;
portC = ((leds & 0x7) << 4); // SL1-SL3
portB = ((leds & SL4) << 4); // SL4
portB |= ((leds & SL5) >> 3); // SL5
portB |= ((leds & SL6) >> 5); // SL6
if( (actLeds & 0x7) != (leds & 0x7) ) // Setzen der LEDs SL1-SL3
PORTC = (PORTC & 0xF8) | portC;
if( (actLeds & 0x38) != (leds & 0x38) )
PORTB = (PORTB & 0xF8) | portB;
nop();
}
/*
void RP6_init_Bumpers(void)
{
;
}
*/
In der ASM-Ansicht bin ich nicht weiter gekommen. Dort schaltet der Debugger zwar an der entsprechenden Stelle nicht auf running, aber er springt auch nicht zurück. Hier fehlt mir dann doch die Erfahrung. Ebenso bzgl WDT.
Hubert.G
02.01.2009, 12:59
Der Wurm liegt in deiner while Schleife, wo hast du denn dein ++i ?
Ohne dem ist sie Sinnlos und daher nicht vorhanden, sprich "wegoptimiert"
Danke für den Tipp. Das i zu inkrementieren habe ich glatt vergessen. Dieses habe ich nun nach der if-anweisung eingefügt, so dass es Sinn macht. Allerdings ändert es nichts daran, dass der Programmablauf nicht mehr aus der Funktion: setLeds(leds) zurückkommt. Diese wird ja beim ersten Mal schon vor der Endlosschleife aufgerufen.
Hab jetzt kurz probiert, die Fkt. setLeds() bereits aus der Fkt. LEDS_init() aufzurufen und die erste Led mit 0x1 anzusteuern. Mit Erfolg! Hier kommt das Programm auch wieder zurück. Jedoch nicht mehr bei einem weiteren Funktionsaufruf der Fkt. setLeds().
Entweder ich habe einen ganz gewaltigen Denkfehler, oder meine Fähigkeiten in der Silvesternacht versoffen. (c;
Hallo,
was machst du denn in der while? Du änderst eine Variable die woanders nicht mehr gebraucht wird. Für den Compiler stellt sich mit oder ohne i++ die while als überflüssig da.
Was soll denn in der while passieren?
An der Speicherverwaltung brauchst du nichts einstellen. Ich müsste jetzt auch erst einmal schauen, was für Möglichkeiten es da gibt. Mit den Defaults bin ich bisher gut gefahren.
Der WDT (Watch Dog) lässt sich bei einigen Controllern über die Fuse Bits aktivieren. Wenn man da im Programm dann nicht dran denkt, kommt es halt zum Reset, ohne das im Programm etwas zu erkennen ist. Beim AtMega 32 gibt es dieses Bit jedoch nicht.
Als bester Optimierungsgrad wird für die Avr's im allgemeinen -Os genannt.
Gruß
Jens
Hubert.G
02.01.2009, 14:56
Wenn du die Optimierung komplett ausschaltest, dann funktioniert die Simulation. Das bedeutet im Allgemeinen das das Programm wohl von Syntax her richtig ist, es der Compiler aber als sinnlos erkennt.
Vielleicht schaust du mal hier wie die allg. gängige Schreibweise ist, deine links/rechts schiebereien sind nicht sehr übersichtlich.
www.mikrocontroller.net/articles/AVR-GCC-Tutorial
Hubert.G
02.01.2009, 16:10
Noch etwas, das i hast du als int deklariert, bis 500000 ist das wohl ein Problem.
Zunächst einmal, vielen Dank für die zahlreiche Unterstützung. Im Wesentlichen muss ich wohl zugeben, dass der Fehler mal wieder zwischen den Ohren lag! (c;
@McJenso:
In der Tat, zu dem Zeitpunkt war eben noch ein logischer Fehler in der Main. Hier sollte in der While-Schleife lediglich ein Bit in der Variable leds immer von 0x01 bis 0x20 geschupst werden und so ein Lauflicht am RP6 zu erzeugen. Sinn des Ganzen war, die bisher erzeugten Funktionen für die Steuerung des RP6 zu testen.
Grundsätzlich ist es mein Beweggrund, Praxis zu sammeln und so den RP6 von Grund auf selbst zu programmieren, ohne die Nutzung der mitgelieferten Libraries.
Der Optimierungsgrad -Os ist der höchste?! Ich hab diesen derzeit auf -O3 gestellt, da ich ansonsten bereits beim kompilieren einen Fehler bekomme, wenn ich mit lokalen Variablen arbeite.
Auch der ATMEGA32 verfügt doch auch über diese Fuse-Bits?! Zumindest werden diese auch in dem 320-Seiten-Wälzer-Datenblatt aufgeführt.
@Hubert.G:
Vor allem was den Wertebereich eines unsigned int angeht, war ich wohl etwas stürmig. (c;
Diese Schiebereien ergibt sich aus der dämlichen Pinbelegung an dem fertig montierten RP6. Ich hab mich zwar bisher nicht sonderlich intensiv mit den Schaltplänen befasst, aber die wilde Zuordnung von den wesentlichen sechs Leds zu den Port-Pins kann ich nicht ganz nachvollziehen. Jedenfalls habe ich keine andere Möglichkeit gefunden, mir ein ordentliches Wort zu bilden, mit dem ich die sechs Leds ansteuern kann. So ergab sich die wilde Schieberei.
Auch das ist meine Meinung nach nun aber in ordnung. Jedenfalls fluppen die Funktionen nun!
Also vielen Dank!
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.