PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ADC-Werte mit Codeschnipsel



NikNek
04.01.2007, 16:11
Hallo, ich habe mir die Codeschnipsel von muraad runtergeladen und aalles funktioniert auhc wunderbar mit einem Eingang, da ich aber 2 Sensoren (CNY70) habe möchte ich ständig die Werte von diesen in 2 unterschiedlichen integern speichern.

Mein jetziger Code
int main(void) // Main-Funktion, d.h. dass was der Roboter macht!
{
init();
warte(2000);

unsigned int l; // ADC-Wert für linken Sensor
unsigned int r; // ADC-Wert für rechten Sensor

ADCinit;
ADCchannel_init;
//ADCfree;
ADCvintern;
//ADCinterrupt_on;
ADCprescaler_16;

while(1==1)
{

ADCchannel_1;
ADCstart;
l=getadc();

ADCchannel_reset;

ADCchannel_2;
ADCstart;
r=getadc();


if (l>0 && l<8) // wenn schwarzer Untergrund
L_Motor_v();

if (l>=8) // wenn weißer Untergrund
L_Motor_r();


if (r>0 && r<8) // wenn schwarzer Untergrund
R_Motor_v();

if (r>=8) // wenn weißer Untergrund
R_Motor_r();


warte(10);
}


return 0;
}

Jedoch funktioniert dieser nicht.

Bitte um schnelle Hilfe.

PS: Hier noch die Defines aus dem Codeschnipsel:

/* Analog/Digital converting */
#define ADCchannel_init DDRA=0x00 // ADC Port als Eingang deklarieren
#define ADCinit ADCSRA|=_BV(ADEN) // Teilt dem Board mit, dass der jeweilige Port für ADC verwendet wird
#define ADCdisable ADCSRA &=~_BV(ADEN) // mach das vorherige wieder rückgängig
#define ADCstart ADCSRA|=_BV(ADSC) // startet eine Konvertierung auf dem gewünschten Kanal/Pin
#define ADCfree ADCSRA|=_BV(ADATE) // schaltet den freilaufenden Modus ein
#define ADCvintern ADMUX|=_BV(REFS0) // interne Spannungsversorgung
#define ADCinterrupt_on ADCSRA|=_BV(ADIE) // ADC interrupt wird freigeschaltet
#define ADCprescaler_2 ADCSRA |=_BV(ADPS0) // gewünschter Teilungsfaktor/Prescaler
#define ADCprescaler_4 ADCSRA|=_BV(ADPS1)
#define ADCprescaler_8 ADCSRA=_BV(ADPS1) | _BV(ADPS0)
#define ADCprescaler_16 ADCSRA|=_BV(ADPS2)
#define ADCprescaler_32 ADCSRA=_BV(ADPS2) | _BV(ADPS0)
#define ADCprescaler_64 ADCSRA=_BV(ADPS2) | _BV(ADPS1)
#define ADCprescaler_128 ADCSRA=_BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0)
#define ADCprescaler_reset ADCSRA = ~_BV(ADPS2) & ~_BV(ADPS1) & ~_BV(ADPS0)
#define ADCchannel_1 // gewünschter Kanal z.B bei ATmega32 PINA0 - PINA7
#define ADCchannel_2 ADMUX|=_BV(MUX0) // wenn kein Freilaufen-Modus muss ADCchannel_x vor ADCstart
#define ADCchannel_3 ADMUX|=_BV(MUX1) // kommen, dann kann man mit getadc() den
#define ADCchannel_4 ADMUX= _BV(MUX1) | _BV(MUX0) // Adcwert des gewählten Kanals auslesen
#define ADCchannel_5 ADMUX|=_BV(MUX2)
#define ADCchannel_6 ADMUX= _BV(MUX2) | _BV(MUX0)
#define ADCchannel_7 ADMUX= _BV(MUX2) | _BV(MUX1)
#define ADCchannel_8 ADMUX= _BV(MUX2) | _BV(MUX1) | _BV(MUX0)
#define ADCchannel_reset ADMUX= ~_BV(MUX2) & ~_BV(MUX1) & ~_BV(MUX0)

inline unsigned int getadc(void)
{
while (ADCSRA & _BV(ADSC)) {}
return ADC;
}

Hubert.G
04.01.2007, 18:20
Was funktioniert nicht? Welchen Kontroller verwendest du? Bist du dir sicher das der Fehler genau in den Codeschnipsel liegt die du gepostet hast?

NikNek
04.01.2007, 18:27
Ich benutze das RN-Control 1.4 Board und ich kann es mithilfe von Schleifen nciht hinbekommen das sowohl der ADC-Wert von Channel1 als auch der von Channel2 ständig in einem integer gespeichert wird.

Es sollen also ständig beide Spannungen der Sensoren umgewandelt werden in digitale Werte.

Im Grunde habe ihc versucht erst den Wert des ersten Sensors zu speichern und dann den des 2., dann sollen die Motoren auf die Werte reagieren(Linienverfolgung) und dann soll wieder der 1. und dann der 2. ausgelesen werden usw...

Hubert.G
04.01.2007, 18:36
Was für einen Sensor wertet er aus? Keinen oder unregelmässig?

NikNek
04.01.2007, 18:40
Er wertet einen CNY70 Optoreflexkopller aus der einfach nur seine Spannung ändert zwischen 0 und 5V. Als ich einfach nur 1 Sensor ausgewertet habe hat er die Werte im Integer immer wieder aktualisiert und halt mti dem Motor drauf reagiert, z.b wenn ich ein Stück Papier vor den Sensor gehalten habe.

linux_80
04.01.2007, 18:40
Hallo,

wo hast Du die Defines her, hab das jetzt nicht nachgerechnet mit den Bitmanipulationen, schaut aber erstmal komisch aus :-k

Vor dem ersten einstellen in der Schleife sollte dann wohl auch noch ein ADCchannel_reset stehen, sonst wird immer nur der 2. Kanal gemessen.

Und so wie das ausschaut muss Du jedesmal den Prescaler neu setzen,
aber ich glaub Du musst erstmal in jeder Zeile die Zuweisung der Bits gleich vornehmen, einmal mit einmal ohne | "oder", da kommt alles durcheinander.

NikNek
04.01.2007, 18:41
Hmm also die defines sind von dem Forum hier aus der Download Sektion:

https://www.roboternetz.de/phpBB2/dload.php?action=file&file_id=178

linux_80
04.01.2007, 18:44
Schau mal im Wiki auf die ADC (Avr) Seite, die ist im Moment auch auf der Hauptseite und verlinkt,
da ist auch ein Beispiel drin, das sollte gehen.

€dit:
Da ist auf jeden Fall der Wurm drin in den Defines, ich würde jede Zeile mit | zuweisen !
zB. bei ADCchannel_reset wird sonst die Referenzeinstellung gelöscht, falls nicht extern.

NikNek
04.01.2007, 18:57
Hmm ich habe jetzt einfach mal die Funktion ausm Wiki genommen, dort wird immer ein Datentyp uint16_t von der Funktion wiedergegeben, kann ich den einfach als normalen int benutzen??

Edit:

Vielen Dank der Code aus dem Wiki ist besser jetzt kann ich beide Sensoren gleichzeitig auslesen und die Motoren danach programmieren.
Hat wunderbar ohne die Defs funktioniert.

Hubert.G
04.01.2007, 19:26
Schau dir in deinen defines den ADCannel_1 an, da ist nichts definiert

NikNek
04.01.2007, 19:29
komischerweise hatten die defines mit channel 1 also pin0 wunderbar alleine funktioniert.

Naja mein neuer Code is jetzt:


#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/signal.h>
#include <string.h>
#include <compat/deprecated.h>
#include <inttypes.h>
#include <myheader.h>

#define SYSCLK 16000000


void init(void);

// Initialisierung
void init(void)
{
DDRD= (1<<PD4) | (1<<PD5); // PWM Pins als ausgang
DDRC= (1<<PC6) | (1<<PC7); // 6=Motor 1 Kanal 1 7= Motor 1 Kanal 2
DDRB= (1<<PB0) | (1<<PB1); // 0=Motor 2 Kanal 1 1= Motor 2 Kanal 2
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<COM1A0) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10);
// 10 Bit Pwm, invertierend
TCCR1B = (1<<CS11) | (1<<CS10); // Prescaler 64
OCR1A=1; // Mindestzeit für PWM1
OCR1B=1; // Mindestzeit für PWM2

}

void warte(unsigned int ms) // Wartet um x ms
{
unsigned int zaehler;

while (ms)
{
zaehler = SYSCLK / 20000;
while (zaehler)
{
asm volatile ("nop");
zaehler--;
}
ms--;
}
}

void R_Motor_r() // Rechter Motor rückwärts
{
sbi(PORTC,6);
cbi(PORTC,7);
}

void R_Motor_v() // Rechter Motor vorwärts
{
sbi(PORTC,7);
cbi(PORTC,6);
}

void R_Motor_s() // Rechter Motor stop
{
cbi(PORTC,7);
cbi(PORTC,6);
}

void L_Motor_r() // Linker Motor rückwärts
{
sbi(PORTB,0);
cbi(PORTB,1);
}

void L_Motor_v() // Linker Motor vorwärts
{
sbi(PORTB,1);
cbi(PORTB,0);
}

void L_Motor_s() // Linker Motor stop
{
cbi(PORTB,1);
cbi(PORTB,0);
}

uint16_t readADC(uint8_t channel) //Funktion um ADC-Wert auszulesen an Pin channel
{
uint8_t i;
uint16_t result = 0;

// Den ADC aktivieren und Teilungsfaktor auf 64 stellen
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);

// Kanal des Multiplexers waehlen
ADMUX = channel;
// Interne Referenzspannung verwenden (also 2,56 V)
ADMUX |= (1<<REFS1) | (1<<REFS0);

// Den ADC initialisieren und einen sog. Dummyreadout machen
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1<<ADSC));

// Jetzt 3x die analoge Spannung and Kanal channel auslesen
// und dann Durchschnittswert ausrechnen.
for(i=0; i<3; i++) {
// Eine Wandlung
ADCSRA |= (1<<ADSC);
// Auf Ergebnis warten...
while(ADCSRA & (1<<ADSC));

result += ADCW;
}

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

result /= 3;

return result;
}

int main(void) // Main-Funktion, d.h. dass was der Roboter macht!
{
init();
warte(2000);

unsigned int r; // ADC-Wert für rechten Sensor
unsigned int l; // ADC-Wert für linken Sensor

for(;;)
{

r = readADC(0); //Auslesen der analogen Spannungen an Pin 0
l = readADC(1); //Auslesen der analogen Spannungen an Pin 1

if (r>0 && r<32) // wenn schwarzer Untergrund
R_Motor_v();

if (r>=32) // wenn weißer Untergrund
R_Motor_r();


if (l>0 && l<32) // wenn schwarzer Untergrund
L_Motor_v();

if (l>=32) // wenn weißer Untergrund
L_Motor_r();

warte(10);
}


return 0;
}

linux_80
04.01.2007, 19:36
Bei 16MHz solltest Du den Prescaler auf 128 stellen, also am Ende der Zeile noch ein | (1 <<ADPS0) dazu, sonst läuft der ADC zu schnell, er sollte unter 200kHz kommen.

so schauts dann aus:

// Den ADC aktivieren und Teilungsfaktor auf 128 stellen
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1 <<ADPS0);

Hubert.G
04.01.2007, 19:37
Er hat mit Channel 1 begonnen auf Channel 2 geschaltet und konnte dann nicht mehr zurück.
Dein Prog hat nur den Schönheitsfehler das du, wenn noch weiterer Code dazukommt, aufgrund der Warteschleifen timingprobleme bekommen wirst. Versuche mit Interrupts zu arbeiten und Timer, auch wenn es so jetzt klaglos funktioniert.