Hallo Leute.
Vorneweg möchte ich sagen, dass ich mich in Sachen Mikrocontroller noch
nicht so gut auskenne. Allerdings hab ich mich daran gewagt eine
Roboterhand für mein Maturaprojekt zu bauen.
Nun hab ich mal so alles schön aufgebaut(also die ganze Schaltung zum
programieren usw) und habe nun folgendes Testprogramm geschrieben:
#include <stdlib.h>
#include <avr/io.h>
#include <string.h>
#include "uart.h"
#include <util/delay.h>
#include <inttypes.h>
#define F_CPU 20000000UL // Systemtakt in Hz
#define BAUD 9600UL //Baudrate
#define UBRR ((F_CPU+BAUD*8)/(BAUD*16)-1) //clever runden
/*void initialUart()
{
UBRR0H = (unsigned char) (UBRR >>8); // Baudrate setzen
UBRR0L = (unsigned char) UBRR;
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
}*/
void uart_Init(void)
{
/* Set baud rate */
UBRR0H = (unsigned char)(UBRR>>8);
UBRR0L = (unsigned char) UBRR;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
int main()
{
char NextSign;
uart_Init();
DDRB|=(1<<DDB1);
DDRB|=(1<<DDB2);
while(1)
{
NextSign = uart_getc();
PORTB |= (1<<PB2);
uart_putc(NextSign);
_delay_ms(50);
PORTB &= ~(1<<PB2);
}
return 1;
}
Das Progi soll mir einfach den Text den ich über die RS232 Schnittstelle
schicke über den Mikrocontroller wieder zurückschicken(max232 ist
zwischen Rs232 und Mikrocontroller). Allerdings empfange ich am Pc nix.
Den Text den ich schicken will schicke ich mit meinen C# Programm:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace Serialport_test
{
public partial class Form1 : Form
{
SerialPort com;
public Form1()
{
InitializeComponent();
this.richTextBox2.Enabled = false;
}
private void button1_Click(object sender, EventArgs e)
{
com = new SerialPort("com3", 9600, Parity.None, 8,
StopBits.Two);
try
{
com.Open();
com.WriteLine(this.richTextBox1.Text);
Thread lese = new Thread(new ThreadStart(tuewas));
lese.Start();
com.Close();
}
catch (Exception)
{
Console.WriteLine("Comportfehler");
}
}
private static void tuewas()
{
try
{
SerialPort com = new SerialPort("com3",
9600, Parity.None, 8, StopBits.Two);
com.Open();
Console.WriteLine(com.ReadTo("n"));
com.Close();
}
catch (Exception e)
{
Console.WriteLine("Bekomme nix");
}
}
}
}
Könnt ihr mir bitte sagen wieso ich keinen Text empfange bzw. ob ich
überhaupt was mache mit dem Programm.
Bitte bitte helft mir, es ist wirklich sehr wichtig.
Mfg Atmega 168
Kennst du den Artikel AVR Checkliste schon?
Bei RS232-Übertragung ist die Verkabelung zwischen µC und PC ein
essentieller Punkt. Hierzu schreibst du in deiner Frage nichts. Ein
Schaltplan/Skizze wäre hier hilfreich.
Um ein Problem mit dem selbstgeschriebenen PC-Programm auszuschliessen,
würde ich die ersten Tests zuerst mit einem bekanntermassen
funktionierenden Terminalprogramm machen (s. Artikel RS232).
Den Artikel hab ich mir schon mal durchgelesen, aber hab nichts
gefunden. Außerdem funktionnieren Testprogramme (wie zum Beispiel ein
LED mit dem atmega168 zum blinken zu bringen).
Den Mikrocontroller vom Typ Atmel atmega168 hab ich mit dem Pc so wie
auf dieser
Seite(http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART)
angeschlossen. Ich hab allerdings einen Nullmodemkabel und so musste ich
Pin3 und 2 am Comport vertauschen.
Außerdem hat mein Mikrocontroller eine stabile 5V
Gleichspannungsversorgung (7805)und ist an einen Quarz von 20Mhz
angeschlossen(Fuses hab ich schon entsprechend gesetzt)...
Mein erster Gedanke, dass mein Programmer(selbstgebaut=) ) nicht
funktioniert war auch falsch. Er lässt sich problemlos programmiern. Wie
gesagt kleine Programe funktionieren sogar schon.
Nur fehlt noch bei der uart...
Kann es sein, dass mein Quellcode falsch ist?
MfG atmega 168
Atmega 168 wrote:
> Den Artikel hab ich mir schon mal durchgelesen, aber hab nichts> gefunden. Außerdem funktionnieren Testprogramme (wie zum Beispiel ein> LED mit dem atmega168 zum blinken zu bringen).
Das ist gut, denn aus der Blinkrate kann man grob ableiten, ob der
Taktgeber wie vorgesehen arbeitet. Zwischen 1 Mhz (Werkseinstellung) und
20 MHz (externer Quarz) sollte man einen Unterschied hinbekommen.
> Den Mikrocontroller vom Typ Atmel atmega168 hab ich mit dem Pc so wie> auf dieser> Seite(http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART)> angeschlossen. Ich hab allerdings einen Nullmodemkabel und so musste ich> Pin3 und 2 am Comport vertauschen.
µC aus der Fassung raus und an der Fassung die Pins RXD udn TXD brücken.
Dann sollte beim Senden mit Terminalprogramm auf dem PC der gesendete
Text als Echo zurückkommen. Damit wäre die RS232-Hardware auf
grundsätzliche Funktion getestet. Die TXD Leitung auf dem einseitig
angeschlossenen Kabel kann man mit einem Mutimeter finden. Sie führt iM
Gegensatz zur RXD Leitung Spannung gegen GND auf dem Kabel.
> Außerdem hat mein Mikrocontroller eine stabile 5V> Gleichspannungsversorgung (7805)und ist an einen Quarz von 20Mhz> angeschlossen(Fuses hab ich schon entsprechend gesetzt)...
Schön. ich will dir auch kein schlampiges Arbeiten unterstellen. NUR
wenn alles per Definition richtig ist, darf auch kein Problem auftreten.
Tritt ein Problem auf, muss irgendwo ein Bug stecken ;-)
> Nur fehlt noch bei der uart...> Kann es sein, dass mein Quellcode falsch ist?
Kann sein. Es kann auch sein, dass die Verbindung zwischen µC udn PC
einen Bug hat. Ich mag/kann in die Diskussion beider Softwares (µC-Teil
(da fehlt Source) und PC-Teil (C# habe ich keine Ahnung)) nicht
einsteigen,
Hallo,
und wie wäre es mit systematischer Eingrenzung des Fehlers?
z.B. festes Zeichen mit dem µC senden, Terminalprogramm auf dem PC
öffnen und schauen, ob es richtig ankommt?
Falls nicht -> Fehler in µC Senderoutine suchen und beheben.
Zeichen mit Terminalprogramm schicken und schauen, ob es der µC richtig
zurückschickt?
Falls nicht -> Fehler in µC Empfangsroutine suchen und beheben.
Test mit Deinem Programm
Falls nicht -> Fehler dort suchen
Evtl. eben Deinen PC mit einem 2. Verbinden, dort Terminalprogramm
aufmachen und schauen, was Dein Programm sendet.
usw. usw.
PS: als Terminalprogramm nutze ich immernoch gern die alte Version von
Teraterm. Ist unkompliziert zu handhaben und macht, was es soll. :-)
Gruß aus Berlin
Michael
Stefan B. wrote:
> µC aus der Fassung raus und an der Fassung die Pins RXD udn TXD brücken.> Dann sollte beim Senden mit Terminalprogramm auf dem PC der gesendete> Text als Echo zurückkommen. Damit wäre die RS232-Hardware auf> grundsätzliche Funktion getestet. Die TXD Leitung auf dem einseitig> angeschlossenen Kabel kann man mit einem Mutimeter finden. Sie führt iM> Gegensatz zur RXD Leitung Spannung gegen GND auf dem Kabel.
Könntest du mir das bitte ein wenig genauer erklären, wie du das da oben
meinst? Wie meinst du das mit µC aus der Fassungraus?...
MfG
Atmega168
Ahm, meine Experimentierboards sind alle mit IC-Fassungen aufgebaut und
in denen steckt eine PDIP-Version des AVRs. Wenn du einen AVR in SMD
Bauform hast, macht das natürlich keinen Sinn. Bei SMD hättest du eine
Chance, wenn die TXD/RXD Leitungen über Jumper geführt sind.
Beim meinem Aufbau kann man einfach den µC rausziehen (und so nicht
elektrisch beschädigen) und an den jetzt freiliegenden Pins der Fassung
Experimente veranstalten. Z.B. ein Drähtchen von der Pinbuchse für TXD
zu der Pinbuchse für RXD stecken.
Damit hat man ein sog. Loopbackdevice geschaffen und mit dem kann man
die ganze Signalkette (Terminalprogramm => PC-Schnittstelle => Kabel =>
Buchse => MAX232 => IC-Fassung => MAX232 => Buchse => Kabel =>
PC-Schnittstelle => Terminalprogramm) auf elektr. Funktion testen.
Nach diesem erfolgreichen Test kann es eigentlich nur noch am Anschluss
des AVRs (Versorgung, Taktquelle) und dessen Programmierung hängen. Bei
einem nicht erfolgreichen Loppbacktest sollte man zuerst in der Hardware
nach Bugs wühlen und danach kann man sich um die AVR Software kümmern,
falls erforderlich.
Achso, dann könnte ich wohl auch den Ausgang vom Max232 (R1out) und den
Eingang vom Max232 (T1In) brücken? Hätte wohl auch den gleichen Effekt
oder?
MfG
atmega168
Ja.
Es geht nur darum, dass alle Signale, die über die RS232 reinkommen ohne
den Umweg über den µC (der sie verarbeitet) sofort wieder über die
andere Leitung zurückgeschickt werden. Der PC bedient mit seinem Ausgang
quasi seinen eigenen Eingang. Nur dass halt die komplette
elektrische/elektronische Kette Kabel+MAX232 dazwischenhängt.
So hab jetzt mal durchgetestet ob vielleicht irgentein Fehler im Max232
ist, aber alles was ich via Comport gesendet habe ist wieder
zurückgekommen.
Folglich ist die Hardware und der Aufbau des Max232 richtig.
Also liegt es nur am µC-Programm. Könnte mir nicht bitte einer von euch
einen Quellcode in C posten, der via Rxd am µC einen String einliest und
ihn dann via TxD wieder zurück zum Max232 bzw. zum PC sendet?
Ich schreibe meinen String im Terminalprogramm mit
com.Open();
com.WriteLine("String");
und lese ihn mit
com.ReadLine();
com.Close();
in eine Variable ein. Folglich muss der µC solange Zeichen aus dem
Ringbuffer einlesen bis er auf \n, also neue Zeile (verwendet ja
WriteLine), stoßt.
Bitte macht mir den Gefallen und postet mir einen Quellcode in C.
MfG
Atmega168
> So hab jetzt mal durchgetestet ob vielleicht irgentein Fehler> im Max232 ist, aber alles was ich via Comport gesendet habe> ist wieder zurückgekommen.>> Folglich ist die Hardware und der Aufbau des Max232 richtig.>> Also liegt es nur am µC-Programm.
Diese letzte Schlussfolgerung kann ich noch nicht ziehen.
Du schreibst nämlich nicht, wie du durchgetestet hast - mit einem
Terminalprogramm oder mit dem selbstgeschriebenen PC-Programm. Es kann
auch ein Problem mit dem selbstgeschriebenen PC-Programm geben.
Z.B. wenn - Spekulation! - dessen Ausgabe gepuffert abläuft und du in
einem Sendeburst interner Flush) beim '\n' den kleinen 2-Byte Puffer des
µC so überfährst, dass das letzte Zeichen - das für readline()
essentielle '\n' - verloren geht.
Abgesehen dacon halte ich das für einen Bug, wenn du auf ein LF warten
willst:
1
Console.WriteLine(com.ReadTo("n"));
2
^
Und in dem PC-Programm oben ist der folgende Block drin:
1
com.WriteLine(this.richTextBox1.Text);
2
3
Threadlese=newThread(newThreadStart(tuewas));
4
lese.Start();
Rein aus dem Bauch raus ist das out-of-sequence. Den Lesethread würde
ich einrichten und starten bevor was an den µC gesendet wird.
In dem Lesethread würde ich auch nicht die Schnittstelle noch mal
initialisieren und aufmachen.
Rein aus dem Bauch raus, würde ich nämlich annehmen, dass dabei Altdaten
verworfen werden. Schmeisst das Programm eigentlich zur Laufzeit die
Exception "Bekomme nix?" - die würde ich erwarten, weil eine bereits
geöffnete Schnittstelle COM3 nochmal aufgemacht werden soll.
> Bitte macht mir den Gefallen und postet mir einen Quellcode in C.
Hier der Quellcode für das µC-Programm quasi direkt aus dem Datenblatt
für USART0 und 9600/8/N/2:
Stefan B. wrote:
> Rein aus dem Bauch raus ist das out-of-sequence. Den Lesethread würde> ich einrichten und starten bevor was an den µC gesendet wird.>> In dem Lesethread würde ich auch nicht die Schnittstelle noch mal> initialisieren und aufmachen.>> Rein aus dem Bauch raus, würde ich nämlich annehmen, dass dabei Altdaten> verworfen werden. Schmeisst das Programm eigentlich zur Laufzeit die> Exception "Bekomme nix?" - die würde ich erwarten, weil eine bereits> geöffnete Schnittstelle COM3 nochmal aufgemacht werden soll.
Ich habe mein C#-Programm leicht umgeändert: hab das mit dem Lesethread
gelassen und auch das Readto("n) ist weg.
Stat dessen steht da jetz sowas:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
namespace Serialport_test
{
public partial class Form1 : Form
{
SerialPort com;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
com = new SerialPort("com3", 9600, Parity.None, 8,
StopBits.Two);
try
{
com.Open();
com.WriteLine(this.richTextBox1.Text);
this.richTextBox2.Text=com.ReadLine();
com.Close();
}
catch(Exception e)
{
Console.WriteLine("e.getMessage()");
}
}
}
}
Mit diesem Programm habe ich den Max232 durchgetestet.
Hab das Problem jetzt gefunden und bekomme jetzt das Signal vom µC auf
mein Terminalprogramm. Allerdings sende ich mit meinem µC ein Byte mit
dem Wert 101 und bekomme im Terminalprogramm als Byte den Wert 229. Weis
jemand von euch warum das so sein könnte?
MfG Atmega168
Was war das Problem?
101dez = 0b01100101
229dez = 0b11100101
^
Hmm. Schuss ins Blaue: Doku auf der PC Seite nachlesen, wie dort das MSB
Bit7 gehandhabt wird. Initialisierung ist auf beiden Seiten bei der
Bitzahl gleich?
Ja auf beiden Seiten hab ich den 8N1-Modus eingestellt (8 Bit,no Parity,
1 Stopbit). Danke Stefan, dass du dir die Mühe gemacht hast mit den
einzelnen Binärcodes der Bytes. Werde das jetzt mal mit den 7. Bit
durchlesen.
Großen Dank=)
MfG Atmega168
>Ja auf beiden Seiten hab ich den 8N1-Modus eingestellt>SerialPort("com3", 9600, Parity.None, 8, StopBits.Two
^^^^^^^^^^^^
Widerspricht sich ein Wenig...
Also hab mir die Handhabung des 7. Bit durchgelesen, bin daraus aber
nicht schlau geworden.
Wenn ich versuche Daten vom µC an mein C#- Programm zu schicken bekomme
ich allerdings immer noch fehlerhafte Bytes im C#-Programm.
Schicken mit dem µC 101 (also 01100101)
Bekomme im Terminalprogramm zusätzlich zu 229 (also 11100101) auch noch
197 (also 11000101)
wird einer von euch daraus schlau?
01100101 = 101
11100101 = 229
11000101 = 197
MfG Atmega 168
Atmega 168 wrote:
> Also hab mir die Handhabung des 7. Bit durchgelesen, bin daraus aber> nicht schlau geworden.>> Wenn ich versuche Daten vom µC an mein C#- Programm zu schicken bekomme> ich allerdings immer noch fehlerhafte Bytes im C#-Programm.>> Schicken mit dem µC 101 (also 01100101)> Bekomme im Terminalprogramm zusätzlich zu 229 (also 11100101) auch noch> 197 (also 11000101)
Zusätzlich?
Du schickst vom µC also 1 Byte weg und am PC werden 2 empfangen?
Dann stimmt irgendwas mit deiner Baudrate nicht. Sicher, dass dein µC
wirklich mit 20 Mhz arbeitet? Also nicht nur ein Quarz angeschlossen
ist, sondern das der auch tatsächlich benutzt wird.
Atmega 168 wrote:
> hier wäre mein derzeitiger Quellcode> hab mich jetzt für die Variante 8N2 entschieden
Und, gleicher Fehler wie oben mit der 8N1 Variante?
In dem µC-Programm sehe ich keine offensichtlichen Fehler. Wie sieht es
auf der PC Seite aus, Terminalprogramm oder selbstgeschriebenes C#
Programm?
Die Fehlerbeschreibung oben ist für den Übertragungsweg µC => PC,
richtig? Wie ist es mit dem Übertragungsweg PC => µC:
Wenn du dem Atmega168 vom PC aus aus einem Terminalprogramm heraus, das
auf 9600/8/N/2 eingestellt ist, das Zeichen 101 ('e') schickst, blinkt
dann die LED an PB1 oder die LED an PB2?
Also mein C#-Programm ist selbst geschrieben. Wäre es sinnvoll den
Quellcode zu posten?
Sobald ich vom Terminal ein 'e' sende leichtet des LED an PB2. Eben
deswegen kann ich mir nicht erklären was los ist. Sende ich mit dem PC
101, bekomme ich 117 zurück. oft auch 'E'. Wenn ich hingegen mit dem µC
an den PC sende empfange ich dort statt 101 229 oder 197.
µC -> Pc
nie 01100101 = 101 (LED an PB2 blinkt)
oft 11100101 = 229 (LED an PB2 blinkt)
oft 11000101 = 197 (LED an PB2 blinkt)
Pc -> µC -> Pc
oft 01100101 = 101 (LED an PB1 blinkt aber nicht!!!!...LED an PB2
blinkt)
oft 01110101 = 117 (LED an PB2 blinkt)
Kann mir bitte einer helfen, glaub nähmlich ich mache da was mit dn Bit
nicht richtig oder so.
C# Serialportinitialisierung:
Kontrolle der Taktrate mit primitiven Mitteln: Kommentiere diese beiden
Zeilen aus
uart_putc(101);
empfangen = uart_getc_wait();
und lasse das Board laufen und zähle 3 Min. lang wie oft es blinkt. Es
sollte genau 180 mal mit höchstens 3 mal mehr oder weniger sein. Bevor
du die Mühe mit dem Zählen machst, kontrolliere, dass die Source mit
Optimierung kompiliert ist, damit die _delay_ms() Zeiten stimmen.
Wird die Baudrate richtig gerundet?
Beim Baudratenrechner sagt, daß ubrr 0x81 (129) enthalten sollte.
http://gjlay.de/helferlein/avr-uart-rechner.html
Evtl. hilft eine Umformulierung von ubrr?
>>>> und U2X_BIT je nach deiner U2X-Einstellung.>> Was ist eine U2X-Einstellung?
Der USRT arbeitet doppelt so schnell, nimmt aber weniger samples. Siehe
U2X-Bit im Handbuch bei der U(S)ART-Config
> Warum ist
1
-.6
in der ubrr-Rundung?
Oje, hatte ich mir wohl irgendwann mal überlegt.
Und bitte: F_CPU, U2X_BIT und BAUDRATE müssen Compilerzeit-Konstanten
sein. Ansonsten wird wie bei util/delay.h die float-Wumme ausgepackt.
Wo war denn der Fehler?
Die Baudrate stimp aber immernoch nicht so. Sobald ich Strings einles
und sie vergleichen will stimp dann wieder nichts. Einzelnen
Char-Zeichen hingegen kann ich vergleichen.
Was kann hier nicht stimmen. Kann mir einer von euch vielleicht einen
Quellcode posten der Strings mit Hilfe der Uart einliest und diesen
String dann vergleicht?
MfG Atmega 168
Ein Fehler in deinem C#-Code? Geht es auf einem Terminal auch nicht,
oder zeigt er da die Zeichen korrekt an?
Vielleicht ist der Host durch die eher unübliche Konfiguration 8N2
überfordert? Also mal 8N1 versuchen auf beiden Seiten.
Der Fehler von 0.2% ist an der Obergrenze des maximal empfohlenen
Fehlers. Also mal 4800 Baud mit U2X=1 versuchen, da ist der Fehler rein
rechnerisch 0, d.h. die Baudrate ist exakt.
Wackler in Steckkontakten? fliegender Aufbau? RS232-Umschaltbox in der
Leitung? Unsaubere Spannungsversorgung? Schlecht bemessene
MAX232-Kondensatoren?
Und die Nr 1 an Debugmöglichkeiten bei derartigen
Problemen:
Den empfangenen String (nicht die Einzelzeichen) gleich mal
zurückschicken damit man am Terminal kontrollieren kann, ob auch alles
so angekommen ist, wie man sich das vorstellt. Am besten noch ein
Sonderzeichen vor und hinter die Ausgabe, damit man auch sieht, ob sich
nicht irgendwo Leerzeichen, Tabulatoren oder Zeilenumbrüche im String
versteckt haben.
Karl heinz Buchegger wrote:
> Und die Nr 1 an Debugmöglichkeiten bei derartigen> Problemen:>> Den empfangenen String (nicht die Einzelzeichen) gleich mal> zurückschicken damit man am Terminal kontrollieren kann, ob auch alles> so angekommen ist, wie man sich das vorstellt. Am besten noch ein> Sonderzeichen vor und hinter die Ausgabe, damit man auch sieht, ob sich> nicht irgendwo Leerzeichen, Tabulatoren oder Zeilenumbrüche im String> versteckt haben.
Das ist ja das Problem, sende ich zum Beispiel "ein" an den µC dann
bekomm ich oft ei oft in oft e?n usw. zurück. einzelnen zeichen 'e' zB
sende ich fehlerfrei...
für Baudrate hab ich sowas eingegeben:
Johann L. wrote:
> Ein Fehler in deinem C#-Code? Geht es auf einem Terminal auch nicht,> oder zeigt er da die Zeichen korrekt an?>> Wackler in Steckkontakten? fliegender Aufbau? RS232-Umschaltbox in der> Leitung? Unsaubere Spannungsversorgung? Schlecht bemessene> MAX232-Kondensatoren?
Also Fehler mit Spannung usw hab ich nicht, C#-Progi müsste auch
einwandfrei sein...soll ich es mal posten?
MfGAtmega 168
Atmega 168 wrote:
> Das ist ja das Problem, sende ich zum Beispiel "ein" an den µC dann> bekomm ich oft ei oft in oft e?n usw. zurück. einzelnen zeichen 'e' zB> sende ich fehlerfrei...
Zeig noch mal deinen kompletten µC Code.
Atmega 168 wrote:
> Also Fehler mit Spannung usw hab ich nicht, C#-Progi müsste auch> einwandfrei sein...soll ich es mal posten?
Du kämpfst im Moment einen 2-Fronten Krieg.
Du weisst nicht ob dein Problem im µC oder im C# Teil liegt.
Also musst du einen der beiden Teile durch etwas nachweislich
funktionierendes austauschen.
Den PC-Teil kannst du zb. durch Hyperterminal oder ein anderes
Terminalprogramm ersetzen. Die meisten dieser Terminalprogramme können
auch eine Textdatei über die serielle Leitung verschicken. Da kannst du
jetzt mal dein Kommando reinschreiben und per 'Dateiversenden' mit
Full-Speed zum µC schicken (wenn du händisch tippst, hast du ja immer
Pausen zwischen den Tastenanschlägen)