Forum: Mikrocontroller und Digitale Elektronik UART AT90CAN128-16AU von ALVIDI


von Jens (Gast)


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
/****************************************************************************/

von cskulkw (Gast)


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?

von MWS (Gast)


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 ?

von Jens (Gast)


Angehängte Dateien:

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.

von cskulkw (Gast)


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.

...

von MWS (Gast)


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.

von Jens (Gast)


Lesenswert?

Die Endlosschleife ist mit der Änderung weg, aber es kommt auch so 
nichts an. Das Mitzählen ist nur sehr begrenzt möglich. Ich hab nur vier 
LED's zur Verfügung.

von Jens (Gast)


Lesenswert?

@MWS:
Ach das hast du damit gemeint. Ich war mir da nicht ganz sicher. Ich hab 
die Variante ohne | auch schon ausprobiert. Es blieb aber bei dem selben 
Ergebnis.

von MWS (Gast)


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.

von Jens (Gast)


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

von MWS (Gast)


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.

von Jens (Gast)


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?

von MWS (Gast)


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.

von Jens (Gast)


Angehängte Dateien:

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.

von MWS (Gast)


Angehängte Dateien:

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.

von Jens (Gast)


Lesenswert?

Ok dann hab ich es richtig gemacht. Da kam nichts am Terminal an.

von MWS (Gast)


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.

von Jens (Gast)


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.

von Jens (Gast)


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.

von MWS (Gast)


Lesenswert?

Besser das Kabel als der Controller ;-)

von Jens (Gast)


Lesenswert?

Da hast du Recht.

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.