修改串列埠連線設定方式,取消連線按鈕,改為直接由下拉式選單選擇後連線
新增Arduino回傳超音波測距數值至C#的功能
C#
程式碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
namespace _0150531
{
public partial class Form1 : Form
{
string dis, text2;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
serialPort1.BaudRate = 9600;
serialPort1.Parity = Parity.None;
serialPort1.DataBits = 8;
serialPort1.StopBits = StopBits.One;
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
comboBox1.Items.AddRange(SerialPort.GetPortNames());
label1.Text = "PC狀態:尚未連線";
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
serialPort1.PortName = comboBox1.Text;
serialPort1.Open();
comboBox1.Enabled = false;
button1.Enabled = true;
button2.Enabled = true;
button3.Enabled = true;
timer1.Enabled = true;
label1.Text = "PC狀態:連線中";
}
private void button1_Click(object sender, EventArgs e)
{
serialPort1.Write("0");
comboBox1.Enabled =true;
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
timer1.Enabled = false;
label1.Text = "PC狀態:斷線中";
label2.Text = "Arduino回傳:";
serialPort1.Close();
}
private void button2_Click(object sender, EventArgs e)
{
serialPort1.Write("1");
button3.Enabled = true;
button2.Enabled = false;
label1.Text = "送出指令:LED ON";
}
private void button3_Click(object sender, EventArgs e)
{
serialPort1.Write("0");
button2.Enabled = true;
button3.Enabled = false;
label1.Text = "送出指令:LED OFF";
}
private void timer1_Tick(object sender, EventArgs e)
{
label2.Text = text2;
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
dis = serialPort1.ReadLine();
if (dis.IndexOf('C') == 0)
text2 = "Arduino回傳:" + dis;
else
text2 = "wrong";
}
}
}
Arduino
這裡不用 Arduino 內建的 Ping 範例,而是使用 HC-SR04 Ultrasonic Sensor Library
這個 library把測距的公式都包成了函式庫,較方便使用
使用時必須先將下載的壓縮檔解壓縮
將 HCSR04Ultrasonic整個檔案夾複製到Arduino的libraries
#include <Ultrasonic.h>
#define TRIGGER_PIN 11
#define ECHO_PIN 12
Ultrasonic ultrasonic(TRIGGER_PIN, ECHO_PIN);
String dis;
void setup() {
Serial.begin(9600); // 開啟 Serial port, 通訊速率為 9600 bps
// 初始化 LED 接腳
pinMode(13, OUTPUT);
}
void loop() {
// 檢查是否有資料可供讀取
if (Serial.available() > 0) {
char inByte = Serial.read();
switch (inByte) {
case '0':
digitalWrite(13, LOW);
break;
case '1':
digitalWrite(13, HIGH);
break;
default:
digitalWrite(13, LOW);
}
}
else{
distance();
}
}
void distance()
{
float cmMsec;
long microsec = ultrasonic.timing();
cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM); // 計算距離,單位: 公分
dis=String(cmMsec);
Serial.println("CM:"+dis);
delay(50);
}
結果
C#的計時器用來每隔一段固定時間顯示label2.Text
即表單上變更顯示Arduino回傳字串的時間間隔是由C#的計時器來決定
並非是串列埠收到data即變更顯示label2.Text
另外 當按下斷線按鈕時 很可能 serialPort1_DataReceived還在執行
(??不確定 但的確出現當掉的狀況)
因此變更作法
不再使用計時器固定時間變更顯示label2.Text
直接當串列埠收到資料時 即變更顯示label2.Text
但是 在serialPort1_DataReceived中採用透過 delegate 及 Invoke 來執行 addData()
這是因為 Windows Forms 是 Multi-threading 的機制
如果不這麼寫,直接在 serialPort1_DataReceived 把資料給label2
會遇到「跨執行緒作業無效」的錯誤
另外將計時器的角色做修改
利用 test2作為判斷 當test2=1時 addData()可執行
test2=0 則否
當按下斷線按鈕時 令test2=0 且啟動計時器
此時 addData()便不再執行
直到計時器時間到 再執行斷線serialPort1.Close();
結果
(1)當C#收到data即變更顯示
(2)解決按下斷線按鈕時出現當掉的狀況
修正後程式碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
namespace _0150531
{
public partial class Form1 : Form
{
int test = 1;
string dis, text2;
public delegate void AddDataDelegate();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
serialPort1.BaudRate = 9600;
serialPort1.Parity = Parity.None;
serialPort1.DataBits = 8;
serialPort1.StopBits = StopBits.One;
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
comboBox1.Items.AddRange(SerialPort.GetPortNames());
label1.Text = "PC狀態:尚未連線";
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
test = 1;
serialPort1.PortName = comboBox1.Text;
serialPort1.Open();
comboBox1.Enabled = false;
button1.Enabled = true;
button2.Enabled = true;
button3.Enabled = true;
label1.Text = "PC狀態:連線中";
}
private void button1_Click(object sender, EventArgs e)
{
serialPort1.Write("0");
comboBox1.Enabled = true;
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
timer1.Enabled = true;
test = 0;
}
private void button2_Click(object sender, EventArgs e)
{
serialPort1.Write("1");
button3.Enabled = true;
button2.Enabled = false;
label1.Text = "送出指令:LED ON";
}
private void button3_Click(object sender, EventArgs e)
{
serialPort1.Write("0");
button2.Enabled = true;
button3.Enabled = false;
label1.Text = "送出指令:LED OFF";
}
private void timer1_Tick(object sender, EventArgs e)
{
serialPort1.Close();
timer1.Enabled = false;
label1.Text = "PC狀態:斷線中";
label2.Text = "Arduino回傳:";
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (test==1)
this.Invoke(new AddDataDelegate(addData));
}
private void addData()
{
dis = serialPort1.ReadLine();
if (dis.IndexOf('C') == 0)
text2 = "Arduino回傳:" + dis;
else
text2 = "wrong";
label2.Text = text2;
}
}
}
Arduino另一個程式
#define trigPin 11
#define echoPin 12
float echotime, distance;
float obs_dis()
{
digitalWrite(trigPin, HIGH);
delayMicroseconds(15);
digitalWrite(trigPin, LOW);
echotime=pulseIn(echoPin, HIGH);
distance=echotime/2/29.1;
}
String dis;
void setup() {
Serial.begin(9600); // 開啟 Serial port, 通訊速率為 9600 bps
// 初始化 LED 接腳
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(13, OUTPUT);
}
void loop() {
// 檢查是否有資料可供讀取
if (Serial.available() > 0) {
char inByte = Serial.read();
switch (inByte) {
case '0':
digitalWrite(13, LOW);
break;
case '1':
digitalWrite(13, HIGH);
break;
default:
digitalWrite(13, LOW);
}
}
else{
obs_dis();
dis=String(distance);
Serial.println("CM:"+dis);
delay(50);
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
回覆刪除{
if (test == 1)
{
this.Invoke(new AddDataDelegate(addData));
}
為甚麼我這一段不會執行
上面還寫著0個參考
如果把serialPort1_DataReceived這個換成一個button_click的話就可以成功執行addData那邊的程式
是我有哪邊沒設定嗎?