PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C#:Wie Nachricht vom Mikrocontroller über dem Com-Port empfangen



Staind
27.05.2011, 14:16
Hallo,

Bin leider noch blutiger Anfänger im programmieren von uC.
(Bin vor 2 Wochen angefangen mit dem assembler Programmieren, sitze aber
teilweise Nachmittags 6-8 Stunden vor mein mC und versuche assembler zu
verstehen, was auch eigentlich ganz gut klappt :-) )
also ich bin momentan voll im rausch zu lernen wie man uC programmiert
und wie man sie benutzt.

Habe das einsteiger set von Myavr. Dort geht es im aktuellen Kapitel um
das Senden über den Com Port.

Das assembler Programm funktioniert so weit. Also der uC sendet das wort
"Hallo " per knopfdruck über das UART Datenregister. Dieses kann ich auch mit der
beigefügten Software myAVR Controlcenter Build 698 am Pc empfangen.

Hier mal das mC Programm

[
;+-----------------------------------------------------------------------------
;| Title : Assembler Grundgerüst für ATmega8
;+-----------------------------------------------------------------------------
;| Funktion : ...
;| Schaltung : ...
;+-----------------------------------------------------------------------------
;| Prozessor : ATmega8
;| Takt : 3,6864 MHz
;| Sprache : Assembler
;| Datum : ...
;| Version : ...
;| Autor : ...
;+-----------------------------------------------------------------------------
.include "AVR.H"
;------------------------------------------------------------------------------
begin:
rjmp main ; RESET External Pin, Power-on Reset, Brown-out Reset and Watchdog Reset
reti ; INT0 External Interrupt Request 0
reti ; INT1 External Interrupt Request 1
reti ; TIMER2 COMP Timer/Counter2 Compare Match
reti ; TIMER2 OVF Timer/Counter2 Overflow
reti ; TIMER1 CAPT Timer/Counter1 Capture Event
reti ; TIMER1 COMPA Timer/Counter1 Compare Match A
reti ; TIMER1 COMPB Timer/Counter1 Compare Match B
reti ; TIMER1 OVF Timer/Counter1 Overflow
reti ; TIMER0 OVF Timer/Counter0 Overflow
reti ; SPI, STC Serial Transfer Complete
reti ; USART, RXC USART, Rx Complete
reti ; USART, UDRE USART Data Register Empty
reti ; USART, TXC USART, Tx Complete
reti ; ADC ADC Conversion Complete
reti ; EE_RDY EEPROM Ready
reti ; ANA_COMP Analog Comparator
reti ; TWI 2-wire Serial Interface
reti ; SPM_RDY Store Program Memory Ready
;------------------------------------------------------------------------------
main:
ldi r16,hi8(RAMEND) ; Main program start
out SPH,r16 ; Set Stack Pointer to top of RAM
ldi r16,lo8(RAMEND)
out SPL,r16
sbi UCSRB,3
ldi r16, 23
out UBRRL,r16
cbi DDRD,2
sbi PORTD,2



;------------------------------------------------------------------------------
mainloop: wdr
sbis PIND,2
rjmp Taster1
rjmp mainloop
;------------------------------------------------------------------------------
Taster1: ldi r16,'H'
rcall putChar
ldi r16,'a'
rcall putChar
ldi r16,'l'
rcall putChar
ldi r16,'l'
rcall putChar
ldi r16,'o'
rcall putChar
ldi r16,' '
rcall putChar
ret
putChar: sbis UCSRA,5
rjmp putChar
out UDR,r16
ret




Jetzt möchte ich allerdings dieses über mein C# Programm Empfangen.
Dort weiß ich aber noch nicht wie ich dieses realisieren kann.
Das Wort "Hallo" (bzw er wiederholt das ein paar mal, da der tastendruck zu lang ist...)soll einfach nur zusammengesetzt, und in einer TextBox
ausgegeben werden sobald ich den button1 drücke.
Der Port an dem mein uC sitzt ist der Com Port 3.

Hier mein aktuelles C# Programm (in C# kenne ich mich eingentlich gut
aus)


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 WindowsFormsApplication1
{
public partial class Form1 : Form
{
SerialPort port = new SerialPort("COM3",9600,Parity.None,8,StopBits.One);

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = "???";
}
}
}





Es wäre nett wenn mir einer das Programm zu ende programmieren würde.
Vielleicht erkenne ich die funktionsweise so. Ansonsten würde ich noch
1-2 fragen stellen :-)

mfg André

Ceos
27.05.2011, 14:26
zuerst einmal musst du dir einen SerialPort aus der Toolbox in dein Programm ziehen, dann die Baudrate einstellen und dich an das "received"-Event hängen ... DA musst du dann deine Methode schreiben um die Daten aus dem COM zu lesen und an das Textfeld zu senden .... du wirst wenn du es erfolgreich bis hierhin geschafft hast eine invalid Thread-Access-Violation bekommen weil du aus einem Asynchronen Prozess heraus versucht den Inhalt der Textbox zu verändern!

Alternativ kannst du auch die Daten vom COM-Port in einen String schreiben und dann in deiner Button1_Click Methode den Inhalt des Strings in dein Textfeld schreiben lassen, dann umgehst du die Violation aber es updatet sich nicht von allein ^^ (man könnte auch nen Timer benutzen)

achja, einen Button für connect und disconnect zum ComPort wären auch nciht verkehrt

PS: DIe Thread Access Violation sauber zu beheben ist eine spur zu kompliziert um sie in diesem Post abzuhandeln, schaff es erstmal bis zum Fehler ^^

Staind
27.05.2011, 14:43
als erstes danke für die antwort!

werde ich nachher einmal ausprobieren.

vielleicht hat einer ja auch ein link (tutorial) in dem genauer beschrieben ist wie sowas funktioniert, bzw wie man über c# mit den mikrocontroller komunizieren kann.

lokirobotics
27.05.2011, 14:50
using System;
using System.IO.Ports;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private SerialPort _port;

public Form1()
{
InitializeComponent();
_port = new SerialPort("COM3",9600,Parity.None,8,StopBits.One)
_port.DataReceived += PortDataReceived;
}

private void button1_Click(object sender, EventArgs e)
{
//clear text
textBox1.Text = String.Empty;
}

void PortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (!(sender is SerialPort)) return;
var port = (SerialPort) sender;
textBox1.Invoke(new StringDelegate(DisplayString), port.ReadExisting());
}

void DisplayString(string value)
{
textBox1.Text += value;
}
}

public delegate void StringDelegate(string value);
}
Edit: Die ThreadAccessViolation sollte nur bei ner WPF-Application auftreten. Bei WinForms läuft das alles in einem Thread.

Ceos
27.05.2011, 15:54
dass alles in einem Thread läuft stimmt aber nicht ganz, der Serial Port erzeugt sein Event asynchron

textBox1.Invoke(new StringDelegate(DisplayString), port.ReadExisting());

nja du hast es ja auch geschickt verpackt, aber erklären sollte man es zwecks verständnis finde ich ^^

Widgets sind halt generell gesperrt gegen Thread-Fremde zugriffe ... und der Serial Port hat seinen eigenen Thread, die "DataReceived"-Methode wird von dem Thread aufgerufen

durch die Invoke-Methode (die man auch etwas ausführlicher schreiben kann und mit einer if-abfrage für die Prüfung der Notwendigkeit versehen kann) wird der Aufruf indirekt an den Thread des Objektes übergeben und in diesem Kontext ausgeführt, was legal ist!

Staind
27.05.2011, 18:28
@ lokirobotics

vielen dank für das programm und deine mühe! hätte nicht gedacht das sich einer wirklich zeit nimmt und mir einer das programm schreibt.

kann es leider heute nicht mehr testen, aber morgen werde ich das sofort ausprobieren.

@ ceos

auch an dir ein danke für deine mühe

hoffentlich funktioniert das, bin schon ganz gespannt

lokirobotics
27.05.2011, 20:29
@ceos: Ja, stimmt. DataReceived wird in nem extra Thread ausgelöst.
Aber ich habs ja gleich Threadsave implementiert ;D
Aber gerne auch nochmal die Erklärung:

textBox1.Invoke(...) sorgt dafür, dass das Aktualisieren des Textfeldes in dem dem Textfeld zugehörigen Thread stattfindet. Man bittet das Textfeld praktisch, die übergebene Funktion (DisplayString) im eigenen Thread auszuführen (theoretisch hätte man auch das Form aufrufen können).

Der Delegate ist ein Funktionszeiger, der die auszuführende Funktion hält. Der zweite Parameter sind die Daten, die der Funktion übergeben werden sollen.

Ich seh grad, dass der Code gar nicht laufen kann. Der Port wird weder geöffnet, noch geschlossen. Das musst du noch einfügen.

shedepe
27.05.2011, 21:40
Noch eine kleine Anmerkung was das Programmieren in C# generell angeht:
Viele Informationen und auch Codebeispiele finden sich im microsoft devoloper network (msdn).
Zur SerialPort-Klasse lässt sich dort das hier finden:
http://msdn.microsoft.com/de-de/library/system.io.ports.serialport.aspx

nanoBean
28.05.2011, 05:26
Falls du probleme mit den umlauten bekommst, hilft dir System.text.encoding.ascii.getstring(...) weiter. Ich hoffe, dass das so ungefaehr passt. Kann grad nicht nachsehen. Wenn du nicht ascii sendest, musst du natuerlich .ascii. durch deine zeichenkodierung ersetzen. (und sorry wegen der kleinschreibung)