PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Mein erster Code auf dem Mega 32: Lauflicht



BlackDevil
15.07.2008, 12:56
Servus

Ich habe heute mal die Zeit gefunden mir ein kleines Lauflicht zu Programmieren. Ich hab zwar keine Experimentierplatine, macht aber auch nix weil das AVRStudio mir ja erlaubt fröhlich zu Simulieren.

Erstmal der Code, dann meine Fragen:

#include <avr/io.h>
#ifndef F_CPU
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert
(z.B. durch Übergabe als Parameter zum Compiler innerhalb
des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
"nachträgliche" Definition hinweist */
#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
#define F_CPU 16UL /* Quarz mit 3.6864 Mhz */
#endif
#include <stdint.h>
#include <util/delay.h>

struct s_bPORTB{
uint8_t PIN;
}bPORTB[8];

int main (void) {

DDRB = 0xff;
DDRA = 0x00;

bPORTB[0].PIN=PINB0;
bPORTB[1].PIN=PINB1;
bPORTB[2].PIN=PINB2;
bPORTB[3].PIN=PINB3;
bPORTB[4].PIN=PINB4;
bPORTB[5].PIN=PINB5;
bPORTB[6].PIN=PINB6;
bPORTB[7].PIN=PINB7;

while(1) {
if(PINA & (1<<PINA1)){
for(int i=0; i<8; i++){
PORTB &= (1<<bPORTB[i].PIN);
PORTB |= (1<<bPORTB[i].PIN);
_delay_ms(10);
}
}
}

/* wird nie erreicht */
return 0;
}


Sooo, das läuft auch alles soweit. Dennoch macht es zwei drei Problemchen... 1. macht _delay_ms(10); nicht das was es soll^^ die angabe in den Klammern sollte eigentlich eine Verzögerung in Millisekunden darstellen. Ergo: Wenig wert, wenig Pause, viel Wert, viel Pause. Ist der Wert allerdings größer als 10 springt er in der delay.h rum macht aber sonst nix mehr. Und bei 10 ist die Pause ziemlich genau eine Sekunde => Sehr komisch.
2. Wie kann ich einen Timer Interrupt abfragen? Sprich: Timer Initialisieren, Timer so laufen lassen das zum Beispiel 10Takte/sekunde (sollten dann 100mHz sein oder?) habe und schluss endlich immer dann PINB eins Hochzählen wenn der Timer hochgezählt wird.
3. Finde ich meine Lösung die Pins an Port B hoch zu zählen nicht sooo Elegant. Ginge das Eleganter?
4. AVR Studio sagt unter "Prozessor" 4MHz - in den Controller Optionen habe ich 16000000Hz eingestellt ... finde ich etwas Merkwürdig ^^

Achja, laufen lassen tu ich das immer so:
Build -> Start Debugging -> AutoStep
Und dann entsprechen PinA1 anklicken und so auf 1 setzen (was nich wirklich gut funktioniert wie ich finde, das reagiert arg blöd (oder brauch ich auch da einen debounce?)


So ich hoffe das ist soweit verständlich. Danke fürs lesen und helfen :)



edit: die lösung mit der ForSchleife ist auch nicht so schön, einfach der Tatsache wegen das das ganze nicht an Ort und Stelle Stoppt sondern immer bis zum Ende durchläuft (logisch). Die Lösung könnte eine While Schleife sein oder? Also


while(PINA1==1){
PINB.i=1;
i++;
}
i=0;


So als halber Pseudocode....

Oder?

grüße

fhs
15.07.2008, 13:51
Hi,

es ist wichtig, dass Du im AVRStudio die Parameter richtig einstellst. Einmal unter "Project|Configuration Options|Frequency" (siehe erste Anlage) und dann unter "Debug"AVR SimulatorOptions" oder direkt im Frequenzfenster des Simulators. Ich habe Deinen Code simuliert und komme auf knapp über 10ms (siehe Anlage 2). Nimm die ganze FCPU-Sache aus Deinem Code und stelle alles im AVRStudio wie oben gesagt ein. In meinem Beispiel (1. Anlage) habe ich "keine Optimierung (=-O0)" gewählt; typischerweise nimmt man mindestens "-O1".

Dein Code ist etwas holprig: Statt
PORTB &= (1<<bPORTB[i].PIN);

PORTB |= (1<<bPORTB[i].PIN); kannst Du z.B. direkt (1<<i) verwenden. Übrigens: Beim ATmega32 kann man die einzelnen Ausgangspins nicht mit Hilfe von PINx |= PINx "togglen" (20:04 editiert: verkehrt -- muss heißen: "PINx |= KONSTANTE;"), aber bei den neueren ATmegas geht das!

Hier eine Lösung für Deine Schleife:

while(!(PINA & (1<<PINA1))){
for(int i=0; i<8; i++){
blablabla();
}
}

Viel Erfolg und Spaß bei der Weiterentwicklung!

Gruß

Fred

sternst
15.07.2008, 14:53
@ Fred:

Sorry, aber ich muss da mal zwei Dinge zu sagen:


In meinem Beispiel (1. Anlage) habe ich "keine Optimierung (=-O0)" gewählt; typischerweise nimmt man mindestens "-O1".
Wenn man die Funktionen aus util/delay.h verwenden will, ist es sehr wichtig, die Optimierungen einzuschalten. Bei einer halbwegs aktuellen AVR-Libc bekommt man ansonsten auch eine entsprechende Warnung beim Compilieren.


Beim ATmega32 kann man die einzelnen Ausgangspins nicht mit Hilfe von PINx |= PINx "togglen", aber bei den neueren ATmegas geht das!
Auch bei neueren ATmegas klappt das so nicht. Mit "PINx |= PINx" bekommt man den Ausgang nur von 1 auf 0, aber nicht wieder zurück.


@ BlackDevil:


3. Finde ich meine Lösung die Pins an Port B hoch zu zählen nicht sooo Elegant. Ginge das Eleganter?
Ich würde ein Lauflicht über den ganzen Port so machen:

while (1) { // oder solange Taste gedrückt, oder ähnlichens
PORTB <<= 1;
if (!PORTB)
PORTB = 1;
_delay_ms(10);
}

Gock
15.07.2008, 15:11
Zu 2.:


ISR(TIMER1_COMPA_vect){
PORTB ^= PORTB; // invertiert PORTB zB
}


void init_Timer1CompMatch(){ //zB Timer1 Compare Match initialisieren
TCCR1X = xy; // hier die entsprechenden Bit setzen wie im Datenblatt beschrieben, je nach Anwendungsfall
// und alle weiteren möglichen Register einstellen
sei();
}

void init_Ports(){} // Ports = Ausgänge usw

int main (void){
init_Ports();
init_Timer1CompMatch();
while(1){}

}

Invertieren so wie im Beispiel
10Takte/s sind 10Hz !
Du musst den Simulator separat einstellen mit 16MHz
Optimierung muss ein sein, wie Sternst sagt.

fhs
15.07.2008, 17:58
Hallo,


...Wenn man die Funktionen aus util/delay.h verwenden will, ist es sehr wichtig, die Optimierungen einzuschalten.
Stimmt -- das hätte ich besser dazuschreiben sollen! Mein Beispiel war also nicht 100% treffend, obwohl ich erwähnt habe, dass man eine Optimierungsstufe >0 einschalten sollte!



Beim ATmega32 kann man die einzelnen Ausgangspins nicht mit Hilfe von PINx |= PINx "togglen", aber bei den neueren ATmegas geht das!
Auch bei neueren ATmegas klappt das so nicht. Mit "PINx |= PINx" bekommt man den Ausgang nur von 1 auf 0, aber nicht wieder zurück.
Dass das Toggeln so nicht geht, ist nicht korrekt: siehe Anlage (Datenblatt Atmega3290P); viele andere der neueren AVRs können das auch!
Hier ein Beispiel zum Ausprobieren im Simulator (Atmega3290P einstellen!):

#include <avr/io.h>

int main (void) {
while(1) {
DDRB = 1;
PORTB=1;
for (uint8_t i=0;i<10;i++)
asm volatile("sbi 3,0"); // = sbi PINB, 0
}
return 0;
}
// -O0, Breakpoint auf die Zeile mit "asm volatile..." setzen;


Gruß

Fred

sternst
15.07.2008, 18:48
Dass das Toggeln so nicht geht, ist nicht korrekt:

Doch. Zum Toggeln muss man eine 1 in das jeweilige Bit von PINx schreiben (so wie bei deinem 2. Beispiel). Überlege mal, was "PINx |= PINx" macht, wenn der Output gerade 0 ist. ;-)

fhs
15.07.2008, 18:54
Hallo,



Dass das Toggeln so nicht geht, ist nicht korrekt:

Doch. Zum Toggeln muss man eine 1 in das jeweilige Bit von PINx schreiben (so wie bei deinem 2. Beispiel). Überlege mal, was "PINx |= PINx" macht, wenn der Output gerade 0 ist. ;-)

Ooops, Entschuldigung - da habe ich tatsächlich Unsinn geschrieben; gemeint war <pre>PINx |= BITS; // BITS ist eine Konstante</pre>, wie ich es im 2. Beispiel ja auch tue...

Viele Grüße

Fred

sternst
15.07.2008, 19:04
PINx |= BITS; // BITS ist eine Konstante
Aber dann wäre "PINx = BITS;" sinnvoller, denn sonst würdest du Outputs, die unangetastet bleiben sollen, die aber gerade auf 1 sind, in 0 ändern.

BlackDevil
15.07.2008, 20:50
while (1) { // oder solange Taste gedrückt, oder ähnlichens
PORTB <<= 1;
if (!PORTB)
PORTB = 1;
_delay_ms(10);
}

Danke, das ist genau das was ich gesucht habe. <<= macht ja nix als PORTB = (1<<PORTB) oder? PortX macht nichts anderes als Pinx - nur auf den ganzen port bezogen oder? Aber eigentlich ist PORTB=1 die Anweisung die Internen PullUps auf 1 zu setzen ^^
Das braucht noch etwas Erklärung, bitte. Funktioniert aber genauso wie ich das wollte :)


Ich hab auch die hälfte der Einstellungen wieder gefunden.
Projekt Konfiguration steht auf 16000000Hz, die Simulator Konfig hab ich dann auch nach langem suchen gefunden ^^


Danke. Wie immer klasse Forum!



Edit: warnt der compiler vor nicht benutzten Variablen wegen Datenmüll?


edit2:
hab meinen code jetzt soweit modifiziert

#include <avr/io.h>
#include <stdint.h>
#include <util/delay.h>



int main (void) {

DDRB = 0xff;
DDRA = 0x00;
char auswahl='n'; // Zum Nichts tun

while(1) {
if((PINA & (1<<PINA0))&&!((PINA & (1<<PINA1)))){ auswahl='r'; }
if((PINA & (1<<PINA0))&&((PINA & (1<<PINA1)))){ auswahl='b'; }
if((!(PINA & (1<<PINA0)))&&((auswahl=='r') || (auswahl=='b'))){
auswahl='n'; // Mache nix
}

switch(auswahl){
case 'r': // VORWÄRTS FWD
PORTB <<= 1;
if (!PORTB){
PORTB = 1;
}
break;
case 'b' : // RÜCKWÄRTS RWD
PORTB <<= 1;
if(!PORTB){
PORTB=1;
}
break;
}
}

/* wird nie erreicht */
return 0;
}


Funktioniert soweit Einwandfrei. Er läuft auch ohne delay schön langsam (warum auch immer).
Zwei Fragen noch: Wie kann ich den wert eines Pins an eine Variable überegeben? mit uint8_t VAR = PINAX oder? Wenn ja tut das nich ...
Und: Warum zur Hölle ist der ATmega 32 mit 16MHz angegeben, läuft in der Simulation aber nur mit 8MHz?

Grüße

sternst
15.07.2008, 21:42
<<= macht ja nix als PORTB = (1<<PORTB) oder?
Oder! Es macht PORTB = PORTB << 1;


PortX macht nichts anderes als Pinx - nur auf den ganzen port bezogen oder?
Oder! Beides bezieht sich auf den ganzen Port, aber PORTx ist für den Output, während PINx für den Input ist.


Aber eigentlich ist PORTB=1 die Anweisung die Internen PullUps auf 1 zu setzen ^^
Nein. PORTx ist für die Pullups nur für die Pins relevant, die als Eingang geschaltet sind. Ist der Pin als Ausgang geschaltet, steht in PORTx einfach das, was ausgegeben werden soll.


hab meinen code jetzt soweit modifiziert
Der Code für Vorwärts und Rückwärts ist ja identisch. Die Richtung ändert sich nicht nur durch Willenskraft. ;-)
Andere Richtung:
PORTB >>= 1;
if (!PORTB) PORTB = 128;

fhs
15.07.2008, 21:43
Hallo,


="BlackDevil.... Er läuft auch ohne delay schön langsam (warum auch immer).
Die tatsächliche Geschwindigkeit kannst Du nur aus dem Simulator-Fenster, wo Takte bzw. Zeit angegeben sind, ablesen. Äußerlich läuft der Simulator immer wesentlich langsamer als der Prozessor mit der angegebenen Taktrate! Um das echte Timing zu sehen, musst Du Dir die Anzahl der Takte (Cycle Counter) oder die Zeit (Stop Watch) im Simulator ansehen.


Zwei Fragen noch: Wie kann ich den wert eines Pins an eine Variable überegeben? mit uint8_t VAR = PINAX oder?
Eher mit
uint8_t VAR;
VAR=PINA&PINAx; // VAR=PINA; liest den ganzen Port



...ist der ATmega 32 mit 16MHz angegeben, läuft in der Simulation aber nur mit 8MHz?
Dann stimmen Deine eingestellten Parameter noch nicht!

Gruß

Fred

sechsrad
15.07.2008, 21:46
....Warum zur Hölle ist der ATmega 32 mit 16MHz angegeben, läuft in der Simulation aber nur mit 8MHz? ......


irgendwie hast du dich überhaupt noch nicht mit dem avrstudio beschäftigt.
deine einstellung vom avr hat nichts mit der einstellung vom avrstudio zu tun.

weiterhin läuft der simulator nicht in echtzeit sondern simuliert.
die zeit für einen befehl usw kannst du dann herauslesen.
auch das portsetzen entspricht nicht der c-schreibweise .
les dir dieses mal genau durch und mach erst dann wieder weiter.
dein code ist zur zeit in der schreibweise chaotisch :

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

BlackDevil
16.07.2008, 09:54
dein code ist zur zeit in der schreibweise chaotisch :

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

Mit dem Tutorial setze ich mich zZt auseinander ;) Das es vielleicht etwas Chaotisch aussieht mag daran liegen das ich immer wieder daran rumpfusche und weniger darauf achte das es nicht nach "Quick'n'Dirty" ausschaut. Habe auf C++ gelernt und C is vom Code her etwas anders - das is ne kleine Umstellung im moment.


Hallo,

Die tatsächliche Geschwindigkeit kannst Du nur aus dem Simulator-Fenster, wo Takte bzw. Zeit angegeben sind, ablesen. Äußerlich läuft der Simulator immer wesentlich langsamer als der Prozessor mit der angegebenen Taktrate! Um das echte Timing zu sehen, musst Du Dir die Anzahl der Takte (Cycle Counter) oder die Zeit (Stop Watch) im Simulator ansehen.
Danke


Zwei Fragen noch: Wie kann ich den wert eines Pins an eine Variable überegeben? mit uint8_t VAR = PINAX oder?
Eher mit
uint8_t VAR;
VAR=PINA&PINAx; // VAR=PINA; liest den ganzen Port


Danke


...ist der ATmega 32 mit 16MHz angegeben, läuft in der Simulation aber nur mit 8MHz?
Dann stimmen Deine eingestellten Parameter noch nicht!

Gruß

Fred

Ich habe in der Project Config sowie in der Simulator Config 16MHz eingestellt und bekomme als Warnung das die Takrate für den angegebenen Prozessor zu hoch ist und er tut - richtig - nichts...

fhs
16.07.2008, 10:10
Hallo,


Ich habe in der Project Config sowie in der Simulator Config 16MHz eingestellt und bekomme als Warnung das die Takrate für den angegebenen Prozessor zu hoch ist und er tut - richtig - nichts...

Kein Ahnung, was die Ursache sein könnte. Bei mir geht es (siehe Anlage). Du hast nicht zufälling den Atmega32L spezifiziert (kommt bei mir im Drop-Down-Menü übrigens nicht vor)?

Viele Grüße

Fred

BlackDevil
16.07.2008, 10:53
Ne schon den Mega32 - ich schmeis nach dem Essen mal den Laptop an und teste noch mal ... (sowieso, der code ist noch ziemlich Dämlich ... zB müssen die Taster gedrückt bleiben das der Spaß funzt :D)

BlackDevil
16.07.2008, 19:41
Here I am again

Die 16MHz habe ich eingestellt bekommen, allerdings etwas Kurios...
Hier
http://img370.imageshack.us/img370/6306/86470274xq9.th.jpg (http://img370.imageshack.us/my.php?image=86470274xq9.jpg)
Sind 16MHz eingestellt, wobei hier
http://img179.imageshack.us/img179/1733/67811396pm0.th.jpg (http://img179.imageshack.us/my.php?image=67811396pm0.jpg)
8MHz eingestellt sind - das Prozessor Fenster sagt 16MHz und es läuft auch doppelt so schnell wie mit 8MHz ...


PORTB <<= 1;
if (!PORTB){
PORTB = 1;
}


PORTB<<=1 shiftet (<<) die 1 durch den ganzen Port, aber warum bei jedem Zyklus das nächse? Und was genau macht die IF Anweisung?
Da steig ich - auch mit dem tutorial - noch nicht ganz durch.



uint8_t run=PINA&PINA0;
if(run==1){ // tu was }


Tut nicht- Erklärung? Vielleicht liegts am Code ... C/C++ hat dann doch ein zwei verschiedenheiten..



#include <avr/io.h>
#include <stdint.h>
#include <util/delay.h>



int main (void) {

DDRB = 0xff;
DDRA = 0x00;
uint8_t run=PINA&PINA0;
char auswahl='n';

while(1) { // MAINSCHLEIFE
if((PINA&(1<<PINA0))&&(auswahl=='n')){ auswahl='r';}
else if((PINA&(1<<PINA0))&&(auswahl=='r')){ auswahl='n'; }
else if((PINA&(1<<PINA0))&&(auswahl=='b')){ auswahl='c'; }
else if((PINA&(1<<PINA0))&&(auswahl=='c')){ auswahl='b'; }
else if((PINA&(1<<PINA1))&&(auswahl=='r')){ auswahl='b'; }
else if((PINA&(1<<PINA1))&&(auswahl=='b')){ auswahl='r'; }
switch(auswahl){
case 'r': // VORWÄRTS FWD
PORTB <<= 1;
if (!PORTB){
PORTB = 1;
}
break;
case 'b' : // RÜCKWÄRTS RWD
PORTB >>= 1;
if(!PORTB){
PORTB=128;
}
break;
}
} // MAINSCHLEIFEN ENDE


return 0;
}


Das tut soweit alles was ich will, auser der Variablen zuweisung.

Was ist daran C Untypisch? Es ist mit der Version vll ungemütlich geschrieben, Funktioniert aber tadellos

fhs
16.07.2008, 20:24
Hallo,


uint8_t run=PINA&PINA0;
Du meinst
<pre> uint8_t run=PINA&(1<<PINA0);</pre>

Tut mir leid, wenn mein obiges Posting diesbezüglich missverständlich war; Ursache ist, dass ich die "alten" Termini PAx usw. verwende.

Gruß

Fred

BlackDevil
16.07.2008, 20:28
Eher mit
uint8_t VAR;
VAR=PINA&PINAx; // VAR=PINA; liest den ganzen Port


Ich hatte mich daran Orientiert - deine Variante hatte ich schon mal getestet, tut aber nich


if((run==1)&&(auswahl=='n')){ auswahl='r';}


Kann aber auch an einer Falschen einbindung liegen. Gibts noch eine Erklärung dazu wie nun der Port durchgeshiftet wird um zu Prüfen ob ein Pin1 ist oder die Register zu setzen?

Woher bekomme ich die lcd.h? Ich hab gegooglet wie ein Ochse, ohne erfolg...

fhs
16.07.2008, 20:30
Hi,

...siehe mein Posting von 21:24!

Gruß

Fred

BlackDevil
16.07.2008, 20:32
Okay danke, damit bleibt der rest aber noch offen.

fhs
16.07.2008, 20:36
Hi,

...damit bleibt der rest aber noch offen.
leider ist mir nicht klar, was "der Rest" ist -- was genau möchtest Du fragen?
Zu einer Deiner Fragen oben: Die if-Anweisung sorgt dafür, dass der Port, wenn er == 0 ist, wieder auf 1 gesetzt wird, damit überhaupt ein Bit zum Shiften da ist.

Gruß

Fred

BlackDevil
16.07.2008, 20:38
if((run==1)&&(auswahl=='n')){ auswahl='r';}


Kann aber auch an einer Falschen einbindung liegen. Gibts noch eine Erklärung dazu wie nun der Port durchgeshiftet wird um zu Prüfen ob ein Pin1 ist oder die Register zu setzen?

Woher bekomme ich die lcd.h? Ich hab gegooglet wie ein Ochse, ohne erfolg...

Genau der rest :D

fhs
16.07.2008, 20:43
Hi,

1. die Sache mit der Variablen "run" ist jetzt OK, oder?
2. welche LCD-Bibliothek benutzt Du? Die dazu passende "lcd.h" musst Du einbinden. Welche das ist, kann ich ohne mehr Informationen nicht erraten. Ganz oben hast Du geschrieben, dass Du allen Code im AVRStudio simulierst. Für eine LCD-Ansteuerung würde ich einiges an Hardware-Aufwand erwarten; simulieren lässt sich das nur sehr schwer.
Habe ich das was missverstanden?

Gruß

Fred

BlackDevil
16.07.2008, 20:50
Nein du hast nichts Missverstanden. Die Variable run will nicht, wie ich Prüfe ob sie 1 oder ist habe ich oben gepostet. So wie ich es eingebunden habe (run==1) funktioniert es nicht.



Das AVRSTudio bietet das einbinden von LCDs, bzw das Simulieren, mit einem Zusatztool (zumindest soweit ich das verstanden habe). Nennt sich dann AVR LCD (Editor).

Selbst wenn es nicht geht - macht nichts. Welche lcd.h ich Verwende? Gar keine - muss man sich die immer je nach LCD selbst zusammen Schustern oder gibts eine Grundlage auf der ich nur den Chip auf dem LCD sowie dessen größe verändern muss? Wenn es so eine gibt fand ich sie bisweilen noch nicht.

http://www.ulrichradig.de/site/infos/pdf/AtmelCprogramming.pdf
Spricht etwas dagegen statt PORTA |= (1<<PINA1), outp (0x04, PORTB); (wenn ich da richtig liege ... ) schreiben? Ich finde dieses etwas elleganter und da die Funktionen vom AVR Studio geliefert werden...


Tut mir leid wenn ich bei sowas nicht immer MrSuperverständlich bin, bin leider nicht so der Riesen Erklärbär ...
Übrigens: Oben schriebe jemand mein Code "sei nicht C Typisch". Warum?

sternst
16.07.2008, 21:34
Gibts noch eine Erklärung dazu wie nun der Port durchgeshiftet wird um zu Prüfen ob ein Pin1 ist oder die Register zu setzen?

"PORTB <<= 1;" ist das gleiche wie "PORTB = PORTB << 1;".
Dabei wird erstmal der aktuelle Wert aus dem Register PORTB gelesen, dann dieser Wert um eine Stelle nach links geschoben (links fällt dabei ein Bit raus, rechts wird eine 0 nachgeschoben) und der geänderte Wert wird zurück in das Register geschrieben. Nach 8 Schleifendurchläufen ist die 1 links rausgefallen (PORTB ist dann also 0) und das if sorgt dann dafür, dass ganz rechts wieder eine 1 reingeschrieben wird.

fhs
16.07.2008, 21:53
Hi,


...Die Variable run will nicht, wie ich Prüfe ob sie 1 oder ist habe ich oben gepostet. So wie ich es eingebunden habe (run==1) funktioniert es nicht.
und Du bist Dir ganz sicher, dass Du jetzt <pre>uint8_t run=PINA&(1<<PINA0);</pre> geschrieben hast? Dann muss "run" funktionieren, wenn Du Bit0 setzt (in Deiner ursprünglichen Code-Variante hattest Du , glaube ich, mit Bit 1 gearbeitet).


Das AVRSTudio bietet das einbinden von LCDs, bzw das Simulieren, mit einem Zusatztool (zumindest soweit ich das verstanden habe). Nennt sich dann AVR LCD (Editor).
OK, davon hatte ich schon peripher mal etwas gehört, habe aber keinerlei Erfahrung damit.


Spricht etwas dagegen statt PORTA |= (1<<PINA1), outp (0x04, PORTB); (wenn ich da richtig liege ... ) schreiben?
Bin mir nicht sicher, dass die alten "outp()" Funktionen bei den neueren gcc Versionen noch unterstützt werden. Die erste Variante ist die übliche. PORTA liegt an der Adresse 0x1B, also sind die beiden Ausdrücke nicht äquivalent.

Gruß

Fred

BlackDevil
17.07.2008, 08:47
Gibts noch eine Erklärung dazu wie nun der Port durchgeshiftet wird um zu Prüfen ob ein Pin1 ist oder die Register zu setzen?

"PORTB <<= 1;" ist das gleiche wie "PORTB = PORTB << 1;".
Dabei wird erstmal der aktuelle Wert aus dem Register PORTB gelesen, dann dieser Wert um eine Stelle nach links geschoben (links fällt dabei ein Bit raus, rechts wird eine 0 nachgeschoben) und der geänderte Wert wird zurück in das Register geschrieben. Nach 8 Schleifendurchläufen ist die 1 links rausgefallen (PORTB ist dann also 0) und das if sorgt dann dafür, dass ganz rechts wieder eine 1 reingeschrieben wird.

Danke - ist also Quasi wie ein Schieberegister/Multiplexer. Den würde man ja Ähnlich Programmieren.


Hi,


...Die Variable run will nicht, wie ich Prüfe ob sie 1 oder ist habe ich oben gepostet. So wie ich es eingebunden habe (run==1) funktioniert es nicht.
und Du bist Dir ganz sicher, dass Du jetzt <pre>uint8_t run=PINA&(1<<PINA0);</pre> geschrieben hast? Dann muss "run" funktionieren, wenn Du Bit0 setzt (in Deiner ursprünglichen Code-Variante hattest Du , glaube ich, mit Bit 1 gearbeitet).
Ich habe die Deklarationszeile mit Copy and Paste eingefügt... Ich machs nachher noch mal und poste den spaß


Spricht etwas dagegen statt PORTA |= (1<<PINA1), outp (0x04, PORTB); (wenn ich da richtig liege ... ) schreiben?
Bin mir nicht sicher, dass die alten "outp()" Funktionen bei den neueren gcc Versionen noch unterstützt werden. Die erste Variante ist die übliche. PORTA liegt an der Adresse 0x1B, also sind die beiden Ausdrücke nicht äquivalent.

Gruß

Fred

Das die beiden nicht Äquivalent sind liegt allein schon daran das in der einen Version PORTA und PINA angesprochen wird und bei der zweiten Variante PORTB ... geht nur um die generelle Funktion. Werde auch das nachher einfach mal ausprobieren... Finde das etwas Eingänglicher als mit den Bitoperatoren :)

Danke

BlackDevil
17.07.2008, 11:34
#include <avr/io.h>
#include <stdint.h>
#include <util/delay.h>

#define run_fwd (PINA&(1<<PA0)) // Start/Stop
#define run_rwd (PINA&(1<<PA1)) // Vorwärts/Rückwärts
#define DDR_LED DDRB // PORTB (LED)
#define DDR_INP DDRA // PORTA (Taster)
#define p_INP PORTA // PORTA für Taster

void fwd(){ // Vorwärts
PORTB<<=1;
if(!PORTB) PORTB=1;
}

void rwd(){ // Rückwärts
PORTB>>=1;
if(!PORTB) PORTB=128;
}

int main (void) {

DDR_LED = 0xff; // Ausgänge EIN für LED
DDR_INP = 0x00; // Eingänge EIN für Taster
p_INP = 0xFF; // PullUp EIN
char auswahl='s'; // Default

while(1) { // MAINSCHLEIFE

if((run_rwd)&&(auswahl=='f')) auswahl='r'; // Run RWD, war FWD
else if((run_rwd)&&(auswahl=='r')) auswahl='f'; // Run FWD, war RWD
else if((run_fwd==1)&&(auswahl=='f')) auswahl='x'; // Stop FWD, war FWD
else if((run_fwd==1)&&(auswahl=='r')) auswahl='y'; // Stop RWD, war RWD
switch(auswahl){
case 'f': // VORWÄRTS FWD
fwd();
break;
case 'r' : // RÜCKWÄRTS RWD
rwd();
break;
case 'x' : // STOP FWD, setze danach FWD (war FWD)
loop_until_bit_is_set(PINA, PA0);
auswahl='f';
break;
case 'y' : // STOP RWD, setzte danach RWD (war RWD)
loop_until_bit_is_set(PINA, PA0);
auswahl='r';
break;
case 's' : // Default Stop, Start drücken zum Starten
loop_until_bit_is_set(PINA, PA0);
auswahl='f';
break;
}
} // MAINSCHLEIFEN ENDE


return 0;
}


So besser? Wenn ich die Variablen mit <pre>#define</pre> Deklariere, funktioniert alles wunderbar. Wenn ich es hingegegen mit <pre>uint8_t</pre> mache Funktioniert es nicht. Genauso: Schreibe ich statt <pre> if((run_rwd)&&(auswahl=='f')) auswahl='r';</pre> dieses <pre> if((run_rwd==1)&&(auswahl=='f')) auswahl='r';</pre> Funktioniert das Rückwärts Shiften auch nicht. Er ändert die Variable dann nicht. Bei <pre>run_fwd</pre> ist es egal wie ichs mach ^^ Irgendwie ... weis nich.
Das AVR Studio bietet dort ein kleines Kuriosum. Genauso wie <pre>_delay_ms(>10)</pre> nicht Funktioniert. Er Springt dann in der delay.h rum, macht aber nichts. Ergo kann ich auch keine debounce Funktion einbauen, bzw den "vorgekauten" Code benutzen.

Ich hoffe auf Lösung und verbleibe mit Freundlichen Grüßen :)

fhs
17.07.2008, 12:28
Hallo,


... Wenn ich die Variablen mit <pre>#define</pre> Deklariere, funktioniert alles wunderbar. Wenn ich es hingegegen mit <pre>uint8_t</pre> mache Funktioniert es nicht.
Was bei Dir funktioniert, ist eine Präprozessor-Anweisung, keine Variablen-Deklaration oder -Definition! Bitte ein (möglichst kurzes, aber kompilierbares!) Beispiel für das, was nicht funktioniert. Vermutlich zeigt Dir mein nächster Absatz aber schon das Problem:


Schreibe ich statt <pre> if((run_rwd)&&(auswahl=='f')) auswahl='r';</pre> dieses <pre> if((run_rwd==1)&&(auswahl=='f')) auswahl='r';</pre> Funktioniert das Rückwärts Shiften auch nicht.
1. Soweit ich mich erinnere, ist in (Standard-)C "unwahr" als "0" definiert; jeder andere Wert ist "wahr"; allerdings ist der Compiler angehalten, für "wahr" eine "1" zu setzen, wenn er selbst einen Vergleich durchführt.
2. Welches Bit ist denn in run_rwd möglicherweise gesetzt? Antwort: Bit1 (nämlich 1<<PA1) --- nicht Bit0! Also darfst Du nicht mit "1", sondern musst mit "2" vergleichen:
if((run_rwd==2)&&(auswahl=='f')) auswahl='r';
Das hatte ich in einem früheren Posting gemeint, als ich schrieb, Du hättest ja ursprünglich mit Bit1 verglichen.
Das ist die Problematik, wenn man Werte anstelle von logischen Typen benutzt.
if((run_rwd)&&(auswahl=='f')) ist aber völlig in Ordnung!

Setze Dich doch auch einmal mit dem Datentyp "bool" auseinander. Wenn Du "bool" verwendest, muss <pre>#include <stdbool.h></pre> eingebunden werden.

Viele Grüße

Fred

BlackDevil
17.07.2008, 13:10
Hi

Ich weis das ich mit <pre>#define</pre> eine Präprozessor Anweisung keine Deklaration vornehme. Ergo ist das ganze dann nur eine andere Bezeichnung für etwas (grob). Funktioniert aber.

Ich hatte gedacht das <pre>PINA&(1<<PAX) </pre> eine 1 zurück gibt wenn PAX gesetzt ist ...also Bool'sch ist - genauso mit uint8_t . <pre>bool VAR = PINA&PAX</pre> kann ich dann nich machen oder?

Das mit der zwei macht sinn ... Das register ist ja <pre>0x00</pre> oder <pre>00000000</pre> - damit wäre ein setzen von Bit 2 <pre>0x02</pre> oder <pre>00000010=2</pre>

Macht sinn ... Entsprechend hätte ich beim setzen von Bit5 die Zahl 00010000 oder 0x10. Daran hab ich nich gedacht

Danke :) Irgendwie steh ich da noch etwas auf dem schlauch - find das Tut auch nich so prall *duck*


Gibts noch generelle Kritik an meinem stück code obeN?

fhs
17.07.2008, 13:20
..Ich hatte gedacht das <pre>PINA&(1<<PAX) </pre> eine 1 zurück gibt wenn PAX gesetzt ist ...also Bool'sch ist -
...ist aber rein arithmetisch und deshalb davon abhängig, welches Bit gesetzt ist. Allerdings kannst Du das Ergebnis immer dann als "wahr" betrachten, wenn es nicht NULL ist und immer als "falsch", wenn es NULL ist. Vom Compiler darfst Du erwarten, dass er Dir eine "1" zurückgibt, wenn Du ein wahres Ergebnis eines Vergleichs einer arithmetischen Variablen zuweist.


Gibts noch generelle Kritik an meinem stück code obeN?
Nö, sieht schon recht gut aus. Einfach weiter programmieren und versuchen, mit dem Simulator die Fehler selbst zu finden -- und hier fragen, wenn das nicht funktioniert! Auch Debugging will gelernt werden!

Viel Spaß dabei!

Fred

sternst
17.07.2008, 14:57
...ist aber rein arithmetisch und deshalb davon abhängig, welches Bit gesetzt ist. Allerdings kannst Du das Ergebnis immer dann als "wahr" betrachten, wenn es nicht NULL ist und immer als "falsch", wenn es NULL ist. Vom Compiler darfst Du erwarten, dass er Dir eine "1" zurückgibt, wenn Du ein wahres Ergebnis eines Vergleichs einer arithmetischen Variablen zuweist.
Um es für BlackDevil noch etwas weiter zu führen:
Wenn du in einer Variablen mit 0 oder 1 festhalten willst, ob ein bestimmtes Bit gesetzt ist, bringe einfach eine zusätzliche logische Operation ins Spiel. Du kannst es z.B. so machen:
BitIsSet = (Reg & (1<<Bit)) > 0;
In diesem Fall ist BitIsSet bei gesetztem Bit immer 1, egal an welcher Position das Bit denn nun genau ist.

BlackDevil
17.07.2008, 16:36
Die AVR Funktionen bit_is_set und outp funktionieren Leider nicht. Danke für die Zahlreichen und hilfreichen Antworten!

fhs
17.07.2008, 16:47
Hi,


Die AVR Funktion bit_is_set und outp funktionieren Leider nicht.
siehe mein Posting von 22:53 ... "outp" ist, glaube ich, ein Teil alter gcc Versionen. "bit_is_clear/set()" funktionieren -- siehe Anlage. Welche gcc Version verwendest Du?

Gruß

Fred

BlackDevil
17.07.2008, 18:36
Ich meine die Aktuellste version runtergeladen zu haben - gut dann funktionieren die beiden nich - macht auch nichts

fhs
17.07.2008, 19:21
Hi,


Ich meine die Aktuellste version runtergeladen zu haben - gut dann funktionieren die beiden nich - macht auch nichts
sieh doch bitte nach, welche gcc Version Du tatsächlich hast und poste ein Beispiel (möglichst abgespeckt), das nicht funktioniert!

Gruß

Fred

BlackDevil
17.07.2008, 19:56
<pre>int main (void) {
DDRA=0x00;
DDRB=0xff;
while(1) { // MAINSCHLEIFE
if(bit_is_set(PINA,PA1)) PB0=1;
}
return 0;
}
</pre>

WinAVR 20080512

Kann aber auch sein das ichs nur Falsch benutz

fhs
17.07.2008, 20:03
Hi,



if(bit_is_set(PINA,PA1)) PB0=1;


jeder anständige Compiler müsste da gewaltig meckern (und keinen Code liefern!), denn Du meinst (rate ich mal) wahrscheinlich PORTB=1; . Hast Du mal auf die Fehler-/Warnmeldungen geschaut?

Gruß

Fred

BlackDevil
17.07.2008, 20:48
Jep, denkfehler gefunden - danke. Lag an PIN/PORT

fhs
18.07.2008, 08:22
Hi,

Jep, denkfehler gefunden - danke. Lag an PIN/PORT
genau! ich habe das Programmieren auf Englisch gelernt und würfele englische und deutsche Fachbegriffe immer durcheinander. Ich glaube aber, man sagt auch auf Deutsch "lvalue" und "rvalue" . Nur ein "lvalue" darf links von einem Gleichheitszeichen stehen; rechts stehen "rvalues". Man kann also z.B. nicht einer numerischen Konstante (ist immer ein "rvalue") einen neuen Wert zuweisen:<pre>1=2;</pre> wäre Unsinn. Gleiches gilt für die I/O-Pins, die eben nur "rvalue" sind.
Ich habe Dein Programm gerade mal zu kompilieren versucht (gcc Version vom Dezember 2007) und bekomme (zu Recht!) die Fehlermeldung:<pre>
..error: lvalue required as left operand of assignment</pre>

Das nur noch als Ergänzung.

Viele Grüße

Fred

BlackDevil
18.07.2008, 09:08
Jep die Fehlermeldung hatte ich auch - ich weis auch das es Rechte und Linke Operanden (R- und LValues) gibt :) Programmieren kann ich ja - mehr oder weniger - nur die Umsetzung C++>C und Konsole>µC fehlt ;)

fhs
18.07.2008, 10:43
Hi,

Jep die Fehlermeldung hatte ich auch - ich weis auch das es Rechte und Linke Operanden (R- und LValues) gibt :) Programmieren kann ich ja - mehr oder weniger - nur die Umsetzung C++>C und Konsole>µC fehlt ;)
danke für die deutschen Begriffe! Ja, bei den μCs ist man beim Programmmieren meist sehr nahe an der Hardware. Bei C++ bin ich dafür eine totale Niete; ich weiß nie, wie ich ein Problem in Klassen aufteile usw. Habe einfach bei OOP keinen Fuß fassen können. Im Vergleich zu C++ ist C bei größeren Projekten nicht gerade "schön", aber ich komme gut damit klar. Gegenüber FORTRAN (das war neben Assembler meine erste Programiersprache) ist das schon ein Fortschritt.


Gruß

Fred

BlackDevil
18.07.2008, 11:03
Wenn ich Assembler könnte würde ich da glaube ich bei den µC dort bleiben ... nächstes Semester soll der Spaß mit C und Inline Assembler Programmiert werden - was für ein Chip weis ich noch nich (Atmel, Intel oder PIC).

Ich bin im moment am überlegen ob ich das Hobby weiter treibe, hab mal geschaut ... ich komm relativ schnell zu Themen wo ich die Hardware nich hier habe und damit entstehen kosten. Und die Kosten stehen dann hier rum und erfüllen keinen Sinn und naja soviel Geld hab ich nun auch nicht ...

Mal sehen

fhs
18.07.2008, 12:06
Hi,


...ich komm relativ schnell zu Themen wo ich die Hardware nich hier habe und damit entstehen kosten. Und die Kosten stehen dann hier rum und erfüllen keinen Sinn ...
Hardware-Kosten sind bei den meisten Projekten wirklich nicht das Thema. Z.B. a. 1 μC +
b. 1 LCD +
c. 1 RTC (real time clock, könnte man auch weglassen)+
d. 1 SSR +
e. 1 Dreh-Encoder mit Taster +
f. 1 Steckergehäuse
zum periodischen Ein-/Ausschalten einer Umwälzpumpe: mit einigen Bauteilen aus der Bastelkiste (Trafo, Kondensatoren, Gleichrichter, Spannungsregler) <20€. OK, kann man für weniger kaufen, aber da ist immer noch der Spaß-Faktor bei der Eigenentwicklung!

Viel Erfolg,

Fred

BlackDevil
18.07.2008, 16:22
Wenn es dann aber an Motoren und deren Steuerung (Brushless etc) geht wirds wieder Sinnlos Teurer - eine Haus und Hof anwendung fällt mir nur in großem Maßstab ein: Das Vernetzte Haus.

Einzige was ich Interessant fände wäre ein Quattrocopter mit DigiCam und Servo-Fernauslöser - das hätte dann auch Nutzen und Spaß. Ein Vierbeiniger Laufroboter würde mich auch jucken.

Nur sind die Entwicklungskosten nicht unbedingt niedrig :( Zumal ich viel testen müsste...