Forum: Mikrocontroller und Digitale Elektronik warnung:"[variable]may be used uninizialized"


von Bakunin (Gast)


Lesenswert?

Hallo,
ich verzewifel hier langsam an dem unten stehenden programmabschnitt
...das ganze soll mal über rs232 nen AD-Wandler-Kanal auswählen und dann 
dauerhaft die werte aus dem gewählten kanal über RS232 an den pc 
senden...

wenn ich mir mit meinem terminalprogramm (HTerm) anschaue was rauskommt 
so sehe ich dass zwar dass daten ankommen, aber ich kann nicht den kanal 
wechseln...

das steuern des PORTB funktioniert, was meiner meineung nach nahe legt 
dass das problem mit folgender warnung zusammenhängt (:-D) :
../ATMega8-UART.c:86: warning: 'adchannel' may be used uninitialized in 
this function

hier der programmabschnitt:
1
int main(void)
2
{  
3
  
4
  DDRB|= (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) | (1<<PB5); //ausgänge für ventilsteuerung angesprochen mit !1...!5 sind pb1...5
5
  char Line[3];
6
  char s[20];                            
7
  uint8_t adchannel;  
8
  InitUART(9600);
9
  sei();    
10
  
11
  while(1){
12
13
    
14
    uint16_t result = ADC_Read(adchannel);    //senden und wandeln des wertes an channel "adchannel"                                  
15
    itoa( result, s, 10 );
16
     uart_puts( s );
17
        uart_putc('\r');
18
19
    uart_gets( Line, sizeof( Line ) );        //verarbeitung eintreffender daten   
20
    switch(Line[0]){    
21
      case '!':                 //! meint steuerbefehl 1...5
22
        switch(Line[1]){  
23
          case '1':PORTB=0b00000010;  break;
24
          case '2':PORTB=0b00000100;  break;  
25
          case '3':PORTB=0b00001000;  break;  
26
          case '4':PORTB=0b00010000;  break;  
27
          case '5':PORTB=0b00100000;  break;  
28
          }
29
      break;
30
      
31
      case '?':               //? meint abfrage des channels 0...7
32
        switch(Line[1]){  
33
          case '0':adchannel=0;  break;
34
          case '1':adchannel=1;  break;
35
          case '2':adchannel=2;  break;
36
          case '3':adchannel=3;  break;
37
          case '4':adchannel=4;  break;
38
          case '5':adchannel=5;  break;
39
          case '6':adchannel=6;  break;
40
          case '7':adchannel=7;  break;          
41
        }
42
      
43
      break;
44
      
45
    }
46
47
  }return 0;
48
}

von Klaus W. (mfgkw)


Lesenswert?

und wo bekommt adchannel beim ersten Durchlauf seinen Wert her?

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
 uint8_t adchannel;  
2
  InitUART(9600);
3
  sei();    
4
  
5
  while(1){
6
7
    
8
    uint16_t result = ADC_Read(adchannel);

Beantworte bitte ganz schnell die Frage:
Beim ersten Aufruf von ADC_Read .... welchen Wert hat da adchannel?

von Karl H. (kbuchegg)


Lesenswert?

> das steuern des PORTB funktioniert, was meiner meineung nach nahe legt
> dass das problem mit folgender warnung zusammenhängt (:-D) :
> ../ATMega8-UART.c:86: warning: 'adchannel' may be used uninitialized in
> this function

Eigentlich nicht.
Wenn du wissen willst, was in der Maschine abgeht, dann bau dir 
zusätzliche Ausgaben ein.

zb so
1
     case '?':               //? meint abfrage des channels 0...7
2
3
        usart_puts( "Schalte nach #" );
4
        usart_putc( Line[1] );
5
        uasrt_puts( "#\r" );
6
7
        switch(Line[1]){


dann erzählt dir der µC, was er empfangen hat und du kannst rausfinden 
warum die Umschaltung nicht klappt.

von Fabian (Gast)


Lesenswert?

Bakunin schrieb:
> case '!':                 //! meint steuerbefehl 1...5
>
>         switch(Line[1]){
>
>           case '1':PORTB=0b00000010;  break;
>
>           case '2':PORTB=0b00000100;  break;
>
>           case '3':PORTB=0b00001000;  break;
>
>           case '4':PORTB=0b00010000;  break;
>
>           case '5':PORTB=0b00100000;  break;
>
>           }
>
>       break;
>
>
>
>       case '?':               //? meint abfrage des channels 0...7
>
>         switch(Line[1]){
>
>           case '0':adchannel=0;  break;
>
>           case '1':adchannel=1;  break;
>
>           case '2':adchannel=2;  break;
>
>           case '3':adchannel=3;  break;
>
>           case '4':adchannel=4;  break;
>
>           case '5':adchannel=5;  break;
>
>           case '6':adchannel=6;  break;
>
>           case '7':adchannel=7;  break;
>
>         }

LOOOOLLLL!!!

Wieso nicht so?
1
if ((Line[1] => '1') && (Line[1] <= '5'))
2
   PORTB = Line[1] - '0';
3
4
\\...
5
6
if ((Line[1] => '0') && (Line[1] <= '7'))
7
   adchannel = Line[1] - '0';

von Bakunin (Gast)


Lesenswert?

wow, das geht ja schnell hier!!!
@kbuchegg: sorry, muss natürlich heissen
1
DDRB|= (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) | (1<<PB5); //ausgänge für ventilsteuerung angesprochen mit !1...!5 sind pb1...5
2
  char Line[3];
3
  char s[20];                            
4
  uint8_t adchannel=0;   //jezt mal default kanal 0, damit hatte ich es auch schon versucht :)
5
  InitUART(9600);
6
  sei();


was natürlich auch die warnung behebt- aber leider nichts daran ändert 
dass die Kanalwahl nicht klappt

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:

> was natürlich auch die warnung behebt- aber leider nichts daran ändert
> dass die Kanalwahl nicht klappt

Wie schon gesagt:
Bau dir zusätzliche Ausgaben ein, damit dir der µC erzählt was er warum 
macht.

Beitrag "Re: warnung:"[variable]may be used uninizialized""

von Fabian (Gast)


Lesenswert?

Ich meinte sO:
1
if ((Line[1] >= '1') && (Line[1] <= '5'))
2
   PORTB = Line[1] - '0';
3
4
...
5
6
if ((Line[1] >= '0') && (Line[1] <= '7'))
7
   adchannel = Line[1] - '0';

von Karl H. (kbuchegg)


Lesenswert?

Immer noch falsch Fabian. SChau dir genau an, was er mit dem PORTB 
macht.
Lass uns bitte erst am Problem arbeiten, ehe wir Vereinfachungen 
vorschlagen. ok?

von Fabian (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Lass uns bitte erst am Problem arbeiten, ehe wir Vereinfachungen
>
> vorschlagen. ok?

Jawohl!

Funktioniert denn überhaupt: ADC_Read(adchannel); richtig? Bzw. woher 
weißt Du, dass der Kanal nicht gewechselt wird?!
Ein häufiges Problem ist, wenn der A/D Kanal gewechselt, aber nicht 
lange genug bis zur Messung gewartet wird. Das S&H Glied muss sich ja 
erstmal umladen.

von STK500-Besitzer (Gast)


Lesenswert?

>Immer noch falsch Fabian.
>Lass uns bitte erst am Problem arbeiten, ehe wir Vereinfachungen
>vorschlagen. ok?

Naja, eine halben Stern im Heft hat er sich verdient ;)

von Klaus W. (mfgkw)


Lesenswert?

Wie lang sind eigentlich die empfangenen Kommandos?
Zwei Zeichen plus \r?
Dann ist die 3 als Feldlänge zu knapp, wenn noch eine
abschließende 0 dazukommt; ggf. noch eines mehr für \n etc..

von Karl H. (kbuchegg)


Lesenswert?

OK
1
printf( "         *\n"
2
        "        * \n"
3
        "       *  \n"
4
        "    ***   \n"
5
        "  **      \n"
6
        "    ***   \n"
7
        "       *  \n"
8
        "        * \n"
9
        "         *\n"
10
      );

Jetzt warten wir mal, ob sich was ergibt d.h. ob seine Empfangsroutine 
überhaupt richtig arbeitet.

von Bakunin (Gast)


Lesenswert?

@Fabian: wesendlich eleganter, soviel steht fest (mach das noch nicht 
lange) ;)

@kbuchegg: stimmt, ausgabe ist jezt in HTerm 'Schal?LL???1023<\r>' um 
diese meldung herum steht der zu erwartende input von ADC0, nämlich jede 
menge '1023'

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:

> @kbuchegg: stimmt, ausgabe ist jezt in HTerm 'Schal?LL???1023<\r>' um
> diese meldung herum steht der zu erwartende input von ADC0, nämlich jede
> menge '1023'

Wie Klaus schon sagte: Geh erst mal mit dem Line Array höher. Solche 
Felder dimensioniert man nie auf Knirsch, sondern immer mit Reserve. 
Mach da mal 80 draus.

Und dann fügst du nach jedem \r noch ein \n in die Ausgabe ein, damit 
neuer Output den alten nicht überschreibt, sondern eine neue Zeile im 
Terminal angefangen wird, damit man auch was sieht.

Und dann zeigst du deine Empfangsroutine.

von Klaus W. (mfgkw)


Lesenswert?

Bakunin schrieb:
> @Fabian: wesendlich eleganter, soviel steht fest (mach das noch nicht
> lange) ;)

Aber bei PORTB falsch.

von Bakunin (Gast)


Lesenswert?

antwort auf
1
uart_puts( "         *\n"
2
        "        * \n"
3
        "       *  \n"
4
        "    ***   \n"
5
        "  **      \n"
6
        "    ***   \n"
7
        "       *  \n"
8
        "        * \n"
9
        "         *\n"

ist:

..."1023<\r>         *<\n>        * <\n>   ??LL???1023<\r>1023<\r>"...

bei sendung von "!1"

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:
> antwort auf
>
1
> uart_puts( "         *\n"
2
>         "        * \n"
3
>         "       *  \n"
4
>         "    ***   \n"
5
>         "  **      \n"
6
>         "    ***   \n"
7
>         "       *  \n"
8
>         "        * \n"
9
>         "         *\n"
10
>
>
> ist:


LOL. Das war auch nicht für dich gedacht :-)
Sondern als Antwort auf
Beitrag "Re: warnung:"[variable]may be used uninizialized""
> Naja, eine halben Stern im Heft hat er sich verdient ;)

von Bakunin (Gast)


Lesenswert?

ok, line mit 80 feldern, noch ein \n hinters \r :

ausgabe ist:

<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023 
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023 
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023 
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023 
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023 
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023 
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>

...also wie vorher

von Karl H. (kbuchegg)


Lesenswert?

Schalte doch bitte dein HTerm in den Modus, dass es Steuerzeichen 
interpretiert anstelle das es sie hinschreibt. Das die Zahlen stimmen 
glaub ich dir ja. Ich bin am Zusatztext interessiert!

Ich brauch den Text der bei der eingefügten Ausgabe rauskommt.
Hast du eh gesehen, dass die 2te Ausgabe kein uart_puts sondern ein 
uart_putc (ein einzelnes Zeichen) ist?
1
     case '?':               //? meint abfrage des channels 0...7
2
3
        usart_puts( "Schalte nach #" );    // <-  String          S
4
        usart_putc( Line[1] );             // <-  Einzelzeichen   C
5
        uasrt_puts( "#\r" );               // <-  String          S
6
7
        switch(Line[1]){

von holger (Gast)


Lesenswert?

Vieleicht sollte er den ADC mal initialisieren
und eine Vref Quelle auswählen;)

von Klaus W. (mfgkw)


Lesenswert?

und vielleicht sind die 1023 ja auch alle richtig; kann ja von mehreren 
Kanälen der gleiche Wert kommen (wenn U über UREF liegt).

von Karl H. (kbuchegg)


Lesenswert?

Hmm

Das lässt sich verifizieren, ob man in der ADC_Read weiter suchen muss
1
 while(1){
2
    uint16_t result;
3
4
    uart_puts( "Sample Kanal " );
5
    utoa( adchannel, s, 10 );
6
    uart_puts( s );
7
    uart_puts( "  -> " );
8
9
    result = ADC_Read(adchannel);    //senden und wandeln des wertes an channel "adchannel"                                  
10
11
    utoa( result, s, 10 );
12
    uart_puts( s );
13
    uart_puts( "\r\n" );
14
15
    ....


Ich bin bisher eigentlich von einem Problem in der gets ausgegangen (ein 
\r der irgendwo übrig geblieben ist, oder so was in der Art). Aber auch 
das könnte man verifizieren (was bei Benutzer-Eingaben sowieso immer 
eine gute Idee ist)

von Bakunin (Gast)


Lesenswert?

ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V 
anliegen, an ADC1 per spannungsteiler ca 2,5V an den anderen rauschen

ausgabe ist


<\n>1023<\r>
<\n>1023<\r>
<\n>1023<\r>
uswusw

wobei sich bei übertragen von !1 oder anderen nichts ändert

von Klaus W. (mfgkw)


Lesenswert?

Bakunin schrieb:
> ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V
und welchen Wet hat die Referenzspannung?

> anliegen, an ADC1 per spannungsteiler ca 2,5V an den anderen rauschen
Wo kommt das Rauschen her? Sind die Pins offen?

von Klaus W. (mfgkw)


Lesenswert?

Ach so: die Frage ist natürlich noch nicht beantwortet, wie der ADC 
initialisiert wird.

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:
> ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V
> anliegen, an ADC1 per spannungsteiler ca 2,5V an den anderen rauschen
>
> ausgabe ist
>
>
> <\n>1023<\r>
> <\n>1023<\r>
> <\n>1023<\r>
> uswusw
>

nochmal.
Die Zahlen dazwischen sind uninteressant.
INteressant ist, wenn du im HTerm das Kommando absetzt

   ?3

was kommt dann am µC an.
Nur das ist momentan interessant.

> wobei sich bei übertragen von !1 oder anderen nichts ändert


wieso ! ?
Ich denke die ADC Kanalumschaltnug geht nicht. Die hast du aber mit ? 
und nicht mit ! programmiert. ! schaltet den Port B um

du kannst auch in die Hauptschleife erst mal einen
 _delay_ms( 500 );
(und natürlich oben das Header File) einfügen, damit dir der µC nicht so 
den Schirm zumüllt.

von Bakunin (Gast)


Lesenswert?

meine (naja, nicht MEINE) ADC_Read sieht volgendermassen aus
1
  
2
uint16_t ADC_Read(uint8_t Mux_channel) 
3
{
4
  uint8_t i;
5
  uint16_t result = 0;   
6
  
7
8
    
9
    
10
  ADC_Init (Mux_channel);
11
12
  ADCSRA |= (1<<ADSC);        //Start conversion
13
  while(ADCSRA & (1<<ADSC));      //wait until converstion completed
14
  result = ADCW;            //ADCW must be read once
15
    result = 0;                    //Otherwise the result of the next transformation is not taken over
16
                          
17
  
18
  //Now reads 4 times the similar tension and selected channel channel 
19
  //And then calculate the average value divided by 4. Because the ADC measeres 0..1023,
20
  //And the Port however can only 0..255 show
21
  for(i=0; i<4; i++) 
22
  {    
23
    ADCSRA |= (1<<ADSC);      //A single conversion    
24
    while(ADCSRA & (1<<ADSC));    //Waiting on conversion closing    
25
    result += ADCW;
26
  }
27
  
28
  ADCSRA &= (0<<ADEN);          // ADC reanables  
29
  result /= 4;
30
    
31
  return result;
32
}//End int ADC_Read()

hierin wird auch der ADC initialisiert -ADC_init():
1
void ADC_Init (uint8_t Mux_channel)
2
{
3
  
4
  TCNT0 = 5;        //Set Timer/counter
5
  TIMSK |= (1<<TOIE0);  //Enable Timer/counter0 overflow interrupt
6
  //TCCR0 |= (1<<CS01);
7
  TCCR0 |= (1<<CS00);
8
  TCCR0 |= (1<<CS02);  //Select the clock source to be used by the timer/counter --> CPU Takt  --> 8MHz/1024 
9
  TIFR |= (1<<TOV0);  //interrupt starts with each overflow 
10
  
11
  ADCSRA = (1<<ADEN);         //Enables the ADC
12
  ADCSRA |= (1<<ADPS2) | (1<<ADPS1);   //Determine the division factor between the XTAL frequency and the input clock to the ADC. 
13
                    //Activate ADC with Prescaler 64 --> 8Mhz/64 = 125khz -optimum range 50-200 khz
14
  
15
  ADMUX = Mux_channel;        //Select pin ADC0 using MUX
16
  _delay_us(40);
17
  //warte ();
18
  ADMUX |= (1<<REFS0) | (1<<REFS1);  //Int. REF Voltage Reference Selection, for extern ARef use ADMUX |= (0<<REFS0) | (0<<REFS1); 
19
  ADMUX |= (0<<ADLAR);        //The result is right adjusted 
20
}

von holger (Gast)


Lesenswert?

>ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V

Was zum Teufel steht in ADC_Read(adchannel)?

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:
> meine (naja, nicht MEINE) ADC_Read sieht volgendermassen aus

Und.
Hast du sie getestet?

Was passiert, wenn du einfach mal ADC_Read mit 1 aufrufst?
Kriegst du dann den erwarteten Wert?

von Spess53 (Gast)


Lesenswert?

Hi

>Vieleicht sollte er den ADC mal initialisieren
>und eine Vref Quelle auswählen;)

>ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V
>anliegen, an ADC1 per spannungsteiler ca 2,5V an den anderen rauschen

Und was ist mit dem Prescaler?

MfG Spess

von Klaus W. (mfgkw)


Lesenswert?

Bakunin schrieb:
> ADMUX |= (1<<REFS0) | (1<<REFS1);  //Int. REF Voltage Reference Selection, for 
extern ARef use ADMUX |= (0<<REFS0) | (0<<REFS1);

Wie groß ist interne Referenzspannung?

von Bakunin (Gast)


Lesenswert?

äh sorry, "?1" war gemeint, das resultat ist das selbe wie oben 
gepostet, keine änderung... (auch bei ?3 nicht)

von Karl H. (kbuchegg)


Lesenswert?

Gewöhn dir das ganz schnell wieder ab
1
void ADC_Init (uint8_t Mux_channel)
2
{
3
  
4
  TCNT0 = 5;        //Set Timer/counter
5
  TIMSK |= (1<<TOIE0);  //Enable Timer/counter0 overflow interrupt
6
  //TCCR0 |= (1<<CS01);
7
  TCCR0 |= (1<<CS00);
8
  TCCR0 |= (1<<CS02);  //Select the clock source to be used by the timer/counter --> CPU Takt  --> 8MHz/1024 
9
  TIFR |= (1<<TOV0);  //interrupt starts with each overflow

Die Funktion heißt ADC_Init. Die hat nichts mit dem Timer zu tun. Das 
gehört da nicht heinein.

(ISt jetzt aber nur ein Nebenschauplatz. Du hast doch hoffentlich eine 
ISR für den Timer geschrieben)

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:
> äh sorry, "?1" war gemeint, das resultat ist das selbe wie oben
> gepostet, keine änderung... (auch bei ?3 nicht)

Nochmal:
Wenn du ?2 im HTerm eingibst .....
.... dann müsste der µC in den Programmteil
1
    case '?':               //? meint abfrage des channels 0...7
2
3
        usart_puts( "Schalte nach #" );
4
        usart_putc( Line[1] );
5
        uasrt_puts( "#\r" );
6
7
        switch(Line[1]){  
8
     ....

kommen und dir ausgeben welches 2.te Zeichen er nach dem '?' empfangen 
hat.

Kommt die Ausgabe und wenn ja, welches Zeichen taucht zwischen den # 
auf? Das kann nur ein einzelnes Zeichen sein. Da kann kein #+34z78 
stehen, es sei denn du hast irrtümlich anstelle von

        usart_putc( Line[1] );

ein

        usart_puts( Line[1] );

geschrieben.

Mach dir ein _delay_ms( 1000 ) in die Hauptschleife rein, wenn die 
Zahlen zu schnell durchrauschen und du nichts mehr sehen kannst. Aber 
ehe wir weiter suchen, sollten wir sicherstellen, dass aus deiner 
uart_gets Funktion auch das rauskommt, was du denkst das rauskommen 
sollte.

von holger (Gast)


Lesenswert?

>Wie groß ist interne Referenzspannung?

Zu klein;)

Ich empfehle die Spannungen an den ADC Eingängen mal
unter 2,56V zu bringen. Oder AVCC als VREF zu nehmen.

von Bakunin (Gast)


Lesenswert?

laut datenblatt ist Vref intern  2,56 V. getestet ist die funktion 
ADC_Read - ich habe passende werte erhalten, nur leider nicht mit von 
mir über rs232 steuerbar sondern nur mit einer konstanten statt 
adchannel sprich mit
1
uint16_t result = ADC_Read(1);    //hier ist die variable "adchannel" mit 1 ersezt                                 
2
    itoa( result, s, 10 );
3
     uart_puts( s );
4
        uart_putc('\r');

das mit dem delay macht das ganze weniger stressig, danke :)

von Klaus W. (mfgkw)


Lesenswert?

oder einfach mal einen Pin auf GND legen, dann wird auch was anderes als 
1023 rauskommen :-)

holger schrieb:
> Ich empfehle die Spannungen an den ADC Eingängen mal
> unter 2,56V zu bringen. Oder AVCC als VREF zu nehmen.

von holger (Gast)


Lesenswert?

>Ich empfehle die Spannungen an den ADC Eingängen mal
>unter 2,56V zu bringen. Oder AVCC als VREF zu nehmen.

Upps, oder je nach CPU Typ (welcher ist das) sogar unter 1V.

von Klaus W. (mfgkw)


Lesenswert?

(langsam tut er mir fast leid, jetzt wird er von 3 oder 4 Seiten in die 
Zange genmommen)

von Karl H. (kbuchegg)


Lesenswert?

Da muss er durch :-)

Debuggen lernt man nicht über Nacht.

von Bakunin (Gast)


Lesenswert?

@kbuchegg: wie gesagt, es tut sich nichts

nochmal der code mit den gemachten variationen, diesmal in der gesamten 
"pracht":
1
/*
2
Das Programm nuzt die Kanäle ADC0...7 als eingänge des ADC. Ausgänge zur steuerung von wasweissichwas 
3
sind PB1...5. Der aktuell gemessene AD wert wird über USART verschickt. 
4
Befehle die angenommen werden: !1...!5 steuert die PB1...5
5
                   ?0...?7 wählt den zu messenden kanal aus
6
zu beachtden: nach jedem befehl muss evl ein "null" gesendet werden um das array abzuschliessen, 
7
geht aber auch jedes andere zeichen (zb !1x)
8
*/
9
10
#define  __AVR_ATmega8__  1
11
#define OSCSPEED  8000000    /* in Hz */
12
13
#include <avr/io.h>
14
#include <inttypes.h>
15
#include <stdlib.h>
16
#include <avr/interrupt.h>
17
#include <util/delay.h>
18
#include "ADC_USART_Read_adc.h"
19
20
void InitUART(uint32_t baud)  /* here a simple int will not suffice*/  
21
{
22
  int baudrate=(OSCSPEED/(16*baud))-1; /* as per pg. 133 of the user manual */
23
  /* Set baud rate */
24
  UBRRH = (unsigned char)(baudrate>>8);
25
  UBRRL = (unsigned char)baudrate;
26
  /* Enable Receiver and Transmitter */
27
  UCSRB = (1<<RXEN)|(1<<TXEN);
28
  /* Set frame format: 8data, 1stop bit */
29
  UCSRC = (1<<URSEL)|(3<<UCSZ0);  
30
}
31
32
uint8_t uart_getc(void)
33
{
34
    while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
35
        ;
36
    return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
37
}
38
 
39
void uart_gets( char* Buffer, uint8_t MaxLen )
40
{
41
  uint8_t NextChar;
42
  uint8_t StringLen = 0;
43
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen 
44
                                  // Sammle solange Zeichen, bis:
45
                                  // * entweder das String Ende Zeichen kam
46
                                  // * oder das aufnehmende Array voll ist
47
  while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
48
    *Buffer++ = NextChar;
49
    StringLen++;
50
    NextChar = uart_getc();
51
  } 
52
                                  // Noch ein '\0' anhängen um einen Standard
53
                                  // C-String daraus zu machen
54
  *Buffer = '\0';
55
}
56
57
58
int uart_putc(unsigned char c)
59
{
60
    while (!(UCSRA & (1<<UDRE)))  // warten bis Senden moeglich
61
    {
62
    }                             
63
 
64
    UDR = c;                      // sende Zeichen 
65
    return 0;
66
}
67
 
68
 
69
/* puts ist unabhaengig vom Controllertyp */
70
void uart_puts (char *s)
71
{
72
    while (*s)
73
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
74
        uart_putc(*s);
75
        s++;
76
    }
77
}
78
79
80
81
int main(void)
82
{  
83
  
84
  DDRB|= (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) | (1<<PB5); //ausgänge für ventilsteuerung angesprochen mit !1...!5 sind pb1...5
85
  char Line[80];
86
  char s[20];                            
87
  uint8_t adchannel=0;  
88
  InitUART(9600);
89
  sei();    
90
  
91
  while(1){
92
93
    
94
    uint16_t result = ADC_Read(adchannel);    //senden und wandeln des wertes an channel "adchannel"                                  
95
    itoa( result, s, 10 );
96
     uart_puts( s );
97
        uart_putc('\r');
98
    uart_putc('\n');
99
100
    uart_gets( Line, sizeof( Line ) );        //verarbeitung eintreffender daten   
101
    switch(Line[0]){    
102
      case '!':                 //! meint steuerbefehl 1...5
103
        switch(Line[1]){  
104
          case '1':PORTB=0b00000010;  break;
105
          case '2':PORTB=0b00000100;  break;  
106
          case '3':PORTB=0b00001000;  break;  
107
          case '4':PORTB=0b00010000;  break;  
108
          case '5':PORTB=0b00100000;  break;  
109
          }
110
      break;
111
      
112
      case '?':               //? meint abfrage des channels 0...7
113
        
114
          uart_puts( "Schalte nach #" );    // <-  String          S
115
          uart_putc( Line[1] );             // <-  Einzelzeichen   C
116
          uart_puts( "#\r" );               // <-  String          S
117
118
    
119
        
120
        switch(Line[1]){  
121
          case '0':adchannel=0;  break;
122
          case '1':adchannel=1;  break;
123
          case '2':adchannel=2;  break;
124
          case '3':adchannel=3;  break;
125
          case '4':adchannel=4;  break;
126
          case '5':adchannel=5;  break;
127
          case '6':adchannel=6;  break;
128
          case '7':adchannel=7;  break;          
129
        }
130
      
131
      break;
132
      
133
    }
134
  _delay_ms( 500 );
135
  
136
  }return 0;
137
}

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:
> @kbuchegg: wie gesagt, es tut sich nichts

Gar nichts?

Dann funktioniert deine uart_gets nicht richtig.

Ändere die mal (Vermutung ins Blaue)
1
void uart_gets( char* Buffer, uint8_t MaxLen )
2
{
3
  uint8_t NextChar;
4
  uint8_t StringLen = 0;
5
  NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen 
6
                                  // Sammle solange Zeichen, bis:
7
                                  // * entweder das String Ende Zeichen kam
8
                                  // * oder das aufnehmende Array voll ist
9
  while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
10
    if( NextChar != '\r' ) {
11
      *Buffer++ = NextChar;
12
      StringLen++;
13
    }
14
    NextChar = uart_getc();
15
  } 
16
                                  // Noch ein '\0' anhängen um einen Standard
17
                                  // C-String daraus zu machen
18
  *Buffer = '\0';
19
}


Moment.
Das ist ein wartendes gets.
Da dürfen überhaupt keine Zahlen in der Hauptschleife durchrauschen, 
weil jedesmal nach dem ADC auslesen darauf gewartet wird, dass du eine 
Zeile vom PC rüberschickst.

<Nachdenk>

von Karl H. (kbuchegg)


Lesenswert?

Schmeiss die Timer Initialisierung aus dem ADC_Init raus.

Dein µC resettet sich laufend selber.

von holger (Gast)


Lesenswert?

>nochmal der code mit den gemachten variationen, diesmal in der gesamten
>"pracht":

Nö.

>  TIMSK |= (1<<TOIE0);  //Enable Timer/counter0 overflow interrupt

Wo ist die Interrupt Routine für Timer0?

>#define  _AVR_ATmega8_  1
>#define OSCSPEED  8000000    /* in Hz */

Auaaaaa...

OSCSPEED interessiert

#include <util/delay.h>

nicht die Bohne.

Die Baustelle ist größer als bisher angenommen;)

von Bakunin (Gast)


Lesenswert?

also ich empfange <\n>1023<\r> ...oft

-bzw eine 1 wenn ichs auf gnd lege bzw rauschen wenn ich den pin offen 
halte , die ADC an sich ist hier denke ich nicht das problem...

was die übertragung von strings angeht,
1
    while(1){
2
        uart_puts( "Hallo" );

gibt aus: ????! oder binär: 10000101 10110001 10110001 10111101 00100001

von Karl H. (kbuchegg)


Lesenswert?

Poste alles.

Da kommen ein paar Dinge zusammen. Einzeln aussortieren ist nicht.

Aber der wichtigste Punkt ist:

WENN DU KEINE INTERRUPT SERVICE ROUTINE HAST, DANN DARFST DU AUCH FÜR 
DEN TIMER KEINEN INTERRUPT FREIGEBEN!

Und das nächste mal versteckst du keinen Timer in den ADC Funktionen. 
Schon gar nicht, wenn da ein Interrupt dafür freigegeben wird. Da sucht 
man sich nämlich dumm und dämlich danach.

von Bakunin (Gast)


Lesenswert?

die Interrupt Routine für Timer0 such ich auch grade :D nee aber es ging 
wie gesagt problemlos ohne, dass ich rauschen emfange belegt das meiner 
meinung

util/delay.h musste ich erst durch die while reinnehmen, änderung: 
eingebut wurde #define F_CPU 8000000L

nun bekomm ich nach resetten lauter Hallos wie gewollt also uart_puts 
läuft

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:
> die Interrupt Routine für Timer0 such ich auch grade :D nee aber es ging
> wie gesagt problemlos ohne,

Nein.
Es geht eben nicht problemlos.
Das hat nur so ausgesehen.
Der gcc Standard ISR Handler hat das Programm alle paar ms neu 
gestartet. Und da du PORTB nicht initialisiert, hat der Wert am PortB 
dieses überlebt.

von Bakunin (Gast)


Lesenswert?

oh äh ok hab mal
TIMSK |= (1<<TOIE0);  //Enable Timer/counter0 overflow interrupt
testweise auf 0 gesezt- resultat war dass nichts mehr gesendet wird...

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:
> oh äh ok hab mal
> TIMSK |= (1<<TOIE0);  //Enable Timer/counter0 overflow interrupt
> testweise auf 0 gesezt-

Schmeiss es ganz raus.
Timerinitialisierung hat in einer Funktion die den ADC initialisiert 
nichts verloren.

> resultat war dass nichts mehr gesendet wird...

Du meinst ausser dem ersten Messergebnis.

Das ist auch nicht anders zu erwarten.
deine uart_gets wartet darauf, dass sie eine Zeile bekommt. Der 
Programmlauf geht erst dann weiter, wenn die Zeile da ist.

Jetzt nähern wir uns langsam.
Vorschläge was du dagegen tun willst?

von Bakunin (Gast)


Lesenswert?

...morgen sicherlich :) danke schonmal bis hier hin, iss ja schon 
ganzschön was zusammengekommen in dem thread ...

von holger (Gast)


Lesenswert?

>oh äh ok hab mal
>TIMSK |= (1<<TOIE0);  //Enable Timer/counter0 overflow interrupt
>testweise auf 0 gesezt- resultat war dass nichts mehr gesendet wird...

>Das ist ein wartendes gets.

Passt doch gut zusammen;)

Der fehlende Timer Interrupt hat dein Programm durch
ständige Resets am Leben gehalten.

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:
> ...morgen sicherlich :) danke schonmal bis hier hin, iss ja schon
> ganzschön was zusammengekommen in dem thread ...

Na komm.
Jetzt sind wir auf der Zielgeraden.

Deine uart_gets muss zuerst prüfen, ob überhaupt etwas an der UART 
eingetroffen ist und wenn nicht liefert sie einfach einen leeren String 
zurück.

Ist was da, dann wartet sie bis die Zeile komplett ist und gibt erst 
dann zurück.


Ist zwar nicht optimal, aber schnell umgesetzt.

von Karl H. (kbuchegg)


Lesenswert?

1
void uart_gets( char* Buffer, uint8_t MaxLen )
2
{
3
  uint8_t NextChar;
4
  uint8_t StringLen = 0;
5
6
  if( UCSRA & (1<<RXC) ) {        // wartet ein Zeichen in der UART?
7
    NextChar = uart_getc();         // Warte auf und empfange das nächste Zeichen 
8
                                    // Sammle solange Zeichen, bis:
9
                                    // * entweder das String Ende Zeichen kam
10
                                    // * oder das aufnehmende Array voll ist
11
    while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
12
      if( NextChar != '\r' ) {
13
        *Buffer++ = NextChar;
14
        StringLen++;
15
      }
16
      NextChar = uart_getc();
17
    } 
18
  }
19
                                 // Noch ein '\0' anhängen um einen Standard
20
                                // C-String daraus zu machen
21
  *Buffer = '\0';
22
}

Dein ADC misst jetzt solange du am Terminal nichts tust.
Fängst du zu tippen an, dann geht die uart_gets in den Wartemodus. Sie 
wartet bis du fertig getippt hast (Return) und gibt die Zeile zurück. 
Die Zeile wird in der Hauptschleife ausgewetret und weiter gehts in der 
Hauptschleife und da dann die UART wieder leer ist, geht auch uart_gets 
nicht mehr in den Wartemodus und wartet danach nicht mehr. Bis du wieder 
zu tippen anfängst.

von Walter (Gast)


Lesenswert?

noch was anderes:
warum muss bei jedem ADCread der AD-Wandler komplett neu initialisiert 
werden?
Ich würde das nur ein Mal machen.

von Bakunin (Gast)


Lesenswert?

ok, änderungen die ich gemacht habe sind: löschen der kompletten 
timerinizialisierung sowie erneuern der uart_gets() nach kbucheggs 
vorschlag(danke!)

...schön ist dass jezt die warteschleife so läuft wie sie soll :)

allerdings resultiert das senden einer abfrage zb ?2 oder auch !2 im 
abbruch der hauptschleife (jedenfalls werden keine werte mehr 
ausgegeben, auchnicht das testweise implementierte "Schalte nach # 
'Line[1]' #")

aber auf jedenfall ist jezt so wie ich das sehe mit der initialisierung 
und den verwendeten funktionen alles im reinen...   ...vorschläge?

von Bakunin (Gast)


Angehängte Dateien:

Lesenswert?

hier nochmal der komplette code im anhang
 - vielleicht hilfts der übersichtlichkeit :)

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Sicher, dass du zu dem ?3 auch ein \n schickst? Ansonsten wartet deine 
getchar-Routine darauf, dass das Array voll ist. Und das bedeutet, dass 
du 80 Zeichen schicken musst.

von Bakunin (Gast)


Lesenswert?

also standardmässig sende ich null (\0) hinterher, \n bewirkt nichts 
anderes (grade getestet)

von Bakunin (Gast)


Lesenswert?

ok es liegt anscheinend auf jeden fall an der uart_gets() genauer gesagt 
an der bedingung
1
while( NextChar != '\n' && StringLen < MaxLen - 1 ) {

sobald ich das array Line[] auf 3 felder länge setze läuft alles wies 
soll...  - beötigt man für StringLen zufällig ne bibliothek die ich nich 
implementiert hab oder sowas?

nachtrag zu oben: dass ich standardmässig \0 am ende sende muss nicht 
sein-schöner währ ja ohne :)


aber wir (oder besser ihr) seit schon nah dran denk ich..

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Deine ganze UART-Empfangsgeschichte sieht für mich sehr komisch aus. Ich 
würde das alles streichen und neu konzipieren ;)

von Bakunin (Gast)


Lesenswert?

um die zu verbessern poste ich dass doch hier :D

"mach neu" ist mir dabei keine grosse hilfe..

von Lasse S. (cowz) Benutzerseite


Lesenswert?

klar :)

Ich würde das so aufbauen:
1
switch(getchar()) {
2
 case '!':
3
  switch(getchar()){
4
   '1': ...
5
  }
6
 break;
7
 case '?':
8
  switch(getchar()){
9
   '1': ...
10
  }
11
 break;
12
}

von Karl H. (kbuchegg)


Lesenswert?

Bakunin schrieb:

> nachtrag zu oben: dass ich standardmässig \0 am ende sende muss nicht
> sein-schöner währ ja ohne :)

Was, oder besser gesagt, wer sendet eigentlich.

Du (an einem Terminal) oder ein anderes Programm.

Ehe du an anderes Programm das Senden übernehmen lässt, solltest du erst 
mal selbst per Hand von einem Terminal aus deinen µC 'füttern'


(die 80 Zeichen können dir nur dann einen Strich durch die Rechnung 
machen, wenn dadurch das SRAM voll ist. Deine 'Lösung' mit Array auf 3 
Zeichen zurückschrauben ist, abgesehen von diesem Sonderfall, keine 
Lösung.


So wie Lasse das vorschlägt, kann man das natürlich auch machen. 
Allerdings ist es zum einen Flucht vor dem Feind, zum anderen wirst du 
deine Debug-Fähigkeiten nie entwickeln wenn du Schwierigkeiten immer nur 
aus dem Weg gehst und zu guter letzt ist eine uart_gets keineswegs eine 
esoterische Funktion, die man nie wieder braucht.

von Karl H. (kbuchegg)


Lesenswert?

Du kennst mitlerweile die Techniken, wie man solchen Problemen auf den 
Grund geht:

Bau dir Ausgaben ein!
In deiner uart_gets kommen die Zeichen herein. Also kannst du dir dort 
Ausgaben einbauen, an Hand derer du verfolgen kannst, was deine UART 
eigentlich empfängt.

von Bakunin (Gast)


Lesenswert?

Haha ok wie bekloppt- mein terminal-programm war so eingestellt dass \0 
on enter gesendet wird- mit der einstelölung \r on enter läufts 
logischer weise :D
später will ich labview zur steuerung nutzen (da ist es auch nicht 
sonderlich wild eben noch nen carriage return als konstante an den 
befehlsstring anzuhängen)

vielen dank fürs aufräumen meines codes und die verbessenungen!!!

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.