Forum: Compiler & IDEs ADC wert über RS232 senden


von carine (Gast)


Lesenswert?

Hallo Zusammen

Ich bin kein µC Profi und arbeite mich gerade durch Beispielprogramme
sowie das Tutorial.
Zur Zeit experimentiere ich gerade mit einem atmega 8 auf der STK500 
Platine

Zu tun:  gewandelten AD-Wert per UART auf dem Hyperterminal 
darzustellen.


Zu der Hardware:
1. ATMega8 auf dem STK500 Platine
2. extene Quarz 4 Mhz
3. int AREF also AREF-Jumper gesetzt.
4. Analog eingang direckt an PINC.0 verbunden.

Schon ausprobieren:
uart (senden und empfangen funktionieren)

Zu der Software:
Ich habe aus ADC-Beispielen eine eigene Code zusammengebastelt.

Code:
1
#ifndef F_CPU
2
#warning "F_CPU was not defined yet, now make up with 4000000"
3
#define F_CPU 4000000L 
4
#endif
5
6
7
#define BAUD 9600L
8
#define UBRR_VAL ((F_CPU+BAUD * 8)/(BAUD*16)-1)     //clever round
9
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))         //real baud rate
10
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)     //Error per thousand
11
12
13
#if ((BAUD_ERROR>10)||(BAUD_ERROR<-10))
14
#error Systematic error in the baud rate more than 1% and thus too high!
15
#endif
16
17
18
#include <avr/io.h>
19
#include <stdlib.h>
20
#include <inttypes.h>
21
#include <util/delay.h>
22
23
void uart_Init() 
24
{
25
  
26
  UBRRH = (unsigned char)(UBRR_VAL>>8);  
27
  UBRRL = (unsigned char)UBRR_VAL;  
28
  UCSRB |= (1<<RXEN)|(1<<TXEN);  
29
  UCSRC = (1<<URSEL) | (1<<UCSZ0)|(1<<UCSZ1);
30
31
}//end uart_Init()
32
33
void uart_Putc(unsigned char c)
34
{
35
    while (!(UCSRA & (1<<UDRE)));     
36
  UDR = c; 
37
   _delay_ms(10);   
38
}//end uart_Putc()
39
40
void uart_Puts (char *string)
41
{
42
    while( *string != '\0' )
43
    {  
44
        uart_Putc(*string);
45
        string++;
46
    }
47
}//end uart_Puts()
48
49
void ADC_Init (uint8_t Mux_channel)
50
{
51
        DDRC = 0x00;  //Define as Input
52
  PORTC = 0xFF;    //Enables Pull-Up on PC0
53
54
  ADCSRA = (1<<ADEN);   //Enables the ADC
55
  ADCSRA |= (1<<ADPS2) | (1<<ADPS0); //Set ADC with Prescaler 32 
56
  
57
  ADMUX = Mux_channel;    //Select pin ADC0 using MUX
58
  _delay_us(40);
59
  ADMUX |= (1<<REFS0) | (1<<REFS1);//Int. REF Voltage Reference 
60
  ADMUX |= (0<<ADLAR);  //The result is right adjusted
61
}
62
63
  
64
uint16_t ADC_Read(uint8_t Mux_channel) 
65
{
66
  uint8_t i;
67
  uint16_t result = 0;
68
  
69
  //interrupt
70
  TCNT0 = 5;    //Zählregister setzen
71
  TIMSK |= (1<<TOIE0);  
72
  TCCR0 |= (1<<CS01);
73
  TCCR0 |= (1<<CS00);  //CPU Takt wird verwendet --> 4MHz
74
  TIFR |= (1<<TOV0);//startet interrupt bei jedem überlauf
75
  
76
  
77
  ADC_Init (Mux_channel);
78
79
  ADCSRA |= (1<<ADSC);//Start conversion
80
  while(ADCSRA & (1<<ADSC));//wait until converstion completed
81
  result = ADCW;  
82
    result = 0;  
83
                          
84
85
  //Mittwert von vier messwerte
86
  for(i=0; i<4; i++) 
87
  {    
88
    ADCSRA |= (1<<ADSC);  //A single conversion    
89
    while(ADCSRA & (1<<ADSC));
90
    result += ADCW;
91
  }
92
  
93
  ADCSRA &= (0<<ADEN);      // ADC reanables  
94
  result /= 4;
95
    
96
  return result;
97
}//End int ADC_Read() 
98
99
//Interrupt Service Routine für AD Wandlung
100
ISR(TIMER0_OVF_vect) 
101
{
102
  ADIteiler++;     //clocks interrupt counter value on each ms 
103
  if(ADIteiler >= 60)  //Counter cycle for all ms 60
104
  {
105
    ADIteiler=0;  //counter 0 set
106
        
107
  uint16_t result = ADC_Read(0);  //Read the Analog volt. on PinC 0
108
  uart_Puts("\r\n\n");
109
  utoa( result, s, 10 );   
110
  uart_Puts( s );  
111
    uart_Putc('$');
112
  }
113
}//End ISR(TIMER0_OVF_vect)
114
115
116
int main()
117
{
118
  uart_Init();
119
  
120
  uart_Puts("\r\n");
121
  uart_Puts("Messung fängt an:");
122
  uart_Puts("\r\n");
123
  
124
  sei(); //Enable Globale Interrupts
125
126
  for (;;); 
127
128
  return (0);
129
}

Problem:
ADC-Werte sind falsch. Für den selben Analog Eingang kriege ich 
Unterschiedliche Digital Wert.
beispiel: für 2.04v ausgabe: 1023 oder 255 oder 3 oder 166 oder 875...

Ist eventuell ein Fehler in meinen Code? fehlt mir eine elektronische 
montage? Kann jemand mirhelfen?

Danke im Voraus.

Gruss carine

von ... .. (docean) Benutzerseite


Lesenswert?

probier es doch erstmal ohen deine Interrupt Service Routine für AD 
Wandlung

sondern stoss über _delay_ms jede sek ein wandlung in der main an...

Was sucht das _delay_ms in der putc?

von Karl H. (kbuchegg)


Lesenswert?

carine schrieb:

> Ist eventuell ein Fehler in meinen Code? fehlt mir eine elektronische
> montage? Kann jemand mirhelfen?

Möglich.
Der Code ist so verworren, das man den erst einmal gründlich auseinander 
nehmen muss

Was hältst du davon, erst einmal die ADC-Routine aus dem Tutorial, so 
wie sie ist, zu benutzen. Und zwar ohne den ganzen Timer Klimbim
1
int main()
2
{
3
  uint16_t result;
4
  ...
5
6
  while( 1 ) {
7
    uint16_t result = ReadChannel( 0 );
8
9
    uart_Puts("\r\n\n");
10
    utoa( result, s, 10 );   
11
    uart_Puts( s );  
12
    uart_Putc('$');
13
  }
14
}

Die ReadChannel Funktion ist die Funktion aus dem Tutorial
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Aktivieren_des_ADC

Wenn du danach immer noch seltsame Werte hast, könnte es ein Hardware 
Problem sein.
Wenn die Werte plausible aussehen, kannst du jetzt immer noch anfangen, 
die ReadChannel Funktion auseinanderzunehmen und umzugestalten. Tauchen 
dann plötzlich seltsame Werte auf, kann es nur noch mit deiner zuletztz 
durchgeführten Änderung zu tun haben.

von Stefan E. (sternst)


Lesenswert?

Karl heinz Buchegger schrieb:
> Der Code ist so verworren

In der Tat. Bei dem geposteten Code kommt z.B. überhaupt nie eine 
ADC-Wandlung zustande. Der einzige ADC_Read Aufruf steckt im 
Timer-Overflow-Interrupt, aber der Timer wird überhaupt erst in ADC_Read 
in Gang gebracht. Es ist somit schon völlig unerklärlich, wie der OP 
überhaupt zu diesem Ergebnis kommt:
> ADC-Werte sind falsch. Für den selben Analog Eingang kriege ich
> Unterschiedliche Digital Wert.
> beispiel: für 2.04v ausgabe: 1023 oder 255 oder 3 oder 166 oder 875...
Da dürfte dann ja wohl mal wieder einiges an relevantem Code fehlen.

von carine (Gast)


Lesenswert?

vielen Dank an alle für die viele Tipps,

leider könnte ich gestern wegen Internet unterbrechung nichts mehr 
machen.

jetzt habe ich eins zu eins den Tutorial Code copier, aber diesmal 
bekommen ich für irgend eine Spannung eingang 1023.

Wo liegt jetzt mein Fehler?
Danke für eure Hilfe im voraus
1
uint16_t ReadChannel(uint8_t mux)
2
{
3
  uint8_t i;
4
  uint16_t result;
5
 
6
  ADMUX = mux;                      // Kanal waehlen
7
  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
8
 
9
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
10
                               // setzen auf 8 (1) und ADC aktivieren (1)
11
 
12
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
13
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
14
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
15
  while ( ADCSRA & (1<<ADSC) ) {
16
     ;     // auf Abschluss der Konvertierung warten 
17
  }
18
  result = ADCW;  // ADCW muss einmal gelesen werden,
19
                  // sonst wird Ergebnis der nächsten Wandlung
20
                  // nicht übernommen.
21
 
22
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
23
  result = 0; 
24
  for( i=0; i<4; i++ )
25
  {
26
    ADCSRA |= (1<<ADSC);        // eine Wandlung "single conversion"
27
    while ( ADCSRA & (1<<ADSC) ) {
28
      ;   // auf Abschluss der Konvertierung warten
29
    }
30
    result += ADCW;    // Wandlungsergebnisse aufaddieren
31
  }
32
  ADCSRA &= ~(1<<ADEN);         // ADC deaktivieren (2)
33
 
34
  result /= 4;              // Summe durch vier teilen = arithm. Mittelwert
35
 
36
  return result;
37
}
38
39
  
40
int main()
41
{
42
  uint16_t result;
43
  DDRC = 0x00;  //Define as Input
44
  PORTC = 0xFF;    //Enables Pull-Up on PC0
45
46
  uart_Init(); 
47
  
48
  uart_Puts("\r\n");
49
  uart_Puts("Messung gestartet:");
50
51
  while( 1 ) {
52
  result = ReadChannel( 0 );
53
54
    uart_Puts("\r\n\n");
55
    utoa( result, s, 10 );   
56
    uart_Puts( s );  
57
    uart_Putc('$');
58
  }
59
}

von Lord Z. (lordziu)


Lesenswert?

Wo hast du denn bitte 's' deklariert?

Ich glaube nicht, dass das so ohne Compilerwarnung kompiliert.

von carine (Gast)


Lesenswert?

s ist global deklariert
char s[20];

Build succeeded with 0 Warnings...

von Lord Z. (lordziu)


Lesenswert?

Wie sieht denn die Beschaltung des ADC-Pins aus?

von STK500-Besitzer (Gast)


Lesenswert?

>bekommen ich für irgend eine Spannung eingang 1023.

Klingt irgendwie nach eingeschaltetem Pull-Up oder einem anderen 
Hardware-Fehler.

(Fehlerfrei) compilierbarer Code wäre übrigens sehr hilfreich.

von carine (Gast)


Lesenswert?

Analog Strom vom Laser ----- direckt an PINC.0
(Ich habe kein Poti benutzt weil der Strom im bereich 0v bis 2,005v 
liegt)
AREF------100n condensator (weil int AREF wird benutzt)

ist das richtig?
danke

von carine (Gast)


Lesenswert?

>>STK500-Besitzer
dachte ich auch und habe ich den Pull-up ausgeschaltet, leider keine 
Änderung.

von carine (Gast)


Lesenswert?

bitte hilfe!!!
ich glaube, dass mein Fehler an der Schaltung liegt!!!!!

von Lord Z. (lordziu)


Lesenswert?

carine schrieb:
> bitte hilfe!!!
> ich glaube, dass mein Fehler an der Schaltung liegt!!!!!

Tja, nur wenn du sie uns nicht ordnetlich zeigst, woher sollen wir 
wissen, WIE deine Schaltung aussieht?

von ... .. (docean) Benutzerseite


Lesenswert?

Analog Strom vom Laser ----- direckt an PINC.0
(Ich habe kein Poti benutzt weil der Strom im bereich 0v bis 2,005v
liegt)

lies mal bitte noch mal den Unterschied von Strom und Spannung nach...

Was kommt von deinem Sensor? ein Strom oder eine Spannung? Wenn eine 
Spannung was zeigt das Multimeter an?

von carine (Gast)


Lesenswert?

entschuldigung Spannung meine ich

von carine (Gast)


Lesenswert?

das Multimeter zeigt 1,8v jetzt.
Aber für den Analog Wert bekomme ich 1023 angezeigt

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>> PORTC = 0xFF;    //Enables Pull-Up on PC0
> Analog Strom vom Laser ----- direckt an PINC.0

Warum schaltest du die Pull-ups an PC0 an?

> AREF------100n condensator (weil int AREF wird benutzt)

Wo ist der Kondensator noch angeschlossen?
Schaltplan wäre gut!

Wie ist das STK500 gejumpert, speziell der VTARGET und der AREF Jumper? 
Bei "interne Referenzspannung" im Programm würde ich den AREF Jumper 
entfernen.
http://www.atmel.com/dyn/resources/prod_documents/doc1925.pdf

>  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
Internal 2.56V Voltage Reference with external capacitor at AREF pin

> (Ich habe kein Poti benutzt weil der Strom im bereich 0v bis 2,005v liegt)
Bist du 100% sicher, dass die zu messende Spannung nicht über Internal 
2.56V Voltage Reference liegt. Wurde das schon im Betrieb nachgemessen? 
Wie wurde das gemessen? Besteht eine Chance kurzzeitige 
Spannungsüberschreitungen zu sehen?

Nicht vergessen der ADC soll laut Datenblatt mit 50 bis 200 kHz messen!

>> 2. extene Quarz 4 Mhz
> ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
> // setzen auf 8 (1) und ADC aktivieren (1)

Vorteiler 8 ist nicht ausreichend. Stell mal einen höheren ein.


Dabei auch beachten, dass die 2.56V kein in Stein gemeisselter Wert 
sind. Der Wert hängt von der Bandgap Referenz ab und die ist abhängig 
von der Versorgungsspannung und der Temperatur.

Ich würde versuchsweise mal AVcc als Referenz einstellen.
ADMUX |= (1<<REFS0); // AVcc als Referenz verwenden

von carine (Gast)


Lesenswert?

Danke für die Antwort.
Aber ist das Problem immer noch nich gelöst, weil für unterschiedlichen 
Werte wird anstatt 1023, jetzt 16 angezeigt.

Initialisierung:
1
void ADC_Init (uint8_t Mux_channel)
2
{
3
  ADCSRA = (1<<ADEN);   //Enables the ADC
4
  ADCSRA |= (1<<ADPS2) | (1<<ADPS0); // ADC Prescaler 32 --> 4Mhz/32 = 125kHz Tmin = 20 , Tmax = 80   
5
  ADMUX = Mux_channel;    //pin ADC0
6
  ADMUX |= (1<<REFS0); // AVcc als Referenz verwenden
7
  ADMUX |= (0<<ADLAR);  //The result is right adjusted
8
}
Ich habe keine Software um Schaltungen aufzuzeichnen, ich hoffe dies 
wird verständlich sein:

AREF----100nF---GND
Analog eingang Spannung-----100K poti-----Masse
                              |
                              |
                             PCO

von carine (Gast)


Lesenswert?

Ich habe der Spannung am AREF von atmega8 gemessen.
Ich merke, dass die Spannung wackeln (Es wird immer weniger).
Ist das normal? wieso verändern sich die Spannung?
danke für euere Hilfe

von carine (Gast)


Lesenswert?

Und sobald ich mit dem Multimeter messen will vergrössert sich der 
angezeigt Didigitalwert

von Stefan E. (sternst)


Lesenswert?

Mal 'ne ganz blöde Frage: AVCC ist aber schon auch angeschlossen, oder?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>>> PORTC = 0xFF;    //Enables Pull-Up on PC0
>> Analog Strom vom Laser ----- direckt an PINC.0
>Warum schaltest du die Pull-ups an PC0 an?

Ist das verbessert? IMHO ist es kontraproduktiv per Pull-up Vcc auf den 
ADC Messeingang zu geben.

> Analog eingang Spannung-----100K poti-----Masse
>                               |
>                               |
>                              PCO

Das 100k Poti hättest du ganz am Anfang erwähnen müssen!

Warum ist das überhaupt drin?

Wo steht der Schleifer bei deinen Experimenten?

Was sagt das Atmega8 Datenblatt zu dem u.U. riesigen Widerstand in der 
zu messenden Leitung?

Kommt durch diese künstliche Einschürung der Messleitung innerhalb der 
Messzeit überhaupt genügend Saft an den ADC?

Aus dem Atmega8 Datenblatt:

"The ADC is optimized for analog signals with an output impedance of 
approximately 10 kΩ or less. If such a source is used, the sampling time 
will be negligible. If a source with higher impedance is used, the 
sampling time will depend on how long time the source needs to charge 
the S/H capacitor, with can vary widely. The user is recommended to only 
use low impedant sources with slowly varying signals, since this 
minimizes the required charge transfer to the S/H capacitor."

> Initialisierung:
> void ADC_Init (uint8_t Mux_channel)

Initialisierst du jetzt zweimal? Einmal in dem ADC_Init() und einmal in 
dem ReadChannel() aus 
Beitrag "Re: ADC wert über RS232 senden"

Würde ich nicht machen. Ich würde bei einer Programmversion bleiben.

> Aber ist das Problem immer noch nich gelöst, weil für unterschiedlichen
> Werte wird anstatt 1023, jetzt 16 angezeigt.

Du hast leider keinen Quellcode angegeben, bei der man sieht, wie du den 
ADC Wert einlesen tust.

Die Timer-Variante (Beitrag "ADC wert über RS232 senden") 
hatten wir ja schon verworfen

Und die ReadChannel()-Variante 
(Beitrag "Re: ADC wert über RS232 senden") hast du 
anscheinend abgeändert indem du eine ADC_Init() geschrieben hast.

Offen ist: Wie und wo wird ADC_Init() aufgerufen. Wie und wo werden die 
Ergebnisse der Wandlung eingelesen, gibt es ein verändertes 
ReadChannel()?

von carine (Gast)


Lesenswert?

>>Mal 'ne ganz blöde Frage: AVCC ist aber schon auch angeschlossen, oder?

ADMUX |= (1<<REFS0); entspricht im Datenblatt AVCC with external 
capacitor at AREF pin

deswegen habe ich
AREF----100nF---GND
bei mir ist gar nichts an AVCC angeschlossen.

habe ich etwas falsch verstanden!!?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ja. AVcc und AGND muss immer angeschlossen werden. Das sollte aber auf 
dem STK500 automatisch erledigt werden (Vcc---AVcc und GND---AGND)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Wie sieht es hiermit aus:

> Wie ist das STK500 gejumpert, speziell der VTARGET und der AREF Jumper?
> Bei "interne Referenzspannung" im Programm würde ich den AREF Jumper
> entfernen.

von carine (Gast)


Lesenswert?

ok, danke

AREF-Jumper ist nicht gesetzt
VTARGET-Jumper ist gesetzt

von Stefan B. (stefan) Benutzerseite


Lesenswert?

ok, gut so.

von carine (Gast)


Lesenswert?

ich benutze den STK500 und Prozessor Atmega8
und finde keine AGND!

von carine (Gast)


Lesenswert?

>> AVcc und AGND muss immer angeschlossen werden. Das sollte aber auf
>>dem STK500 automatisch erledigt werden (Vcc---AVcc und GND---AGND)

ich finde keine Pin für AVCC und AGND um die beide anzuschliessen, ich 
nehme also an dass es vom STK500 schon gemacht wurde.

am PORTE/AUX
schliessen ich an
PE4 (REF)-------100nF--------PE5 (GND)

ist das so richtig ?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ja.

Woher kommt deine Messspannung und was ist deren Bezugspunkt (Masse, 
GND)? Ist dieses GND das gleiche, wie das GND des STK500 oder - im 
anderen Fall - sind beide GNDs miteinander verbunden? => Schaltplan?

Deine Messungen mit dem Multimeter: Wo genau befinden sich die 
Kontaktpunkte der Messleitungen an der Schaltung?

Bereits gestellte und noch offene Fragen:
Was ist mit dem 100k Poti?
Wie sieht der aktuelle Quellcode aus?

von carine (Gast)


Lesenswert?

>>Das 100k Poti hättest du ganz am Anfang erwähnen müssen!
>>Warum ist das überhaupt drin?
>>Wo steht der Schleifer bei deinen Experimenten?

ICh will eine Spanung von ov bis 2,05v messen, um sicher zu sein, dass 
meine zu messende Spannung nicht die Internal Ref 2.56 überschreit, 
benutze ich das Poti.
Wo der Schleifer steht, kann ich nicht genau sagen.
Aber für Spannung eingang 1,8v zum Beipiel habe ich 1,6v am PCO.
Und jetzt benutze ich 1k Poti.

Analog eingang Spannung-----1K poti-----Masse
                              |
                              |
                             PCO

>>Woher kommt deine Messspannung und was ist deren Bezugspunkt (Masse,
>>GND)? Ist dieses GND das gleiche, wie das GND des STK500 oder - im
>>anderen Fall - sind beide GNDs miteinander verbunden? => Schaltplan?

Messspannung kommt aus einer Laser (DT50 vom Sick)

(GND = Masse) verbunden mit GND von STK500


>>Wie sieht der aktuelle Quellcode aus?
1
#include <avr/io.h>
2
#include <inttypes.h>
3
#include <stdlib.h>
4
5
#include "uart.h"
6
7
//defineglobal variables
8
int ADIteiler=0;
9
char s[20];
10
11
uint16_t ReadChannel(uint8_t mux)
12
{
13
  uint8_t i;
14
  uint16_t result;
15
 
16
  ADCSRA = (1<<ADEN);   //Enables the ADC
17
  ADCSRA |= (1<<ADPS2) | (1<<ADPS0); // ADC Prescaler 32 --> 4Mhz/32 = 125kHz Tmin = 20 , Tmax = 80   
18
  ADMUX = Mux_channel;    //pin ADC0
19
  ADMUX |= (1<<REFS0); // AVcc als Referenz verwenden
20
  ADMUX |= (0<<ADLAR);  //The result is right adjusted
21
22
  while ( ADCSRA & (1<<ADSC) ) {
23
     ;     // auf Abschluss der Konvertierung warten 
24
  }
25
  result = ADCW; 
26
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
27
  result = 0; 
28
  for( i=0; i<4; i++ )
29
  {
30
    ADCSRA |= (1<<ADSC);      // eine Wandlung "single conversion"
31
    while ( ADCSRA & (1<<ADSC) ) {
32
      ;   // auf Abschluss der Konvertierung warten
33
    }
34
    result += ADCW;        // Wandlungsergebnisse aufaddieren
35
  }
36
37
  ADCSRA &= ~(1<<ADEN);           // ADC deaktivieren 
38
  result /= 4;             // Summe durch vier teilen = arithm. Mittelwert 
39
  return result;
40
}
41
42
  
43
int main()
44
{
45
  uint16_t result;
46
  DDRC = 0x00;  //Define as Input
47
  uart_Init(); 
48
  
49
  uart_Puts("\r\n");
50
  uart_Puts("Messung gestartet:");
51
52
  while( 1 ) {
53
    result = ReadChannel( 0 );
54
55
    uart_Puts("\r\n\n");
56
    utoa( result, s, 10 );   
57
    uart_Puts( s );  
58
    uart_Putc('$');
59
  }
60
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

carine schrieb:

> Messspannung kommt aus einer Laser (DT50 vom Sick)

http://www.sick.co.uk/de/products/productnews/industrial/distancesensor/dt50/de.html
1
DT50 - Abstandsensor mit Analogausgang
2
    * HDDM - modernste Lichtlaufzeittechnologie
3
    * Messbereich 200 ... 10.000 mm
4
    * 4... 20 mA Analogausgang + zusätzlich 1x PNP Schaltausgang
5
      ^^^^^^^^^^^^^^^^^^^^^^^^
6
    * Display mit intuitiv bedienbarer Menüführung
7
    * Fremdlichtsicher bis 40 klux
8
    * Großer Betriebstemperaturbereich von -30 °C bis +65 °C
9
    * Robustes Druckguss-Zinkgehäuse

Der Sensor gibt also analog 4 mA (minimaler Abstand) bis 20 mA 
(maximaler Abstand) aus.

Das wäre in den Bereich ca. 0V (minimaler Abstand) bis ca. Aref 
(maximaler Abstand) umzuformen.

Das Umformen kann nach dem Ohmschen Gesetz U = R * I mit einem 
Widerstand gemacht werden.

Sensor Out o----------+----------o ADC0 (PC0) µC
                      |
                      #
                    R #
                      #
                      |
Sensor GND o----------+----------o AGND (GND) µC

Angenommen du hast Aref auf Vcc (5V) eingestellt. Dann soll bei Imax. = 
20 mA die maximale Spannung 5V an R abfallen:
R <= 5V / 20 mA <= 250 Ohm

Wenn du für R einen 1 kOhm Poti nimmst:

Sensor Out o----------+
                      |
                      #
                    R #<---------o ADC0 (PC0) µC
                      #
                      |
Sensor GND o----------+----------o AGND (GND) µC

Dann fällt an R eine max. Spannung von 20 mA * 1 kOhm = 20V ab, wenn der 
Sensor versucht 20 mA auszugeben. Damit der Sensor das schafft müsste er 
allerdings eine Spannung von 20V an Sensor Out ausgeben. Bei einer 
Betriebsspannung des DT50 von 10..30V wäre das sogar denkbar.

Bei dem 100 kOhm Poti kann der Sensor allerdings nur bis zu seiner 
Betriebsspannung schuften, die 2000 V um 20 mA zu treiben, wird er nicht 
schaffen...

Steht in diesen Fällen der Schleifer des Potis ganz oben, ist der µC 
vielleicht Geschichte, weil die Absolute Maximal Electrical Ratings 
überschritten werden (ADC0 Eingangsspannung >> Vcc+0,5V).

Zurück zu den 250 Ohm...

Beim unteren Messwert (Mindestabstand) liefert der Sensor 4 mA. Das 
ergibt nach der Umformung U = 4 mA * 250 Ohm = 1 V.

Dein 4 mA .. 20 mA Sensorsignal wird also in ein ca. 1 V .. ca. 5 V 
Spannungssignal umgeformt. Das ca. weil die Präzision von R und 
Leitungswiderstände zusammenwirken.  Du musst deinen ADC Messwert 
kalibrieren.

Wenn du max. 2,56 V haben willst, dann wäre R <= 2,56 V / 20 mA <= "128" 
Ohm. Der Messbereich wäre dann 0,512V...2,56V

>>>Wie sieht der aktuelle Quellcode aus?
>   ADMUX |= (1<<REFS0); // AVcc als Referenz verwenden
>   ADMUX |= (0<<ADLAR);  //The result is right adjusted

Hier fehlt das Einschalten der ADC Single Conversion. Die nächste 
Schleife ist deswegen endlos. Das gezeigte Programm kann keine Werte 
ausgeben!

>   while ( ADCSRA & (1<<ADSC) ) {
>      ;     // auf Abschluss der Konvertierung warten
>   }

Abhilfe:

ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion" auslösen

vor der while-Schleife einfügen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Stopp, Fehler meinerseits, die Schleife ist nicht endlos, sondern 
rauscht direkt durch. Der Sinn der Schleife (Dummyreadout des ersten 
ADC-Wertes) wird verfehlt. Die vorgeschlagene Zeile sollte dennoch 
eingefügt werden.

von carine (Gast)


Lesenswert?

vielen Dank Stefan

Wenn du max. 2,56 V haben willst, dann wäre R <= 2,56 V / 20 mA <= "128"
Ohm. Der Messbereich wäre dann 0,512V...2,56V

ich habe einen Wiederstand R=100 Ohm genohmen und so angeschlossen

Sensor Out o----------+----------o ADC0 (PC0) µC
                      |
                      #
                    R #
                      #
                      |
Sensor GND o----------+----------o AGND (GND) µC

>>Dein 4 mA .. 20 mA Sensorsignal wird also in ein ca. 1 V .. ca. 5 V
>>Spannungssignal umgeformt. Das ca. weil die Präzision von R und
>>Leitungswiderstände zusammenwirken.  Du musst deinen ADC Messwert
>>kalibrieren.
Wie mache ich die Kalibrierung?
versuche ich noch es hinzukriegen.
und melde mich dann wieder

>>Abhilfe:
>>ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion" auslösen

ja, schon korriegiert

von carine (Gast)


Lesenswert?

vielen vielen Dank
problem gelöst.

Problem
vorher:
GND sensor -------GND voltmeter(12v Betriebsspannung des DT50 )

lösung:
)

Sensor Out o----------+
                      |
                      #
                    R #<---------o ADC0 (PC0) µC
                      #
                      |
Sensor GND o----------+----------o AGND (GND) µC

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.