String ueber UART ausgeben geht nur teilweise

Gast #1573712
Lesenswert?

Hallo zusammen,
ich habe da ein merkwürdiges Verhalten, das ich mir nicht erklären kann. 
Wenn ich versuche einen String über den Uart des Atmega8 auszugeben sehe 
ich nur Fragezeichen auf dem Terminal. Wenn ich allerdings die funktion 
itoa() benutze werden die Zahlen korrekt angezeigt...
Ich habe schon sämtliche Baudraten zw. 9600 und 57600 ausprobiert. Der 
Atmega läuft mit einem externen 8MHz Quarz...
1
#define F_CPU 8000000UL
2
#define BAUD 9600UL
3

4
void init_usart()
5
{
6
     uint16_t ubrr = (F_CPU / (BAUD * 8L) -1 );
7
 
8
     /* Set baud rate */
9
     UBRRH = (uint8_t) (ubrr>>8);
10
     UBRRL = (uint8_t) (ubrr);
11

12
     /*
13
     Enable receiver and transmitter; RXCIE aktiviert Interruptbetrieb
14
     zum Empfangen von Daten am
15
     */
16
     UCSRA = (1<<U2X);
17
     UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
18

19
     /* Set frame format: 8data, 2stop bit */
20
     UCSRC = (1<<USBS)|(3<<UCSZ0)| (1<<URSEL);
21
 
22
}
23

24
int uart_putc( unsigned char data )
25
 {
26
     /* Wait for empty transmit buffer */
27
     while ( !( UCSRA & (1<<UDRE)) )
28
     ;
29
     /* Put data into buffer, sends the data */
30
     UDR = data;
31
     return 1;
32
 }
33
 
34
 void uart_puts (char *s)
35
 {
36
         while (*s)
37
         {
38
             uart_putc(*s);
39
             s++;
40
         }
41
 
42
}

Die Ausgabe erfolgt z.B. mit:
1
char s[7];
2
itoa(OCR1A,s,10);
3
uart_puts(s); // -> FUNKTIONIERT
4

5
// ABER
6

7
uart_puts("abc");
8
// ODER 
9
char abc[] = "abc";
10
uart_puts(abc); // FUNKTIONIERT NICHT

Woran kann das liegen?

PS: Ich muss noch dazusagen, das der Atmega über den MySmartUSB progger 
mit Spannung via USB Port versorgt wird. Kann es sein dass die Spannung 
nicht stabil genug ist?!?
#1573739
Lesenswert?

Chris schrieb:

> uart_puts("abc");
> // ODER
> char abc[] = "abc";
> uart_puts(abc); // FUNKTIONIERT NICHT
>
> Woran kann das liegen?

Das sollte iegentlich kein Problem sein.
Zeig mal mehr Code aus der Umgebung.
Idealerweise den kompletten Code.

> PS: Ich muss noch dazusagen, das der Atmega über den MySmartUSB progger
> mit Spannung via USB Port versorgt wird. Kann es sein dass die Spannung
> nicht stabil genug ist?!?

Eher unwahrscheinlich.
Gast #1573751
Lesenswert?

Hier ist der komplette Code. Uart wird nicht zwingend benoetigt, soll 
nur zum debuggen sein...
1
#define F_CPU 8000000UL
2

3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
#include <stdlib.h>
7

8
#define BAUD 9600UL
9

10
#define OCR1_MIN 350
11
#define OCR1_MAX 1150
12

13
#define HORI_MITTE 750
14
#define VERTI_MITTE 750
15
#define HORI OCR1A
16
#define VERTI OCR1B
17

18
#define T_1MS 131
19

20
//Variablendeklaration
21
uint16_t ms = 0;
22
uint16_t us = 0;
23

24
struct Point{
25
    uint16_t x; //aka VERTI aka OCR1A
26
    uint16_t y; // aka HORI aka OCR1B
27
}lastPoint;
28

29
struct Point *p;
30

31
void init_servo(){
32

33
    // 16bit Timer1
34
    TCCR1A |= (1<<COM1A1) | (1<<COM1B1);
35
    TCCR1B |= (1<<WGM13) | (1<<CS11);
36
        
37
    ICR1 = 0x2710; // 10000 und entspricht 20ms bei 8MHz Takt
38
    TCNT1 = 0x00; //Timer startet bei 0
39

40
    // 8bit Timer0
41
    TCCR0 |= (1<<CS01) | (1<<CS00); // prescaler=256 -> macht 31,250kHz 
42
    
43
    
44
    /*
45
     *
46
     *  TIMSK hier deaktivieren um den Timer bei Bedarf fuer Movements zu
47
     *  starten (z.B. aus der move Funktion heraus)
48
     *
49
     */
50
    TIMSK |= (1<<TOIE0); // timer overflow interrupt auf enabled setzen
51
    TCNT0 = T_1MS; // bei jedem Overflow sind 250us vergangen -> macht 4000Hz
52
    DDRB = 0xff; //PortB auf Ausgang schalten
53

54
}
55

56
void init_usart()
57
{
58
    // alt: uint16_t ubrr = (uint16_t) ((uint32_t) ((F_CPU/(16*BAUD))-1));
59

60
    uint16_t ubrr = (F_CPU / (BAUD * 8L) -1 );
61

62
    /* Set baud rate */
63
    UBRRH = (uint8_t) (ubrr>>8);
64
    UBRRL = (uint8_t) (ubrr); 
65
    /*
66
    Enable receiver and transmitter; RXCIE aktiviert Interruptbetrieb
67
    zum Empfangen von Daten am
68
    */
69
    UCSRA = (1<<U2X);
70
    UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
71
    /* Set frame format: 8data, 2stop bit */
72
    UCSRC = (1<<USBS)|(3<<UCSZ0)| (1<<URSEL);
73

74
}
75

76
int uart_putc( unsigned char data )
77
{
78
    /* Wait for empty transmit buffer */
79
    while ( !( UCSRA & (1<<UDRE)) )
80
    ;
81
    /* Put data into buffer, sends the data */
82
    UDR = data;
83
    return 1;
84
}
85

86
void uart_puts (char *s)
87
{
88
        while (*s)
89
        { 
90
            uart_putc(*s);
91
            s++;
92
        }
93

94
}
95

96

97
ISR(TIMER0_OVF_vect) 
98
{
99
    ms++;
100
    if(ms == 1000) // eine Millisekunde vergangen
101
    {
102
        ms = 0;
103
    //    PORTB = ~PORTB;
104
    }
105

106

107
    TCNT0 = T_1MS;
108
}
109

110
void center(void) // speed ist ein wert von 0 (min) bis 7 (max)
111
{
112
    // alles auf Mittelstellung
113
    HORI = HORI_MITTE;
114
    VERTI = VERTI_MITTE;
115
    p->x = HORI;
116
    p->y = VERTI;
117
}
118

119
ISR(USART_RXC_vect)
120
{
121
    //hier den Code fuer Datenempfang einfuegen
122
    //UDR muss gelesen werden, da sonst der Interrupt immer wieder angerannt kommt :)
123
    char s[7];
124
    char tab[] = "\t";
125
    itoa(OCR1A,s,10);
126
    switch(UDR)
127
    {
128
        case 0x61: // 'a'
129
            if((OCR1A - 20) < OCR1_MIN)
130
                OCR1A = OCR1_MIN;
131
            else
132
                OCR1A -= 20;
133
            uart_puts(s);
134
            uart_puts(tab);
135
            break;
136
        case 0x64: // 'd' 
137
            if((OCR1A + 20) > OCR1_MAX)
138
                OCR1A = OCR1_MAX;
139
            else
140
                OCR1A += 20;
141
            break;
142
        case 0x77: // 'w'
143
            if((OCR1B - 20) < OCR1_MIN)
144
                OCR1B = OCR1_MIN;
145
            else
146
                OCR1B -= 20;
147
            break;
148
        case 0x73: // 's'
149
            if((OCR1B + 20) > OCR1_MAX)
150
                OCR1B = OCR1_MAX;
151
            else
152
                OCR1B += 20;
153
            break;
154
        case 'm':
155
                center();
156
            break;
157
        case 'o': // PB1 togglen laser an/aus
158
            if(PORTB == (1<<PB1))
159
                PORTB = ~(1<<PB1);
160
            else
161
                PORTB = (1<<PB1);
162
            break;
163
        default:
164
        break;
165
    }
166

167
}
168

169
int main( void )
170
{
171
    init_usart();
172
    init_servo();
173

174
    //enable global interrupts to enable the ISR
175
    sei();
176

177
    // Pointer auf aktuelle ServoWerte
178
    p = &lastPoint;
179
    
180
    //Servos auf Mittelstellung
181
    center(); 
182

183
    int16_t grad = 555;
184

185
    char res[10];
186
    itoa(grad,res,10);
187
    char abc[7] = "abc";
188

189
    while(1)
190
    {
191

192
        _delay_ms(1000);
193
        uart_puts(res); 
194
        uart_puts(abc);
195

196
    }
197

198
    return 0;
199
}
#1573766
Lesenswert?

Chris schrieb:

Hmm.
Meine ursprüngliche Vermutung war, dass du irgendwo ein Array 
niederbügelst und wild in den Speicher schreibst und dabei zufällig den 
String erwischt hast.

Das einzige in dieser Richtung könnte hier stecken:

> int main( void )
> {
>     init_usart();
>     init_servo();
>
>     //enable global interrupts to enable the ISR
>     sei();
>
>     // Pointer auf aktuelle ServoWerte
>     p = &lastPoint;

Interrupts sind schon freigschaltet.
Wenn die USART vor deiser Zuweisung an p bereits einen Empfangsinterrupt 
gefeuert hat, besteht die Chance, dass p benutzt wird noch ehe es einen 
Wert erhalten hat.

Ich gebe zu, dass ist nicht besonders wahrscheinlich.
Trothdem sollte man es korrigieren:

Den sei() macht man immer erst, wenn ausnahmslos alles initialisiert 
ist. Sonst verliert man schnell den Überblick, ob man schon darf oder 
nicht. Am besten kommt der sei() als letzter Funktionsaufruf vor die 
Hauptschleife
1
int main()
2
{
3
  Initialisierung
4
  Grundzustand herstellen
5

6
  sei()
7
  while( 1 ) {
8
    und los gehts
9
  }
10
}

da gibts am wenigsten Überraschungen.

Aber abgesehen davon ist mir jetzt nichts aufgefallen, was den Effekt 
erklären könnte.

Noch Manöverkritik
1
    switch(UDR)
2
    {
3
        case 0x61: // 'a'

schreibs doch gleich so
1
    switch(UDR)
2
    {
3
        case 'a':

dann brauchts keinen Kommentar und man sieht auch im Code, was 
angestrebt wird.
Gast #1573775
Lesenswert?

Stefan Ernst schrieb:
> Wie erstellst du denn das Hex-File?

Muss ich da noch ein Flag an den gcc uebergeben?
Hier ist mein Makefile:
1
PROJECT = uartmitpwm
2
#TARGET = attiny26
3
TARGET = atmega8
4
CC = avr-gcc
5
OBJCOPY = avr-objcopy
6
CFLAGS = -mmcu=$(TARGET) -Os -Wall $(DEBUG)
7
INCLUDES = -I.
8
SRC = $(PROJECT).c
9
OBJ = $(SRC:.c=.o)
10
UISP_OPTS = -dserial=/dev/tty.SLAB_USBtoUART -dprog=avr910 -dpart=M8
11

12
# "-c" means compile but don't link
13
.c.o:
14
  $(RM) $@
15
  $(CC) -c $(CFLAGS) $(INCLUDES) $*.c
16

17

18
# Targets...
19

20
all: $(OBJ)
21

22
$(PROJECT).S:
23
  $(CC) -S -c $(PROJECT).c
24

25
$(PROJECT).hex: $(PROJECT).elf
26
  $(OBJCOPY) -j .text -O ihex $(PROJECT).elf $(PROJECT).hex
27

28
$(PROJECT).bin: $(PROJECT).elf
29
  $(OBJCOPY) -j .text -O binary $(PROJECT).elf $(PROJECT).bin
30

31
$(PROJECT).elf: $(OBJ)
32
  $(CC) $(CFLAGS) -o $(PROJECT).elf -Wl,-Map,$(PROJECT).map $(OBJ)
33

34
simulate: $(PROJECT).bin
35
  simulavr -d atmega8 -P simulavr-disp $(PROJECT).bin
36

37
identify:
38
  uisp $(UISP_OPTS) --rd_fuses
39

40
erase:
41
  uisp $(UISP_OPTS) --erase
42

43
upload: $(PROJECT).hex
44
  avrdude -p $(TARGET) -P /dev/cu.SLAB_USBtoUART -c avr911  -v  -U flash:w:$(PROJECT).hex:i
45

46
clean:
47
  rm -f *.o *.elf *.map *.hex *.bin $(PROJECT)
Gast #1573786
Lesenswert?

Karl heinz Buchegger schrieb:
> Den sei() macht man immer erst, wenn ausnahmslos alles initialisiert
> ist. Sonst verliert man schnell den Überblick, ob man schon darf oder
> nicht. Am besten kommt der sei() als letzter Funktionsaufruf vor die
> Hauptschleife

Danke fuer deine Tipps. Ich werd sie mir in Zukunft zu Herzen nehmen.
Steh' ja noch ganz am Anfang der AVR Programmierung, da ist man noch 
lernfaehig :) Aber ich muss sagen, es macht Spass.

Gruss
#1573799
Lesenswert?

Chris schrieb:
> Karl heinz Buchegger schrieb:
>> Den sei() macht man immer erst, wenn ausnahmslos alles initialisiert
>> ist. Sonst verliert man schnell den Überblick, ob man schon darf oder
>> nicht. Am besten kommt der sei() als letzter Funktionsaufruf vor die
>> Hauptschleife
>
> Danke fuer deine Tipps. Ich werd sie mir in Zukunft zu Herzen nehmen.
> Steh' ja noch ganz am Anfang der AVR Programmierung, da ist man noch
> lernfaehig :) Aber ich muss sagen, es macht Spass.

Schade, dass ich dir da nicht mehr helfen kann.
Das Verhalten ist seltsam. All die üblichen Verdächtigen greifen nicht.

(An die Sache mit der .data Section glaub ich nicht. Da müsstest du 
schon wissen, mit welchen Compiler/Linker Optionen man das umstellt. 
Ausser Jörg und noch ein paar anderen kennt die aber kaum wer. Und 
ausserdem müsstest du dann nicht nachfragen :-)
#1573858
Lesenswert?

Karl heinz Buchegger schrieb:

> (An die Sache mit der .data Section glaub ich nicht.

Ist aber genau das Problem:
1
$(PROJECT).hex: $(PROJECT).elf
2
  $(OBJCOPY) -j .text -O ihex $(PROJECT).elf $(PROJECT).hex
Nur .text landet im Hex-File, nicht auch .data.

@ Chriss:
Füge noch ein "-j .data" hinzu.
Oder noch besser: benutze MFile oder zumindest sein Makefile-Template 
als Vorlage.
#1573898
Lesenswert?

Stefan Ernst schrieb:
> Karl heinz Buchegger schrieb:
>
>> (An die Sache mit der .data Section glaub ich nicht.
>
> Ist aber genau das Problem:
>
1
> $(PROJECT).hex: $(PROJECT).elf
2
>   $(OBJCOPY) -j .text -O ihex $(PROJECT).elf $(PROJECT).hex
3
>
> Nur .text landet im Hex-File, nicht auch .data.

I stand corrected :-)

Wer macht denn auch sowas!
Makefiles kopiert man doch einfach von einer vertrauenswürdigen Quelle 
und ändert tunlichst nur die Filenamen :-)
#1573953
Lesenswert?

Hc Zimmerer schrieb:
> Nein.  In der .text-section ist ganz hinten ein Spiegel der data
> section.  Die wird beim C-Start umkopiert.

Nein, dieser "Spiegel" ist nicht in der .text-Section enthalten. Er wird 
erst "erzeugt", indem man die .data-Section dem Hex-File hinzufügt, und 
dadurch hinter .text mit ins Flash programmiert wird.
Gast #1573994
Lesenswert?

Keine Ahnung wo ich das Makefile her hatte. Zumindest funktioniert es 
jetzt, obwohl ich noch nicht wirklich verstanden habe warum.
Vielleicht sollte ich mir mal ein Howto bzgl. Makefiles durchlesen...
Danke nochmals fuer eure Hinweise...
Gruss
Chris

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