Forum: Mikrocontroller und Digitale Elektronik sprintf mehrfach


von Tom (Gast)


Lesenswert?

Hallo,
ich hab jetzt ne Weile die Beiträge zum Thema sprintf gelesen aber 
leider nichts gefunden was meinem Problem ähnelt.
Und zwar läuft die Funktion wenn ich sie nur einmal aufrufe wunderbar. 
Sobald aber ein zweiter sprintf Befehl hinzukommt, erhalte ich einen 
HardFault_Handler. Kann es Probleme geben wenn man die Funktion zweimal 
aufruft?
ich arbeite mit einem LPC1768 und möchte Daten vom CAN-Bus ausgeben. 
Hier beide anweisungen, falls ihr was seht immer her damit =)
1
mph = 123;
2
char feld[12];
3
sprintf(feld,"%1u",mph); 
4
lcd_draw_string(font_vw_24px, NORMAL_STYLE,feld,43,60,255);
5
6
kmm = 123459;
7
char kmm[12];
8
sprintf(kmm,"%1u",km);
9
lcd_draw_string(font_vw_24px, NORMAL_STYLE,kmm,5,155,255);

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> kmm = 123459;
  ^^^
> char kmm[12];
       ^^^
> sprintf(kmm,"%1u",km);
          ^^^       ^^

Tippfelher

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Tom schrieb:
> sprintf(feld,"%1u",mph);
Was willst du mit dem Modifier %1u (prozent eins u) erreichen?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

ADD: Dein Compiler sollte eine Warnung geschmissen haben. Wenn keine 
Warnung kam, nachsehen, wie man die Warnungen aktiviert.

von Lehrmann M. (ubimbo)


Lesenswert?

Tom schrieb:
> kmm = 123459;
> char kmm[12];

was genau bezweckst du mit diesem Code?

Zuerst weißt du einer nicht deklarierten Variable den Wert 123459 zu 
(schon das müsste einen Fehler ergeben). Danach deklarierst du die 
Variablen (12 Stück) als char (=8bit). Solltest du kmm vorher schon 
deklariert haben ergibt das auch einen Fehler da Redeklarationen 
verboten sind.

Wenn du das Array mit 123459 füllen möchtest geht das so:

kmm[12]={1,2,3,4,5,9,0,0,0,0,0,0};

Wenn man ein Array nullen / mit nur einem Wert füllen will geht das so:

kmm[12]={0};

von Tom (Gast)


Lesenswert?

okay vielen dank für die Antworten, hab nun von der sprintf abstand 
genommen und arbeite stattdessen mit einer funktion die den Wert manuell 
in ein ascii zeichen umwandelt und das ganze dann ausgibt, aber vielen 
dnak bis hierher.

Die Ausgabe funktioniert auch jedoch wiederum nur wenn ich eine der 
beiden werte verarbeite, sobald ich den zweiten hinzuschalte erhalte ich 
wieder den HardFault_Handler.
ich poste einfach mal den Code =)
1
#include "type.h"
2
#include "can.h"
3
#include "mfa_display.h"
4
5
CAN_MSG MsgBuf_TX1, MsgBuf_TX2; /* TX and RX Buffers for CAN message */
6
CAN_MSG MsgBuf_RX1, MsgBuf_RX2; /* TX and RX Buffers for CAN message */
7
8
volatile uint32_t CAN1RxDone = FALSE, CAN2RxDone = FALSE;
9
volatile uint32_t data[12];
10
volatile uint32_t Schalter;
11
volatile uint8_t TasterCount       = 0;      // Zähler für Wipptasterbetätigung
12
volatile uint32_t kmph              = 0;      // Variable Stundenkilometer
13
volatile uint16_t mph               = 0;      // Variable Meilen pro Stunde
14
volatile uint8_t TASTER_MASK_HOCH   = 0b10;   // Maske Menü hoch
15
volatile uint8_t TASTER_MASK_RUNTER = 0b01;   // Maske Menü zurück
16
volatile uint8_t black              = 0;      // Variable für schwarzen Hintergrund
17
volatile uint32_t km                = 0;      // Variable Kilometerstand
18
19
20
/*****************************************************************************
21
** Function name:    main
22
**
23
** Descriptions:    main routine for CAN module test
24
**
25
** parameters:      None
26
** Returned value:    int
27
** 
28
*****************************************************************************/
29
int main( void )
30
31
{
32
  SystemInit();   // Funktionsaufruf Systeminitialisierung
33
  lcd_init();
34
  INOUT_Def();
35
 
36
  /* Please note, the bit timing is based on the setting of the 
37
  PCLK, if different PCLK is used, please read can.h carefully 
38
  and set your CAN bit timing accordingly. */  
39
 
40
  CAN_Init(BITRATE500K15MHZ);       // Bitrate = 500kbaud bei 15MHz
41
  
42
 CAN_SetACCF( ACCF_ON );          // Filtermodus festlegen
43
44
  while ( 1 )
45
  { 
46
    // Wipptasterauswertung
47
        if((data[0]>>20)&TASTER_MASK_HOCH)   // Tasterauswertung hochzählen
48
        { LPC_GPIO2->FIOPIN &= ~0xFF;
49
          TasterCount++;
50
          data[0] = 0;
51
          black=1;
52
        }
53
        if((data[0]>>20)&TASTER_MASK_RUNTER)   // Tasterauswertung hochzählen
54
        {LPC_GPIO2->FIOPIN |= 0xFF;
55
          TasterCount--;
56
          data[0] = 0;
57
          black=1;
58
        }
59
        if(TasterCount > 8 && TasterCount <=16)
60
        {
61
          if(black==1)
62
          {
63
            lcd_draw_area(0, 120, 0, 176, 0);
64
            black = 0;
65
          }
66
          // Kilometerstand Ausgabe
67
          lcd_draw_string(symbols_16px,NORMAL_STYLE,"km",5,140,255);
68
          km=((data[6]>>8)&0b11111111111111111111);
69
          lcd_draw_double (font_vw_24px,NORMAL_STYLE,km,7,0,5,155,255);
70
71
          // Meilen pro Stunde Ausgabe
72
          lcd_draw_string(symbols_16px, NORMAL_STYLE,"9",110,30,255);
73
          lcd_draw_string(symbols_16px, NORMAL_STYLE,"mph",79,60,255);
74
          kmph=(((data[3]>>14))&0b1111111111)*0.32;
75
         if(kmph)
76
          {
77
            mph = kmph/(1.609);
78
            lcd_draw_double (font_vw_24px,NORMAL_STYLE,mph,3,0,43,60,255);
79
          }
80
          else
81
          {
82
            lcd_draw_string(font_vw_16px, NORMAL_STYLE,"-.-",43,60,255);
83
          }
84
        }
85
        else if (TasterCount<9)
86
        {
87
        if(black==1)
88
          {
89
            lcd_draw_area(0, 120, 0, 176, 0);
90
            black = 0;
91
          }
92
        lcd_draw_string(font_vw_24px, NORMAL_STYLE,"Normal",43,60,255);
93
        }
94
  /* please note: FULLCAN identifier will NOT be received as it's not set 
95
  in the acceptance filter. */
96
   if ( CAN1RxDone == TRUE )
97
  {  
98
           if ( MsgBuf_RX1.Frame & (1 << 10) )  /* by pass mode */
99
    {
100
    MsgBuf_RX1.Frame &= ~(1 << 10 );
101
    }
102
          CAN1RxDone = FALSE;         
103
  } /* Message on CAN 2 received */
104
   
105
  }
106
107
}
108
109
110
111
void lcd_send_byte(uint8_t u8_Type, uint8_t u8_Byte)
112
{
113
  if (u8_Type == CMD)
114
  {
115
    LCD_COMMAND_MODE();
116
  }
117
  else
118
  {
119
    LCD_PARAMETER_MODE();
120
  }
121
  
122
  // -> Serielle Übertragung des Bytes
123
  for (uint8_t x = 0; x <= 7 ; x++)
124
  {
125
    LPC_GPIO1 -> FIOPIN &= ~XWR;
126
    
127
    if (u8_Byte & (1<<(7 - x)))
128
    {
129
      LPC_GPIO1 -> FIOPIN |= D0;
130
    }
131
    else
132
    {
133
      LPC_GPIO1 -> FIOPIN &= ~D0;
134
    }
135
136
    LPC_GPIO1 -> FIOPIN |= XWR;        
137
  }
138
139
}
140
141
void lcd_send_pixel(uint32_t u32_Block)
142
{
143
  LPC_GPIO1 -> FIOPIN &= ~XWR;
144
  for (uint32_t x = 0; x <= 31 ; x++)
145
  {
146
    if (u32_Block & (1<<(31 - x)))
147
    {
148
      LPC_GPIO1 -> FIOPIN |= D0;
149
    }
150
    else
151
    {
152
      LPC_GPIO1 -> FIOPIN &= ~D0;
153
    }    
154
  }
155
   LPC_GPIO1 -> FIOPIN |= XWR;
156
}

von Karl H. (kbuchegg)


Lesenswert?

Tom schrieb:

> ich arbeite mit einem LPC1768 und möchte Daten vom CAN-Bus ausgeben.
> Hier beide anweisungen, falls ihr was seht immer her damit =)

Hauptsächlich sehen wir, dass das nicht der Code ist so wie er in deinem 
Programm steht. Poste bitte deinen richtigen Code.
Viele Leute hier haben die Schnauze voll davon, in im Forum eingetippten 
Code nach Fehlern zu suchen, die im richtigen Code gar nicht vorhanden 
sind. Dafür dürfen wir dann immer die Dinge erraten, die der Poster gut 
meinend, nicht gezeigt hat.
Keine Sorge. Die Profis hier haben überhaupt kein Problem damit, 40, 50, 
100 Zeilen Code zu überblicken und mit 1 oder 2 mal durchlesen zu 
verstehen. Das ist unser täglich Brot.

von Tom (Gast)


Lesenswert?

ja ich hab ihn jetzt gepostet, mir ist eben aufgefallen, dass der 
Interrupt auch auftritt, wenn ich nur einen der beiden schreibe jedoch 
erst nach einigen sendevorgängen

hier nochmal was zu dem data[] array, in ihm stehen die Daten zugeordnet 
zu den jeweiligen Identifiern also je nachdem welcher identifier gerade 
empfangen wurde wird das dem entsprehcendem feld im array zugeordnet.

von Karl H. (kbuchegg)


Lesenswert?

Was genau macht die Funktion

          lcd_draw_double (font_vw_24px,NORMAL_STYLE,km,7,0,5,155,255);


Das 'double' im Funktionsnamen, dazu das Argument km als uint32_t, das 
macht mich nervös


Die LCD Funktionen .... hast du die geschrieben, oder ist das eine 
ausführlich getestete Library?

von Tom (Gast)


Lesenswert?

// LCD-Funktion: Gibt eine positive double-Zahl auf dem LCD Display aus
// - Parameter dbl_value: auszugebende Zahl
// - Parameter u8_lenght: Größe des LCD Feldes (Zahl wird rechtsbündig 
im Feld ausgegeben)
// - Paramter u8_decimals: Anzahl der anzuzeigenden Nachkommastellen
// - Funktion dürfen nur positive Zahlen übergeben werden
// - Funktion sichert sich nicht gegen zu große Zahlen und unplausbile 
Werte ab !!!

Die LCD-Funktionen hab ich übernommen, das hatte ich nur mit eurer Hilfe 
auf meinen Controller angepasst.

Problem des gesamten programmes ist auch noch, dass es viele daten 
hintereinander nicht verarbeiten kann da kommt ein data overrun und 
nichts geht mehr, aus diesem Grund shcicke ich die Daten momentan auch 
einzeln, damit dieser Fehler nicht auftritt, da ich noch nicht weiß wie 
ich das overrun verhindern kann.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Tom schrieb:
> Die Ausgabe funktioniert auch jedoch wiederum nur wenn ich eine der
> beiden werte verarbeite, sobald ich den zweiten hinzuschalte erhalte ich
> wieder den HardFault_Handler.
Dann ist der Fehler wohl woanders...

> sobald ich den zweiten hinzuschalte erhalte ich
> wieder den HardFault_Handler.
Was heißt dazuschalten?



Das verdreht mir ja das Auge. Wieviele Einsen sind das denn?
          km=((data[6]>>8)&0b11111111111111111111);
Ich würde es so schreiben:
          km=((data[6]>>8)&0xFFFFF);
Da sehe ich schneller: 5 x 4 Einsen.


Das ist bedenklich:
volatile uint32_t kmph      = 0;    // Variable Stundenkilometer
    kmph=(((data[3]>>14))&0b1111111111)*0.32;
Hier muß der Compiler etliche implizite Konvertierungen durchführen, um 
vom int32 über einen float wieder auf einen int32 zu kommen...

von Tom (Gast)


Lesenswert?

dazuschalten heißt in meinem Fall ich kommentiere eine aus und hab nur 
noch eine der beiden stehen, hab aber gemerkt, dass es nen Fehler war, 
dass der Fehler dann nicht mehr auftritt, er kommt nur später hinzu ...

hm okay das war mir nicht bewusst, dass dies zu kompliziert ist, kannst 
du mir helfen und sagen wie es einfacher geht?

von Tom (Gast)


Lesenswert?

also das ganze funktioniert nur zuverlässig, wenn ich einfach nur die 
festen sachen (linien feste werte) ausgebe und nichts von den 
empfangenen Nachrichten als string versuche auszugeben.

von Tom (Gast)


Lesenswert?

so also mit sprintf funktioniert das programm nur solange, solange 
sprintf nur einmal aufgerufen wird

mit der ersatzfunktion funktioniert es selbst wenn sie nur einmal 
aufgerufen wird nur eine zeit lang und dann nicht mehr.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Tom schrieb:
> dazuschalten heißt in meinem Fall ich kommentiere eine aus und hab nur
> noch eine der beiden stehen, hab aber gemerkt, dass es nen Fehler war,
> dass der Fehler dann nicht mehr auftritt, er kommt nur später hinzu ...
???????...????

Tom schrieb:
> also das ganze funktioniert nur zuverlässig, wenn ich einfach nur die
> festen sachen (linien feste werte) ausgebe und nichts von den
> empfangenen Nachrichten als string versuche auszugeben.
Auch eine Zeichenkette ist ein statischer Wert. Nur scheint mir, du 
probierst da mal alle funktionen isrgendwie durch und hoffst, dass sich 
was ändert.
Ich tippe auf einen Stack-Overflow (wobei das bei 64k RAM eher 
unwahrscheilich ist) oder einen amoklaufenden Pointer...
1
:
2
CAN_MSG MsgBuf_TX1, MsgBuf_TX2; /* TX and RX Buffers for CAN message */
3
CAN_MSG MsgBuf_RX1, MsgBuf_RX2; /* TX and RX Buffers for CAN message */
4
5
volatile uint32_t CAN1RxDone = FALSE, CAN2RxDone = FALSE;
6
volatile uint32_t data[12];
7
:
Verschieb mal die CAN-Puffer woanders hin. Evtl. ändert das was...
So:
1
volatile uint32_t CAN1RxDone = FALSE, CAN2RxDone = FALSE;
2
volatile uint32_t data[12];
3
volatile uint32_t Schalter;
4
:
5
CAN_MSG MsgBuf_TX1, MsgBuf_TX2; /* TX and RX Buffers for CAN message */
6
CAN_MSG MsgBuf_RX1, MsgBuf_RX2; /* TX and RX Buffers for CAN message */
Oder so:
1
CAN_MSG MsgBuf_TX1, MsgBuf_TX2; /* TX and RX Buffers for CAN message */
2
CAN_MSG MsgBuf_RX1, MsgBuf_RX2; /* TX and RX Buffers for CAN message */
3
4
volatile uint32_t xxx[1000];
5
6
volatile uint32_t CAN1RxDone = FALSE, CAN2RxDone = FALSE;
7
volatile uint32_t data[12];
8
volatile uint32_t Schalter;
9
:

von Tom (Gast)


Lesenswert?

nee ändert leider nichts

von Tom (Gast)


Lesenswert?

so zu meinem Problem mit dem Empfangen der Nachrichten nocheinmal zurück 
ich werd langsam wahnsinnig

hier ist der Beispielcode von der NXP-Homepage (Sample Code Bundle for 
LPC17xx Peripherals using Keil's MDK-ARM V1.02 )
1
/*****************************************************************************
2
 *   cantest.c:  CAN test module file for NXP LPC17xx Family Microprocessors
3
 *
4
 *   Copyright(C) 2009, NXP Semiconductor
5
 *   All rights reserved.
6
 *
7
 *   History
8
 *   2009.05.27  ver 1.00    Prelimnary version, first Release
9
 *
10
******************************************************************************/
11
#include "lpc17xx.h"
12
#include "type.h"
13
#include "can.h"
14
15
CAN_MSG MsgBuf_TX1, MsgBuf_TX2; /* TX and RX Buffers for CAN message */
16
CAN_MSG MsgBuf_RX1, MsgBuf_RX2; /* TX and RX Buffers for CAN message */
17
18
volatile uint32_t CAN1RxDone = FALSE, CAN2RxDone = FALSE;
19
20
#if CAN_WAKEUP
21
extern volatile uint32_t CANActivityInterruptFlag;
22
#endif
23
24
#if CAN_WAKEUP
25
/*****************************************************************************
26
** Function name:    CAN_WakeupTest
27
**
28
** Descriptions:    main routine for CAN wakeup test
29
**
30
** parameters:      None
31
** Returned value:    None
32
** 
33
*****************************************************************************/
34
void CAN_WakeupTest( void )
35
{
36
  uint32_t i, j;
37
38
  CAN_SetACCF( ACCF_BYPASS );
39
  NVIC_EnableIRQ(CANActivity_IRQn);       /* enable USB activity interrupt */
40
41
  /* Put the MCU into deep sleep mode first. Any CAN message on RX 
42
  should wake up the MCU. CAN Activity interrupt won't occur until Deepsleep 
43
  bit is set in SCR. UM needs to be updated regarding this. */
44
  SCB->SCR |= 0x04;  /* Set SLEEPDEEP bit in SCR in Cortex M3 core. */  
45
  LPC_SC->PCON = 0x1;
46
  __WFI();
47
48
  while (1)                            /* Loop forever */
49
  {
50
  if ( CANActivityInterruptFlag )
51
  {
52
    /* If the MCU is waked up from power down mode, the PLL needs to
53
    be reconfigured, and USB block needs tn be reset and reconnect. */
54
    CANActivityInterruptFlag = 0;
55
    SystemInit();
56
57
    CAN_Init( BITRATE125K18MHZ );
58
    CAN_SetACCF( ACCF_BYPASS );
59
    while ( CAN2RxDone != TRUE );
60
    CAN2RxDone = FALSE;
61
62
    LPC_GPIO2->FIODIR = 0x000000FF;    /* P1.16..23 defined as Outputs */
63
    LPC_GPIO2->FIOCLR = 0x000000FF;    /* turn off all the LEDs */
64
      
65
    /* Wake up first time, now, blink 10 times. */
66
    for ( j = 0; j < 10; j++ )
67
    {
68
    for ( i = 0; i < 0x200000; i++ );
69
    LPC_GPIO2->FIOSET = 0x000000FF;
70
    for ( i = 0; i < 0x200000; i++ );
71
    LPC_GPIO2->FIOCLR = 0x000000FF;
72
    }
73
74
    /* Once the LED blink number of times, the MCU will go to sleep
75
    or power down mode again. Another incoming CAN message will wake up
76
    the MCU again. */
77
    SCB->SCR |= 0x04;  /* Set SLEEPDEEP bit in SCR in Cortex M3 core. */  
78
    LPC_SC->PCON = 0x1;
79
    __WFI();
80
  }
81
  }
82
}
83
#endif
84
85
/*****************************************************************************
86
** Function name:    main
87
**
88
** Descriptions:    main routine for CAN module test
89
**
90
** parameters:      None
91
** Returned value:    int
92
** 
93
*****************************************************************************/
94
int main( void )
95
{
96
97
  SystemInit();
98
  /* Please note, the bit timing is based on the setting of the 
99
  PCLK, if different PCLK is used, please read can.h carefully 
100
  and set your CAN bit timing accordingly. */  
101
  //CAN_Init( BITRATE100K24MHZ );
102
  CAN_Init( BITRATE125K18MHZ );  
103
104
#if CAN_WAKEUP
105
  CAN_WakeupTest();
106
#endif
107
  
108
  /* send one message from CAN1(TX) and verify received message on 
109
  CAN2(RX) if it's a match, both CAN TX and RX are working. 
110
  For more details on acceptance filter program, see Philips
111
  appnote AN10438 and the zip file associated with this appnote. */
112
113
#if !ACCEPTANCE_FILTER_ENABLED
114
  /* Initialize MsgBuf */
115
  MsgBuf_TX1.Frame = 0x80080000; /* 29-bit, no RTR, DLC is 8 bytes */
116
  MsgBuf_TX1.MsgID = 0x00012345; /* CAN ID */
117
  MsgBuf_TX1.DataA = 0x3C3C3C3C;
118
  MsgBuf_TX1.DataB = 0xC3C3C3C3;
119
120
  MsgBuf_RX2.Frame = 0x0;
121
  MsgBuf_RX2.MsgID = 0x0;
122
  MsgBuf_RX2.DataA = 0x0;
123
  MsgBuf_RX2.DataB = 0x0;
124
  CAN_SetACCF( ACCF_BYPASS );
125
126
  /* Test bypass */
127
  while ( 1 )
128
  {
129
  /* Transmit initial message on CAN 1 */
130
  while ( !(LPC_CAN1->GSR & (1 << 3)) );
131
  if ( CAN1_SendMessage( &MsgBuf_TX1 ) == FALSE )
132
  {
133
    continue;
134
  }
135
   if ( CAN2RxDone == TRUE )
136
  {
137
    CAN2RxDone = FALSE;
138
    if ( MsgBuf_RX2.Frame & (1 << 10) )  /* by pass mode */
139
    {
140
    MsgBuf_RX2.Frame &= ~(1 << 10 );
141
    }
142
    if ( ( MsgBuf_TX1.Frame != MsgBuf_RX2.Frame ) ||
143
      ( MsgBuf_TX1.MsgID != MsgBuf_RX2.MsgID ) ||
144
      ( MsgBuf_TX1.DataA != MsgBuf_RX2.DataA ) ||
145
      ( MsgBuf_TX1.DataB != MsgBuf_RX2.DataB ) )
146
    {
147
    while ( 1 );
148
    }
149
    /* Everything is correct, reset buffer */
150
    MsgBuf_RX2.Frame = 0x0;
151
    MsgBuf_RX2.MsgID = 0x0;
152
    MsgBuf_RX2.DataA = 0x0;
153
    MsgBuf_RX2.DataB = 0x0;
154
  } /* Message on CAN 2 received */
155
  }
156
#else
157
  /* Test Acceptance Filter */
158
  /* Even though the filter RAM is set for all type of identifiers,
159
  the test module tests explicit standard identifier only */
160
  MsgBuf_TX1.Frame = 0x00080000; /* 11-bit, no RTR, DLC is 8 bytes */
161
  MsgBuf_TX1.MsgID = EXP_STD_ID; /* Explicit Standard ID */
162
  MsgBuf_TX1.DataA = 0x55AA55AA;
163
  MsgBuf_TX1.DataB = 0xAA55AA55;
164
165
  MsgBuf_RX2.Frame = 0x0;
166
  MsgBuf_RX2.MsgID = 0x0;
167
  MsgBuf_RX2.DataA = 0x0;
168
  MsgBuf_RX2.DataB = 0x0;
169
  CAN_SetACCF( ACCF_ON );
170
171
  while ( 1 )
172
  {
173
  /* Transmit initial message on CAN 1 */
174
  while ( !(LPC_CAN1->GSR & (1 << 3)) );
175
  if ( CAN1_SendMessage( &MsgBuf_TX1 ) == FALSE )
176
  {
177
    continue;
178
  }
179
180
  /* please note: FULLCAN identifier will NOT be received as it's not set 
181
  in the acceptance filter. */
182
   if ( CAN2RxDone == TRUE )
183
  {
184
    CAN2RxDone = FALSE;
185
    /* The frame field is not checked, as ID index varies based on the
186
    entries set in the filter RAM. */
187
    if ( ( MsgBuf_TX1.MsgID != MsgBuf_RX2.MsgID ) ||
188
      ( MsgBuf_TX1.DataA != MsgBuf_RX2.DataA ) ||
189
      ( MsgBuf_TX1.DataB != MsgBuf_RX2.DataB ) )
190
    {
191
    while ( 1 );
192
    }
193
    /* Everything is correct, reset buffer */
194
    MsgBuf_RX2.Frame = 0x0;
195
    MsgBuf_RX2.MsgID = 0x0;
196
    MsgBuf_RX2.DataA = 0x0;
197
    MsgBuf_RX2.DataB = 0x0;
198
  } /* Message on CAN 2 received */
199
  }
200
#endif
201
}
202
203
/******************************************************************************
204
**                            End Of File
205
******************************************************************************/
206
/******************************************************************************
207
**                            End Of File
208
******************************************************************************/
1
/*****************************************************************************
2
 *  can.c:  CAN module API file for NXP LPC17xx Family Microprocessors
3
 *
4
 *   Copyright(C) 2009, NXP Semiconductor
5
 *   All rights reserved.
6
 *
7
 *   History
8
 *   2009.05.27  ver 1.00    Prelimnary version, first Release
9
 *
10
*****************************************************************************/
11
#include "lpc17xx.h"
12
#include "type.h"
13
#include "can.h"
14
15
/* Receive Queue: one queue for each CAN port */
16
extern CAN_MSG MsgBuf_RX1, MsgBuf_RX2;
17
extern volatile uint32_t CAN1RxDone, CAN2RxDone;
18
19
volatile uint32_t CANStatus;
20
uint32_t CAN1RxCount = 0, CAN2RxCount = 0;
21
uint32_t CAN1ErrCount = 0, CAN2ErrCount = 0;
22
23
#if CAN_WAKEUP
24
volatile uint32_t CANActivityInterruptFlag = 0;
25
#endif
26
27
/******************************************************************************
28
** Function name:    CAN_ISR_Rx1
29
**
30
** Descriptions:    CAN Rx1 interrupt handler
31
**
32
** parameters:      None
33
** Returned value:    None
34
** 
35
******************************************************************************/
36
void CAN_ISR_Rx1( void )
37
{
38
  uint32_t * pDest;
39
40
  /* initialize destination pointer  */
41
  pDest = (uint32_t *)&MsgBuf_RX1;
42
  *pDest = LPC_CAN1->RFS;  /* Frame  */
43
44
  pDest++;
45
  *pDest = LPC_CAN1->RID; /* ID  */
46
47
  pDest++;
48
  *pDest = LPC_CAN1->RDA; /* Data A */
49
50
  pDest++;
51
  *pDest = LPC_CAN1->RDB; /* Data B  */
52
  
53
  CAN1RxDone = TRUE;
54
  LPC_CAN1->CMR = 0x01 << 2; /* release receive buffer */
55
  return;
56
}
57
58
/******************************************************************************
59
** Function name:    CAN_ISR_Rx2
60
**
61
** Descriptions:    CAN Rx2 interrupt handler
62
**
63
** parameters:      None
64
** Returned value:    None
65
** 
66
******************************************************************************/
67
void CAN_ISR_Rx2( void )
68
{
69
  uint32_t *pDest;
70
71
  /* initialize destination pointer  */
72
  pDest = (uint32_t *)&MsgBuf_RX2;
73
  *pDest = LPC_CAN2->RFS;  /* Frame  */
74
75
  pDest++;
76
  *pDest = LPC_CAN2->RID; /* ID  */
77
78
  pDest++;
79
  *pDest = LPC_CAN2->RDA; /* Data A  */
80
81
  pDest++;
82
  *pDest = LPC_CAN2->RDB; /* Data B  */
83
84
  CAN2RxDone = TRUE;
85
  LPC_CAN2->CMR = 0x01 << 2; /* release receive buffer */
86
  return;
87
}
88
89
/*****************************************************************************
90
** Function name:    CAN_Handler
91
**
92
** Descriptions:    CAN interrupt handler
93
**
94
** parameters:      None
95
** Returned value:    None
96
** 
97
*****************************************************************************/
98
void CAN_IRQHandler(void)  
99
{
100
  CANStatus = LPC_CANCR->CANRxSR;
101
  if ( CANStatus & (1 << 8) )
102
  {
103
  CAN1RxCount++;
104
  CAN_ISR_Rx1();
105
  }
106
  if ( CANStatus & (1 << 9) )
107
  {
108
  CAN2RxCount++;
109
  CAN_ISR_Rx2();
110
  }
111
  if ( LPC_CAN1->GSR & (1 << 6 ) )
112
  {
113
  /* The error count includes both TX and RX */
114
  CAN1ErrCount = LPC_CAN1->GSR >> 16;
115
  }
116
  if ( LPC_CAN2->GSR & (1 << 6 ) )
117
  {
118
  /* The error count includes both TX and RX */
119
  CAN2ErrCount = LPC_CAN2->GSR >> 16;
120
  }
121
  LPC_GPIO2 -> FIOPIN &= ~0xF;
122
  return;
123
}
124
125
#if CAN_WAKEUP
126
/******************************************************************************
127
** Function name:    CANActivity_IRQHandler
128
**
129
** Descriptions:    Wake up from CAN handler
130
**
131
** parameters:      None
132
** Returned value:    None
133
** 
134
******************************************************************************/
135
void CANActivity_IRQHandler (void) 
136
{
137
  CANActivityInterruptFlag = 1;
138
139
  LPC_SC->CANSLEEPCLR = (0x1<<1)|(0x1<<2);
140
  LPC_CAN1->MOD = LPC_CAN2->MOD &= ~(0x1<<4);
141
  LPC_SC->CANWAKEFLAGS = (0x1<<1)|(0x1<<2);
142
  return;
143
}
144
#endif
145
146
/******************************************************************************
147
** Function name:    CAN_Init
148
**
149
** Descriptions:    Initialize CAN, install CAN interrupt handler
150
**
151
** parameters:      bitrate
152
** Returned value:    true or false, false if initialization failed.
153
** 
154
******************************************************************************/
155
uint32_t CAN_Init( uint32_t can_btr )
156
{
157
  CAN1RxDone = CAN2RxDone = FALSE;
158
159
  LPC_SC->PCONP |= ((1<<13)|(1<<14));  /* Enable CAN1 and CAN2 clock */
160
161
  LPC_PINCON->PINSEL0 &= ~0x0000000F;  /* CAN1 is p0.0 and p0.1  */
162
  LPC_PINCON->PINSEL0 |= 0x00000005;  
163
  LPC_PINCON->PINSEL4 &= ~0x0003C000;  /* CAN2 is p2.7 and p2.8 */
164
  LPC_PINCON->PINSEL4 |= 0x00014000;
165
166
  LPC_CAN1->MOD = LPC_CAN2->MOD = 1;    /* Reset CAN */
167
  LPC_CAN1->IER = LPC_CAN2->IER = 0;    /* Disable Receive Interrupt */
168
  LPC_CAN1->GSR = LPC_CAN2->GSR = 0;    /* Reset error counter when CANxMOD is in reset  */
169
170
  LPC_CAN1->BTR = LPC_CAN2->BTR = can_btr;
171
  LPC_CAN1->MOD = LPC_CAN2->MOD = 0x0;  /* CAN in normal operation mode */
172
173
  NVIC_EnableIRQ(CAN_IRQn);
174
175
  LPC_CAN1->IER = LPC_CAN2->IER = 0x01; /* Enable receive interrupts */
176
  return( TRUE );
177
}
178
179
/******************************************************************************
180
** Function name:    CAN_SetACCF_Lookup
181
**
182
** Descriptions:    Initialize CAN, install CAN interrupt handler
183
**
184
** parameters:      bitrate
185
** Returned value:    true or false, false if initialization failed.
186
** 
187
******************************************************************************/
188
void CAN_SetACCF_Lookup( void )
189
{
190
  uint32_t address = 0;
191
  uint32_t i;
192
  uint32_t ID_high, ID_low;
193
194
  /* Set explicit standard Frame */ 
195
  LPC_CANAF->SFF_sa = address;
196
  for ( i = 0; i < ACCF_IDEN_NUM; i +=2 )
197
  {
198
  ID_low = (i << 29) | (0x23 << 16); 
199
  ID_high = (i+1 << 13) | (0x05 << 0);
200
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
201
  address += 4; 
202
203
  }
204
    
205
  /* Set group standard Frame */
206
  LPC_CANAF->SFF_GRP_sa = address;
207
  for ( i = 0; i < ACCF_IDEN_NUM; i += 2 )
208
  {
209
  ID_low = (i << 29) | (GRP_STD_ID << 16);
210
  ID_high = ((i+1) << 13) | (GRP_STD_ID << 0);
211
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low | ID_high;
212
  address += 4; 
213
  }
214
 
215
  /* Set explicit extended Frame */ 
216
  LPC_CANAF->EFF_sa = address;
217
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
218
  {
219
  ID_low = (i << 29) | (EXP_EXT_ID << 0);
220
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
221
  address += 4; 
222
  }
223
224
  /* Set group extended Frame */
225
  LPC_CANAF->EFF_GRP_sa = address;
226
  for ( i = 0; i < ACCF_IDEN_NUM; i++  )
227
  {
228
  ID_low = (i << 29) | (GRP_EXT_ID << 0);
229
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = ID_low;
230
  address += 4; 
231
  }
232
   
233
  /* Set End of Table */
234
  LPC_CANAF->ENDofTable = address;
235
  return;
236
}
237
238
/******************************************************************************
239
** Function name:    CAN_SetACCF
240
**
241
** Descriptions:    Set acceptance filter and SRAM associated with  
242
**
243
** parameters:      ACMF mode
244
** Returned value:    None
245
**
246
** 
247
******************************************************************************/
248
void CAN_SetACCF( uint32_t ACCFMode )
249
{
250
  switch ( ACCFMode )
251
  {
252
  case ACCF_OFF:
253
    LPC_CANAF->AFMR = ACCFMode;
254
    LPC_CAN1->MOD = LPC_CAN2->MOD = 1;  // Reset CAN
255
    LPC_CAN1->IER = LPC_CAN2->IER = 0;  // Disable Receive Interrupt
256
    LPC_CAN1->GSR = LPC_CAN2->GSR = 0;  // Reset error counter when CANxMOD is in reset
257
  break;
258
259
  case ACCF_BYPASS:                    // can.h -->0x03
260
    LPC_CANAF->AFMR = ACCFMode;
261
  break;
262
263
  case ACCF_ON:                       // can.h --> 0x00
264
  case ACCF_FULLCAN:                  // can.h --> 0x04
265
    LPC_CANAF->AFMR = ACCF_OFF;
266
    CAN_SetACCF_Lookup();
267
    LPC_CANAF->AFMR = ACCFMode;
268
  break;
269
270
  default:
271
  break;
272
  }
273
  return;
274
}
275
276
/******************************************************************************
277
** Function name:    CAN1_SendMessage
278
**
279
** Descriptions:    Send message block to CAN1  
280
**
281
** parameters:      pointer to the CAN message
282
** Returned value:    true or false, if message buffer is available,
283
**            message can be sent successfully, return TRUE,
284
**            otherwise, return FALSE.
285
** 
286
******************************************************************************/
287
uint32_t CAN1_SendMessage( CAN_MSG *pTxBuf )
288
{
289
  uint32_t CANStatus;
290
291
  CANStatus = LPC_CAN1->SR;
292
  if ( CANStatus & 0x00000004 )
293
  {
294
  LPC_CAN1->TFI1 = pTxBuf->Frame & 0xC00F0000;
295
  LPC_CAN1->TID1 = pTxBuf->MsgID;
296
  LPC_CAN1->TDA1 = pTxBuf->DataA;
297
  LPC_CAN1->TDB1 = pTxBuf->DataB;
298
  LPC_CAN1->CMR = 0x21;
299
  return ( TRUE );
300
  }
301
  else if ( CANStatus & 0x00000400 )
302
  {
303
  LPC_CAN1->TFI2 = pTxBuf->Frame & 0xC00F0000;
304
  LPC_CAN1->TID2 = pTxBuf->MsgID;
305
  LPC_CAN1->TDA2 = pTxBuf->DataA;
306
  LPC_CAN1->TDB2 = pTxBuf->DataB;
307
  LPC_CAN1->CMR = 0x41;
308
  return ( TRUE );
309
  }
310
  else if ( CANStatus & 0x00040000 )
311
  {  
312
  LPC_CAN1->TFI3 = pTxBuf->Frame & 0xC00F0000;
313
  LPC_CAN1->TID3 = pTxBuf->MsgID;
314
  LPC_CAN1->TDA3 = pTxBuf->DataA;
315
  LPC_CAN1->TDB3 = pTxBuf->DataB;
316
  LPC_CAN1->CMR = 0x81;
317
  return ( TRUE );
318
  }
319
  return ( FALSE );
320
}
321
322
/******************************************************************************
323
**                            End Of File
324
******************************************************************************/


ich habe für meine Zwecke den Empfang auf den CAN1 umgeschrieben (da 
CAN2 bei mir nicht angeschlossen ist) den Wakeup teil weggenommne 
(benötige ich nicht) sowie die Lookuptable vereinfacht und die Taktrate 
geändert.
Sieht jemand so was daran nciht funktionieren könnte? wie gesagt ich 
kann Daten nur empfangen wenn sie sehr sehr langsam kommen, sobald dies 
schneller ist (bei einer Sekunde schon) wird ein Data overrun ausgelöst.
Mein CPU Takt beträgt 96MHz und der Peripherietakt 48MHz

1
/******************************************************************************
2
** Function name:    CAN_SetACCF_Lookup
3
**
4
** Descriptions:    unlock IDs 
5
**
6
** parameters:      none
7
** Returned value:    none
8
** 
9
******************************************************************************/
10
void CAN_SetACCF_Lookup( void )
11
{
12
  uint32_t address = 0; /* effective address */    
13
  uint32_t Id11_lo_1, Id11_hi_1;  /* ID1 and ID2 */
14
  uint32_t Id11_lo_2, Id11_hi_2;  /* ID3 and ID4 */
15
  uint32_t Id11_lo_3, Id11_hi_3;  /* ID5 and ID6 */
16
17
  /* IDs --> Attention IDs in ascending order if FullCAN or explicit 11Bit Mode!! */
18
  Id11_lo_1 = 0x2C1;
19
  Id11_hi_1 = 0x320;
20
  Id11_lo_2 = 0x3E1;
21
  Id11_hi_2 = 0x65D;
22
  /*Id11_lo_3 = 0x25;
23
  Id11_hi_3 = 0x26;*/
24
25
  LPC_CANAF->SFF_sa = address;    /*score the effective address in SFF_sa --> Start 11Bit explicit IDs */
26
  /* unlock ID1 and ID2 and adapt address --> next row */
27
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = (Id11_lo_1 << 16) | Id11_hi_1;
28
  address += 4;
29
  /* unlock ID3 and ID4 and adapt address --> next row */
30
  *((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = (Id11_lo_2 << 16) | Id11_hi_2;
31
  address += 4;
32
  /* unlock ID5 and ID6 and adapt address --> next row */
33
  /**((volatile uint32_t *)(LPC_CANAF_RAM_BASE + address)) = (Id11_lo_3 << 16) | Id11_hi_3;
34
  address += 4;*/
35
36
  LPC_CANAF->SFF_GRP_sa = address;  /* start 11-Bit group */
37
  LPC_CANAF->EFF_sa = address;      /* start 29-Bit explicit ID */
38
  LPC_CANAF->EFF_GRP_sa = address;  /* start 29-Bit group */
39
 
40
  LPC_CANAF->ENDofTable = address; /* end of table */
41
42
  return;
43
}
44
45
/******************************************************************************************
46
*
47
*   main.c: Hauptprogramm zur Fremdansteuerung der Multifunktionsanzeige im Golf VI
48
*   Maike Drewitz
49
*   History:
50
*   Version 1.0 13.10.2010    CAN Anbindung
51
*   Version 2.0 25.10.2010    Displayanbindung
52
*******************************************************************************************/
53
54
/******************************Header Dateien einbinden***********************************/
55
#include "lpc17xx.h"
56
#include "type.h"
57
#include "can.h"
58
59
CAN_MSG MsgBuf_TX1, MsgBuf_TX2; /* TX and RX Buffers for CAN message */
60
CAN_MSG MsgBuf_RX1, MsgBuf_RX2; /* TX and RX Buffers for CAN message */
61
62
volatile uint32_t CAN1RxDone = FALSE, CAN2RxDone = FALSE;
63
volatile uint32_t data[12];
64
volatile uint32_t Schalter; 
65
66
67
68
69
/*****************************************************************************
70
** Function name:    main
71
**
72
** Descriptions:    main routine for CAN module test
73
**
74
** parameters:      None
75
** Returned value:    int
76
** 
77
*****************************************************************************/
78
int main( void )
79
{
80
81
  SystemInit();
82
  INOUT_Def();
83
 
84
  /* Please note, the bit timing is based on the setting of the 
85
  PCLK, if different PCLK is used, please read can.h carefully 
86
  and set your CAN bit timing accordingly. */  
87
 
88
  CAN_Init(BITRATE500K15MHZ);       // Bitrate = 500kbaud bei 15MHz
89
  NVIC_EnableIRQ(CAN_IRQn);         // Interrupts freischalten
90
91
  MsgBuf_TX1.Frame = 0x00080000;  // 11-bit, no RTR, DLC is 8 bytes 
92
  MsgBuf_TX1.MsgID = 0x2ee;       // Explicit Standard ID 
93
  MsgBuf_TX1.DataA = data[0];
94
  MsgBuf_TX1.DataB = data[1];
95
96
 CAN_SetACCF( ACCF_ON );          // Filtermodus festlegen
97
  while ( 1 )
98
  {
99
  /* Transmit initial message on CAN 1 */
100
  while ( !(LPC_CAN1->GSR & (1 << 3)) );
101
         MsgBuf_TX1.DataA = data[0];
102
         MsgBuf_TX1.DataB = data[1];
103
  if ( CAN1_SendMessage( &MsgBuf_TX1 ) == FALSE )
104
  {
105
    continue;
106
  }
107
108
  /* please note: FULLCAN identifier will NOT be received as it's not set 
109
  in the acceptance filter. */
110
   if ( CAN1RxDone == TRUE )
111
  {
112
    CAN1RxDone = FALSE;
113
   
114
  } /* Message on CAN 2 received */
115
116
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

1
Wichtige Regeln - erst lesen, dann posten!
2
    * Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang


> hier ist der Beispielcode von der NXP-Homepage (Sample Code Bundle for
> LPC17xx Peripherals using Keil's MDK-ARM V1.02 )
Schöner Code. Und was ist damit?

von Tom (Gast)


Lesenswert?

okay sorry

ähm ich habe diesen Code benutzt und ein paar änderungen vorgenommen wie 
oben im letzten Teil beschrieben, und es wird jedes mal wenn ich 
nachrichten hintereinander Sende auch wenn dies eine sekunde 
auseinanderliegt ein Dataoverrun erzeugt.
Daher wollte ich mal fragen, ob sich jemand das mal ansehen könnte ob 
eine meiner Änderungen schuld daran ist.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

1. Beitrag "Re: sprintf mehrfach" ist noch offen

2.

> Die Ausgabe funktioniert auch jedoch wiederum nur wenn ich eine der
> beiden werte verarbeite, sobald ich den zweiten hinzuschalte erhalte ich
> wieder den HardFault_Handler.

Wie sieht der Code aus, wenn der HardFault_Handler nicht angesprungen 
wird und wie wenn er angesprungen wird. Gut lesbar wäre ein Listing im 
Anhang mit einem #if DIES_ERGIBT_FEHLER #endif Konstrukt.

3.

> ähm ich habe diesen Code benutzt und ein paar änderungen vorgenommen wie
> oben im letzten Teil beschrieben, und es wird jedes mal wenn ich

In einem übernommenen Code, den man ändert, sollte man die Änderungen 
unbedingt kennzeichnen. Wenn es sich um größere Teile handelt auch mit 
#if #else #endif, so dass man immer den Originalcode sehen und ggf. auch 
zurückbauen kann. Die Chance ist hoch, dass sich der Fehler in den 
Änderungen befindet.

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

so ich hab mich mal dran  gesetzt und den originalcode zu meinen 
gepackt, hab das immer so gekennzeichnet, dass der originale Code 
auskommentiert ist und drüber /**********ORIGINAL****************/ steht

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du machst es einem (anderen, dir kurzfristig schon) wirklich nicht 
leicht.

von Tom (Gast)


Lesenswert?

sorry ich geb mein bestes, und ich mache es mir auch nicht wirklich 
leicht, da mittlerweile schon Wochen so ins Land gegangen sind und ich 
nicht drauf komme was da falsch ist und ich halte euch alle für extrem 
kompetent und hoffe einfach auf dem weg hilfe zu bekommen =)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich würde die CAN_SetACCF_Lookup() kritisch unter die Lupe nehmen.

von Karl H. (kbuchegg)


Lesenswert?

Mein Tipp wäre, dass irgendwo ein Array überlaufen wird und du dir den 
Stack ganz kräftig zerschiesst.
Was du mit dem sprintf siehst, sind die Symptome aber nicht die 
eigentliche Ursache. Die liegt ganz woanders und daher hat es auch 
keinen Sinn, da jetzt nach einer Alternative für den sprintf zu suchen.

Wenn ich den Code übernehmen müsste, dann würde ich

abspecken, abspecken, abspecken.

Die lcd Funktionen durchgehen, nach Buffer Overruns Ausschau halten und 
die erst mal gründlichst testen.

Dann sukzessive den CAN Teil, so wie es eben möglich ist, ins Programm 
wieder einbauen. Dabei wieder: den Teil den ich einbaue, kritisch unter 
die Lupe nehmen. Wenn es gar nicht anders geht, dann müssen da 
Sicherungen rein. Die Alarm schlagen, wenn Indizes zu hoch werden oder 
Pointer ihren erlaubten Bereuich verlassen.

Wenn du, wie du sagst, schon Wochen an dem Problem sitzt, dann wärst du 
schon 3 mal fertig geworden, wenn du mit einem neuen Pgm angefangen 
hättest und dieses schön langsam hochgezogen hättest. Sukzessive immer 
einen vorhandenen Baustein einbauen, gründlich unter die Lupe nehmen und 
exzessiv testen.

Solche Rundumschlagdinger, ala ich kopiere mir da 200kB Code aus 25 
verschiedenen Quellen zusammen, garniere das mit meinen eigenen Routinen 
- so was funktioniert meistens nicht.

von Tom (Gast)


Lesenswert?

okay gut dann werde ich das mal so probieren =)
Kannst du mir noch sagen wie du erkennst wann ein Array überläuft?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Tom schrieb:
> Kannst du mir noch sagen wie du erkennst wann ein Array überläuft?
Oh, da gibt es einige Fehlerbilder:
Das Programm "stürzt" ab...
Irgendwas tut nicht mehr so wie es eigentlich soll...
Variable verändern ihre Werte selbständig...
Es werden die falschen Funktionen aufgerufen...
Der uC kommt nach einer Unterroutine nicht mehr "richtig" zurück...
Das Programm funktioniert nicht mehr, wenn irgendwo eine Zeile eingefügt 
wird...

von Tom (Gast)


Lesenswert?

hm okay klingt nach meinem programm =) und woher weißt du um welches 
array oder welchen pointer es sich dabei genau handelt? bzw wie gehts du 
vor um das zu vermeiden?

von Tom (Gast)


Lesenswert?

soho ich hab neuigkeiten =)
Also ich hab in meiner Lookuptable den Beginn der FullCAN IDs auf 0 
gesetzt gehabt (bzw im beispiel war dies auch so) jedoch ist es so, dass 
sollte dieser wert 0 sein die FullCAN IDs disabled werden setzte ich das 
ganze nun auf 1 also ungleich null so läuft es bisher durch ich kann 
zyklische daten senden ohne unterberechungen drin zu haben

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.