2020年12月28日 星期一

海瑞思氣密機自動控制應用

 為了測試產品的防水效果, 使用海瑞思的氣密測試設備如下圖

與上位機的溝通介面 為RS485,  
主要使用的指令為:

byte[] resp = new byte[] { 0x01, 0x03, 0x00, 0x0C, 0x00, 0x01, 0x44, 0x09 };  //讀取狀態
byte[] resp = new byte[] { 0x01, 0x03, 0x00, 0x80, 0x00, 0x01, 0x85, 0xe2 };   //讀取氣密機程序
byte[] resp = new byte[] { 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x8C, 0x3A };   //執行氣密機程序
byte[] resp = new byte[] { 0x01, 0x03, 0x16, 0x1B, 0x00, 0x0E, 0xB0, 0x41 };   //讀取條碼
byte[] resp = new byte[] { 0x01, 0x03, 0x16, 0xDC, 0x00, 0x02, 0x01, 0xB9 };   //测试气压读取
byte[] resp = new byte[] { 0x01, 0x03, 0x16, 0x90, 0x00, 0x02, 0xC0, 0x6E }; //读直压型测试泄漏值

機器本身就可以單機做測試也有紀錄檔分時間跟序號做紀錄!只是要連上資料庫才用程式去控制測試與讀值上傳到Database!

一開始需要與治具商配合 找出GOOD與 洩露的待測物去設定洩露的壓力與洩露值的上下限
就可以直接 上位機的GUI 去進行測試!



2020年8月21日 星期五

C# 與 ModBus RTU 通訊練習

目的:
收到一顆 RS485 通訊協定的電壓表頭,  就來練習一下 MODBUS RTU的讀取練習!
首先利用RS485toRS232的轉板, 將資料轉為COM Port 讀取!
MODBUS RTU CRC計算方式有兩種, 一種為邏輯運算, 另一種為查表方式!
此機台採用MODBUS RTU 通信協定, 其CRC計算方式採用查表方式.
查表方式的Csharp Code如下:
        public ushort Cal_crc16(byte[] data, ushort usDataLen)
        {
            UInt16 crc = 0;

            ushort uchCRCHi = 0xFF; /* high CRC byte initialized */
            ushort uchCRCLo = 0xFF; /* Low CRC byte initialized */
            ushort uIndex; /* will index into CRC lookup */

            for (int i = 0; i < usDataLen; i++)
            {

                uIndex = (ushort)(uchCRCHi ^ data[i]); /* calculate the CRC */
                uchCRCHi = (ushort)(uchCRCLo ^ auchCRCHi[uIndex]);
                uchCRCLo = auchCRCLo[uIndex];
            }
            return (ushort)(uchCRCHi << 8 | uchCRCLo);
        }

        ushort[] auchCRCHi = new ushort[]{
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
            0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
            0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
            0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
            0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
            0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
            0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
            0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
            0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
            0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
        };

        ushort[] auchCRCLo = new ushort[]{
            0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 
            0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 
            0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
            0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 
            0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 
            0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
            0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 
            0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 
            0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
            0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 
            0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 
            0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
            0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 
            0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 
            0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
            0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 
            0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 
            0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
            0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 
            0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 
            0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
            0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 
            0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 
            0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
            0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 
            0x43, 0x83, 0x41, 0x81, 0x80, 0x40
            };
再利用03H的指令 讀取所量測的電壓值










 



2020年7月31日 星期五

IQxel與C#的學習

一. 前提
      最近為了測試MTK 的MT7915又重新將IQ的測試儀器學習了一遍!!
用到的儀器是 IQxel 比之前用的IQ2010的好處是IQxel支援了 SCPI的指令了!! 這真是太棒了~~
以後IQ儀器若都有支援就開發這一次就可以全部都可以控制!
首先先以IQ的VSG跟VSA做自我儀器測試與控制的議題!!
架構為下圖:
配了一台頻譜來確定VSG打出來的訊號,用功率分配器來分接!



二. 儀器簡介

IQxel是litepoint公司推出的一款功能強大的無線產品測試儀,可用於WLAN SISO(包括802.11b/g/n/ac),WLAN MOIO , Bluetooth的無線產品測試儀。IQxel是一台內嵌式的測試儀器,他不含有顯示器,我們只需要使用普通的網線連接我們的PC,用瀏覽器打開相應的網址http://192.168.100.254(默認出廠IP位址)就可以用我們的PC控制儀器進行相應射頻的指標測試,我們也可以通過儀器接一個顯示器查看其IP位址。使用標準的Gigabit乙太網路連線,內建作業系統的獨立式網路圖形使用者介面與SCPI相容的控制指令.

R&S的FSV頻譜也可以用TCPIP的方式控制, 所以接一台switch就可以同時去控制兩台儀器了.

三. 軟體架構

以C#來做開發, 先把IQxel跟SA的TCPIP控制利用NI的VISA寫成模組!!

, 再來就規劃儀器設定頁面, 頻譜的設定跟 IQ的設定.

在IQ的模組上,規劃 RF port1 為VSG, RF2為VSA, 用程式介面先將流程順序寫出, 爾後再來設計GUI介面

VSG打出的wave form為IQxel機子本身的固定 wave form如下:
命名意義:WIFI_AC_BW20_SS2_MCS2_BCC_Fs80M.iqvsg
wifi, 802.11ac, BandWidth 20MHz, Spatial Streams2, MCS2 (modulation and coding scheme), BCC2(Binary convolutional coding), Fs80M(Frame Sample Rate)  參考網站1, 參考網站2
下圖為在R&S的頻譜抓到的數據所繪製的圖型!
下圖為在IQxel上讀取到的Spectrm的資料所繪製的圖型

目前為止將 IQxel的C#控制與資料讀取 的基本功能模組 已建立,  下篇來寫 MT7915的測試!!




2020年3月12日 星期四

Arduino應用之3D印表機改裝成繪圖機

剛好朋友有一台3D印表機壞掉了, 就跟他要來改裝成繪圖機!!
結合之前的一些文章做個統合練習!
1. Arduino Grbl指令解碼撰寫:
    在解指令得時候要注意GCode的格式, 我現在只有 G1, G4, G92, M300
2. Motor  driver A4988 控制

下圖一為3D印表機的結構
下圖二為A4988的pin out 
下圖三為arduino與 A4988最簡單接法 
下圖四為GRBL controller 執行圖形 

如下影片為繪圖狀況

2020年2月15日 星期六

Arduino 測試治具的應用 - 抽屜式治具控制

案件需求為:
1. 兩個按鍵作為進出平台的開關 另一按鍵為平台上另一上下動作的開關
2. 完成所有動作後按任一進出按鍵就進行退出動作在退出時 蜂鳴器要發聲
3. 完成進入動作 COUNTER 要記數加一次為了控制頂針壓合次數
4. 手動跟程式控制同時可以動作



零件配置如圖:
1. Arduino 控制板
2. 8 Port Relay board
3. 3 個 push button
4. 3個氣壓控制閥
5. 1個蜂鳴器
6. 次數記數器
7. 4個磁簧開關
8. ACto12VDC變壓器



2020年2月6日 星期四

Arduino Yun 配合 C# Dropbox 的應用 - 上傳檔案篇


本來是想直接在 Arduino Yun 上安裝dropbox 的API 上傳Webcam 拍到的照片, 可是怎麼安裝就是裝不起來, 所以就用另一個方式:系統架構為
由arduino Yun 接上 PIR 感測器 偵測到物體經過 就用 webcam 拍照 然後由上機介面把存在Yun的SD card的照片抓回本機上傳到 dropbox!!
感謝從網路參考的這篇文章仙草奶綠的程式筆記本, 了解 Dropbox API 的使用方式
Yun 上的code主要是 PIR的 input pin 偵測事件
判斷有物體後 下拍照指令
p.runShellCommand("fswebcam /mnt/sda1/test.png");


上機介面用 c#所寫用到的dll有
using Renci.SshNet;
using Dropbox.Api;

抓取 Yun SD Card上的圖片
string remoteDirectory = "/mnt/sda1";
using (var sftp = new SftpClient(yun._host, yun._username, yun._password))
{
      sftp.Connect();
      var files = sftp.ListDirectory(remoteDirectory);
       using (Stream fileStream = File.Create(@"D:\temp\test.png"))
      {
           sftp.DownloadFile("/mnt/sda1/test.png", fileStream);
       }
}

上傳到 Dropbox 用到的API 為
var task = Task.Run((Func)UploadDoc);
task.Wait();

public async Task UploadDoc()
{
    string uploadname = "yun.jpg";
    using (var dbx = new DropboxClient(this.AccessToken))
    {
         var full = await dbx.Users.GetCurrentAccountAsync();
         await Upload(dbx, "/software", "test1.txt", @"D:\Test\test.txt");
    }
}
private async Task Upload(DropboxClient dbx, string folder, string file, string fileToUpload)
{
     using (var mem = new MemoryStream(File.ReadAllBytes(fileToUpload)))
     {
            var updated = await dbx.Files.UploadAsync(
                folder + "/" + file,
                Dropbox.Api.Files.WriteMode.Overwrite.Instance,
                body: mem);
            Console.WriteLine("Saved {0}/{1} rev {2}", folder, file, updated.Rev);
     }
}

這樣就完成初步的照片上傳了!! 後續可以做一些 IoT 的應用.





2020年1月6日 星期一

Arduino Yun 與 Mega 2560 透過 I2C 的通訊

最近用 Arduino Mega2560 做了一個中控盒包含 各種sensor的偵測與 IR和喇叭的應用.
而Arduino Yun有不一樣的功能展示. 所以就想說 兩種板子 來透過I2C bus 來做連結!
Mega 2560 作為 I2C的 Master 因為之前已經有一些 I2C的功能寫在這裡!
//---------I2C Address------------------------------------------
#define DS90UB953TRHBTQ1_ADDRESS  0x18
#define LIS3MDLTD_ADDRESS 0x1E
#define CAT24C02_ADDRESS 0x50
#define LSM6DSM_ADDRESS 0x6A
#define SI7034_ADDRESS 0x70
#define BMP280_ADDRESS 0x76
#define TCA_ADDRESS 0x71
#define BMP180_ADDRESS 0x77
#define Gyro3Axis_ADDRESS 0x68
#define Gyr_address 0x68
#define SLAVE_ADDRESS 0x01

而就把 Yun 當作Slave來用 位址為 0x01.[注意 ATmega32u4 used in Yun has I2C: on 2 (SDA) and 3 (SCL)]


#include
Wire.begin(); // begin 沒帶參數就為master
//-----Arduino i2c slave

void vI2C_readTask1()
{
  Wire.requestFrom(SLAVE_ADDRESS, 6);
  Wire.beginTransmission(SLAVE_ADDRESS);
  int i = 0;
  if(Wire.available())
  {
    //Serial.print("Data returned: ");
    //Serial.print((char) Wire.read());
    while(Wire.available())
    {
      //Serial.print((char) Wire.read());
      Uart.line[i++] = Wire.read();
    }
    //Serial.println();
  }
  Wire.endTransmission();
  Uart.line[ i ] = '\0';                   // Terminate string
  processCommand(Uart.line);
  //Serial.println(Uart.line);
}
以上為接收到 slave 送回的指令處理, 目前為控制servo馬達的轉動角度

Slave端設定如下:
#define SLAVE_ADDRESS 0x01
Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 1
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register event

void requestEvent()
{
  if(flag.I2C_Flag==1)
  {
    //Serial.println( Uart.line );
    Wire.write(Uart.line,6);
  }
}

//-----servo1 angle---------
  if(strstr(data, "S1_") != NULL)
  {
    for(int i=3;i    {
      Uart.ctemp[i-3]=data[i];
    }
    Uart.ctemp[ len-3 ] = '\0';
    tempDIO=atoi(Uart.ctemp);
    Serial.println(tempDIO);
    flag.I2C_Flag=1;
  }
將UART收到的 "S1_100"的格式拆解  馬達servo1 轉 100度 再轉發給 master 去控制 master的servo1 轉動100度!

將Arduino 的code 編輯完後! 就可以到 c#上的上機介面去做開發!!


2020年1月4日 星期六

Arduino Yun 與兩台 USB Camera 的 video stream

最近在玩servo 馬達時把Yun 重新拿出來研究一番!!
心血來潮接上USB HUB然後把手上兩個usb camera同時接上!

用SSH 進去 OpenWRT的 Linux operating system 
先安裝 opkg install usbutils 以便檢查 USB device
root@Arduino:~# find /dev/bus/usb

/dev/bus/usb
/dev/bus/usb/001
/dev/bus/usb/001/005
/dev/bus/usb/001/004
/dev/bus/usb/001/002
/dev/bus/usb/001/003
/dev/bus/usb/001/001

root@Arduino:/# lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-platform/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/7p, 480M
            |__ Port 2: Dev 6, If 0, Class=Video, Driver=uvcvideo, 480M
            |__ Port 2: Dev 6, If 1, Class=Video, Driver=uvcvideo, 480M
            |__ Port 2: Dev 6, If 2, Class=Audio, Driver=snd-usb-audio, 480M
            |__ Port 2: Dev 6, If 3, Class=Audio, Driver=snd-usb-audio, 480M
            |__ Port 3: Dev 5, If 0, Class=Video, Driver=uvcvideo, 480M
            |__ Port 3: Dev 5, If 1, Class=Video, Driver=uvcvideo, 480M
        |__ Port 4: Dev 4, If 0, Class=Mass Storage, Driver=usb-storage, 480M

確定有兩台 video device後 開始進行介面的開發
在openWRT 下
mjpg_streamer -i \"input_uvc.so -d /dev/video0 -r 640x480 -f 6\" -o \"output_http.so -p 8080 -w /www/webcam

mjpg_streamer -i \"input_uvc.so -d /dev/video1 -r 640x480 -f 6\" -o \"output_http.so -p 8081 -w /www/webcam

將/dev/video0 的影像stream到 port 8080
/dev/video1的影像stream到port 8081
兩台Camera 對照的stream 照片