[英]C# Serial Communication to Arduino
我正在開展一個項目,涉及我的客戶端軟件通過串行通信將數據發送到Arduino微控制器AtMega32U4。 到目前為止,我已經查看了很多已回答的問題,但沒有一個問題與我的問題有關。 但是,我相信我的問題可能僅限於線程問題或Arduino自動復位問題。
代碼1:
public MainForm()
{
InitializeComponent();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.DtrEnable = true;
//serialPort1.RtsEnable = true;
}
private void button3_Click(object sender, EventArgs e)
{
// Disables button while processing
button3.Enabled = false;
GetDir dir = new App.GetDir();
dir.getCoords(Origin.Text, Destination.Text, Application.StartupPath + @"\temp2.html", "temp2.xml");
dataBrowser.Navigate(Application.StartupPath + @"\temp2.html");
dataBrowser.Update();
waypoints = dir.coordsLat.Length;
counter = dir.coordsLat.Length;
coords = new double[dir.coordsLat.Length, 2];
for (int i = 0; i < counter; i++)
{
coords[i, 0] = (Convert.ToDouble(dir.coordsLat[i]));
coords[i, 1] = (Convert.ToDouble(dir.coordsLon[i]));
}
//serialPort1.Close();
//System.Threading.Thread.Sleep(1000);
if (serialPort1.IsOpen && !doubleClick)
{
serialPort1.Close();
System.Threading.Thread.Sleep(2000);
try
{
serialPort1.Open();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
System.Threading.Thread.Sleep(2000);
}
else
{
if (!serialPort1.IsOpen)
{
try
{
serialPort1.Open();
doubleClick = true;
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
System.Threading.Thread.Sleep(2000);
serialPort1.Write("^");
System.Threading.Thread.Sleep(1000);
Console.WriteLine('^');
//button3.Enabled = true;
}
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//System.Threading.Thread.Sleep(1000);
readData = serialPort1.ReadLine();
Console.WriteLine(readData);
// If microcontroller sends "&", it is ready to receive next piece of data
if (readData == "&")
{
sendRequest = true;
}
else
{
sendRequest = false;
}
// Write next piece of data to microcontroller if it is ready
if (sendRequest)
{
this.BeginInvoke( new EventHandler (write_serialPort1));
}
}
在代碼1的調試期間,永遠不會調用事件處理程序(serialPort1_DataReceived)。 在這個過程中,當控制台輸出'^'兩次時,會以某種方式調用button3_click兩次。 之后,客戶端停止運轉,因為沒有收到任何信息。 請記住,一旦收到回旋('^'),Arduino將以&符號('&')作出響應。 Arduino代碼已經在Arduino IDE上進行了測試,似乎工作正常。 我相信button3_click被調用兩次的問題來自button3_down和button3_up。
但是,我能夠通過代碼2繞過這個問題。但也打了另一個磚牆。
代碼2:
private void button3_Click(object sender, EventArgs e)
{
// Disables button while processing
button3.Enabled = false;
GetDir dir = new App.GetDir();
dir.getCoords(Origin.Text, Destination.Text, Application.StartupPath + @"\temp2.html", "temp2.xml");
dataBrowser.Navigate(Application.StartupPath + @"\temp2.html");
dataBrowser.Update();
waypoints = dir.coordsLat.Length;
counter = dir.coordsLat.Length;
coords = new double[dir.coordsLat.Length, 2];
for (int i = 0; i < counter; i++)
{
coords[i, 0] = (Convert.ToDouble(dir.coordsLat[i]));
coords[i, 1] = (Convert.ToDouble(dir.coordsLon[i]));
}
serialPort1.Close();
try
{
serialPort1.Open();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
if (serialPort1.IsOpen)
{
System.Threading.Thread.Sleep(2000);
using (serialPort1)
{
serialPort1.Write("^");
System.Threading.Thread.Sleep(1000);
Console.WriteLine("^");
serialPort1.Close();
System.Threading.Thread.Sleep(5000);
}
}
else
{
button3.Enabled = true;
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//SerialPort sp = (SerialPort)sender;
System.Threading.Thread.Sleep(10000);
/*if (!serialPort1.IsOpen)
{
serialPort1.Close();
System.Threading.Thread.Sleep(10000);
serialPort1.Open();
System.Threading.Thread.Sleep(10000);
}*/
//serialPort1.Open();
//using (sp)
using (serialPort1)
{
serialPort1.Open();
System.Threading.Thread.Sleep(5000);
readData = serialPort1.ReadExisting();
Console.WriteLine(readData);
// If microcontroller sends "&", it is ready to receive next piece of data
if (readData == "&")
{
sendRequest = true;
}
else
{
sendRequest = false;
}
// Write next piece of data to microcontroller if it is ready
if (sendRequest)
{
this.BeginInvoke(new EventHandler(write_serialPort1));
}
}
}
在代碼2中,事件處理程序確實被調用,而button3_click只運行一次。 但是當它嘗試打開端口時,它會返回錯誤“ Access to Port X denied
”。 此外,我希望我不必像這樣關閉和打開端口,但是當調用事件處理程序時(在早期的代碼中),它返回了未打開COM端口的錯誤。 為了滿足該錯誤,我必須關閉它並在button3_click
和事件處理期間重新打開它。
在我閱讀了許多處理串行通信線程問題的問題之后,我在代碼中添加了很多延遲。 我甚至試過了一分鍾的延遲,希望線程能夠解決問題。 但是,那里沒有運氣。
我還在MainForm設計器中指定了我的串口,而不是在代碼中聲明它(起初我做了兩個並且意識到它是多余的)。 我不確定這是否有助於解決這個問題,但我已經看到了這兩個問題的例子。
最后,無論何時進行串行連接(例如打開和關閉端口),它都可以處理Arduino自動復位。 總之,它似乎是通過串行發送數據,但無法從串行讀取傳入的數據。
感謝您閱讀本文,如果有人能指出我正確的方向,我將非常感激。
編輯#1:即使在代碼1中使用BeginInvoke之后,它仍然會死鎖,因為從未調用過事件處理程序。
編輯#2:根據新手的建議編輯代碼1。
編輯#3:添加了主窗體初始化並將代碼1更新為當前狀態。
編輯#4:在事件處理程序中刪除(注釋掉)睡眠。 我在事件處理程序期間正在睡覺,因此我無法收到微控制器發送給我的任何信息。 代碼工作正常,如預期。
確保您使用的是COM1 ,如果您沒有COM1串口,請通過計算機 - > 設備管理器 - > 端口(COM和LPT) - > 選擇要更改的COM - > 端口設置 - > 高級 - > ComPort編號 - > 選擇COM1 。
確保在COM1的 pin2和pin3之間用螺絲刀安裝了跳線/連接器。
將button1和textBox1添加到Form並運行此程序
using System;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.Text;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
const int MAX_BUFFER = 100;
int i = 0;
byte[] DataReceived = new byte[MAX_BUFFER];
SerialPort serialPort = new SerialPort();
public Form1() {
InitializeComponent();
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
}
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {
// wait data ready
Thread.Sleep(500);
// while data ready in buffer
while (serialPort.IsOpen && serialPort.BytesToRead > 0) {
// read data serial
DataReceived[i] = Convert.ToByte(serialPort.ReadByte());
// counter data
i++;
// reset conter if more then maxvalue
if (i >= MAX_BUFFER) {
i = 0;
}
}
if (i == 1 && DataReceived[0] == ASCIIEncoding.ASCII.GetBytes("^")[0]) {
this.textBox1.Invoke(new Action(() => {
this.textBox1.Text = ASCIIEncoding.ASCII.GetString(DataReceived, 0, 1);
}));
}
}
public void InitSerialPort() {
serialPort.PortName = "COM1";
serialPort.BaudRate = 9600;
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
serialPort.ReceivedBytesThreshold = 1;
}
private void Form1_Load(object sender, EventArgs e) {
// initialize serial port
InitSerialPort();
// assure port is closed before open it
if (serialPort != null && serialPort.IsOpen) {
serialPort.Close();
}
serialPort.Open();
}
private void button1_Click(object sender, EventArgs e) {
if (serialPort.IsOpen) {
serialPort.Write("^");
// wait data sent
Thread.Sleep(500);
}
}
}
}
按照我的第4次編輯,刪除(注釋掉)事件處理程序的睡眠。 我在事件處理程序期間正在睡覺,因此我無法收到微控制器發送給我的任何信息。 代碼工作正常,如預期。 任何組件上的串行端口都沒有問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.