Forum: Mikrocontroller und Digitale Elektronik Zwei bis drei Fehler im Programmcode


von Julian K. (Gast)


Lesenswert?

Hallo Entwickler,

ich habe zum ersten Mal ein kleines Programm für einen uC geschrieben. 
Bei mir kommen nach dem Debuggen folgende Fehlermeldungen:

undefined reference to `sei'
undefined reference to `cli'
ld returned 1 exit status

In einem Thread hier im Forum habe ich gelesen, dass sich die ersten 
beiden Fehler dadurch beheben lassen, wenn ich

#include <avr/interrupt.h>

in mein Programm einbinde. Das habe ich bereits getan. Allerdings 
besteht der Fehler weiterhin.

Hatte jmd. von euch schon ein mal das Problem? Kann mir jemand 
weiterhelfen. Das wäre wirklich freundlich.

Ich verwende AtmelStudio 6.1

Ich kann euch auch den Code posten, wenn sich heraustellen sollte, dass 
ihr mir auf Grund meiner bisherigen Angaben nicht helfen könnt. Lasst es 
mich wissen, falls dem so ist.

Julian K.

von blue man (Gast)


Lesenswert?

Julian K. schrieb:
> Ich kann euch auch den Code posten, wenn sich heraustellen sollte, dass
> ihr mir auf Grund meiner bisherigen Angaben nicht helfen könnt. Lasst es
> mich wissen, falls dem so ist.

Ich lass es Dich hiermit wissen.

------------

soll "sei" und "cli" C oder Assembler sein?

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

hat der GCC keinen Inlineassembler?

von Walter T. (nicolas)


Lesenswert?

Winfried J. schrieb:
> hat der GCC keinen Inlineassembler?

Hat er. Aber dann muß ihm auch gesagt werden ("asm volatile").

Oder eben die Makros cli() und sei() benutzen.

von Christian K. (christiankarle)


Lesenswert?

Schreib mal anstatt:
sei(); -> SREG |=   ( 1 << I );

und anstatt:
cli(); -> SREG &= ~ ( 1 << I );

Das wäre der ausführlichere Weg... Compiliere das Ganze mal und schau 
dann ob das Problem immer noch besteht.

von Julian K. (Gast)


Lesenswert?

Also hier der Code:


#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#define F_CPU 1000000
#define BAUD 9600
#include <util/setbaud.h>

volatile uint16_t Mittelwert;

void ADC_Konfig(void)
{
  ADCSRA |= (1<< ADPS0) | (1<<ADPS1);
  ADMUX  |= (1<< REFS0) | (1<<REFS1);
}

void USART_Konfig(void)
{
  UBRR1H |= (UBRRH_VALUE) ;
  UBRR1L |= (UBRRL_VALUE) ;

  UCSR1C = (1<< UCSZ11) | (1<< UCSZ10);

  UCSR1B = (1<<TXEN1);
}

void Timer_Konfig(void)
{
  TCCR1B |= (1<<WGM12);
  TCCR1B |= (1<<CS11);

  TIMSK1 |= (1<<OCIE1A);

  OCR1A = 1000;
}

void usart_putc ( unsigned char c)
{
  while (UCSR1A != (UDRE1)) {}

  while (UCSR1A != (UDRE1)) {}

  while (UCSR1A != (UDRE1)) {}
}

void usart_puts (char *s)
{
  while (*s !='\0') {usart_putc (*s); s++;}
}


int main(void)
{
  DDRD |= (1<<PD3);

  char s[6];

  ADC_Konfig();
  USART_Konfig();
  Timer_Konfig();

  while (1)
  {
    if (Mittelwert == 0){}
    else {
      utoa(Mittelwert, s, 10);
      usart_puts (s);

      Mittelwert = 0;
       }
  }
  return 0;
}



ISR(TIMER1_COMPA_vect)
{
  uint8_t i;
  uint16_t result;

  ADCSRA = (1<<ADEN);


  result = 0;
  for( i=0; i<10; i++ )
  {
    ADCSRA |= (1<<ADSC);
    while ( ADCSRA & (1<<ADSC) )
    { ;  }

    result += ADC;
  }

  ADCSRA &= ~(1<<ADEN);

  Mittelwert = result / 10;
}

von Walter T. (nicolas)


Lesenswert?

Bin ich der Einzige, der in dem Quelltext weder "cli" noch "sei" findet?

von Patrick (Gast)


Lesenswert?

Julian K. schrieb:
> Also hier der Code:

Hm... Es mag an mir liegen, aber ich sehe hier weder ein "sei" noch ein 
"cli"...
Bitte poste den vollständigen Quellcode, der den Fehler verursacht.

PS: Bitte hänge das nächste Mal den Quellcode in Form einer Datei mit 
der Dateiendung .c an.

von Julian K. (Gast)


Lesenswert?

Das merkwürdige ist, dass die Fehlermeldung selbst dann auftauchen, wenn 
ich vor bzw. nach OCRA1A = 1000; sei() und cli() auslasse, so wie im 
Code oben zu sehen ist.

von Julian K. (Gast)


Lesenswert?

Ja sry: In Bezug auf das Fehlen von sei() und cli() seht bitte mein 
letzte Posting.

@ christian karle: danke für den Alternativvorschlag. Den habe ich 
vergebens versucht.

@ walter tarplan: Was meinst du mit ("asm volatile"). Da muss ich doch 
gleich mal googlen

von Oliver S. (oliverso)


Lesenswert?

Am Programm liegt es nicht. Entweder ist da was bei der Installation des 
Studios schiefgegangen, oder du hast beim Anlegen des Projektes was 
falsch gemacht.

Kopier doch mal den kompletten Compileraufruf hier rein. Alles, was da 
im Comsolenfenster erscheint.

Oliver

von Christian K. (christiankarle)


Lesenswert?

Gibt der Compiler dann immer noch die gleiche Fehlermeldung aus?
Also wenn Du es so wie von mir vorgeschlagen machst?

von Julian K. (Gast)


Lesenswert?

@ Christian Karle: ja trotzdem funktioniert es nicht.

@ Oliver: Jo, du hast die Lösung gebracht. Ich habe einfach ein neues 
Prokjekt erstellt und den Code darein kopiert. Jetzt geht's. Danke dir. 
Darauf wäre ich nicht so schnell gekommen.

Und auch allen anderen einen herzlichen Danke, die sich die Mühe gemacht 
haben mir helfen zu wollen. Spitzen Forum!

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

wetten das der hund in io.lib liegt welche durch io.h eingebunden wird.
und wo cli() und Sei() aufgerufen werden  um die soft_com gegen 
interupts zu schützen?


versuch mal die Reihenfolge

#include <avr/interrupt.h>
#include <stdlib.h>
#include <avr/io.h>
#include <stdio.h>
#define F_CPU 1000000
#define BAUD 9600
#include <util/setbaud.h>

möglich das der Compiler stolpert bevor die Definition erfolgt

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Was soll io.lib sein? Sowas gibt's nicht.  avr/io.h ist ein Header, mehr 
nicht.

sei() und cli() werden in avr/interrupt.h definiert, es sind Makros.

Fehler vom Linker wie ober geschehen dann, wenn man avr/interrupt nicht 
includet und sei() und cli() als Funktionsaufrufe interpretiert werden. 
Das sollte aber mindestens eine Warnung vom Compiler geben!

Der Vorschlag, das I-Bit in SREG von Hand zu setzen, ist nicht gut.

von Christian K. (christiankarle)


Lesenswert?

Wieso sollte man das I-Bit in SREG nicht selber setzten dürfen? Nichts 
andres tut der Befehl sei();... Lediglich wird das Bit 3 Takte früher 
gesetzt.

von Thomas E. (thomase)


Lesenswert?

Christian Karle schrieb:
> Wieso sollte man das I-Bit in SREG nicht selber setzten dürfen? Nichts
> andres tut der Befehl sei();... Lediglich wird das Bit 3 Takte früher
> gesetzt.
Andere Frage: Warum glaubst du, daß es besser ist als es mit sei();
und cli(); zu machen? Dein toller Tip war absolut wertlos.

sei(); und cli(); tun sehr Wohl was anderes. Sie benutzen nämlich die 
Aseemblerbefehle SEI und CLI, die das Setzen bzw. Zurücksetzen in einem 
Taktzyklus ausführen.

mfg.

von Christian K. (christiankarle)


Lesenswert?

Ich habe nirgendwo geschrieben das es besser sei! Durch das manuelle 
Setzten des Bits sollte lediglich überprüft werden ob das Problem an 
#include <avr/interrupt.h> liegt. Es hätte durchaus möglich sein können, 
dass die Datei beschädigt oder verändert wurde!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Und duch Setzen von I per Hand erkennt man, daß interrupt.h kaputt ist. 
Aha.

von Paul Baumann (Gast)


Lesenswert?

Ich bin so froh, daß mich niemand zwingt, mit "C" herumzufuhrwerken.
Das mußte ich sagen, komme, was da wolle.

MfG Paul

von Thomas E. (thomase)


Lesenswert?

Christian Karle schrieb:
> Ich habe nirgendwo geschrieben das es besser sei! Durch das manuelle
> Setzten des Bits sollte lediglich überprüft werden ob das Problem an
> #include <avr/interrupt.h> liegt. Es hätte durchaus möglich sein können,
> dass die Datei beschädigt oder verändert wurde!
interrupt.h gehört zur Toolchain. Es ist äusserst unwahrscheinlich, daß 
diese beschädigt ist. Wenn es doch so ist, ist davon auszugehen, daß die 
gesamte Installation Schrott ist und wiederholt werden muß.
Wenn man sie allerdings selbst verändert hat, hat man auch nichts 
anderes verdient, als daß es danach nicht mehr läuft.
1
SREG |=   ( 1 << I );
2
SREG &=   ~( 1 << I );

Das sind Read-Modify-Write-Operationen, die aus mehreren Befehlen 
bestehen. Das bedeutet, daß insbesondere der "cli" mittendrin durch 
einen Interrupt unterbrochen werden kann, was widerum zu unerwünschtem 
Verhalten führen kann.
Deswegen:
Johann L. schrieb:
> Der Vorschlag, das I-Bit in SREG von Hand zu setzen, ist nicht gut.

Dafür hat Atmel den Controllern extra 2 Befehle spendiert, die in einem 
Zyklus abgehandelt werden.

Man sollte Anfängern nicht solche Vorschläge machen. Die gewöhnen sich 
das nur unnötigerweise an. Nach dem Motto: Was einmal gut war, ist immer 
gut.

mfg.

von Thomas E. (thomase)


Angehängte Dateien:

Lesenswert?

Paul Baumann schrieb:
> Ich bin so froh, daß mich niemand zwingt, mit "C" herumzufuhrwerken.
> Das mußte ich sagen, komme, was da wolle.
>
> MfG Paul

Das reimt sich ja gar nicht.
Aber man könnte in C Programme schreiben, die sich reimen. Dann wäre C 
doch noch was für dich.
1
#include "paul.h"
2
int  
3
  Meen Veut
4
  Init heut
5
  Weil
6
  Das ist geil
7
  Taste rein
8
  Lampe ein
9
  Taste raus
10
  Lampe aus
11
}}

mfg.

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Sowas gibt's nicht.

mag sein. aber *.h sind dafür gedacht Funktionen zu deklarieren dies mus 
vor dem ersten Aufruf geschehen. Die Definition findet üblicher Weise in 
einer *.lib statt.

rufen nun *.h bereits Funktionen auf welche erst später deklariert 
werden kommt es zu dieser Art Fehler.

Das setzen und löschen von Interruptenablebits in eigenen Funktionen 
erscheint freilich als oversiced, zumindest für einen 
Assemblerproggrammierer

von Thomas E. (thomase)


Lesenswert?

Winfried J. schrieb:
> Johann L. schrieb:
>> Sowas gibt's nicht.
>
> mag sein. aber *.h sind dafür gedacht Funktionen zu deklarieren dies mus
> vor dem ersten Aufruf geschehen. Die Definition findet üblicher Weise in
> einer *.lib statt.
Headerdateien können Funktionsprototypen enthalten, müssen sie aber 
nicht. Sie können genauso gut nur Defines und Makros enthalten. Z.B. die 
Adressen der Register, auf die per Registernamen zugegriffen werden 
soll.

> rufen nun *.h bereits Funktionen auf welche erst später deklariert
> werden kommt es zu dieser Art Fehler.
Nur in Schrottprogrammen. Eine vernünftige Headerdatei, die das 
Vorhandensein einer anderen Headerdatei voraussetzt, bindet diese selbst 
ein. Damit durch mehrfaches Einbinden dieser Headerdatei nicht 
massenhaft Redefines entstehen, baut man da für paul.h
1
#ifndef PAUL_H
2
#define PAUL_H
3
4
//Alles , was da reingehört
5
6
#endif /*PAUL_H*/
ein.

> Das setzen und löschen von Interruptenablebits in eigenen Funktionen
> erscheint freilich als oversiced, zumindest für einen
> Assemblerproggrammierer

Auch ein Assemblerprogrammierer muß manche Zugriffe atomar machen.

mfg.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Winfried J. schrieb:
> Johann L. schrieb:
>> Sowas gibt's nicht.
>
> mag sein. aber *.h sind dafür gedacht Funktionen zu deklarieren dies mus
> vor dem ersten Aufruf geschehen. [...]
>
> rufen nun *.h bereits Funktionen auf welche erst später deklariert
> werden kommt es zu dieser Art Fehler.
>
> Das setzen und löschen von Interruptenablebits in eigenen Funktionen
> [...]

Es sind eben keine Funktionen sondern funktionsähnliche Makros, wie 
man leicht in avr/interrupt.h nachlesen kann:
1
# define sei()  __asm__ __volatile__ ("sei" ::: "memory")
2
# define cli()  __asm__ __volatile__ ("cli" ::: "memory")

Als Funktionsaufrufe werden sie nur dann interpretiert, wenn diese 
Makros nicht vorhanden sind, etwa weil avr/interrupt.h nicht includet 
wird.  Das hab ich aber alles bereits oben erklärt.

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.