Merhabalar.
Forumda çok yeniyim. Pic proje geliştirmekte de yeniyim sayılır. Bitirme ödevimi yapmak için sizlerden yardım almak istedim.
Ödevim ekg sensörünü arduino ya bağlayıp arduinoda programlayarak sonuçları c# ta tasarlayacağım arayüzde göstermek. arduino programlama kısmını hallettim sayılır bir kaç eksiği var ama az kaldı fakat c # hakkında çok bir bilgim yok. Tasarlayacağım arayüzde nabzı nasıl göstericem hangi kütüphaneyi kullanmam gerekiyor, form'a hangi göstergeyi koyucam hiç bilmiyorum. İnternette 2 gündür araştırıyorum ama pek bir şey bulamadım. Bu konuda sizlerin yardımınızı bekliyorum.
Bu projenin iki alt kısmı bulunuyor: Arduino, ve PC arayüzü. Ayrıca bu iki alt sistemin kullanacağı ortak protokol. Siz Arduino ile C# arasındaki bu protokolden hiç söz etmemişsiniz?
"C# arayüzünde ne gösterilecek" sorusunun cevabı belli: Arduino'dan hangi veriler gönderiliyorsa, onlar gösterilecek. Sizin yerinizde olsam, öncelikle bu verileri basit bir C# console programı ile DOS ekranına yazdırırdım. Böylece protokol kısmını hallettikten sonra, GUI arayüzün tasarımına geçerdim.
Üstad sanırım ben derdimi anlatamadım.
Bahsettiğiniz iki alt programdan arduino kısmı zaten tamam diyorum. c# arayüzünde ne göstericem diye de sormadım ayrıca. Ben bu iki program arasında bağlantıyı nasıl yapıcam? ekg sensöründen gönderilen sinyalleri hangi göstergeyi kullanarak yapıcam bunları sordum. Bununla ilgili örnek varsa çok yardımcı olur.
edit: elde etmem gereken görüntü bu tarz olacak. ECG Machine (http://www.youtube.com/watch?v=UJRxHfsLoZo#ws)
O arkadaş ta benim gibi arduino'yu android anlamıştır belki de :) Diyorum hem android hem pc niye..
Yapacağın şu: arduino kablosunu pc' ye takacaksın muhtemelen COMx adında sanal port olarak görünecek. C# form app başlatacaksın ve oraya portu ekleyip kullanmaya başlayacaksın.
Artık neyi nasıl ekranda göstermek istersin sana kalmış.
NOT: İki program arası bağlantı diye bir şey olmuyor orada... Protokol (farklı cihaz sistem vb. haberleşmesi için ortak dil) ortak olursa mesela seri haberleşme gibi, senin arduino da çalışan C programın PC de çalışan C# ile konuşabiliyor.
Yapacağın C# da seri port kullanımı.
Alıntı yapılan: atioky_216 - 22 Aralık 2013, 00:11:24
O arkadaş ta benim gibi arduino'yu android anlamıştır belki de :) Diyorum hem android hem pc niye..
Yok, ben Arduino olarak anlamıştım! Herhalde şuradaki Arduino shield kullanılmakta: https://www.olimex.com/Products/Duino/Shields/SHIELD-EKG-EMG/ (https://www.olimex.com/Products/Duino/Shields/SHIELD-EKG-EMG/)
Şu projede açık kaynak C# grafik/şema çizim kütüphanesi ile ilgili bilgi var:
http://www.codeproject.com/Articles/32836/A-simple-C-library-for-graph-plotting (http://www.codeproject.com/Articles/32836/A-simple-C-library-for-graph-plotting)
Aşağıdaki gibi bir GUI elde etmek mümkün:
(http://www.codeproject.com/KB/miscctrl/GraphPlotting/graph_stacked.png)
Ayrıca şurada açık kaynak bir C# EKG yazılımı var: http://sourceforge.net/projects/ecgtoolkit-cs/ (http://sourceforge.net/projects/ecgtoolkit-cs/)
Belki işe yarayabilir.
Şuradaki stackoverflow sorusu aynı konuda: http://stackoverflow.com/questions/1299816/plot-ecg-in-winforms (http://stackoverflow.com/questions/1299816/plot-ecg-in-winforms)
Şu kaynak C/C++ ile yazılmış EKG kütüphanesi: http://www.codeproject.com/Articles/4353/ECG-recording-storing-filtering-and-recognition (http://www.codeproject.com/Articles/4353/ECG-recording-storing-filtering-and-recognition)
Çok teşekkür ederim arkadaşlar. Çok yardımcı oldunuz. Allah razı olsun. Deneyip tekrar döneceğim inşaallah.
kolay gelsin.
edit: bu arada evet olimex'in ürettiği shield'i kullanmaktayım. bulgaristandan sipariş verdik çok masraf yaptırdı bana. öğrenciyim ben daha :D
Projede baya ilerleme kaydetmiş bulunmaktayım. Yalnız hata alıyorum sizlere danışmak istedim tekrar.
arduino kod/**********************************************************/
/* Demo program for: */
/* Board: SHIELD-EKG/EMG + Olimexino328 */
/* Manufacture: OLIMEX */
/* COPYRIGHT (C) 2012 */
/* Designed by: Penko Todorov Bozhkov */
/* Module Name: Sketch */
/* File Name: ShieldEkgEmgDemo.ino */
/* Revision: Rev.A */
/* -> Added is suppport for all Arduino boards. */
/* This code could be recompiled for all of them! */
/* Date: 19.12.2012 */
/* Built with Arduino C/C++ Compiler, version: 1.0.3 */
/**********************************************************/
/**********************************************************
Purpose of this programme is to give you an easy way to
connect Olimexino328 to ElectricGuru(TM), see:
[url]https://www.olimex.com/Products/EEG/OpenEEG/EEG-SMT/resources/ElecGuru40.zip[/url]
where you'll be able to observe yours own EKG or EMG signal.
It is based on:
***********************************************************
* ModularEEG firmware for one-way transmission, v0.5.4-p2
* Copyright (c) 2002-2003, Joerg Hansmann, Jim Peters, Andreas Robinson
* License: GNU General Public License (GPL) v2
***********************************************************
For proper communication packet format given below have to be supported:
///////////////////////////////////////////////
////////// Packet Format Version 2 ////////////
///////////////////////////////////////////////
// 17-byte packets are transmitted from Olimexino328 at 256Hz,
// using 1 start bit, 8 data bits, 1 stop bit, no parity, 57600 bits per second.
// Minimial transmission speed is 256Hz * sizeof(Olimexino328_packet) * 10 = 43520 bps.
struct Olimexino328_packet
{
uint8_t sync0; // = 0xa5
uint8_t sync1; // = 0x5a
uint8_t version; // = 2 (packet version)
uint8_t count; // packet counter. Increases by 1 each packet.
uint16_t data[6]; // 10-bit sample (= 0 - 1023) in big endian (Motorola) format.
uint8_t switches; // State of PD5 to PD2, in bits 3 to 0.
};
*/
/**********************************************************/
#include <compat/deprecated.h>
#include <FlexiTimer2.h>
//http://www.arduino.cc/playground/Main/FlexiTimer2
// All definitions
#define NUMCHANNELS 6
#define HEADERLEN 4
#define PACKETLEN (NUMCHANNELS * 2 + HEADERLEN + 1)
#define SAMPFREQ 256 // ADC sampling rate 256
#define TIMER2VAL (1024/(SAMPFREQ)) // Set 256Hz sampling frequency
#define LED1 13
#define CAL_SIG 9
// Global constants and variables
volatile unsigned char TXBuf[PACKETLEN]; //The transmission packet
volatile unsigned char TXIndex; //Next byte to write in the transmission packet.
volatile unsigned char CurrentCh; //Current channel being sampled.
volatile unsigned char counter = 0; //Additional divider used to generate CAL_SIG
volatile unsigned int ADC_Value = 0; //ADC current value
//~~~~~~~~~~
// Functions
//~~~~~~~~~~
/****************************************************/
/* Function name: Toggle_LED1 */
/* Parameters */
/* Input : No */
/* Output : No */
/* Action: Switches-over LED1. */
/****************************************************/
void Toggle_LED1(void){
if((digitalRead(LED1))==HIGH){ digitalWrite(LED1,LOW); }
else{ digitalWrite(LED1,HIGH); }
}
/****************************************************/
/* Function name: toggle_GAL_SIG */
/* Parameters */
/* Input : No */
/* Output : No */
/* Action: Switches-over GAL_SIG. */
/****************************************************/
void toggle_GAL_SIG(void){
if(digitalRead(CAL_SIG) == HIGH){ digitalWrite(CAL_SIG, LOW); }
else{ digitalWrite(CAL_SIG, HIGH); }
}
/****************************************************/
/* Function name: setup */
/* Parameters */
/* Input : No */
/* Output : No */
/* Action: Initializes all peripherals */
/****************************************************/
void setup() {
noInterrupts(); // Disable all interrupts before initialization
// LED1
pinMode(LED1, OUTPUT); //Setup LED1 direction
digitalWrite(LED1,LOW); //Setup LED1 state
pinMode(CAL_SIG, OUTPUT);
//Write packet header and footer
TXBuf[0] = 0xa5; //Sync 0
TXBuf[1] = 0x5a; //Sync 1
TXBuf[2] = 2; //Protocol version
TXBuf[3] = 0; //Packet counter
TXBuf[4] = 0x02; //CH1 High Byte
TXBuf[5] = 0x00; //CH1 Low Byte
TXBuf[6] = 0x02; //CH2 High Byte
TXBuf[7] = 0x00; //CH2 Low Byte
TXBuf[8] = 0x02; //CH3 High Byte
TXBuf[9] = 0x00; //CH3 Low Byte
TXBuf[10] = 0x02; //CH4 High Byte
TXBuf[11] = 0x00; //CH4 Low Byte
TXBuf[12] = 0x02; //CH5 High Byte
TXBuf[13] = 0x00; //CH5 Low Byte
TXBuf[14] = 0x02; //CH6 High Byte
TXBuf[15] = 0x00; //CH6 Low Byte
TXBuf[2 * NUMCHANNELS + HEADERLEN] = 0x01; // Switches state
// Timer2
// Timer2 is used to setup the analag channels sampling frequency and packet update.
// Whenever interrupt occures, the current read packet is sent to the PC
// In addition the CAL_SIG is generated as well, so Timer1 is not required in this case!
FlexiTimer2::set(TIMER2VAL, Timer2_Overflow_ISR);
FlexiTimer2::start();
// Serial Port
Serial.begin(57600);
//Set speed to 57600 bps
// MCU sleep mode = idle.
//outb(MCUCR,(inp(MCUCR) | (1<<SE)) & (~(1<<SM0) | ~(1<<SM1) | ~(1<<SM2)));
interrupts(); // Enable all interrupts after initialization has been completed
}
/****************************************************/
/* Function name: Timer2_Overflow_ISR */
/* Parameters */
/* Input : No */
/* Output : No */
/* Action: Determines ADC sampling frequency. */
/****************************************************/
void Timer2_Overflow_ISR()
{
// Toggle LED1 with ADC sampling frequency /2
Toggle_LED1();
//Read the 6 ADC inputs and store current values in Packet
for(CurrentCh=0;CurrentCh<6;CurrentCh++){
ADC_Value = analogRead(CurrentCh);
TXBuf[((2*CurrentCh) + HEADERLEN)] = ((unsigned char)((ADC_Value & 0xFF00) >> 8)); // Write High Byte
TXBuf[((2*CurrentCh) + HEADERLEN + 1)] = ((unsigned char)(ADC_Value & 0x00FF)); // Write Low Byte
}
// Send Packet
for(TXIndex=0;TXIndex<17;TXIndex++){
Serial.write(TXBuf[TXIndex]);
}
// Increment the packet counter
TXBuf[3]++;
// Generate the CAL_SIGnal
counter++; // increment the devider counter
if(counter == 12){ // 250/12/2 = 10.4Hz ->Toggle frequency
counter = 0;
toggle_GAL_SIG(); // Generate CAL signal with frequ ~10Hz
}
}
/****************************************************/
/* Function name: loop */
/* Parameters */
/* Input : No */
/* Output : No */
/* Action: Puts MCU into sleep mode. */
/****************************************************/
void loop() {
__asm__ __volatile__ ("sleep");
}
C # GUI
using System.Windows.Forms;
using System.IO.Ports;
using ZedGraph;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
private SerialPort port;
private static int tickStart = 0; //timer
private double counter = 0;
private int addindex = 0;
private double[] datasend = new double[10000];
private static ArrayList portdata;
private Thread newthread;
private Thread beepthread;
private Thread OLthread;
private Thread qrsthread;
private Thread threshdecrement;
private Boolean beeper = false;
private double qrsaverage = 0;
private double finitedif = 0;
private double thresh = 10;
private double[] qrs = new double[10]; //qrs detection array
private double[] recentd = new double[150]; //overload detection array
private double[] lowarray = new double[150];
private double[] higharray = new double[150];
private Boolean gainselect = false;
private double heartbeat = 0;
private DateTime oldbeep = DateTime.Now;
private DateTime newbeep = DateTime.Now;
public Form1()
{
InitializeComponent();
for (int i = 0; i < 150; i++) //overload checker
{
lowarray[i] = 0;
}
for (int j = 0; j < 150; j++)
{
higharray[j] = 1000;
}
// This is to remove all plots
zedGraphControl1.GraphPane.CurveList.Clear();
// GraphPane object holds one or more Curve objects (or plots)
GraphPane pane = zedGraphControl1.GraphPane;
//Set up Graph Pane
pane.Fill.Color = System.Drawing.Color.RoyalBlue;
pane.Title.Text = "ECG Machine";
pane.XAxis.Title.Text = "Time (Seconds)";
pane.YAxis.Title.Text = "Voltage (mV)";
pane.Legend.IsVisible = false;
pane.XAxis.Scale.MajorUnit = DateUnit.Millisecond;
pane.XAxis.Scale.MinorUnit = DateUnit.Millisecond;
zedGraphControl1.GraphPane.XAxis.Scale.Max = 30;
// zedGraphControl1.GraphPane.XAxis.Scale.Min = 0;
zedGraphControl1.GraphPane.YAxis.Scale.Max = 1024;
zedGraphControl1.GraphPane.YAxis.Scale.Min = 0;
zedGraphControl1.IsShowHScrollBar = true;
zedGraphControl1.IsAutoScrollRange = true;
zedGraphControl1.AxisChange();
// PointPairList holds the data for plotting, X and Y arrays
PointPairList points = new PointPairList();
// Add cruves to myPane object
LineItem myCurve = pane.AddCurve("Heart Rate", points, Color.Red, SymbolType.None);
tickStart = Environment.TickCount;
portdata = new ArrayList();
}
private void EstablishConnection()
{
port = new SerialPort("COM3", 57600, Parity.None, 8, StopBits.One);
port.Handshake = Handshake.None;
port.ReadTimeout = 500;
port.WriteTimeout = 500;
if (!(port.IsOpen == true)) port.Open();
port.Write("B");
port.Write("D");
port.Write("E");
}
/* This begins data reading from serial Port */
private void button1_Click(object sender, EventArgs e)
{
EstablishConnection();
button1.Enabled = false;
pointHP.Select();
newthread = new Thread(new ThreadStart(this.reader));
newthread.IsBackground = true;
newthread.Start();
beepthread = new Thread(new ThreadStart(this.beepcontrol));
beepthread.IsBackground = true;
beepthread.Start();
OLthread = new Thread(new ThreadStart(this.OLdetection));
OLthread.IsBackground = true;
OLthread.Start();
qrsthread = new Thread(new ThreadStart(this.qrsdetection));
qrsthread.IsBackground = true;
qrsthread.Start();
threshdecrement = new Thread(new ThreadStart(this.threshdec));
threshdecrement.IsBackground = true;
threshdecrement.Start();
timer1.Interval = 1;
timer1.Enabled = true;
timer1.Start(); //start timer to add points to chart
}
private void threshdec()
{
while (port.IsOpen)
{
if (thresh > 0)
{
if (!gainselect)
{
thresh = thresh - 1;
Thread.Sleep(80);
}
else
{
thresh = thresh - 2;
Thread.Sleep(20);
}
}
}
}
private void qrsdetection()
{
while (port.IsOpen)
{
if (addindex > 10)
{
int sum = 0;
int C = portdata.Count - 1;
for (int i = 0; i < 10; i++)
{
qrs[i] = (double)portdata[C - (9 - i)];
}
foreach (int num in qrs)
{
sum += num;
}
qrsaverage = sum / 10; //smooth out signal
finitedif = qrs[9] - qrsaverage;
if (finitedif > thresh)
{
thresh = finitedif;
if (thresh > 8)
{
beeper = true;
}
}
}
}
}
private void OLdetection()
{
while (port.IsOpen)
{
if (addindex > 150) {
int C = portdata.Count - 1;
for (int i = 0; i < recentd.Length; i++)
{
recentd[i] = (double)portdata[C - (149 - i)];
}
if (lowcheck(recentd) || highcheck(recentd))
{
setOL("Overload");
//set to 5 hp filter
Thread.Sleep(150);
selectfilter();
}
else
{
setOL("");
}
}
}
}
private void selectfilter()
{
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate() { selectfilter(); }));
}
else
{
pointHP.Select();
pointHP.Enabled = false;
port.Write("D");
thresh = 0;
}
}
private void setOL(string text)
{
if (this.OverLoad.InvokeRequired)
{
try
{
this.Invoke(new Action<string>(setOL), new object[] { text });
return;
}
catch (ObjectDisposedException) { }
}
try
{
OverLoad.Text = text;
}
catch (Win32Exception) { }
}
private void setHeartRate(double bpm)
{
if (this.HeartRate.InvokeRequired)
{
try
{
this.Invoke(new Action<double>(setHeartRate), new object[] { bpm });
return;
}
catch (ObjectDisposedException) { }
}
try
{
HeartRate.Text = String.Format("{0:0.0}", bpm);
}
catch (Win32Exception) { }
}
private void beepcontrol()
{
while (port.IsOpen)
{
if (beeper)
{
Thread.Sleep(80); //makes sure it doesnt beep twice within 1/120 sec
Console.Beep();
//get BPM
oldbeep = newbeep;
newbeep = DateTime.Now;
double span = (newbeep-oldbeep).Milliseconds;
heartbeat = 60000 / span;
setHeartRate(heartbeat);
beeper = false;
}
}
}
public void reader()
{
while (port.IsOpen)
{
double pt;
string dat = port.ReadLine();
if (Double.TryParse(dat, out pt)) //if data read is a double value
{
portdata.Add(pt);
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
//make sure curvelist isnt empty
if (zedGraphControl1.GraphPane.CurveList.Count <= 0)
return;
//get first curve in graph
LineItem curve = zedGraphControl1.GraphPane.CurveList[0] as LineItem;
if (curve == null)
return;
IPointListEdit list = curve.Points as IPointListEdit;
if (addindex < portdata.Count)
{
list.Add(counter, (double)portdata[addindex]);
addindex = addindex + 20;
counter = counter + .02;
}
zedGraphControl1.GraphPane.XAxis.Scale.Max = counter + 5;
zedGraphControl1.GraphPane.XAxis.Scale.Min = zedGraphControl1.GraphPane.XAxis.Scale.Max - 10;
zedGraphControl1.AxisChange();
zedGraphControl1.Invalidate();
zedGraphControl1.Refresh();
}
private void NotchBox_CheckedChanged(object sender, EventArgs e)
{
if (NotchBox.Checked)
{
port.Write("F");
}
else
{
port.Write("E");
thresh = 0;
}
}
private void GainBox_CheckedChanged(object sender, EventArgs e)
{
thresh = 0;
if (GainBox.Checked)
{
port.Write("A");
gainselect = true;
}
else
{
port.Write("B");
gainselect = false;
}
}
private void radioButton2_CheckedChanged(object sender, EventArgs e)
{
pointHP.Enabled = false;
fiveHP.Enabled = true;
port.Write("D");
}
private void fiveHP_CheckedChanged(object sender, EventArgs e)
{
fiveHP.Enabled = false;
pointHP.Enabled = true;
port.Write("C");
}
private void Snapshot_Click(object sender, EventArgs e)
{
this.Hide();
int currentday,currentmonth,currentyear,currenthour,currentminute,currentsecond;
double currentheartrate;
string currenttime, currentdate;
currentday = DateTime.Today.Day;
currentmonth = DateTime.Today.Month;
currentyear = DateTime.Today.Year;
currenttime = DateTime.Now.ToString("hh:mm:ss tt", System.Globalization.DateTimeFormatInfo.InvariantInfo);
currentdate = DateTime.Now.ToString();
currenthour = DateTime.Now.Hour;
currentminute = DateTime.Now.Minute;
currentsecond = DateTime.Now.Second;
currentheartrate = heartbeat;
if (addindex > 9999)
{
for (int i = 0; i < 10000; i++)
{
datasend[i] = (double)portdata[portdata.Count - (10000 - i)];
}
Database d = new Database(currentheartrate,currentday, currentmonth, currentyear, currenthour, currentminute, currentsecond, currentdate, currenttime, datasend,this);
//timer1.Stop();
d.Show();
}
else
{
MessageBox.Show("Not Enough Data Collected");
this.Show();
}
}
private Boolean lowcheck(double[] a)
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] != lowarray[i])
return false;
}
return true;
}
private Boolean highcheck(double[] a)
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] < higharray[i])
return false;
}
return true;
}
/* Unused methods */
private void chart1_Click(object sender, EventArgs e) { }
private void Form1_Load(object sender, EventArgs e) { }
private void zedGraphControl1_Load(object sender, EventArgs e){ }
private void textBox1_TextChanged(object sender, EventArgs e) { }
private void Overload_TextChanged(object sender, EventArgs e) { }
}
}
aldığım hata ise string dat = port.ReadLine(); kod satırı zaman aşımına uğradı diyor. anladığım kadarıyla devreden bilgileri ya çok geç okuyor ya da hiç okumuyor.
Şu kod satrıındaki tüm tanımlar doğru mu?
port = new SerialPort("COM3", 57600, Parity.None, 8, StopBits.One);
Baund değerini değiştirip denemeler yapın bir de.
Hız farkı olabilir Arduino çıkışı ile PC girişi arasında
Ki 57600 baund oldukça yüksek bir hız.
baund -> baud
;-)
baud hızıyla alakalı olduğunu sanmıyorum. establishconnection'ın altındaki point.write("B") nin ve diğerlerinin içini değiştirmem gerekiyor bence. ama ne yazacağımı bilemedim.
C# ile Arduino kodlarinin arasinda baglanti yok.
C# programi degerleri tek tek bekliyor, text olarak yazilmis ve CR ile biten. ornegin "14.45\r". O yüzden readLine timeout veriyor.
Olimex'teki abiler ise header + binary olarak 6 kanal ADC (16 bit üzerinden) girisilerini gönderiyor.
atioky'nin ön tespiti dogru imis :
Alıntı YapNOT: İki program arası bağlantı diye bir şey olmuyor orada... Protokol (farklı cihaz sistem vb. haberleşmesi için ortak dil) ortak olursa mesela seri haberleşme gibi, senin arduino da çalışan C programın PC de çalışan C# ile konuşabiliyor.
Alıntı yapılan: picusta - 25 Aralık 2013, 20:30:10
C# ile Arduino kodlarinin arasinda baglanti yok.
C# programi degerleri tek tek bekliyor, text olarak yazilmis ve CR ile biten. ornegin "14.45\r". O yüzden readLine timeout veriyor.
Olimex'teki abiler ise header + binary olarak 6 kanal ADC (16 bit üzerinden) girisilerini gönderiyor.
atioky'nin ön tespiti dogru imis :
arduinodaki gönderilen kodları stringe çevirip sonuna \r eklersem sorun çözülür mü yani? biraz daha açar mısınız?
ya da c# taki beklenen verileri sayısala mı çevirmeliyim? öyleyse nereleri değiştirmem gerekir?
seri porttan hiç anlamıyorum daha bu ilk projem affınıza sığınıyorum.
lütfen yardımcı olur musunuz?
Arduino da degerini println fonksyonu çagirirsan olur.
Sonuna otomatik olarak Carriage Return (CR , veya 13 degerindeki byte (\r ) örnek :
Serial.println("14.56");
Koddaki timer2 overflow interuptta degistirmen gereken :
//Read the 1 ADC inputs and store current values in Packet
ADC_Value = analogRead(CurrentCh);
//send packet
Serial.println(ADC_Value );
CurrentCh degiskeninde ise hangi ADC girisi ile ilgileniyorsan o olacak.
C# :
C# ta port.ReadLine(); fonksyonu CR alana kadar bekler.
"portdata" listesi sonsuza kadar gidebilir, arada bir bosaltmak gerekir.
Ek bir not:
Serial.Println() fonksiyonu satır sonuna iki karakter ekler: ASCII 13, '\r' (satırbaşı - carriage return - karakteri) ve ASCII 10, '\n' (yeni satır - newline - karakteri).
Windows satır sonunu bu iki karakterle gösterir.
Linux (Unix) sistemleri ise satır sonu için sadace newline karakteri kullanır.
cevaplarınız için teşekkürler arkadaşlar fakat yine olmadı. c# kodlarını sıfırdan yazmaya başlıcam artık.
sonuç olarak geldiğim nokta bir richtextbox'a sensörden gelen verileri yazdırabilmek oldu fakat grafiğe dökemiyorum. ayrıca gelen veriler arduino derleyicisindeki serial monitörde sürekli akarken c#'a sadece bir yere kadar geliyor. bu verinin sürekli akmasını sağlayabileceğim bir kod var mı ?