記錄一下事件經過。
現在的項目是採集儀表的數據。以前都是配置好串口,波特率,數據位,停止位,校驗位然後就可以接受儀表發送來的數據進行解析了。
現在遇到了一種新的儀表,分為兩個模式。一個是數據模式,像其他儀表一樣,將儀表的數據主動發送給串口,但是不能接受命令數據。一種是命令模式,可以接受命令數據,但是不會主動發送數據。也就是説你想要實現遠程控制儀表,給他發送命令的話,就需要主動發送獲取數據的命令去主動讀數。
/// <summary>
/// 串口類
/// </summary>
private SerialPort _spCom; 這是微軟提供的串口類
/// <summary>
/// 打開串口,並註冊數據接收方法
/// </summary>
/// <returns></returns>
public bool Open()
{
var rtn = false;
if (_curWeightCfg != null)//_curWeightCfg 是從配置文件中讀取配置的串口信息,COM口,波特率,數據位,停止位,校驗位
{
WeightDeviceLogger.Debug(
string.Format("設置串口參數。ComPort={0},Baudrate={1},DataBits={2}, Parity={3},StopSize={4}",
_curWeightCfg.ComPort, _curWeightCfg.Baudrate, _curWeightCfg.ByteSize, _curWeightCfg.Parity,
_curWeightCfg.StopSize));
_spCom = new SerialPort(_curWeightCfg.ComPort, int.Parse(_curWeightCfg.Baudrate))
{
DataBits = _curWeightCfg.ByteSize,
ReadBufferSize = 100
};
//奇偶校驗
if (_curWeightCfg.Parity == ParityType.Even)
{
_spCom.Parity = Parity.Odd;
}
else if (_curWeightCfg.Parity == ParityType.Odd)
{
_spCom.Parity = Parity.Even;
}
else
{
_spCom.Parity = Parity.None;
}
//停止位
if (_curWeightCfg.StopSize == StopBitsType.One)
{
_spCom.StopBits = StopBits.One;
}
else if (_curWeightCfg.StopSize == StopBitsType.OnePointFive)
{
_spCom.StopBits = StopBits.OnePointFive;
}
else if (_curWeightCfg.StopSize == StopBitsType.Two)
{
_spCom.StopBits = StopBits.Two;
}
else
{
_spCom.StopBits = StopBits.None;
}
_spCom.DataReceived += new SerialDataReceivedEventHandler(_spCom_DataReceived);
try
{
WeightDeviceLogger.Debug("表頭打開串口。IsOpen=" + _spCom.IsOpen);
_spCom.Open();
_closeComPort = false;
ThreadStart ts1 = GetWeight;// 開啓一個線程,發送讀取數據命令,之後讀取數據,解析數據,再通過委託事件傳遞給程序
_threadWeight1 = new Thread(ts1)
{
IsBackground = true,//表示後台線程
};
_threadWeight1.Start();
WeightDeviceLogger.Debug("啓動表頭獲取數據線程成功。");
rtn = true;
}
catch (Exception ex)
{
WeightDeviceLogger.Error("打開表頭失敗。", ex);
ShowErrorMsg(ErrorType.Error, "打開串口失敗.");
}
}
else
{
WeightDeviceLogger.Error("表頭配置信息不存在。");
ShowErrorMsg(ErrorType.Error, "配置信息不存在.");
}
return rtn;
}
/// <summary>
/// 提取重量數據
/// </summary>
private void GetWeight()
{
while (true)
{
if (_spCom.IsOpen)
{
if (isclearzero)
{
continue;
}
try
{
Thread.Sleep(100);
ComSend(s1);//發送獲取數據命令 s1是儀表廠家提供的讀數命令16進制字符"01 03 00 01 00 04 15 C9"
var readDataLen = _spCom.BytesToRead;//獲取接受緩衝區的字節數
var buf = new byte[readDataLen];//創建一個和接收區字節數一樣的字節數組用來接收數據
_isDataReceiving = true;
Thread.Sleep(100);//發送讀數命令之後要等一會再讀取數據
var length = _spCom.Read(buf, 0, readDataLen);//從緩衝區讀取readDataLen長度的數據寫入buf字節數組
_isDataReceiving = false;
if (length <= 0) continue;
var aaa = System.Text.Encoding.Default.GetString(buf);//將字節數組轉換成字符串
var weightTemp = aaa.Substring(3, 7);//從字符串中截取使用的那幾位數據
if (!_canRaiseWeightDataEvent) continue;//判斷程序是否暫停取數
OnGetWeightData(weightTemp, "");//將數據發送給程序使用
}
catch(Exception e)
{
WeightDeviceLogger.Debug("讀取數據線程出現錯誤"+e.Message);
}
}
}
}
private void ComSend(string obj)//發送數據 獨立線程方法 發送數據時UI可以響應
{
if (Sending)
{
return;
}
//lock (this)//由於send()中的if (Sending == true) return,所以這裏不會產生阻塞,如果沒有那句,多次啓動該線程,會在此處排隊
{
Sending = true;//正在發生狀態字
byte[] sendBuffer = null;//發送數據緩衝區
string sendData = obj;//複製發送數據,以免發送過程中數據被手動改變
if (true)//16進制發送
{
try //嘗試將發送的數據轉為16進制Hex
{
sendData = sendData.Replace(" ", "");//去除16進制數據中所有空格
sendData = sendData.Replace("\r", "");//去除16進制數據中所有換行
sendData = sendData.Replace("\n", "");//去除16進制數據中所有換行
if (sendData.Length == 1)//數據長度為1的時候,在數據前補0
{
sendData = "0" + sendData;
}
else if (sendData.Length % 2 != 0)//數據長度為奇數位時,去除最後一位數據
{
sendData = sendData.Remove(sendData.Length - 1, 1);
}
List<string> sendData16 = new List<string>();//將發送的數據,2個合為1個,然後放在該緩存裏 如:123456→12,34,56
for (int i = 0; i < sendData.Length; i += 2)
{
sendData16.Add(sendData.Substring(i, 2));
}
sendBuffer = new byte[sendData16.Count];//sendBuffer的長度設置為:發送的數據2合1後的字節數
for (int i = 0; i < sendData16.Count; i++)
{
sendBuffer[i] = (byte)(Convert.ToInt32(sendData16[i], 16));//發送數據改為16進制
}
}
catch //無法轉為16進制時,出現異常
{
WeightDeviceLogger.Debug("無法轉為16進制時,出現異常");
Sending = false;//關閉正在發送狀態
//_spCom.Abort();//終止本線程
return;//輸入的16進制數據錯誤,無法發送,提示後返回
}
}
else //ASCII碼文本發送
{
sendBuffer = System.Text.Encoding.Default.GetBytes(sendData);//轉碼
}
try//嘗試發送數據
{//如果發送字節數大於1000,則每1000字節發送一次
//int sendTimes = (sendBuffer.Length / 1000);//發送次數
//for (int i = 0; i < sendTimes; i++)//每次發生1000Bytes
//{
// //_spCom.Write(sendBuffer, sendTimes * 1000, sendBuffer.Length % 1000);
// _spCom.Write(sendBuffer, 0, sendBuffer.Length); //發送sendBuffer中從第i * 1000字節開始的1000Bytes
//}
//if (sendBuffer.Length % 1000 != 0)//發送字節小於1000Bytes或上面發送剩餘的數據
//{
// //_spCom.Write(sendBuffer, sendTimes * 1000, sendBuffer.Length % 1000);
// _spCom.Write(sendBuffer, 0, sendBuffer.Length);
//}
_spCom.Write(sendBuffer, 0, sendBuffer.Length);
}
catch(Exception ex)//如果無法發送,產生異常
{
WeightDeviceLogger.Debug("指令發送錯誤"+ex.Message);
}
//sendScrol.ScrollToBottom();//發送數據區滾動到底部
Sending = false;//關閉正在發送狀態
}
}
本文章為轉載內容,我們尊重原作者對文章享有的著作權。如有內容錯誤或侵權問題,歡迎原作者聯繫我們進行內容更正或刪除文章。