falsche Zuweisung

Gast #1359301
Lesenswert?

ich fange an mit gcc und habe ein Problem mit meine Serielle 
Kommunikation.
Hier unten ein Teil des Kodes.
1
#define UART_TX_BUFFER_SIZE 32
2
...
3
static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
4
....
5
unsigned char tmptail;
6
....
7
UDR = UART_TxBuf[tmptail];
8
....

Beim Debuggen merkt ich das der Wert  UART_TxBuf[tmptail] ganz gut die 
richtige Werte kriegt (s. unten), aber UDR nicht.
Es sieht als ob die Zuweisung "UDR = UART_TxBuf[tmptail]" ungültig wäre.
und UDR bleibt leer.

Weiß jemand warum?
Danke

UART_TxBuf[...]
[0]   0
[1]   21
[2]   33
[3]   0
[4]   0
[5]   0
[6]   0
[7]   1
[8]   0
[9]   0
[10]  5
[11]  2
[12]  0
[...] ...
[32]  2
Gast #1359312
Lesenswert?

Irgendwie faellt mir zunehmend auf, dass gerade die, die es am 
Noetigsten haben nur dann in's Forum gucken, wenn sie Hilfe brauchen. 
Sonst wuessten sie, dass sie

a) uebersetzbaren Code
b) verwendete Hardware
c) verwendete Tools
d) eine nachvollziehbare Fehlerbeschreibung

posten sollen.
Gast #1359358
Lesenswert?

ok
Projekt: Befehlt an einem Gerät senden.

Hardware: STK 500 mit Atmega8 externe Quarz 4 Mhz, Fuses richtig 
eingestellt.

Tool AVR Studio 4, WinAVR-20090313
Kommunikation: format -> 8data, 1stop bit Baud 9600 auch beim Empfamger.

Probleme: Es erscheint am Terminal PC gar nichst am Bildschirm.
Beim Debuggen habe bemerkt das UDR  keinen Wert kriegt.

vielen Dank für eure Hilfe
1
#ifndef F_CPU
2
#warning "F_CPU was not defined yet, now make up with 4000000"
3
#define F_CPU 4000000L   // Systemtakt in Hz 
4
#endif
5

6

7
#define BAUD 9600L
8
#define UBRR_VAL ((F_CPU+BAUD * 8)/(BAUD*16)-1)     //clever round
9
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))         //real baud rate
10
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)     //Error per thousand
11

12

13
#if ((BAUD_ERROR>10)||(BAUD_ERROR<-10))
14
#error Systematic error in the baud rate more than 1% and thus too high!
15
#endif
16

17

18
#include <avr/io.h>
19
#include <avr/interrupt.h>
20
#include <stdlib.h>
21
#include <inttypes.h>
22
#include <util/delay.h>
23

24
/** Size of the circular transmit buffer, must be power of 2 */
25
#ifndef UART_TX_BUFFER_SIZE
26
#define UART_TX_BUFFER_SIZE 32
27
#endif
28

29
/* size of TX buffers */
30
#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1)
31

32
#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
33
#error TX buffer size is not a power of 2
34
#endif
35

36

37
/*
38
 *  module global variables
39
 */
40
static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
41
static volatile unsigned char UART_TxHead;
42
static volatile unsigned char UART_TxTail;
43

44
SIGNAL(SIG_UART_DATA)
45
{
46
    unsigned char tmptail;
47
  unsigned char wert;
48

49
    
50
    if ( UART_TxHead != UART_TxTail)
51
  {
52
        /* calculate and store new buffer index */
53
        tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
54
        UART_TxTail = tmptail;
55
        /* get one byte from buffer and write it to UART */    
56
        UDR = UART_TxBuf[tmptail];  /* start transmission */
57
    }
58
  else
59
  {
60
        /* tx buffer empty, disable UDRE interrupt */
61
        UCSRB &= ~_BV(UDRIE);
62
    }
63
}
64

65
void USART_Init() 
66
{
67
  UART_TxHead = 0;
68
  UART_TxTail = 0;
69
    
70
  UBRRH = (unsigned char)(UBRR_VAL>>8);  // Set baud rate
71
  UBRRL = (unsigned char)UBRR_VAL;
72
  
73
  // Enable transmitter and Interrupt
74
  UCSRB |= (1<<TXCIE)|(1<<RXEN)|(1<<TXEN);
75
  
76
  UCSRC = (1<<URSEL) | (1<<UCSZ1)|(1<<UCSZ0); //format:8data, 1stop b      
77
}
78

79

80
void USART_Putc(unsigned char c)
81
{
82
    unsigned char tmphead;
83

84
    
85
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
86
    
87
    while ( tmphead == UART_TxTail ){
88
        ;/* wait for free space in buffer */
89
    }
90
    
91
    UART_TxBuf[tmphead] = c;
92
    UART_TxHead = tmphead;
93
  
94
    /* enable UDRE interrupt */
95
   UCSRB    |= _BV(UDRIE);  
96
  
97
}//end USART_Putc()
98

99
// command sequences im EEPROM (first program Flash, then EEPROM)
100
unsigned char eeMenue[] EEMEM = { 0x02, 0x21, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x9D, 0x2A };
101
unsigned char eeExit[] EEMEM  = { 0x02, 0x21, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5C, 0x2A };
102

103
unsigned char cSend;
104

105
// Sends a 19 character command found in EEPROM
106
void SendCommand(unsigned int iNo)
107
{
108
  unsigned int i;  
109
  for  (i = (18 * iNo); i <= ((18 * iNo) + 18); i++ )
110
  {
111
  cSend = eeprom_read_byte(&eeMenue[i]);
112
  USART_Putc(cSend);
113
  }
114
}
115

116
int main(void)
117
{
118

119
  PORTD = 0x0C;    // pull ups for key inputs  PortD2 and portD3
120
 
121
  
122
   USART_Init();
123
   sei();
124
  iState = 0;
125
  for(;;)
126
    {  
127
  if (iState != PIND)  // Key state changed ?
128
  {
129
    _delay_ms(50);
130
  if ((PIND & 0x08) == 0x00)
131
    SendCommand(0);
132
  else
133
  {
134
   if ((PIND & 0x04) == 0x00)
135
      SendCommand(1);
136
  }
137
        _delay_ms(1000);// dirty "debounce"
138
    }
139
}
#1359366
Lesenswert?

Warum am PC nichts ankommt, steht auf einem anderen Blatt, aber
daß du aus UDR nicht das auslesen kannst, was du vorher reinschreibst,
ist normal.
UDR ist nämlich ein Register, sondern zwei.
In das eine schreibt man rein (das, was gesendet werden soll), aus
dem anderen liest man empfangene Zeichen aus.
Die beiden heißen nur zufällig gleich...
Gast #1359383
Lesenswert?

gast schrieb:

> Was meinst du damit?

Wenn du aus UDR liest, liest du das, was du auf der seriellen 
Schnittstelle empfaengst. Guck mal in deine eigene Empfangsroutine.

Wenn du wissen willst, ob du etwas sendest, mach entweder den 
Loopbacktest aus dem Tutorial oder nimm ein Oszi/Logicanalyzer.
Persönliche Seite #1359385
Lesenswert?

Hi,

a) wäre es schön, wenn du etwas lesbarer schreiben könntest. Je 
fehlerfreier ein Beitrag geschrieben ist, desto mehr Leute werden diesen 
lesen & ev. beantworten.

b) fehlt noch eine ganze Menge zu deinem Code. Was du beim Posten 
weggelassen hast, kann man hier logischerweise nicht erahnen, und meine 
Glaskugel ist gerade zur Reparatur.

Eine sendString sieht z.B. so aus:
1
void SendString(char *string)
2
{
3
  while(*string)
4
  {
5
    while(UART->SR & TX_BUSY);   // Uart Status Register
6
    UART->DATA = *string++;      // Uart Data Register
7
  }
8
}

Damit wartet man darauf, dass der Sendebuffer bereit ist, und schickt 
jeweils das nächste Zeichen eines Strings.

Genaugenommen schreibt man sich eigentlich eine
1
void sendchar(char c);
die dieses Low-Level-Handling übernimmt, und füttert die mit Daten (z.B. 
aus fputc, einer SendString, o.ä.


VG,
/th.
#1359390
Lesenswert?

gast schrieb:

> Probleme: Es erscheint am Terminal PC gar nichst am Bildschirm.

Womit siehst du dir das Übertragene an?

Mit einem Terminalprogramm im ASCII Modus?
Da wunderst es mich dann wenig, dass du nichts siehst, du überträgst ja 
praktisch nur ASCII Zeichen, die keine visuelle Repräsentierung haben 
(mit Ausnahme von 0x21, 0x32, 0x2A, 0x5C und 0x9D. Wobei der Himmel 
alleine weiß, welches Zeichen dein Terminal für 0x9D anzeigen wird)

PS: Die Berechnungen in SendCommand solltest du nochmal durchschauen. 
Insbesondere dann, wenn iNo gleich 1 ist.

PS2: Wenn in einer for-Schleife die sich mit Arrays beschäftigt im 
Bedingungsteil ein <= vorkommt, kann man in 90% aller Fälle davon 
ausgehen, dass da was faul ist. Du hast dir mit der komplizierten 
Formulierung ganz einfach selber ein Eigentor geschossen. Solange du das 
nicht überblicken kannst, quetche nicht alles in eine Berechnung 
zusammen
1
void SendCommand( unsigned char iNo )
2
{
3
  unsigned char i;
4

5
#define BYTES_IN_COMMAND 19
6

7
  // jeweils 19 Bytes sind 1 Kommando
8
  iNo = BYTES_IN_COMMAND * iNo;
9
 
10
  for  (i = 0; i < BYTES_IN_COMMAND; i++ )
11
  {
12
    cSend = eeprom_read_byte(&eeMenue[ i + iNo ]);
13
    USART_Putc( cSend );
14
  }
15
}
Gast #1359393
Lesenswert?

Ich habe einen Test gemacht.
Der Kode läuft ganz gut und es erscheint am Terminal PC:  Kommunikation 
Test.

Aber der Fehler in den anderen Kode finde ich nicht!
1
#ifndef F_CPU
2
#warning "F_CPU was not defined yet, now make up with 4000000"
3
#define F_CPU 4000000L 
4
#endif
5

6

7
#define BAUD 9600L
8
#define UBRR_VAL ((F_CPU+BAUD * 8)/(BAUD*16)-1)     //clever round
9
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))         //real baud rate
10
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)     //Error per thousand
11

12

13
#if ((BAUD_ERROR>10)||(BAUD_ERROR<-10))
14
#error Systematic error in the baud rate more than 1% and thus too high!
15
#endif
16

17

18
#include <avr/io.h>
19
#include <stdlib.h>
20
#include <inttypes.h>
21
#include <util/delay.h>
22

23

24

25
void USART_Init(void) 
26
{
27
  
28
  UBRRH = (unsigned char)(UBRR_VAL>>8);  // Set baud rate
29
  UBRRL = (unsigned char)UBRR_VAL;
30
  
31
  UCSRB |= (1<<RXEN)|(1<<TXEN);    // Enable receiver and transmitter
32
  
33
  UCSRC = (1<<URSEL) | (1<<UCSZ0)|(1<<UCSZ1);  // Set frame format: 8data, 1stop bit        
34

35
}//end USART_Init()
36

37

38
void USART_Putc(unsigned char c)
39
{
40
    while (!(UCSRA & (1<<UDRE))); // Do nothing until data have been transmited 
41
    
42
  UDR = c;                 // Put data into Buffer, sends the data
43
  _delay_ms(10);   
44
}//end USART_Putc()
45

46
void USART_Puts (char *string)
47
{
48
    while( *string != '\0' )  //as long as *string != '\0' so unlike the "stringer end-character"
49
    {  
50
        USART_Putc(*string);
51
        string++;
52
    }
53
}//end USART_Puts()
54

55
int main(void) 
56
{
57
    USART_Init();
58
  
59
    USART_Puts("Kommunikation Test");
60
   return 0;                     
61
} //end main()
Gast #1359414
Lesenswert?

>Womit siehst du dir das Übertragene an?

Zuerst danke für deinen HIlfe

ja mit einem Terminalprogramm im ASCII Modus.
Ich habe gerade noch etwas getestet. (S. erste Kode)

anstatt
1
/* get one byte from buffer and write it to UART */    
2
        UDR = UART_TxBuf[tmptail];  /* start transmission */
1
/* get one byte from buffer and write it to UART */    
2
        UDR = 0;  /* start transmission */

Am Terminalprogramm kriege ich 
<0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0>

Das heisst mein Terminalprogramm kann meine Zeichen ganz gut übertragen 
oder!!!

>PS: Die Berechnungen in SendCommand solltest du nochmal durchschauen.
>Insbesondere dann, wenn iNo gleich 1 ist.

bin ich dabei
#1359425
Lesenswert?

gast schrieb:

> Am Terminalprogramm kriege ich
> <0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0>
>
> Das heisst mein Terminalprogramm kann meine Zeichen ganz gut übertragen
> oder!!!

Anzeigen, nicht übertragen.
Und du siehst nur, dass es für 0x00 eine Anzeige hat.
Ob und was es aus den restlichen Bytes macht, welche keine anzeigbare 
Darstellung haben, steht in den Sternen.

Aber da du anscheinend sowieso nur daran interessiert bist, welche Bytes 
aus dem EEPROM gelesen werden, warum machst du dir nicht einfach eine 
SendFunktion die ein Byte in seiner HexForm anzeigen kann. Ist doch 
simpel.
1
void USART_Puts( const char * text )
2
{
3
  while( *text )
4
    USART_Putc( *text++ );
5
}
6

7
void USART_PutNibble( unsigned char nibble )
8
{
9
  if( nibble < 0x0A )
10
    USART_Putc( nibble + '0' );
11
  else
12
    USART_Putc( nibble - 10 + 'A' );
13
}
14

15
void USART_PutHex( unsigned char byte )
16
{
17
  USART_Puts( "0x" );
18
  USART_PutNibble( byte >> 4 );
19
  USART_PutNibble( byte & 0x0F );
20
}
21

22
void SendCommand( unsigned char iNo )
23
{
24
  unsigned char i;
25
  unsigned char cSend;
26

27
#define BYTES_IN_COMMAND 19
28

29
  // jeweils 19 Bytes sind 1 Kommando
30
  iNo = BYTES_IN_COMMAND * iNo;
31
 
32
  for  (i = 0; i < BYTES_IN_COMMAND; i++ )
33
  {
34
    cSend = eeprom_read_byte(&eeMenue[ i + iNo ]);
35
    USART_PutHex( cSend );
36
  }
37
}
Gast #1359441
Lesenswert?

Danke an alle für die schnelle Antworten.

>Poste bitte mal den ganzen Code.
habe ich als zweite Post

>fehlt noch eine ganze Menge zu deinem Code. Was du beim Posten
>weggelassen hast, kann man hier logischerweise nicht erahnen, und meine
>Glaskugel ist gerade zur Reparatur.

Für mih wäre alles!!!
dann vielleich liegt meinem Fehler

>void SendString(char *string)
>{
  >while(*string)
  >{
   > while(UART->SR & TX_BUSY);   // Uart Status Register
   > UART->DATA = *string++;      // Uart Data Register
  >}
>}

meinst du, dass ich die Funktion brauche !?!
Ich sende keine String!! sondern nur ASCII Zeichen !!
Ich bin neu bitte sagen Sie mir ob ich mir irre

danke
Gast #1359523
Lesenswert?

>Anzeigen, nicht übertragen.
>Und du siehst nur, dass es für 0x00 eine Anzeige hat.
>Ob und was es aus den restlichen Bytes macht, welche keine anzeigbare
>Darstellung haben, steht in den Sternen.

Danke für die Antwort

eingentlcih möchte ich Am Terminalprogramm das Angezeigt kriegen
<2><33><1><0><0><0><0><0><0><0><0><0><0><0><0><0><3><157><42>

Weil übertragen will ich an meinem Gerät Den Befehlt senden.
#1359541
Lesenswert?

gast schrieb:

>>void SendString(char *string)
>>{
>   >while(*string)
>   >{
>    > while(UART->SR & TX_BUSY);   // Uart Status Register
>    > UART->DATA = *string++;      // Uart Data Register
>   >}
>>}
>
> meinst du, dass ich die Funktion brauche !?!

Eine String-Funktion kann man immer brauchen.
Aber die hier passt nicht zu deinen restlichen USART-Funktionen (*).
Am einfachsten und am wenigsten fehlerträchtig ist es normalerweise, 
wenn man die String-Funktion so aufbaut, dass sie die 
Einzelzeichen-Funktion in einer Schleife mit den einzelnen Zeichen 
füttert. Dann sind die Details, wie ein Zeichen versendet wird, nur in 
einer Funktion beisammen und man bekommt keinen Wickel, wenn 
Einzelzeichen-Senden und String-Senden abwechselnd benutzt wird.

> Ich sende keine String!! sondern nur ASCII Zeichen !!

Ein String ist eine Folge von ASCII Zeichen.

Was ist dir lieber
1
  USART_Putc( 'H' );
2
  USART_Putc( 'a' );
3
  USART_Putc( 'l' );
4
  USART_Putc( 'l' );
5
  USART_Putc( 'o' );

oder
1
  USART_Puts( "Hallo" );

Wenn man eine USART hat, braucht man praktisch immer eine Stringausgabe 
in irgendeiner Form. Und sei es nur, dass man Zahlen ausgeben möchte
1
void USART_putInt( int number )
2
{
3
  char Buffer[10];
4
  itoa( number, Buffer, 10 );
5
  USART_Puts( Buffer );
6
}

Sieh diese Funktionen als Baukasten an, die du bei Bedarf benutzt, und 
wo sich eine Funktion auf die anderen stützt. Ganz unten steht die 
Einzelzeichenausgabe. Alle anderen Ausgaben landen letztendlich dort.

Ausserdem sind die Ausgabefunktionen normalerweise nicht sehr lang, 
sodass man davon ausgehen kann, diesen Flash-Speicher praktisch immer 
zur Verfügung zu haben.


(*) Edit:
Ich habe noch nicht mitbekommen, dass du zwischendurch den Ringbuffer 
über Bord geschmissen hast.
#1359544
Lesenswert?

gast schrieb:
>>Anzeigen, nicht übertragen.
>>Und du siehst nur, dass es für 0x00 eine Anzeige hat.
>>Ob und was es aus den restlichen Bytes macht, welche keine anzeigbare
>>Darstellung haben, steht in den Sternen.
>
> Danke für die Antwort
>
> eingentlcih möchte ich Am Terminalprogramm das Angezeigt kriegen
> <2><33><1><0><0><0><0><0><0><0><0><0><0><0><0><0><3><157><42>

Na dann mach das doch!

Alledings musst du dir im klaren sein, dass DU dafür verantworltich 
bist, dass die Zahlen richtig kommen, dass die '<' und '>' richtig 
ausgegeben werden.

PS: Ob das so sinnvoll ist, die Anzeige mit Dezimalzahlen zu machen, 
wenn du in deinem C-Programm dieselben Zahlen in Hex-Form eingibst, 
solltest du nochmal überprüfen.
Gast #1359572
Lesenswert?

Vergiss es, es handelt sich offensichtlich um den droeflhundertsten der 
meint man koennte programmieren indem man ein paar Beispielsourcen 
zusammenklebt und die Trottel im Forum den Rest machen laesst. :-/

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren