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差異截圖



2016年12月28日 星期三

[My SQL] 計算同一列幾個欄位加總

我有一個資料表的內容如下











































我想要列出以下結果




















也就是把a,b,c,d四個欄位加總 ,透過以下語法來達成


select name ,  (a+b+c+d) as total from test2

最神奇的是,我的欄位資料型態全都是VARCHAR
















2016年12月27日 星期二

[Rust] 格式化輸出

Rust也可以像C的printf一樣格式化輸出


fn main()
{
    let x=10*5;
    println!("x={}",x);
}


輸出為:

x=50


試試字串

fn main()
{
    let name="boywhy";
    println!("My Name is {}",name);
}

輸出為:


My Name is boywhy


也可以透過指定Index的方式輸出



fn main()
{
  println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");
}

輸出為:


Alice, this is Bob. Bob, this is Alice


也可以透過命名參數來格式化輸出


fn main()
{
    println!("{subject} {verb} {object}",
             object="the lazy dog",
             subject="the quick brown fox",
             verb="jumps over");
}

輸出為:


the quick brown fox jumps over the lazy dog


也可以直接指定輸出為進制 ,例如{:b}


fn main()
{
  println!("{} of {:b} people know binary, the other half don't", 1, 2);  
}


1 of 10 people know binary, the other half don't

共輸出長度為6的number,所以輸出了5個空白以及1個數值


fn main()
{
 println!("{number:>width$}", number=1, width=6);i
}

輸出為      1


也可以輸出補0,差別在width$前面要補0


fn main()
{
 println!("{number:>0width$}", number=1, width=6);i
}

輸出為:


000001




參考資料:

1.2 Formatted print

「iOS」Web View

Web View是讓APP可以造訪網頁,下載圖片,顯示地方等等功能的元件,

它就像是一個小小瀏覽器,也可以顯示圖片、GIF動畫,GOOGLE MAP等等。


Web View常用的方法如下:

loadRequest(request:NSURLResuest)  載入URL請求以顯示網頁

loadHTMLString(string:String!,baseURL:NSURL!) 載入網頁內容

loadData(file:NSData!,MIMEType:String!,textEncodingName:String!,baseURL:NSURL!)

reload()  重新載入

stropLoading() 停止載入

goBack() 在歷史紀錄中回到上一頁,如果沒有上一頁則不會有任何處理。

goForware() 在歷史紀錄中進到下一頁,如果沒有下一頁則不會有任何處理


以下是範例

載入Yahoo新聞 https://tw.news.yahoo.com/

先拉一個WebView元件出來,與程式碼建立連結

























這裡注意一件事,Storage必須選擇Strong,否則你會無法找到loadRequest之類的方法。

俺在這裡吃了一個晚上的悶虧。


程式碼如下:


  override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
            let url = NSURL(string:"https://tw.news.yahoo.com/")
            let request = NSURLRequest(URL:url!)
            myWebView.loadRequest(request);
        
          }

執行結果











































接下來我試Load一個HTTP網站(沒有SSL認證)是不行的,一片空白,並出現警告訊息




爬文後發現:

在 iOS 9 之後,應用程式內的 UIWebView 預設為只能載入 https 的網頁

(也就是加密過的),如果是普通 http 的網頁會無法開啟。

如果要允許開啟HTTP網頁,需要額外設定。

(1)打開info.plist




















(2)空白處按右鍵 Add Row









































輸入NSAppTransportSecurity 後按下Enter


























然候點一下這一行,讓箭頭向下,再按右鍵Add Row





























輸入NSAllowsArbitraryLoads 後按下Enter,型別為Boolean,值為Yes






再重新Build一次程式就可以Run一般的網頁了。

程式碼如下,我們來開一下蕃薯藤網站,沒有HTTPS的入口網頁之一,也沒有RWD。


 @IBOutlet var myWebView: UIWebView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
            let url = NSURL(string:"http://www.yam.com/")
            let request = NSURLRequest(URL:url!)
            myWebView.loadRequest(request);
        
          }
















































接下來示範另一個有用的功能,讀取HTML字串(或者稱為HTML原始碼)。

例如我有一個網頁的原始碼長這樣。


<html>
<head>
<title>Test Read HTML String</title>
</head>
<body>
<h1>test h1</h1><br><h2>test h2</h2>
</body>
</html>

我們用loadHTMLString方法來顯示這段程式碼

   @IBOutlet var myWebView: UIWebView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let source:String = "<html><head><title>Test Read HTML String</title></head><body><h1>test h1</h1><br><h2>test h2</h2></body></html>"
              myWebView.loadHTMLString(source, baseURL: nil)
          }

執行畫面如下































參考資料:



網頁 UIWebView

[電路] PT 100

Pt100,就是說它的阻值在 0 度時為 100 歐姆,

負 200 度時為 18.52 歐姆,

200 度時為 175.86 歐姆,

800 度時為 375.70 歐姆。


熱電阻公式都是

Rt=Ro(1+A*t+B*t*t);Rt=Ro[1+A*t+B*t*t+C(t-100)*t*t*t] 的形式,

t 表 示攝氏溫度,

Ro 是零攝氏度時的電阻值,

A、B、C 都是規定的係數,

對於 Pt100,Ro 就等於 100。


主要技術參數:

測量範圍:-200℃~+850℃;

允許偏差值△℃:A 級±(0.15+0.002│t│), B 級±(0.30+0.005│t│);

熱回應時間<30s;

最小置入深度:熱電阻的最小置入深度≥200mm;

允通電流≤5mA。

另外,Pt100 溫度感測器還具有抗振動、穩定的特性。


參考資料:

http://www.dmatek.com.tw/tn/download/SensorData_E390.pdf

2016年12月26日 星期一

[電路] PH電極的輸入阻抗

今天被廠商問倒,爬文後紀錄一下,PH電極的輸入阻抗(impedance)。


一般而言要>= 10^12歐姆



輸入阻抗即輸入電壓與電流之比,即 Ri = U/I。在同樣的輸入電壓的情況下,

如果輸入阻抗很低,就需要流過較大電流,這就要考驗前級的電流輸出能力了;

而如果輸入阻抗很高,那麼只需要很小的電流,這就為前級的電流輸出能力減

少了很大負擔。所以電路設計中儘量提高輸入阻抗。

[電路]BNC接頭

今天被問到才發現,原來BNC(Bayonet Neill-Concelman)接頭有2種不同的電阻,

外觀也有所差異,做個紀錄。



BNC連結器有50歐姆和75歐姆兩個版本。50歐姆連結器和其他阻抗電纜連線時,

傳輸出錯的可能性較小。不同版本的連結器互相相容,但如電纜阻抗不同,

訊號可能出現反射。通常BNC連結器可以使用在4GHz或2GHz。



75歐姆連結器用於影片和DS3到電話公司中心局的連線,

而50歐姆連結器用於資料和射頻傳輸。

錯誤接在75歐姆插座上的50歐姆插頭可能會損害插座。

甚高頻應用中使用75歐姆連結器。


以上資料取自WiKi



EX: 

SPDIF的BNC一定要是75歐姆.




















圖取自以下連結:

http://www.myav.com.tw/bbs/showthread.php?threadid=20459442&pagenumber=0

[Rust] Mac OSX Install Rust

紀錄一下在Mac安裝Rust語言的流程。

(1)輸入curl https://sh.rustup.rs -sSf | sh  會出現如下圖



































沒有特別情況的話,按下1以及Enter, 讓它以預設值安裝




































安裝完畢




































接下來要設環境變數,不然會找不到指令

編輯~/.bash_profile








增加一行export PATH="$PATH:"/Users/使用者名稱/.cargo/bin




























存檔後,關掉終端機重新開啟,輸入echo "$PATH" 確定路徑有成功寫入













我們來寫個範例吧


fn main()
{
    println!("Hello WOrld!")
}
~    

















編譯並執行


$ rustc hello.rs 
$ ./hello 


















參考來源:

https://www.rust-lang.org/en-US/install.html

[名詞定義] Rust

Rust是一個由Mozilla主導開發的通用、編譯型程式語言。

它的設計準則為「安全,並行,實用」,支援函數式並行式

程序式以及物件導向的 程式風格 。

Rust 的設計目標之一,是要使設計大型的網際網路客戶端伺服器的任務變得更容易。

因此更加強調安全性、記憶體配置、以及並行處理等方面的特性。在效能上,

具有額外安全保證的代碼會比 C++ 慢一些,但是如果以 C++ 也手工提供保證的情況下,

則兩者效能上是相似的。


它的語法設計,與 C語言C++ 相當相似,區塊 (block) 使用大括號隔開,
流程控制的關鍵字如 if, else, while 等等。在保持相似性的同時,

Rust 也加進了新的關鍵字,如用於模式符合 (pattern matching) 的 match

(與 switch 相似) 則是使用 C/C++ 系統程式語言的人會相對陌生的概念。

儘管在語法上相似,Rust 的語義 (semantic) 和 C/C++ 非常不同。。

為了提供記憶體安全,它的設計不允許空指標懸空指標

資料只能透過固定的初始化形態來建立。




Rust 1.0已不再使用垃圾回收器,而是全面改用基於參照計數的智慧指標來管理記憶體。

型別推導也是 Rust 提供的特性之一,使用 let 語法宣告的變數可以不用宣告型別,

亦不需要初始值來推斷型別。但如果在稍後的程式中從未指派任何值到該變數,

編譯器會發出編譯時 (compile time) 錯誤。 函式可以使用泛型化參數 (generics),

但是必須綁定 Trait。沒有任何方法可以使用方法或運算子,

又不宣告它們的型別,每一項都必確明確定義。


以上資料取自 WiKi  

[iOS]UIAlertView (2)

UIAlert除了可以用來提示使用者外,還可以用來輸入帳密。

只要將UIAlertViewStyle屬性設定為LoginAndPasswordInput,

對話方塊中就會同時提供PlainTextInpu以及一個SecureTextInput。


使用textFieldAtIndex(index)方法,可以取得UITextField型別的文字方塊。


畫面如下
















設定Button事件與連結





















設定Label連結










程式碼


//
//  ViewController.swift
//  book
//
//  Created by boywhy chen on 2016/12/25.
//  Copyright © 2016年 boywhy chen. All rights reserved.
//

import UIKit

class ViewController: UIViewController,UIAlertViewDelegate {

    @IBOutlet weak var mLabel: UILabel!
    @IBOutlet weak var mButton: UIButton!
    
    //來個一組帳密
    let UserName:String = "boywhy"
    let Password:String = "1234"
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        //心情好,用個圓角按鈕
        mButton.layer.backgroundColor = UIColor.brownColor().CGColor
        mButton.layer.cornerRadius = 15
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    @IBAction func showAlertView(sender: AnyObject) {
        //create UIAlertView
        var alertView:UIAlertView = UIAlertView()
        
        alertView.title = "登入"
        alertView.message = "Welcome"
        alertView.delegate = self
        alertView.addButtonWithTitle("取消")
        alertView.addButtonWithTitle("登入")
        //Set Style to Login And Password
        alertView.alertViewStyle = UIAlertViewStyle.LoginAndPasswordInput
        alertView.show()
    }
    
    //處理函式名字固定是alertView
    func alertView(alertView:UIAlertView!,clickedButtonAtIndex buttonIndex:Int)
    {
        
        switch(buttonIndex)
        {
            case 0: //cancel button
                break
            case 1://login button
                var textUserName:UITextField = alertView.textFieldAtIndex(0)!
                var textPassword:UITextField = alertView.textFieldAtIndex(1)!
                if(textUserName.text == UserName && textPassword.text == Password)
                {
                    mLabel.text = "Welcom \(textUserName.text!)"
                }
                else
                {
                    mLabel.text = "login fail"
                }
                break
            default:
                mLabel.text = "error"
            }
        
        
    }


}

執行畫面























輸入正確帳密













輸入錯誤帳密
















Swift比較特別的一點是字串的比較可以直接用== ,

和Java或C#不一樣,==只是比記憶體位置。








2016年12月25日 星期日

[iOS]UIAlertView (1)

ULAlertView元件可以顯示對話方塊,製做按鈕與使用者互動,

直到使用者按下按鈕後,才關閉對話方塊並回應使用者用者的按鈕動作。


UIAlertView常用屬性如下:

title 設定對話方塊的標題

message 設定對話方塊的內容

delagate 設定對話方塊的委派物件

numberOfButtons  傳回共有幾個按鈕

ULAlertViewStyle 設定對話方塊的樣式 ,
               
                                 Default 顯示單純的文字訊息。

                                 PlainTextInput 提供輸入文字後不會隱形的文字方塊讓

                                 使用者輸入資料。

                                 SecureTextInput,提供輸入文字後會隱形

                                 的文字方塊讓使用者輸入資料。

                                 LoginAndPasswordInput提供一個PlanTextInput和一個

                                 SecureTextInput,可以同時輸入帳號和密碼。

常用方法如下:


init()  預設建構式

addButtonWithTitle() 依序建立按鈕並設定按鈕文字,傳回建立按鈕的索引值,第一個建立

                                         的按鈕為0 。

buttonTitleAtIndex()  傳回指定索引的文字。

show()   顯示對話方塊

alertView(alertView,clickButtonAtIndex()  按下按鈕要解發的事件。

textFieldAtIndex(index)  取得文字方塊。index=0 取得帳號,index =1 取得密碼。

預設的UIAlertView 建構式語法

init(title:String? , message:String? , delegate:AnyObject? ,  cancelButtonTitle:String?)

如果要取得按下按鈕的動入,delegate 參數必須是self,否則設定nil即可。

cancelButtonTitle為第一個按鈕,通常會加上按鈕文字。

UIAlertView基本樣式












程式碼


UIAlertView(title: "Title", message: "message", delegate: nil, cancelButtonTitle: "cancelButton").show()


UIAlert按鈕的排列方式:

如果有2個按鈕,cancelButton會在左方,otherButton會在右方。













程式碼


UIAlertView(title: "title", message: "message", delegate: nil, cancelButtonTitle: "cancelButton", otherButtonTitles: "otherButtons").show()

如果有3個按鈕或以上,則會變成垂直排列


















除了用建構子,也能用別的方式建立UIAlertView
























程式碼

var alertView:UIAlertView = UIAlertView()
        
alertView.title = "視窗標題"
alertView.message = "我用的是Default 樣式對話方塊"
alertView.delegate = nil
alertView.addButtonWithTitle("1個按鈕")
alertView.addButtonWithTitle("2個按鈕")
alertView.addButtonWithTitle("3個按鈕")
alertView.addButtonWithTitle("other按鈕")
        

alertView.show()

用addButtonWithTitle()加入的按鈕會依加入的順序由上而下排列













程式碼

var alertView:UIAlertView = UIAlertView()
        
alertView.title = "視窗標題"
alertView.message = "我用的是Default 樣式對話方塊"
alertView.delegate = self
alertView.addButtonWithTitle("1個按鈕")

alertView.addButtonWithTitle("2個按鈕")

如果是2個按鈕,則會由左而右排列


接下來來說明一下按鈕觸發事件,需要繼承UIAlertViewDelegate

接一個Button和Label出來



























然候建立一個Button的Touch Up Inside事件, 並連結到程式碼






















把Label連結到程式碼











程式碼如下

//
//  ViewController.swift
//  book
//
//  Created by boywhy chen on 2016/12/25.
//  Copyright © 2016年 boywhy chen. All rights reserved.
//

import UIKit

class ViewController: UIViewController,UIAlertViewDelegate {

    @IBOutlet weak var mLabel: UILabel!
    @IBOutlet weak var mButton: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        //心情好,用個圓角按鈕
        mButton.layer.backgroundColor = UIColor.brownColor().CGColor
        mButton.layer.cornerRadius = 15
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    @IBAction func showAlertView(sender: AnyObject) {
        //create UIAlertView
        var alertView:UIAlertView = UIAlertView()
        
        alertView.title = "確認視窗"
        alertView.message = "確認要結束應用程式"
        alertView.delegate = self
        alertView.addButtonWithTitle("取消")
        alertView.addButtonWithTitle("確定")
        alertView.show()
    }
    
    //處理函式名字固定是alertView
    func alertView(alertView:UIAlertView!,clickedButtonAtIndex buttonIndex:Int)
    {
        var buttonTitle:String = alertView.buttonTitleAtIndex(buttonIndex)!
        
        mLabel.text = buttonTitle
    }


}

執行結果