PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Morsecode und Bitverschiebung



runner02
18.09.2010, 12:29
Hallo,

Bräuchte wieder mal etwas Hilfe:

Um Floats zu umgehen rechne ich meinen ADC*30805

z.B. bei spannung=1023*30805 -> 31513515


Mit spannung=spannung<<4;
müsste es dann doch 3151 heißen, oder??
Also das Komma wird verschoben und die Stellen gehen verloren?

Also habe ich 3151 mV gemessen. Soweit richtig?


Dann würde ich nochmal sp.=sp.<<1
Dann kommt mir 315 raus, das würde ich gern mit Leds morsen....

Kann man irgendwie die Hunderter, Zehner, Einser auslesen, ohne mit floats zu arbeiten??



Vielen Dank im Vorraus!!

Richard
18.09.2010, 14:53
Ich bin ja kein C Spezialist, eher C-Dummi aber "<<4" sollte
4x links schieben bedeuten. Damit ist NICHT das "," gemeint!

Jedes links schieben verdoppelt den Wert , jedes >> rechts schieben halbiert den Wert.

00000001
<<1
00000010
<<1
000000100...u.s.w.

Gruß Richard

BurningWave
18.09.2010, 17:09
Das komme kann man immernoch mit x * 10 um eine Stelle nach rechts und mit x / 10 um eine Stelle nach links schieben.



Kann man irgendwie die Hunderter, Zehner, Einser auslesen, ohne mit floats zu arbeiten??

Ja, mit Bitmasken: x & 0x1 liefert dir das erste Bit, x & 10 das 2. usw.

runner02
18.09.2010, 17:28
Das Komma kann man immernoch mit x * 10 um eine Stelle nach rechts und mit x / 10 um eine Stelle nach links schieben.

Naja, bei mir funktioniert ja das float nicht, daher kann ich wohl kaum /10 rechnen... Bin zwar dabei das AVR-Studio zu erlernen, aber bis dahin hätte ich es gerne mal so gemacht...

Zu den Bitmasken:
0x1 sieht mir nach Hexadezimal aus, muss das noch prüfen... Denn verstehen tu ichs leider noch nicht, was da passiert...

Achso, das ist binär.. 0x11 ist dann 3?

also i=x&(00000001) ?? wobei i=einerstelle, x=Zahl

BurningWave
18.09.2010, 17:34
Oh sry, das muss 0b1, 0b10, usw. heißen, nicht 0x. 0x Ist Hexadezimal 0b binär, was du hier auch brauchst. Du kannst bei Integern genauso durch 10 teilen, dann wird alles nach rechts verschoben und die letzte Stelle fällt eben weg.

Richard
18.09.2010, 17:41
Das komme kann man immernoch mit x * 10 um eine Stelle nach rechts und mit x / 10 um eine Stelle nach links schieben.



Kann man irgendwie die Hunderter, Zehner, Einser auslesen, ohne mit floats zu arbeiten??

Ja, mit Bitmasken: x & 0x1 liefert dir das erste Bit, x & 10 das 2. usw.

Mit Multiplizieren oder dividieren Kann man beinahe jede gewünschte Zahl "einstellen". Mit Bit schieben kann man nur verdoppeln oder Halbieren = x2 oder/2 Pro <<1.2.3.....
also 1,4,8,16,32......3,5,6,7 kann man mit <<(x) nicht erreichen.

5x10 = 50 ist Dezimal damit kannst Du natürlich jede belibige Integerzahl darstellen.

Gruß Richard

runner02
18.09.2010, 17:41
Du kannst bei Integern genauso durch 10 teilen, dann wird alles nach rechts verschoben und die letzte Stelle fällt eben weg.

Ah, danke. Das ist schon mal sehr gut...

Und als Quellcode?

Kann ich da dann:


intger zahl = 1234;

einerstelle=zahl&0b1

Hoffe das stimmt soweit???

Besserwessi
18.09.2010, 18:21
Das & und der << operator sind für die Binärdarstellung. Man bekommt in dem Porgramm oben schon die einerstelle, aber die aus der Binärdarstellung, also eine 1 oder 0. Für die Dezimaldarstellung müßte man schon mit Modulo (%) und Division arbeiten. Alternativ gibt es die Funktion atoi() aus Stdlib, um von Integer in einen String zu wandeln.

runner02
18.09.2010, 18:38
Alternativ gibt es die Funktion atoi() aus Stdlib, um von Integer in einen String zu wandeln.

Aber einen String brauche ich doch nicht, sonern eine verwertbare Zahl.

Dann gibt es eine schleife, die eine Led blinken lässt und die läuft ''einerstelle'' - mal. (1,2,3,...9)



Man bekommt in dem Porgramm oben schon die einerstelle, aber die aus der Binärdarstellung, also eine 1 oder 0. Für die Dezimaldarstellung müßte man schon mit Modulo (%) und Division arbeiten.

Wie das?

12345 dann kann ich zb. 45 wegoperieren, aber 12 kann ich nicht mittels Bitverschiebung streichen...

einerstelle=(%spannung)&(%0b1) kann es so hinhauen? Hab da sonst absolut keine Idee, wie man das bewerkstelligen könnte...

BurningWave
18.09.2010, 18:45
Ein komplett neuer Lösungsansatz:


int x = 12345;
int y = x % 10; //= 5
x /= 10; //x = 1234
y = x % 10; //= 4
x /= 10; //x = 123
y = x % 10; //= 3

Gock
19.09.2010, 14:17
Mit R2D2s Methode geht es zwar, bei größeren Zahlen jedoch stößt die Modulo Operation an ihre Grenzen bzw erzeugt unnötig großen Code und damit Rechenzeit, was in zeitkritischen Anwendung ausgeschlossen ist.
Es geht auch mit den Grundrechenarten, für den Controller je nach Zahlengröße schneller gerechnet:


Int Zahl = 12345;
Stelle_5 = Zahl / 10000; // =1
Stelle_4 = Zahl - Stelle_5*10000 / 1000; //=2
...

Das kann man jetzt auch noch optimieren, aber so versteht man es besser.
Gruß

runner02
19.09.2010, 17:43
@Gock

Ich glaube hiermit habe ich das selbe geschrieben (Idee hab ich beim Surfen gefunden):



uint16_t readADC(uint8_t channel)
{
// Funktion 1 zum Auslesen der Spannung

uint8_t i; // Variablen definieren (Zählervariable i + Resultat)
uint16_t result = 0;

ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1); //ADEN = ADC Enable
// wenn adps1+2 on sind und adps0 off, dann ist der Teilungsfaktor 64 (Tabelle Datasheet)

ADMUX = channel; //Kanal wählen; REFs0+1 -> interne Referenz 2,56V verwenden, REFS1 gibt es bei Attiny13 nicht
//externen Kondensator mit 100nF (Aufdruck 104) an AREF auf Masse

//Dummy-Readout (unten), misst 1* Ergebnis, wird nicht gespeichert
ADCSRA = ADCSRA | (1<<ADSC); // Schaltet bei ADCSRA das ADSC-Bit ein, d.h. Messung starten
while(ADCSRA & (1<<ADSC)); //Warte bis Messvorgang vorbei ist

// Nun 3* Spannung auslesen, Durchschnittswert ausrechnen
for (i=0; i<3; i++)
{
// Schleife, startet 3*
ADCSRA = ADCSRA |(1<<ADSC); // Einmal messen
while(ADCSRA & (1<<ADSC)); //Warte bis Messung vorbei

result = result + ADCW; // Resultate zusammenzählen (R1+R2+R3) -> später alles /3
}

ADCSRA = ADCSRA & (~(1<<ADEN)); //ADC wieder deaktivieren

result=result/3; // Durchschnittswert

return result;
}

main () // Hauptprogramm, startet bei Power ON und Reset
{
int spannung; //Definiere Ganzzahl-Variable Spannung
int einer,zehner, hunderter, startwert, mittelwert, endwert;
int i,j,k = 0;

DDRB=0b00001111;

while (true)
{

uint16_t result = readADC(0); // ruft die ADC Funktion auf an Pin0 =ADC0

spannung = result*3086;
spannung = spannung/1000;

startwert=spannung/10;
hunderter=startwert/100;
mittelwert=startwert-100*hunderter;
zehner=mittelwert/10;
endwert=mittelwert-10*zehner;
einer=endwert;

for (i=0;i<einer;i++)
{
PORTB=PORTB|(1<<PB0);
waitMs(50);
PORTB=PORTB&(~(1<<PB0));
waitMs(50);
}

for (j=0;j<zehner;j++)
{
PORTB=PORTB|(1<<PB1);
waitMs(50);
PORTB=PORTB&(~(1<<PB1));
waitMs(50);
}

for (k=0;k<hunderter;k++)
{
PORTB=PORTB|(1<<PB2);
waitMs(50);
PORTB=PORTB&(~(1<<PB2));
waitMs(50);
}

waitMs(1100);

}

return 0;
}

Der Code klappt zum draufbrennen, aber in der Schaltung funktioniert er nicht... HAb ich nen Fehler eingebaut??

Gock
19.09.2010, 18:03
Gelöscht, war.Unsinn
Aber bei mir oben ist auch ein kleiner Fehler: Hab die Klammer vergessen...


Int Zahl = 12345;
Stelle_5 = Zahl / 10000; // =1
Stelle_4 = (Zahl - Stelle_5*10000) / 1000; //=2345/1000=2
...

Gruß

runner02
19.09.2010, 18:26
Hey, glaube das stimmt schon.

Spannung ist nicht 3086, sondern (ADC)result (0...1024) * 3086;

Dh. zb. 1023*3086 also 3156978.... Das durch 1000 ist 3156 mV !

Gock
19.09.2010, 18:50
Hast natürlich recht, hab die Multiplikation ignoriert.
Der Code sieht eigentlich gut aus beim Überfliegen.
Was funktioniert denn nicht genau?
Gruß

runner02
19.09.2010, 18:56
Kann passieren ;)

Naja, der Code wird vom AVR-Workpad raufgebrannt, und er schreibt ''erfolgreich gebrannt''...

Das heißt, wenn ich den Chip in die Schaltung gebe, müsste es gehen.

Ich stecke ihn also in die AVR-Chip-Halterung und schließe die Batterie an... Die Schaltung müsste dann funktionieren, tut sie aber nicht... (Momentan habe ich keine LED an den Pin der einerstelle angeschlossen, das sollte aber kein Problem sein... )

Nichts leuchtet oder blinkt...

Gock
19.09.2010, 19:14
Du scheinst einen Tiny13 zu benutzen und willst ADC0 auslesen. Der zugeordnete Pin ist auch der Reset!
Hast Du das entsprechend gefust? -> Datenblatt "Table 10-4. Overriding Signals for Alternate Functions in PB5:PB3"
Aber Achtung, wenn Du den Reset deaktivierst, kannst Du danach nicht mehr mit Deinem Brenner zugreifen. Nimm also lieber einen anderen ADCPin.
Gruß

runner02
20.09.2010, 09:08
Hey, Danke. Das ist eine Idee... werd mal versuchen, das auf den ADC1 zu legen...

(zu den waitMs(50), da muss ich nochml umschreiben, aber normalerweise ist die Taktung automatisch falsch eingestellt, dass 50Ms ca. 300-500 sind, man es also sieht... Könnte auch dran liegen, dass es diesmal irgendwie die richtige Taktung ist und man die Blinksignale einfach nicht sieht... Aber sehr unwahrscheinlich...)

runner02
13.10.2010, 17:28
Hey,

habe gerade folgendes Programm ausprobiert



int hunderter=5;
int i;

main ()

{

while (true)
{
for (i = 0; i < hunderter; i++)
{

PORTB=PORTB|(1<<PB1);
waitMs(100);
PORTB=PORTB&(~(1<<PB1));
waitMs(100);
}

waitMs(1100);
}
}

Das sollte doch gehen, oder?

Nur, bei mir leider wieder mal nicht :(

Hunderter soll hierbei den Hunderterwert einer gemessenen Variable sein, provisorisch habe ich sie mal auf 5 gesetzt, um zu sehen, ob dieses Minimalprogramm geht.... Leider eben nicht. Wäre echt grooßartig, falls mir da jemand weiterhelfen könnte...!

BurningWave
13.10.2010, 17:55
Globale Variablen sind nicht gut, int i kann im Kopf der Schleife erstellt werden:



int hunderter=5;

main ()
{
while (true)
{
for (int i = 0; i < hunderter; i++)
{

PORTB |= (1<<PB1);
waitMs(100);
PORTB &= ~(1<<PB1);
waitMs(100);
}

waitMs(1100);
}
}


Im Prinzip sollte es funktionieren, vorausgesetzt, deine waitMs arbeitet richtig. Schau dir mal die _delay_ms(x) Funktionen aus der util\delay.h an.

runner02
13.10.2010, 18:35
Im Prinzip sollte es funktionieren, vorausgesetzt, deine waitMs arbeitet richtig.

Also sie arbeiten eigentlich nicht richtig - und sind so ausgelegt, dass der Fehlfaktor genau so hoch ist, dass sie wieder sichtbar blinken.

Also das klappte heute schon 5-6 mal bei nem Programm, mit if (hunderter==0) ....... if (hunderter== 1 ...... if (hunderter==2)

Das delay habe ich mir mal angeschaut, hat aber nicht ordentlich funktioniert (eig. gar nicht)...

Sobald mein Temperatursensor fertig ist, beschäftige ich mich näher damit...

BurningWave
13.10.2010, 19:13
Funktioniert es jetzt oder funktioniert es nicht?

Hast du auch F_CPU definiert, als du _delay_ms verwendet hast?

runner02
17.10.2010, 14:21
Es funktioniert, abwer die Taktung ist offensichtlich falsch.


Hast du auch F_CPU definiert, als du _delay_ms verwendet hast?

Ich denke schon, so wie es in nem Beispielprogramm vorkam...

BurningWave
17.10.2010, 17:28
Hm, die _delay-Funktionen sind eigentlich die genausten Warte-Funktionen, wenn man keinen Timer benutzt.

Funktioniert es so nicht:
#include <util/delay.h>
#define F_CPU [die Taktrate deines µCs (in Hz!), z.B. 4000000ul]

Jetzt sollte _delay_ms(x) funktionieren.

Du musst aber beachten, dass die Funktionen sehr ungenau arbeiten, falls du den internen Quarzoszillator nutzt.

runner02
19.10.2010, 16:13
Ich denke, das Problem liegt nicht in dem Programm, das ich eingebe, sondern entwerder im MK2 oder im Compiler.

Habe eine E-Mail an den Support von myAVR geschickt, eine Bestätigungsmail kam bereits.

Ich hoffe, dass bald eine Lösung kommt...


Mfg

runner02
07.12.2010, 17:09
Ok, habe schlussendlich das Problem gefunden.

Ist zwar ziemlich peinlich, dennoch poste ich es:

Bei for-schleifen darf man auf keinen Fall DDRB vergessen, sonst blinkt die LED logischerweise nicht, man verstellt nur den pull-up!!

hardware.bas
07.12.2010, 19:43
Ja - unprogrammiert werden die freien Ports auf Eingang ohne
PullUp declariert. Eigentlich bei ISP in der bestückten Schaltung
sehr sinnvoll. VG Micha

hardware.bas
07.12.2010, 19:43
Ja - unprogrammiert werden die freien Ports auf Eingang ohne
PullUp declariert. Eigentlich bei ISP in der bestückten Schaltung
sehr sinnvoll. VG Micha

BurningWave
07.12.2010, 20:24
Bei for-schleifen darf man auf keinen Fall DDRB vergessen, sonst blinkt die LED logischerweise nicht, man verstellt nur den pull-up!!


Nicht nur in for-Schleifen. Es ist imnmer wichtig, mittels DDRX anzugeben, in welche Richtung Daten fließen sollen, wenn man nicht aus Versehen einen µC-Pin zerstören will.

hardware.bas
07.12.2010, 21:12
Was -R2D2 schreibt, trifft den Nagel 100prozentig auf den Kopf.
Für Anwender, die immer die AVRs erst nach dem Bestücken ohne
Sockel in der Anwendung programmieren - ich gehöre zu Denen -
ist das schon Gewöhnungssache. VG Micha