2016年12月30日 星期五

[C#] 讀取center 306 thermometer

今天遇到一個很神奇的溫度計,Center 306 thermometer ,需要用PC透過RS232 ,

將溫度值讀出來。


首先它的連接參數如下:

Baud Rate : 9600 , N , 8 , 1

需要設定啟用以下設定,否則會一直發送卻沒有人回你。

DTR – Data Terminal Ready

RTS – Request To Send


接下來說明Command



RS232 command
Function
Remarks
K(ASC 4BH)
Ask for model No.
Return 4 bytes
A(ASC 41H)
Inquire all encoded data
Return encoded 10 byte
H(ASC 48H)
Hold button

M(ASC 4DH)
MAX/MIN button

N(ASC 4EH)
Exit MAX/MIN mode

T(ASC 52H)
TIME button

C(ASC 43H)
C/F button

U(ASC 55H)
Dump all memory of thermometer
return 32768 bytes
P(ASC 50H)
Load recorded data


主要會用到2個,一個是K,一個是A。

K是會回傳型號,例如'3' '0' '6'  ASCII(13) ,'3'  '0'  '1'  ASCII(13) 。

而A則是溫度資訊,其他的功能本次沒有實作。

301和306在溫度的回傳的資料,有差一個byte,在實作時要注意。

我有一組306的回傳值,共九個BYTE。

02 80 00 B2 29 BB 00 B2 28 03

只會用到其中5個byte

第2個byte的第1個bit和第4個bit (由0開始計算)表示T1和T2是否為負值(1為負值)。

例如目前為00, 則T1和T2都是正值。

第3~4個BYTE代表T1的溫度值,B2 29  --> 022.9 ℃

第7~8個BYTE代表T2的溫度值,B2 28  --->022.8 ℃

一開始我是把B給濾掉,但後來發現降到9.8℃ 時,會出現BB.98 ,才推測B是0  。


以下是我的程式碼



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Collections;
namespace TEST
{
    class Center_306
    {

        private SerialPort port;
        private Test.Form1.MyDelegate md;
        public Center_306(String comport, TH300Monitor.Form1.MyDelegate md)
        {
            this.md = md;
            port = new SerialPort(comport, 9600, Parity.None, 8, StopBits.One);
           // Enable DTR  
            bool s = port.DtrEnable = true;
            port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
        }

        public void QueryTemp()
        {
            port.Write(new char[] { 'A' }, 0, 1);
        }


        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            int bytes = port.BytesToRead;
            byte[] comBuffer = new byte[bytes];
            port.Read(comBuffer, 0, bytes);
            if (bytes == 9)
            {

                byte[] t1 = new byte[2];
                byte[] t2 = new byte[2];

                bool t1_sign = (comBuffer[2] & (1 << 1)) != 0;
                bool t2_sign = (comBuffer[2] & (1 << 4)) != 0;



                Array.Copy(comBuffer, 3, t1, 0, 2);
                Array.Copy(comBuffer, 7, t2, 0, 2);


                string hex1=BitConverter.ToString(t1);
                string hex2 = BitConverter.ToString(t2);

                hex1 = hex1.Replace("-", "").Replace("B", "0");
                hex2 = hex2.Replace("-", "").Replace("B", "0");
                
                double temp1 = Double.Parse(hex1) / 10.0;
                double temp2 = Double.Parse(hex2) / 10.0;

                if (t1_sign == true)
                {
                    temp1 = temp1 * -1;
                }

                if (t2_sign == true)
                {
                    temp2 = temp2 * -1; 
                }

                Console.WriteLine(temp1 + " " + temp2);

                md.Invoke(temp1, temp2);
            }
        }


      

        public void Open()
        {
            port.Open();
        }

        public void Close()
        {
            port.Close();
        }
    }
}

呼叫方式如下:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using TH300;
using System.IO.Ports;

namespace TH300Monitor
{
    public partial class Form1 : Form
    {
   
        //add for Center 306
        public delegate void MyDelegate(double temp1, double temp2);
        Center_306 c306;
        MyDelegate oMyDel;

       bool isConnect=false;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnConn_Click(object sender, EventArgs e)
        {
            

            TimerRead.Enabled = true;
          
            //add center 306 
            oMyDel = new MyDelegate(Show);
            c306 = new Center_306(C306_com.Text, oMyDel);

            c306.Open();

    
        }


        //for center 306 display
        MyDelegate uu;
        public void Show(double temp1, double temp2)
        {

            if (this.InvokeRequired)
            {
                uu = new MyDelegate(Show);
                this.Invoke(uu, temp1, temp2);
            }
            else
            {
                c306_temp1.Text = temp1.ToString();
                c306_temp2.Text = temp2.ToString();
            }
        }

        private void btnDisconn_Click(object sender, EventArgs e)
        {
            TimerRead.Stop();
            System.Threading.Thread.Sleep(1000);

            //ad for center 306
            
            c306.Close();
        }

      

        private void btnStop_Click(object sender, EventArgs e)
        {
            TimerRead.Stop();
            
        }

        /// <summary>
        /// Read data per sec  
        /// </summary>
        private void TimerRead_Tick(object sender, EventArgs e)
        {
            

            //add for c306
            c306.QueryTemp();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
          

            // Set Timer
            TimerRead.Interval = 1000;
        }

    }
}

當有回傳值時,會自動顯示在c306_temp1及c306_temp2 二個Lable上




參考資料

C306
https://www.instrumart.com/assets/MARTEL306_manual.pdf

C301差異截圖



沒有留言:

張貼留言