Forum: Mikrocontroller und Digitale Elektronik Variable aus externen Funktion holen


von Mark (Gast)


Lesenswert?

Hallo,
ich möchte mein Programm übersichtlicher machen, indem ich für die 
einzelnen Funktionen einzelne .c und .h dateien erstelle.

Z.B. habe ich für UART zwei eigene Dateien, in denen die Funktionen 
drinn stehen.

header:
1
#ifndef UART_H_
2
#define UART_H_
3
4
void usart_init(unsigned int ubrr);
5
void usart_transmit_char(unsigned char data);
6
void usart_transmit_string (char *s);
7
ISR(USART_RX_vect);
8
9
10
volatile unsigned char usart_data;
11
12
#endif /* UART_H_ */

c-file
1
 #include <avr/io.h>
2
 #include "uart.h"
3
4
5
void usart_init(unsigned int ubrr){
6
  /* Set Baud-Rate */
7
  UBRR0H = (unsigned char) (ubrr >> 8);
8
  UBRR0L = (unsigned char) ubrr;
9
  /* Enable Receiver and Transmitter and receiver-interrupt*/
10
  UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
11
  /* Set Frame format: 8 data, 2 stop bit */
12
  UCSR0C = (1 << USBS0) | (1 << UCSZ01) | (1 << UCSZ00);
13
 }
14
15
void usart_transmit_char(unsigned char data){
16
  /* Wait for empty transmit buffer */
17
  while ( !( UCSR0A & (1<<UDRE0)) );
18
  /* Put data into buffer, sends the data */
19
  UDR0 = data;
20
}
21
22
void usart_transmit_string (char *s){
23
  while (*s){   /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
24
    usart_transmit_char(*s);
25
    s++;
26
  }
27
}
28
29
ISR(USART_RX_vect){
30
  usart_data = UDR0;
31
}

Jetzt bekomme ich beim kompilieren u.a. die Meldung:

Severity  Code  Description  Project  File  Line
Warning    type of '__vector_18' defaults to 'int'  SPI_Atmega 
c:\users\Documents\Atmel Studio\7.0\SPI_Atmega\SPI_Atmega\uart.c  36
Error    recipe for target 'SPI_Atmega.elf' failed  SPI_Atmega 
c:\users\Documents\Atmel Studio\7.0\SPI_Atmega\SPI_Atmega\Debug\Makefile 
129
Error    multiple definition of `ISR'  SPI_Atmega 
c:\users\Documents\Atmel Studio\7.0\SPI_Atmega\SPI_Atmega\uart.c  37
Error    ld returned 1 exit status  SPI_Atmega  collect2.exe  0
Warning    return type defaults to 'int'  SPI_Atmega 
c:\users\Documents\Atmel Studio\7.0\SPI_Atmega\SPI_Atmega\uart.c  36
Warning    control reaches end of non-void function [-Wreturn-type] 
SPI_Atmega  c:\users\Documents\Atmel 
Studio\7.0\SPI_Atmega\SPI_Atmega\uart.c  38
Warning    parameter names (without types) in function declaration 
SPI_Atmega  c:\users\Documents\Atmel 
Studio\7.0\SPI_Atmega\SPI_Atmega\uart.h  15
Warning    data definition has no type or storage class  SPI_Atmega 
c:\users\Documents\Atmel Studio\7.0\SPI_Atmega\SPI_Atmega\uart.h  15
Warning    type defaults to 'int' in declaration of 'ISR'  SPI_Atmega 
c:\users\Documents\Atmel Studio\7.0\SPI_Atmega\SPI_Atmega\uart.h  15


Der erste Error lautet
multiple definition of `ISR'

ist das wegen der header, die ich in usart.c und in main.c inkludiere?
wie muss ich das sonst machen?


Mark

von Mullwark (Gast)


Lesenswert?

Nimm mal "ISR(USART_RX_vect);" aus uart.h

Die ISR ist dem Compiler bereits über die interrupt.h bekannt. Du kannst 
sie in der uart.c nutzen ohne sie in der Headerdatei listen zu müssen.

von holger (Gast)


Lesenswert?

Mach den Prototypen für die ISR aus uart.h mal weg.

von Mark (Gast)


Lesenswert?

mh, das wusste ich nicht, doch leider bekomme ich immer noch den fehler. 
Ist es überhaupt geschickt, ISRs aus der Hauptdatei zu entfernen? Wenn 
ich diese nämlich in uart.c komplett raus nehme, wird das Programm ohne 
Fehler gebaut.

Error    recipe for target 'SPI_Atmega.elf' failed
Error    multiple definition of `ISR'
Error    ld returned 1 exit status
Warning    return type defaults to 'int'
Warning    type of '__vector_18' defaults to 'int'
Warning    control reaches end of non-void function [-Wreturn-type]

von holger (Gast)


Lesenswert?

>Error    multiple definition of `ISR'

Hast du irgendwo ein

#include "uart.c"

gemacht?

von holger (Gast)


Lesenswert?

>>Error    multiple definition of `ISR'
>
>Hast du irgendwo ein
>
>#include "uart.c"
>
>gemacht?

Ach quark, da fehlt ein

#include <avr/interrupt.h>

von Mark (Gast)


Lesenswert?

nein, nur #include uart.h in der main-datei.
Habe jetzt auch noch einmal alles andere raus genommen, was nicht dafür 
verwendet wird
1
#define F_CPU 16000000UL // for _delay_ms(); _delay_us()
2
#define FOSC 16000000UL // for Baudrate
3
4
/* -- includes -- */
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <util/delay.h>
8
#include "uart.h"
9
10
/* -- USART -- */
11
#define USART_BAUD 1200
12
#define USART_MYUBRR FOSC/16/USART_BAUD-1
13
/* --  -- */
14
15
16
17
int main(void){
18
  usart_init(USART_MYUBRR);
19
  usart_transmit_string("RX devices ready \r\n"); 
20
21
  sei(); // Global Interrupts activate
22
  while (1){
23
24
  }
25
}

von Mark (Gast)


Lesenswert?

ahhhhhhhh,
ja, das war es. hatte das nur in der hauptdatei. Da kann das ja jetzt 
natürlich raus.

von Mark (Gast)


Lesenswert?

nein, kann es doch nicht, da sei() ja ebenfalls da drinn ist

von Mark (Gast)


Lesenswert?

Ich habe noch einmal eine Nachfrage,

wenn ich jetzt Variablen in beiden Dateien benutzen möchte.
deklariere ich diese als volatiele in der header, bekomme ich die 
Meldung multiple definition. Deklariere ich die Variablen in der 
c-datei, bekomme ich die Meldung variable undeclared.

Muss ich diese als Globale Variable machen und dann überhall hinzufügen? 
Wenn ich später mehrere dateien habe und überall globale variablaen 
habe, können diese ja quasi überall geändert werden.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Mark schrieb:
> deklariere ich diese als volatiele in der header

volatile ("flüchtig") ist nur nötig, wenn aus einer Interruptroutine 
und einer anderen, quasi parallellaufenden Funktion auf eine Variable 
zugegriffen werden soll.

Du suchst das Schlüsselwort extern.

von header (Gast)


Lesenswert?

Schau dir mal an, was ein header eigentlich ist.

Der Präprozessor (der vor dem Compiler durchläuft) nimmt den Inhalt im 
header, copy+pasted den da hin wo #include "header.h" steht.
Diese resultierende Textwurst bekommt der Compiler dann gefüttert.
Man kann sich auch ankucken, wenn man sich den Ouput des Präprozessors 
ansieht. Das kann ...erschreckend sein.

Drum empiehlt sich:
Den Header so minimalistisch wie möglich machen.
Vor allem keine Variablendeklarationen im Header. Die hat man sonst die 
Variabel überall neu deklariert wo ein include steht, und der Compiler 
ist verwirrt, was er mit seltsamen Meldungen quittiert.

Im Header sollten nur:
- Datentypen, die man auch außerhalb der zugehörigen C verwendet
- Funktionsprototypen, und da auch nur die, die man außerhalb verwendet 
*1)
- nur #defines, die man auch wirklich wonanders braucht. Soweinige wie 
möglich

*1) d.h: ein Prototyp für die ISR muss da nicht rein.

PS:
Um Irgendwelche tollen Effekte zu vermeiden, sollte man unbedingt 
include guards verwenden:
https://de.wikipedia.org/wiki/Include-Guard

von Mark (Gast)


Lesenswert?

Irgendwie will das nicht funktionieren.

Das mit extern habe ich mir zunächst durchgelesen und dann angewendet. 
Es heisst ja, dass dem Kompiler klar gemacht wird, dass diese Variable 
schon irgendwo definiert ist.

habe jetzt in uart.h
1
extern unsigned char usart_data;
2
extern unsigned char new_usart_data;

in der ISR vom uart (in uart.c) beschreibe ich usart_data mit den 
reinkommenden Daten und setze new_usart_data=1.
1
void usart_transmit_char(unsigned char data){
2
  /* Wait for empty transmit buffer */
3
  while ( !( UCSR0A & (1<<UDRE0)) );
4
  /* Put data into buffer, sends the data */
5
  UDR0 = data;
6
}
7
8
ISR(USART_RX_vect){
9
  usart_data = UDR0;
10
  new_usart_data = 1;
11
}


der Hauptdatei habe ich über der main-function
1
unsigned char usart_data = 0;
2
unsigned char new_usart_data = 0;

und in der hauptschleife frage ich new_usart_data ab. Wenn diese gleich 
1 ist, soll mir die uart-funktion die Variable usart_data doppelt so 
groß wieder raus geben.
1
  while (1){
2
    if(new_usart_data == 1){
3
      usart_transmit_char(usart_data*2);
4
      new_usart_data = 0;
5
6
    }
7
8
  }
doch es kommt nichts heraus, als ob es die variable in der main-function 
nicht geändert wurde und somit nicht in die Bedingung gegangen worden 
ist.

Vor der hauptschleife sende ich einmal usart_transmit_char(0x22); 
heraus. Diese kommen auch an, daher weiss ich, dass die uart-Funktion an 
sich funktioniert.

von Mark (Gast)


Lesenswert?

konnte es jetzt so lösen, dass ich in der uart.h die Variablen als
extern volatile unsigned char deklariert habe
und in der uart.c als
volatile unsigned char.
ist das so richtig?
es funktioniert zumindest, ist nur die Frage, ob das auch so gut ist

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.