PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Mikrocontroller Programmierung


Zergra
2013-01-12, 16:17:11
Hallo, ich habe ein Problem, wir Programmieren gerade für ein Projekt mit einem ATmega32 etwas.
Es geht um eine Sensorauswertung, und wir wollen die Motoren ausschalten wenn der Abstand zwischen 10-12 cm ist.
Es geht aber nicht, wir haben den Verdacht das in der Berechnung ein Fehler liegt.
Kann der Mikrocontroller eine Binäre zahl durch eine Dezimal teilen ?
oder muss ich erst eine Umwandlung schreiben ? (wäre dann eine Binär zu Dezimal umwandlung)
Wen ja wie geht diese ?

Marscel
2013-01-12, 18:22:31
Vielleicht postest du mal einen Code-Ausschnitt, bei der Fragestellung werd ich den Eindruck nicht los, dass ihr bei Zahlensystemen nicht so ganz durchgestiegen seid.

mksn7
2013-01-12, 19:20:43
Ihr habt den Umgang eines Prozessors mit Zahlensystemen wirklich nicht ganz verstanden. In der internen Repräsentation sind das immer Binärzahlen, einen dezimalen Datentyp gibt es (in der Regel) nicht.

Der Compiler wird, wenn ihr im Code eine Zahl stehen habt, die ins Binärsystem umwandeln. Man kann Zahlen auch hexadezimal ( 0xff123 ) oder im Mikro controllerbereich binär angeben ( 0b0100100 ). Im Binärcode werden alle Zahen binär stehen. (Hm, macht Sinn)

Zergra
2013-01-12, 23:23:42
ADMUX = 0b01100001; // AD Wandlung
ADCSRA = 0b10000111;
ADCSRA |= (1<<ADSC);
_delay_ms(1);
erg = ADCH;
PORTC = 0b00101000;

if (erg<75) // Kleinere Werte herausfiltern
{
PORTC=0;
}



abstanda = 3/256; //Kennlinie des Sensores (als
abstandb = erg*abstanda*7; //Funktion)
abstandc = 81/abstandb;
abstandd = 4/7;
abstand = abstandc+abstandd;

if (abstand>10 && abstand<12) //In dem Bereich Abschalten
{
PORTC=0;
}
OCR1A = erg; // Motor ansteuern
OCR1B = erg;
Ich bin mir auch gerade nicht Sicher, die Verschiedenen Abstände haben wir nur so genommen weil wir Dachten das der Mikrocontroller mit der Funktion nicht klar kommt.

Wenn ich von erg=100 ausgehe dann müsste abstand= ca. 10.4 sein

moBi
2013-01-13, 03:08:00
"abstandX" sind integer?

Gast
2013-01-13, 09:41:35
abstanda = 3/256; //Kennlinie des Sensores (als
abstandb = erg*abstanda*7; //Funktion)
abstandc = 81/abstandb;
abstandd = 4/7;
abstand = abstandc+abstandd;

if (abstand>10 && abstand<12) //In dem Bereich Abschalten
{
PORTC=0;
}
OCR1A = erg; // Motor ansteuern
OCR1B = erg;

Beim ersten Hingucken würde ich sagen: Dieser Code ist ganz großer Quatsch. Mich wundert, daß der Compiler dir das nicht gleich um die Ohren wirft.

Ich hab allerdings zugegebenermaßen nicht intensiv drüber nachgedacht, und ich hab damals auch nur hardcore auf dem ATTiny programmiert, das ist zum einen schon 3 Jahre her und ich muß mich da erstmal wieder reinlesen, und zum anderen kann ist der Mega ja bißchen mehr als der Tiny.

PatkIllA
2013-01-13, 09:50:41
"abstandX" sind integer?
ist das nicht egal?
In so ziemlich allen Sprachen sind die Werte eh alle 0, da erst die IntegerDivision durchgeführt wird und dann gewandelt wird.
Wäre höchstens noch das Verhalten bei Division durch 0 unterschiedlich. Das was der Threadersteller haben will kommt jedenfalls nicht raus.

Zergra
2013-01-13, 10:27:11
"abstandX" sind integer?
Hatten wir erst, jetzt sind es Float....
Beim ersten Hingucken würde ich sagen: Dieser Code ist ganz großer Quatsch. Mich wundert, daß der Compiler dir das nicht gleich um die Ohren wirft.

Naja der Obere Teil Fehlt ja, aber die ganzen floats waren nur da um zu testen ob es an der Funktion liegt.

Trap
2013-01-13, 10:40:26
4/7 und 3/256 sind beide exakt 0, weil der Compiler auf Ganzzahlkonstanten auch Ganzzahlarithmetik verwendet.

Nakai
2013-01-13, 11:39:25
4/7 und 3/256 sind beide exakt 0, weil der Compiler auf Ganzzahlkonstanten auch Ganzzahlarithmetik verwendet.

1. Das!
zB.: 4.0/7.0 oder 3.0/256.0. Ansonsten würde ich eher auf Festkommazahlen umschwenken, als auf Gleitkommazahlen. Letzteres ist beim Atmega(ohne FPU) einfach nur langsam.

2. Das ist ein 10Bit ADC, welcher von 0 bis 1023 auswerten kann.
Warum nimmt ihr nur die oben 2 Bits bzw. das Highbyte?!


erg = ADCH;

Das Ergebnis ist maximal 3.

Richtig wärs:

erg = ADCW;

Und wehe, erg ist ein char oder short. Bitte ein int oder gar long.
;)

moBi
2013-01-13, 13:58:55
ist das nicht egal?
In so ziemlich allen Sprachen sind die Werte eh alle 0, da erst die IntegerDivision durchgeführt wird und dann gewandelt wird.
Wäre höchstens noch das Verhalten bei Division durch 0 unterschiedlich. Das was der Threadersteller haben will kommt jedenfalls nicht raus.

Wollte nur einen sanften Tipp in Richtung Integer Division geben. :wink:

Tiamat
2013-01-13, 18:44:06
Bei Verwendung des ADCs ist ein dummy readout empfohlen. D.h ein mal konvertieren und diesen verwerfen, da man im Anschluss erst sicher sein kann, das der ADC zuverlässig Daten liefert. Der Rest wurde schon genannt.

Zergra
2013-01-14, 17:27:34
1. Das!
zB.: 4.0/7.0 oder 3.0/256.0. Ansonsten würde ich eher auf Festkommazahlen umschwenken, als auf Gleitkommazahlen. Letzteres ist beim Atmega(ohne FPU) einfach nur langsam.

2. Das ist ein 10Bit ADC, welcher von 0 bis 1023 auswerten kann.
Warum nimmt ihr nur die oben 2 Bits bzw. das Highbyte?!


erg = ADCH;

Das Ergebnis ist maximal 3.

Richtig wärs:

erg = ADCW;

Und wehe, erg ist ein char oder short. Bitte ein int oder gar long.
;)
Danke erstmal
1. Festkommazahlen ist "double" ?

Ich habe mal aus dem int ein long gemacht. Sollte aber beides gehen oder ? :D und ob ADCW oder ADCH dort habe ich den Unterschied nicht wirklich verstanden.

zu 2. haben wir erstmal nur zum Testen gemacht. Ist aber auch für unsere Sache mehr als Ausreichend.

Habe erstmal den Code ganz gepostet. Was würdest du den ändern ?


#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
DDRA = 0;
DDRB = 0xff;
DDRC = 0b00111100;

long erg;
float abstanda;
float abstandb;
float abstandc;
float abstandd;

float abstand;

TCCR1A |= (1<<WGM10);
TCCR1B |= (1<<WGM12);

TCCR2 = 0b01101111;

TCCR1A |= ((1<<COM1A1) | (1<<COM1B1));
TCCR1B |= (1<<CS12);
DDRD |= ((1<<PD4) | (1<<PD5) | (1<<PD7));

while(1)
{
ADMUX = 0b01100001;
ADCSRA = 0b10000111;
ADCSRA |= (1<<ADSC);
_delay_ms(1);
erg = ADCW;
PORTC = 0b00101000;

if (erg<75)
{
PORTC=0;
}



abstanda = 3.0/256.0;
abstandb = erg*abstanda*7.0;
abstandc = 81.0/abstandb;
abstandd = 4.0/7.0;
abstand = abstandc+abstandd;

if (abstand>10 && abstand<12)
{
PORTC=0;
}
OCR1A = erg;
OCR1B = erg;
}
}

moBi
2013-01-14, 17:50:17
Du solltest dir erst mal klar machen warum "3/4" 0 ergibt und zwar egal wohin man das speichert. Beides sind für den Compiler Integer also ergibt das 0 Rest 3, also wird 0 abgespeichert. Primitives Festkomma wäre jetzt (10*3)/4 = 7 Rest 2. So hat man die erste Nachkommastelle, wobei natürlich nicht gerundet wird. Darauf folgende Rechnungen müssen die Multiplikation mit 10 natürlich berücksichtigen.

Im Datenblatt/ReferenceManual des µC sollte das Verhalten des ADC ausführlich beschrieben sein. Mehr kann ich nicht sagen, ich kenn mich nur mit den STM32 Teilen aus.:redface:

Zergra
2013-01-14, 18:02:23
Du solltest dir erst mal klar machen warum "3/4" 0 ergibt und zwar egal wohin man das speichert. Beides sind für den Compiler Integer also ergibt das 0 Rest 3, also wird 0 abgespeichert. Primitives Festkomma wäre jetzt (10*3)/4 = 7 Rest 2. So hat man die erste Nachkommastelle, wobei natürlich nicht gerundet wird. Darauf folgende Rechnungen müssen die Multiplikation mit 10 natürlich berücksichtigen.

Im Datenblatt/ReferenceManual des µC sollte das Verhalten des ADC ausführlich beschrieben sein. Mehr kann ich nicht sagen, ich kenn mich nur mit den STM32 Teilen aus.:redface:
Naja dann kann ich 10,4 zb. garnicht Speicher sondern müsste mit 104 arbeiten.. das könnte natürlich gehen -.-

Coda
2013-01-14, 18:09:06
Du hast es erfasst.

moBi
2013-01-14, 18:11:58
@Zergra

Gleitkomma geht natürlich. Aber dann darfst du dem Compiler nicht"3/4" geben sondern "3.0/4", "3/4.0" oder "3.0/4.0". Der Compiler konvertiert nach gleitkomma, sobald ein Operand eine Gleitkommazahl ist. Bestimmt gibt es da aber Spitzfindigkeit mit der Reihenfolge bei verschachtelten Ausdrücken, also besser "3.0/4.0". Das ganze in ein float oder double schreiben und gut ist.

Die meisten (billigen) µC können aber nur viel(signifikant) langsamer mit Gleitkommazahlen rechnen als mit Integer. Deswegen rechnen viele mit Festkomma, was natürlich Konfort kostet. Teilen möchte man übrigends in der Regel auch nicht ;-):

Zergra
2013-01-14, 18:29:09
@Zergra

Gleitkomma geht natürlich. Aber dann darfst du dem Compiler nicht"3/4" geben sondern "3.0/4", "3/4.0" oder "3.0/4.0". Der Compiler konvertiert nach gleitkomma, sobald ein Operand eine Gleitkommazahl ist. Bestimmt gibt es da aber Spitzfindigkeit mit der Reihenfolge bei verschachtelten Ausdrücken, also besser "3.0/4.0". Das ganze in ein float oder double schreiben und gut ist.

Die meisten (billigen) µC können aber nur viel(signifikant) langsamer mit Gleitkommazahlen rechnen als mit Integer. Deswegen rechnen viele mit Festkomma, was natürlich Konfort kostet. Teilen möchte man übrigends in der Regel auch nicht ;-):
Okay danke, ich habe das oben mal soweit geändert. So müsste das gehen oder ?
Naja wir haben eine ATmega32 auf einem Board was unser Lehrer Designt hat, der ist zwar nicht der schnellste. Er wird mit 16Mhz getaktet :D

KhanRKerensky
2013-01-14, 18:38:40
2. Das ist ein 10Bit ADC, welcher von 0 bis 1023 auswerten kann.
Warum nimmt ihr nur die oben 2 Bits bzw. das Highbyte?!


erg = ADCH;

Das Ergebnis ist maximal 3.

Bit 5 in ADMUX ist gesetzt.

• Bit 5 – ADLAR: ADC Left Adjust Result
The ADLAR bit affects the presentation of the ADC conversion result in the ADC Data
Register. Write one to ADLAR to left adjust the result. Otherwise, the result is right
adjusted.

Das ist also durchaus in Ordnung, wenn einem 8 bit reichen.

Zergra
2013-01-14, 20:07:13
Also erstmal großes Danke, das geht so. Nur schaltet der Motor in dem Bereich nicht zu 100% ab ;D was er eigentlich sollte wenn ich die Ports auschalte. Oder liegt das daran das er für die Berechnung solange braucht und dabei den Motor wieder einschaltet ?

Oid
2013-01-14, 21:24:20
Kleine Integer skaliert man hoch, am besten mit einer zweier-Potenz (z.B. 256, 1024, usw.), damit man mit Shift-Operationen wieder herunterskalieren kann.

Ansonsten steht - wie bereits erwähnt - irgendwann mal eine Null im Prozessor, was die ganze Geschichte hinfällig macht.

Zergra
2013-01-17, 19:41:44
Hey, habe ein neues Problem
Wir sind wegen der überlastung unseres Motortreibers (Ausgelegt auf 2x600mA) und bei 2Motoren a 3.6A wegen Rauchentwicklung :D auf 2 Brushed Regler umgestiegen die auch Vor und Rückwärt den Motor ansteuern können.
Das Input Signal ist aber PPM.
Ich habe dafür erstmal ein kurzes Programm geschrieben, (das wird später noch besser nur momentan möchte ich nur Testen wie ich die Signallängen verschieben muss)
#define F_CPU 16000000
#include <util/delay.h>

int main (void)
{


DDRB = 0b11111111;



while(1)
{
PORTB = 255;
_delay_ms(19.6);
PORTB = 0;
_delay_ms(0.3);
PORTB = 255;
_delay_ms(1.7);
PORTB = 0;
_delay_ms(0.3);


}

}



Nur habe ich mich schon ziemlich lange eingelesen und finde meinen Fehler nicht, die Motoren möchten nicht drehen -.-
Hat jmd. eine Idee ? oder muss ich auch 8 Kanäle verwenden ? :rolleyes:

Danke schonmal ;)

moBi
2013-01-17, 20:21:28
Ich nehme an PWM.

1. Mit ziemlicher Sicherheit gibt es eine Peripherie im µC, welche PWM-Signale ausgeben kann. Imho der bessere Weg.

2. Datenblätter lesen und ggf. mit Oszilloskop gegenprüfen, ob der Code auch wirklich das produziert was der Empfänger braucht.

Zergra
2013-01-17, 20:36:44
Ich nehme an PWM.

1. Mit ziemlicher Sicherheit gibt es eine Peripherie im µC, welche PWM-Signale ausgeben kann. Imho der bessere Weg.

2. Datenblätter lesen und ggf. mit Oszilloskop gegenprüfen, ob der Code auch wirklich das produziert was der Empfänger braucht.
Nein, du hast richtig gelesen PPM. PWM Signale sind kein Problem das bekomme ich auch hin. Oszi kann ich nochmal schauen, aber da muss ich erst zu meinem Bruder fahren.. (4km immerhin :D)

moBi
2013-01-17, 21:09:05
Interessant, evtl. hilft das (http://procopterx.chisaw.de/?page_id=55).

DraconiX
2013-01-20, 10:31:28
Mit einem Atmega32 kann man doch den Hardwareseitigen PWM auch als PPM nutzen - das ist doch quasi völlig identisch?! Mom... schguck mal Datenblatt...

EDIT:
Jo... Datenblatt Seite 76 "Phase Correct PWM Mode" dürfte für dich ganz interessant sein. Im Grunde unterscheidet sich ein PPM von einem PWM ja bloß das das High Signal nicht den kompletten Takt umfasst sondern bloß so ungefähr ein Drittel, ergo bedarf es da bloß einer höheren Auflösung bzw. geringer Frequenz. Ich kenne mich nun im Modellbau nicht wirklich aus, aber so um die 50Hz dürften da optimal sein.

Zergra
2013-01-20, 12:12:25
Interessant, evtl. hilft das (http://procopterx.chisaw.de/?page_id=55).
Mit einem Atmega32 kann man doch den Hardwareseitigen PWM auch als PPM nutzen - das ist doch quasi völlig identisch?! Mom... schguck mal Datenblatt...

EDIT:
Jo... Datenblatt Seite 76 "Phase Correct PWM Mode" dürfte für dich ganz interessant sein. Im Grunde unterscheidet sich ein PPM von einem PWM ja bloß das das High Signal nicht den kompletten Takt umfasst sondern bloß so ungefähr ein Drittel, ergo bedarf es da bloß einer höheren Auflösung bzw. geringer Frequenz. Ich kenne mich nun im Modellbau nicht wirklich aus, aber so um die 50Hz dürften da optimal sein.
Okay, danke euch beiden ich werde es heute mal testen und dann berichten ;)

DraconiX
2013-01-20, 20:45:40
Ich schreib mal schnell was... Wie sehen deine Frequenzen aus?!

Zergra
2013-01-23, 10:39:21
Wie meist du das? Der Motor hat eine Ansteuerfrequenz von 2kHz.
Ich würde aber von eine Frequenz von 50Hz ausgehen

DraconiX
2013-01-23, 14:39:53
Moment... wie sieht denn dein Aufbau aus?! Nutz du den Motor direkt am µC? Ohne Motortreiber dazwischen?!

Zergra
2013-01-23, 15:30:19
Moment... wie sieht denn dein Aufbau aus?! Nutz du den Motor direkt am µC? Ohne Motortreiber dazwischen?!
Nein ein Motortreiber ist vorhanden L293D ist es.

DraconiX
2013-01-24, 08:05:28
Nein ein Motortreiber ist vorhanden L293D ist es.


Ah, ok - schöner Treiber übrigens. Dein Motor ist Bidirektional und hängt am Port 1Y und 2Y?

Dazu musst du erstmal Pin1 des Treibers auf High setzen damit du den Treiber überhaupt für Port 1,2Y aktivierst. Dann musst du aber ein Gegensätzlichen Puls auf Pin 2 (1A) und Pin 13 (2A) geben.

So wie dein Programm aussieht (kompletter Port des µC schaltet (PortB = 255)) schaltest du aber dann komplett den 1A und 2A auf high / low, somit dürfte sich im Treiber bzw. im Motor garnichts bewegen.

Zergra
2013-02-06, 16:33:27
Ah, ok - schöner Treiber übrigens. Dein Motor ist Bidirektional und hängt am Port 1Y und 2Y?

Dazu musst du erstmal Pin1 des Treibers auf High setzen damit du den Treiber überhaupt für Port 1,2Y aktivierst. Dann musst du aber ein Gegensätzlichen Puls auf Pin 2 (1A) und Pin 13 (2A) geben.

So wie dein Programm aussieht (kompletter Port des µC schaltet (PortB = 255)) schaltest du aber dann komplett den 1A und 2A auf high / low, somit dürfte sich im Treiber bzw. im Motor garnichts bewegen.
Hey,
nein das waren nicht die Probleme, ich habe ihn hierbei direkt an PortB angeschlossen. Ich habe aber nach langem Testen und vielen Stunden verzweifeltem lesen aufgegeben. Da das Projekt auch fertig werden muss, bin ich auf 2 einfache Regler umgestiegen die über PWM angesteuert werden. Dies kann ich ja :D. Jetzt habe ich ein Relais mit 2 Wechslern eingebaut und das Problem des fehlenden Schubumkehrs ist gelöst.

Danke nochmal ;)