UART AT90CAN128-16AU von ALVIDI

Gast #2333190
Lesenswert?

Hallo,

ich habe ein Problem mit dem UART des ALVIDI AT90CAN128-16AU Board.
Ich kann Daten an den Controller richtig versenden, aber keine vom
Controller zum PC. Manchmal kommt etwas an, aber nur falsche Zeichen.
Ich kann zwar mit dem Oszilloskop auf der Senseleitung Signale sehen,
die sind jedoch sehr kurz. Ich hab mich im Datenblatt und anderen Foren
bei ähnlichen Problemen eingelesen und bin der Meinung, dass der UART 
richtig
eingestellt ist.
Das ist der gesamte Code für den UART. Wenn ich ein Zeichen senden 
möchte,
rufe ich nur die Funktion send_char('c'); auf.
Da das empfangen richtig funktioniert, müsste die Baudrate eigentlich 
richtig sein.
Ich bin mit meinem Latein am Ende. Mit den LED's auf dem Board konnte 
ich sehen, dass die Funktion send_char(); vollständig abgearbeitet wird.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdlib.h>
4
#include "uart.h"
5
#include "value.h"
6

7

8

9
/***** ISR USART RECEIVE ****************************************************/
10
ISR(USART0_RX_vect){
11
  *write = UDR0;        // Copy UDR0 to the ringbuffer 
12
  write++;          // Increment the write pointer for the next receive
13
  if(write == buffer+max){  // To start over if the end of the buffer is arrive
14
    write = buffer;      // Set the pointer
15
  }
16
}
17
/****************************************************************************/
18

19

20

21
/***** FUNKTION UART_INIT ***************************************************/    
22
void uart_init( void ){
23
  UBRR0H = 0x00;//(unsigned char)(BAUDRATE>>8);     //Set baud rate
24
  UBRR0L = 0x33;//(unsigned char)BAUDRATE;
25
  UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);  //Enable receiver and transmitter
26
  UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);      //Set frame format: 8data, 1stop bit
27

28
  read = buffer;      //Initialization of the pointer
29
  write = buffer;
30
}  
31
/****************************************************************************/
32

33

34

35
/***** FUNKTION UART_BYTE_AVAILABLE *****************************************/ 
36
uint8_t uart_byte_available(void){
37
  if(write != read)        
38
    return 1;    //Return True, if the two pointer aren't equal and
39
  else         //a byte is available
40
    return 0;    //Return false, if the two pointer are equal
41
}
42
/****************************************************************************/
43

44

45

46
/***** FUNKTION UART_GET_BYTE ***********************************************/   
47
uint8_t uart_get_byte(void){
48
  uint8_t databyte = 0;
49
  if(write != read){        //If a byte is available
50
    databyte = *read;       //Readout the Ringbuffers 
51
    read++;            //Increment the read pointer                 
52
    if(read == buffer+max){    //To start over if the end of the buffer is arrive  
53
      read = buffer;
54
    }
55
  }
56
  return databyte;
57
}
58
/****************************************************************************/
59

60

61

62
/***** FUNKTION SEND_CAHR ***************************************************/ 
63
void send_char(unsigned char i){
64
  while(!(UCSR0A & (1<<UDRE0)));//Wait for empty transmit buffer
65
  UDR0 = i;            //Put data into buffer -> sends the data
66
}
67
/****************************************************************************/
68

69

70

71
/***** FUNKTION SEND_STRING *************************************************/ 
72
void send_string(char *string){
73
    while(*string != 0){        //display the string up to the endlabel
74
        send_char(*string);      //give the several character to the send_char function
75
    string++;          //increment the string Pointer
76
    }
77
}
78
/****************************************************************************/
79

80

81

82
/***** FUNKTION SEND_INT ****************************************************/ 
83
void send_int(unsigned int zahl){
84
  char string[10];      //declaration of char array to save the string
85
  itoa(zahl, string, 10);    //convert integar -> string
86
  send_string(string);    //send the string
87
}
88
/****************************************************************************/
Gast #2333252
Lesenswert?

Hallo Jens,

auf den ersten Blick sehe ich auch keinen Fehler.

Aber alternativ zum

Jens schrieb:
> while(!(UCSR0A & (1<<UDRE0)));//Wait for empty transmit buffer


kannst Du mal
while(!(UCSR0A & (1<<TXC0)); ausprobieren.

// wenn 1 dann zurücksetzen.
    USCR0A |= (1<<TXC0); // Datenblatt unter UART-Discriptionregister.

Dieses Flag muss bewußt mit 1 beschrieben werden, um es zu löschen.

Hier solltest Du Deine LED toggeln lassen, damit Du auf dem Scope etwas 
sehen kannst, dass die Bytes alle gesendet worden sind. Oder Du zählst 
einen PORT hoch (inkrementieren) und gibst ihn LEDs aus. Anhand derer 
kannst Du dann nachzählen (binär natürlich) wie viele Bytes tatsächlich 
gesendet worden sind.

Ansonsten empfehle ich Dir die Anschaffung eines Debuggers. So ein 
Dragon kostet nur 50-60 Euro. Die Dinger sind eine große Hilfe.

Wie Du festgestellt hast, dass Du korrekt vom PC empfängst?

Mit welcher Baudrate und Quarzfreguenz arbeitest Du?
Gast #2333306
Lesenswert?

So ein Verhalten wäre erklärlich, wenn nach dem send_char() ein sleep 
käme. Und im Falle daß ein Bootlader installiert ist, wäre es sicher 
besser die Register beim Init nicht zu verodern. 19.2kB@16MHz ? Fuses 
richtig gesetzt ?
Gast #2333359
Lesenswert?

Danke für die Antworten.

Ich arbeite mit einer Baufrate von 19200 bei einer Frequenz von 16MHz. 
Im Hauptprogramm wird permanent abgefragt, ob ein Byte angekommen ist. 
Ich frage dann nach den übertragenen Befehlen ab und setze bei Erfolg 
eine LED. Ausserdem wird dann ein Pulsbreitenmuster an einem Ausgang 
geändert. So weit
funktioniert alles. Bei einem Befehl soll allerdings eine Antwort 
gesendet werden, die jedoch nicht ankommt.
Die Fuse-Bits hab ich im Anhang als Bild engehängt. Ich glaube bei dem 
Board wird ein Bootloader verwendet, allerdings weiß ich nicht gut 
darüber bescheid. Welche Register sollte ich denn nicht ändern?

@cskulkw: Ich habe es so ausprobiert:
1
while(!(UCSR0A & (1<<TXC0)));
2
UDR0 = i;
3
UCSR0A |= (1<<TXC0);
hat allerdings nicht geholfen. Das Programm läuft nicht weiter. Es 
scheint als wäre das eine Endlosschleife.
Angehängte Dateien:
Gast #2333430
Lesenswert?

Hallo Jens,

wenn Du meinen Vorschlag benutzt, dann mußt Du erst die Daten in das 
UDR0 laden und dann auf das Gesendet-Bit prüfen.

UDR0 = i;
while(!(UCSR0A & (1<<TXC0)));
UCSR0A |= (1<<TXC0);

Ich gebe zu, daß ich daran nicht gedacht hatte. Wenn nach der 
Initialisierung noch nichts gesendet worden ist, dann wird das Flag noch 
nicht gesetzt sein. Insofern erklärt sich mir die Endlosschleife.

Bei jedem erfolgreichen Durchlauf würde ich eine Variable mitzählen 
lassen und auf einem Port ausgeben, wenn Du das umsetzen kannst.

...
Gast #2333446
Lesenswert?

Jens schrieb:
> Welche Register sollte ich denn nicht ändern?

Ändern schon, ich wollte nur darauf hinweisen, daß das hier:
1
  UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
2
  UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
bei einem Bootlader gefährlich ist, denn es bleiben vom BL ggf. gesetzte 
Registerinhalte in UCSR0B/0C durch das "oder" erhalten.

Wenn man die Inhalte genau bestimmen möchte, dann würde man nur "=" ohne 
"|" schreiben.
Gast #2333506
Lesenswert?

Jens schrieb:
> Ich kann Daten an den Controller richtig versenden

Das impliziert zwar, daß die Registereinstellungen passen, nur wenn ein 
Bootlader drauf ist, dann würde ich schon sichergehen wollen, daß jedes 
der beteiligten Register neu initialisiert wurde, da gehört auch UCSR0A 
und darin U2X0 und MPCM0 dazu.

Wie umfangreich ist denn der gesamte Code ? Meist ist der Fehler im 
nicht geposteten Teil.
Gast #2333630
Lesenswert?

Da geb ich dir Recht. Ich poste dann mal das komplette Hauptprogramm.
Ich werd die Register mal setzen und poste dann das Ergebnis.

Der Controller soll bei den Befehl "con" alle Variablen über die UART 
senden. Der Rest des Codes funktioniert. Der Controller gelangt auch zu 
den Aufrufen der send_char() Funktionen.
1
/***** MAIN ******************************************************************/
2
int main(void){ 
3

4
  /***** The first initalization *****************************/
5
  DDRB = 0xFF;  //Port B is configured as an output port
6
  DDRE = 0xFF;  //Port E is configured as an output port
7
  DDRF = 0xFF;  //Port D is configured as an output port
8

9
  //open initalization funktions
10
  initialize_Values();
11
  uart_init();
12
  dac_init();
13
  timer1_init();  
14
  timer2_init();
15
  timer3_init();
16

17
  sei(); //enable - globel interrupts
18

19
  //set DA output voltage  
20
  dac_write((uint16_t)((((uint32_t)vlevel)*4095)/10000),DA_HIGH_VOLTAGE);
21
  dac_write((uint16_t)((((uint32_t)plevel)*4095)/100),DA_LINKAGE_POSITION);
22

23
  //uart acknowledgement disabled
24
  flag.uart_ack = 0;
25
  
26
  uint8_t i = 0;
27
  inout_work_indication();
28
  /***********************************************************/
29
    PORTF = 0b11111111;
30
    char dlm = '.';
31

32
  while(1){
33

34
    if(uart_byte_available()){
35
      uart_command[i] = uart_get_byte();
36

37
      if(flag.uart_ack){  //Uart acknowledgement ?
38
        send_char(uart_command[i]);
39
      }
40

41
      if(uart_command[i] == dlm){
42
      
43
        uint8_t count_1;
44
        uint8_t count_2;
45
        uint8_t j = 1;
46

47
        for(count_1 = 0 ; (uart_command[count_1] != ':' && uart_command[count_1] != dlm) ; count_1++){
48
          signal[count_1] = uart_command[count_1];
49
        }  //end for      
50
        
51
        if(uart_command[count_1] != dlm){
52
          count_1++;
53
          for(count_2 = 0 ; uart_command[count_2 + count_1] != dlm ; count_2++){
54
            if(j){
55
              value = uart_command[count_2 + count_1] - 48;
56
              j = 0;
57
            }
58
            else{
59
              value = (value * 10) + (uart_command[count_2 + count_1] - 48); 
60
            }
61
          }  //end for
62
        }  //end if
63
        j = 1;
64

65
        if(flag.uart_ack){  //Uart acknowledgement ?
66
          send_char('\n');
67
          send_char('\r');
68
        }
69

70
        /***** UART-COMMANDS ************************************/
71
        //Voltage High Values
72
        if(equation_string(signal,"vlevel") && (vlevel_min <= value) && (value <= vlevel_max)){
73
          vlevel = value;
74
          dac_write((uint16_t)((((uint32_t)value)*4095)/10000),DA_HIGH_VOLTAGE);
75
        }
76
        if(equation_string(signal,"plevel") && (plevel_min <= value) && (value <= plevel_max)){
77
          plevel = (uint8_t)value;
78
          dac_write((uint16_t)((((uint32_t)value)*4095)/100),DA_LINKAGE_POSITION);
79
          inout_work_indication();
80
        }
81

82
        //Theoretical pulses and speed
83
        if(equation_string(signal,"tpulse") && (tspeed_pulse_min <= value) && (value <= tspeed_pulse_max)){
84
          theoretical_speed.pulse = value;
85
          timer1_init();
86
        }
87
        if(equation_string(signal,"tspeed") && (tspeed_speed_min <= value) && (value <= tspeed_speed_max)){
88
          theoretical_speed.speed = value;
89
          timer1_init();
90
        }
91

92
        //Ground pulses and speed
93
        if(equation_string(signal,"gpulse") && (gspeed_pulse_min <= value) && (value <= gspeed_pulse_max)){
94
          ground_speed.pulse = value;
95
          timer3_init();
96
        }
97
        if(equation_string(signal,"gspeed") && (gspeed_speed_min <= value) && (value <= gspeed_speed_max)){
98
          ground_speed.speed = value;
99
          timer3_init();
100
        }
101

102
        //PTO pulses and speed
103
        if(equation_string(signal,"ppulse") && (pspeed_pulse_min <= value) && (value <= pspeed_pulse_max)){
104
          pto_speed.pulse = value;
105
          timer2_init();
106
        }
107
        if(equation_string(signal,"pspeed") && (pspeed_speed_min <= value) && (value <= pspeed_speed_max)){
108
          pto_speed.speed = value;
109
          timer2_init();
110
        }
111

112
        //In-Work / Out-Work Indication
113
        if(equation_string(signal,"iowork") && (iowork_min <= value) && (value <= iowork_max)){
114
          iowork = (uint8_t)value;
115
          inout_work_indication();
116
        }
117

118
        //connect -> Send all values
119
        if(equation_string(signal,"con")){
120
        //PORTF |= (1<<PF0);
121
          send_int(theoretical_speed.speed);
122
          send_char(':');
123
          send_int(theoretical_speed.pulse);
124
          send_char(':');
125
          send_int(ground_speed.speed);
126
          send_char(':');
127
          send_int(ground_speed.pulse);
128
          send_char(':');
129
          send_int(pto_speed.speed);
130
          send_char(':');
131
          send_int(pto_speed.pulse);
132
          send_char(':');
133
          send_int(plevel);
134
          send_char(':');
135
          send_int(vlevel);
136
          send_char(':');
137
          send_int(iowork);
138
          send_char(':');
139
        }
140

141
        //enable - disable uart acknowledgement
142
        if(equation_string(signal,"ack")){
143
          flag.uart_ack = !flag.uart_ack;  
144
        }
145
        /*******************************************************/
146

147
        /***** DELET BUFFER ************************************/
148
        for(uint8_t k=i+2 ; k != 0 ; k--){
149
          uart_command[i] = 0;
150
          i--;
151
        }
152
        count_1++;
153
        for( ; count_1 != 0 ; count_1--){
154
          signal[count_1-1] = 0;
155
        }
156
        /*******************************************************/
157

158
        i = 0;
159
      }
160
      else i++;
161
  
162
    }  //end if(uart_byte_available)
163
      
164
  }  //end while
165

166
}  //end main
Gast #2333694
Lesenswert?

Daraus ist nicht viel zu erkennen, außer den paar UART-Ausgabeaufrufen.
Seit wann hast Du denn das Problem ? Sieht mir doch wie einigermaßen 
fortgeschrittener Code aus, der zudem das UART benötigt, das muss Dir 
doch schon länger aufgefallen sein.

Die HW-Seite sollte man zuerst überprüfen, da gibt's 2 Jumper am UART, 
sind die richtig gesteckt ? Auch geht das UART an den ISP, da ist auch 
nichts verbunden ?

Ich würde versuchen ob die Kommunikation über den PC ohne Controller 
klappt. Schau Dir den Schaltplan zu dem Modul an. Man könnte über einen 
Kontakt des Jumpers an Out des MAX3232 wieder auf den anderen Kontakt 
des Jumpers an In zurückschleifen. Damit sieht man dann im Terminal ob 
die Verbindung PC/MAX und zurück ok ist.

Auch wär's sinnvoll einen abgespeckten Code zu schreiben, der nur den 
Fehler des UART's zeigt und dann eine compilierbare Version hier 
einstellen, sonst ist das wie im Trüben fischen.
Gast #2333722
Lesenswert?

Der Fehler ist mir erst seit ein paar Tagen bekannt. Ich habe aber noch 
keine funktionierende Version gehabt, da ich es erst vor kurzem 
fertiggestellt habe.
Die Register habe ich jetzt wie folgt geändert.
1
void uart_init( void ){
2
  UBRR0H = 0x00;//(unsigned char)(BAUDRATE>>8);     //Set baud rate
3
  UBRR0L = 0x33;//(unsigned char)BAUDRATE;
4
  UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)|(0<<RXB80)|(0<<TXB80)|(0<<UCSZ2);  //Enable receiver and transmitter
5
  UCSR0C = (0<<UMSEL0)|(0<<UPM00)|(0<<UPM01)|(1<<UCSZ01)|(1<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01)|(0<<UCSZ02);      //Set frame format: 8data, 1stop bit
6
    UCSR0A = (0<<U2X0)|(0<<MPCM0)|(0<<UDRE0);
7
  read = buffer;      //Initialization of the pointer
8
  write = buffer;
9
}

Die Jumper sind richtig gesetzt, das habe ich schon mehrmals geprüft. 
Den Programmer ziehe ich immer wieder ab, sodass am ISP ebenfalls nichts 
verbunden ist.
Den Code werde ich mal auf ein Minimum herabsetzen. Den letzten Teil 
habe ich nicht verstanden. Ich soll quasi die TxD und RxD Leitungen 
kurzschliessen, aber die Verbindung über das RS232-Kabel bestehen 
lassen, damit ich das abgeschickte Zeichen im Terminal auch empfange?
Gast #2333757
Lesenswert?

Jens schrieb:
> Den letzten Teil
> habe ich nicht verstanden. Ich soll quasi die TxD und RxD Leitungen
> kurzschliessen, aber die Verbindung über das RS232-Kabel bestehen
> lassen, damit ich das abgeschickte Zeichen im Terminal auch empfange?

Ja, genau. Ein Loopback-Test. Ich fand 2 Schaltpläne, einmal mit 
externen Ram, einmal ohne, bei beiden sind es aber R12/R13 470 Ohm, die 
vom MAX auf die Jumper gehen, verbindet man diese an den Jumpern 
miteinander, so müssen eingegebene Zeichen am Terminal erscheinen. Wenn 
das nicht klappen würde, braucht man an der SW nicht groß weitersuchen.

Hab' mir die Fusesettings von oben nochmal angesehen, wenn Du nichts 
verändert hast, dürftest Du sowieso keine Probleme mit dem Bootlader 
bzw. mit Überresten davon bekommen, da der ausgeschaltet ist, BOOTRST = 
1.
Gast #2333799
Lesenswert?

Die Fuse Bits sind genauso wie im Bild gesetzt.
Ich habe jetzt einfach die beiden Kabel RxD und TxD vom RS232-Kabel das 
am PC angeschlossen ist kurzgeschlossen. Die abgesendeten Zeichen kamen 
nicht an. Allerdings bin ich mir jetzt nicht sicher ob ich es richtig 
gemacht habe.
Ich habe HTerm verwendet. Im Bild sind die Einstellungen zu sehen.
Angehängte Dateien:
Gast #2333867
Lesenswert?

Jens schrieb:
> Allerdings bin ich mir jetzt nicht sicher ob ich es richtig
> gemacht habe.

Das Zusammenschließen oder die Benutzung von HTerm ?

Aber mir ist da auch ein faux-pas unterlaufen, sorr. Hab's gerade 
gemerkt als ich die Zeichnung für Dich gemacht hab'. Nicht die 
Widerstände untereinander verbinden, sondern so wie in der Zeichnung.

Konnte aber nix passieren, außer daß es halt nicht geht.
Angehängte Dateien:
Gast #2333912
Lesenswert?

Jens schrieb:
> Ok dann hab ich es richtig gemacht. Da kam nichts am Terminal an.

Einstellungen HTerm alle ok ?
Würd' mir zyklisch immer nur ein Zeichen schicken lassen, außer Du bist 
sicher, daß der Empfang klappt.

Evtl. wär' jetzt ein guter Zeitpunkt die Kabelverbindung PC/µC zu 
prüfen, man kann selbiges auch direkt mit dem Kabel machen, also Brücke 
TX/RX, natürlich ohne angeschlossenen MAX. Sollte das dann gehen, wäre 
der Fehler im oder in der Elektrik zum MAX zu suchen.

Serielles Kabel auch an Pin 34 & 36, DB S. 4 angeschlossen ?

Ich finde die Beschreibung des DB's irreführend, wenn man auf Seite 2 
schaut, steht bei PE0..1 Pin 9 & 10 auch RS232, wobei RS232 da nix zu 
suchen hat, denn das sind die µC-Pins und die haben TTL-Level.

RS232 hat üblicherweise ~ +-12V und ist gegenüber RDX/TXD invertiert, 
genau dafür braucht's ja den MAX.
Gast #2333932
Lesenswert?

Der Empfang klappt definitiv. Die direkte Brücke am Kabel hab ich auch 
schon getestet. Hat auch nicht geklappt. Mit dem HTerm kenn ich mich 
nicht aus, kann auch ein Bedienungsfehler sein.

Die Anschlüsse am Controller hab ich geprüft, die ist definitiv richtig.

Mit dem Datenblatt hast du Recht, ist ein wenig irreführend. Ich werd 
als nächstes mal das Kabel auf einen Bruch testen. Das kann ich 
allerdings erst morgen machen, da ich kein Messgerät habe.
Ansonsten werde ich mal den zweiten UART ausprobieren.

Vielen Dank, dass du dir die Zeit genommen hast mir zu helfen. Ich werde 
dann morgen berichten.
Gast #2334887
Lesenswert?

Jetzt funktioniert auch die Datenübertragung vom Controller zum PC. Das 
RS232-Kabel hatte einen Kabelbruch. Nach dem Austausch hat alles 
reibungslos funktioniert.
Vielen Dank an alle, die mir geholfen haben.

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