/* 自定義代碼塊樣式 */
顯示具有 Arduino 標籤的文章。 顯示所有文章
顯示具有 Arduino 標籤的文章。 顯示所有文章

2020年6月19日 星期五

使用 VB 透過 SCPI 控制儀器設備

markdown
因要讀取電表的資料,所以接觸了SCPI這個語言,這次又要讀取示波器的波形資料,所以乾脆整理了一下使用的命令,方便於日後查詢

SCPI (Standard Command for Programmable Instrumentation)可程式化儀器標準語言,是透過ASCII語法來與儀器做溝通

簡單的命令範例如下
MEASure:VOLTage:DC?;:MEASure:CURRent:AC?
當然首先要先安裝電腦端的驅動程式,因為電表是使用Keysight的,所以就上Keysight網站找驅動程式了,下載網址

網站中有三套軟體,IO Libraries Suite是最主要的驅動,會安裝VisaComLib這個Library,主要是透過這個Library跟儀器做溝通的,所以至少要安裝這套軟體

在VB6中,要使用VisaComLib時,需要先引用它,所以要到 [專案] --> [設定引用項目] 中,選取 [VISA-COM 5.12 Type Library] 後才能開始寫應用程式

在VB6中宣告如下

 '--- General define ---
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 'declare to use "sleep"
Dim ioMgr As VisaComLib.ResourceManager
Dim instrument As VisaComLib.FormattedIO488

'--- function define ---
Dim ioMgr As VisaComLib.ResourceManagerDim instrument As VisaComLib.FormattedIO488
Dim sndBuffer As String
Dim rcvBuffer As String
Set ioMgr = New VisaComLib.ResourceManager
Set instrument = New VisaComLib.FormattedIO488
Set instrument.IO = ioMgr.Open("USB0::10893::4865::MY59022278::0::INSTR")
instrument.SetBufferSize IO_IN_AND_OUT_BUFS, 64

*IDN?是所有儀器通用的命令,透過這個指令來查詢儀器的 ID。儀器通常會回傳製造商名稱、儀器型號,以及製造商提供的韌體版本英數字元
instrument.WriteString "*IDN?"
Debug.Print instrument.ReadString
讀取電壓與電流的程式如下
'--------------------------
' Volt
'--------------------------
    status = commSend(instrument, "SENSe:VOLTage:DC:NULL:VALue:AUTO 1")
    status = commSend(instrument, "CONFigure:VOLTage:DC 10,0.001")        ' mV resolution
    status = commSend(instrument, "SAMPle:COUNt 1")
    status = commSend(instrument, "*WAI")
    rcvBuffer = commQuery(instrument, "READ?")
    
'--------------------------
' Current
'--------------------------
    status = commSend(instrument, "SENSe:CURRent:DC:NULL:VALue:AUTO 1")
    status = commSend(instrument, "CONFigure:CURRent:DC 1E-6")        
    status = commSend(instrument, "CURRent:DC:RES 1E-6")                        ' uA resolution
    status = commSend(instrument, "SAMPle:COUNt 1")
    status = commSend(instrument, "*WAI")
    rcvBuffer = commQuery(instrument, "READ?")
電表是使用USB連接,後來要控制R&S示波器,就想改用TCP/IP的方式試試,也是OK的喔,下面列出幾個範例,讀取波形電壓平均值、上升時間及波形的各點電壓資料
'==================================
' R&S RTM3004 波形平均值
'==================================
    instrument.WriteString "TRIGger:A:EDGE:SLOpe NEGative"
    instrument.WriteString "MEASurement1:SOURce CH2"
    instrument.WriteString "MEASurement1:MAIN MEAN"
    instrument.WriteString "MEASurement1:RESult? MEAN"
'==================================
'Measure rise time 
'==================================
    instrument.WriteString "TRIGger:A:EDGE:SLOpe NEGative"
    instrument.WriteString "MEASurement1:SOURce CH2"
    instrument.WriteString "REFLevel:RELative:MODE TEN"		' 10% - 90%
    instrument.WriteString "MEASurement1:MAIN RTIMe"
    instrument.WriteString "MEASurement1:RESult?"  
'==================================
' Wave RAW data
'==================================  
    instrument.WriteString "TRIGger:A:MODE NORMal"           ' Normal trigger
    instrument.WriteString "TRIGger:A:EDGE:SLOpe NEGative"      ' Negative edge
    
    instrument.WriteString "FORM ASC"							  ' output format ASCii
    instrument.WriteString "FORM:BORD LSBF"
    instrument.WriteString "CHAN1:DATA:POIN DEF"
    
    instrument.WriteString "SINGle"                     ' Single trigger
    
    instrument.WriteString "CHANnel1:DATA:HEAD?"
    Debug.Print instrument.ReadString
    
    instrument.WriteString "CHANnel1:DATA?"
    Debug.Print instrument.ReadString
下面是UART、USB與TCP/IP的宣告方式
'=========
 'UART
 '=========
    Set instrument.IO = ioMgr.Open("ASRL6::INSTR")  ' COM6
    
    Dim serInfc As VisaComLib.ISerial
    Set serInfc = instrument.IO
    serInfc.BaudRate = 9600                         ' 9600bps baud rate
    serInfc.FlowControl = ASRL_FLOW_NONE
    serInfc.Timeout = 10000
    instrument.IO.SendEndEnabled = True
    instrument.IO.TerminationCharacter = 10          ' could be 10 (line feed) or 13 (carriage return)
    instrument.IO.TerminationCharacterEnabled = True
    instrument.IO.Timeout = 10000
    
 '=========
 'USB
 '=========
    Set instrument.IO = ioMgr.Open("USB0::0x0AAD::0x01D6::104068::INSTR")
    instrument.SetBufferSize IO_IN_AND_OUT_BUFS, 64
    Set serInfc = instrument.IO
    
 '=========
 'TCP/IP
 '=========
    
    Set instrument.IO = ioMgr.Open("tcpip0::192.168.0.13::instr")        ' ip addr 192.168.0.13
    instrument.SetBufferSize IO_IN_AND_OUT_BUFS, 64
    Set serInfc = instrument.IO
下面是用Arduino與ADS1015做的4通道電表,解析度至小數第二位,使用VBA透過UART讀取電表至Excel表格中
Arduin 用的SCPI Library 有蠻多個 (Vrekrer_scpi_parser) (Open Instrument Control),下面範例是使用OIC的Library完成的



2020年6月4日 星期四

智能插座改造

markdown
最近看到一個智能插座,因為沒有App的支援,所以老闆就便宜賣,價格超便宜,就買了幾個回來準備拆開研究看看,拆開後如下


底部插座跟Relay部分可以延用,上面有一片小板,是藍芽控制板,既然沒有App支援,就乾脆改裝WiFi版的智能插座吧

從抽屜中拿出ESP8266模組,研究一下藍芽小板的走線後,便把藍芽模組拆掉


因為頂部空間有限,要焊接ESP8266上去似乎不太夠,便用漆包線延長,固定在側邊

最後再裝回原來的樣子,WiFi版的智能插座硬體部分就完成了



ESP8266的韌體一樣使用Arduino做開發,使用 IotWebConf 及 arduino-mqtt 的Library,
並以 IotWebConf07MqttRelay 範例進行修改

韌體/硬體完成後,就可以用手機進行設定了,如下是連線後跳出的畫面,按下configure page就可以進行設定



Thing name 可以修改成自己想要的名稱,之後設定 MQTT 時會需要這個名稱
AP password 就是登入這個裝置的WiFi密碼
WiFi SSID 要讓裝置連線的 AP SSID名稱
WiFi password 要讓裝置連線的 AP SSID 密碼  
MQTT server 讓裝置可登入的MQTT sever,因我自己是在 NAS 上增加MQTT的服務,所以這邊是填家中的NAS IP address

接著是新增加的功能,本來的範例除了可以遠端控制外,我還想讓裝置有定時的功能,所以多增加五組的開關機時間

--------------------------------------------------------------------------------

都設定完成後,準備進行測試

安裝 Chrome MQTT延伸擴充功能進行測試,如下為 MQTTLens 套件



一樣將MQTT server設定好,訂閱的路徑設定好,應該就可以對裝置進行操作了

如下圖

Subscribe : /devices/testThing/status 
Publish : /devices/testThing/action

其中的 testThing 就是前面透過手機所設定的 Thing name 名稱

在 Message 填入ON或OFF即可進行測試



--------------------------------------------------------------------------------

以上都在電腦端測試完成後,手機App呢? 

參考另一篇文章,App的設定

https://mattlinotes.blogspot.com/2020/10/app.html

下一步,準備把溫度與濕度 sensor 也一併整合進這個智能插座中,掌握當下的房間狀況,決定要不要遠端啟動受控裝置了


2019年4月25日 星期四

新增 PM2.5 Homekit 裝置

markdown

手上買了一個Sharp GP2Y1010AU0F PM2.5的感測器,就只在買來的當下用UNO測試了一下,嗯~~可用,就收起來了,一直到這次要整合在一個能夠顯示時間又有Homekit功能的系統板上(暫且稱它為家庭顯示中心吧),才又把它拿出來了。

把UNO的code  Ctrl+C、Ctrl+V到ESP32下,理論上應該是沒問題的,所以就做啦,只把Delay的部分修改為vTaskDelay,因為我是採用ESP-IDF + RTOS + Arduino 的平台,Flash完,怎麼收到的電壓都是0V,用VR分壓測試,A/D沒問題啊,怎麼沒收到GP2Y的電壓,換回UNO,一切正常啊,甚麼問題???

好,Hardward沒問題,Firmware我只修改Delay,問題不會就在這吧

沒錯,在UNO下的Delay是
delayMicroseconds(280)
ESP32是
vTaskDelay(280/portTICK_RATE_MS)
這可是差1000倍呀!!

既然在ESP-IDF下已經有支援arduino的套件,那就在這裡也改用delayMicroseconds函數吧,應該不至於影響整個系統太多,畢竟我還有其他task在執行

compiler...  flash... run... ,Yes~ got it ,讀到值啦,那就繼續往下一步去,增加到Homekit裝置

新增Homekit裝置時,都需要滿足Apple的servicecharacteristics定義,但因為我不是ios developer,所以也不知道定義的方式為何,不過沒關係,網路上很多神人的,下面就有一個 characteristics.h 的定義檔可以參考

characteristics.h

用一個開關當範例說明 (參考characteristics.h)

在SERVICE中需要的的是ON這個Characteristics
NAME就列為選項,可有可無了

/**
 Defines that the accessory contains a switch.
 
 Required Characteristics:
 - ON
 
 Optional Characteristics:
 - NAME
 */
#define HOMEKIT_SERVICE_SWITCH HOMEKIT_APPLE_UUID2("49")


ON這個Characteristics的定義如下

(第6行).permissions中有read、write與notify三個函數
(第9行).value中描述值為BOOL

所以我們共要有三個函數加一個BOOL值

#define HOMEKIT_CHARACTERISTIC_ON HOMEKIT_APPLE_UUID2("25")
#define HOMEKIT_DECLARE_CHARACTERISTIC_ON(_value, ...) \
    .type = HOMEKIT_CHARACTERISTIC_ON, \
    .description = "On", \
    .format = homekit_format_bool, \
    .permissions = homekit_permissions_paired_read \
                 | homekit_permissions_paired_write \
                 | homekit_permissions_notify, \
    .value = HOMEKIT_BOOL_(_value), \
    ##__VA_ARGS__

回到程式碼中,(第13行)struct hap\_characteristic switch1[]中
switch\_state 就是.value的 BOOL 定義,true 就是switch on,false即為switch off
switch1\_read、switch1\_write與switch1\_notify 就分別是三個函數啦
void *accessory_object = hap_accessory_add(acc);
    struct hap_characteristic cs[] = {
        {HAP_CHARACTER_IDENTIFY, (void *)true, NULL, identify_read, NULL, NULL},
        {HAP_CHARACTER_MANUFACTURER, (void *)MANUFACTURER_NAME, NULL, NULL, NULL, NULL},
        {HAP_CHARACTER_MODEL, (void *)MODEL_NAME, NULL, NULL, NULL, NULL},
        {HAP_CHARACTER_NAME, (void *)ACCESSORY_NAME, NULL, NULL, NULL, NULL},
        {HAP_CHARACTER_SERIAL_NUMBER, (void *)"0123456789", NULL, NULL, NULL, NULL},
        {HAP_CHARACTER_FIRMWARE_REVISION, (void *)"1.0", NULL, NULL, NULL, NULL},
    };
    hap_service_and_characteristics_add(acc, accessory_object, HAP_SERVICE_ACCESSORY_INFORMATION, cs, ARRAY_SIZE(cs));


struct hap_characteristic switch1[] = {
        {HAP_CHARACTER_ON, (void *)switch_state,NULL, switch1_read, switch1_write, switch1_notify},
    };
    hap_service_and_characteristics_add(acc, accessory_object, HAP_SERVICE_SWITCHS, switch1, ARRAY_SIZE(switch1));

switch1\_read、switch1\_write與switch1\_notify 三個函數範例程式如下

void *switch1_read(void *arg)
{
    return (void *)switch_state;
}

void switch1_write(void *arg, void *value, int len)
{
    switch_state= ((int)value) ? true : false;

    if (switch_state)
        LED_ON();
    else
        LED_OFF();

    if (_switch1_ev_handle)
        hap_event_response(acc, _switch1_ev_handle, (void *)switch_state);
    return;
}

void switch1_notify(void *arg, void *ev_handle, bool enable)
{
    if (enable)
        _switch1_ev_handle = ev_handle;
    else
        _switch1_ev_handle = NULL;
}



好了,進入主題了,新增PM2.5的Homekit裝置

當我們要使用 air quality 時,需要AIR\_QUALITY的Characteristics,PM2\.5(PM25_DENSITY) 則是列為選項

/**
 Defines that the accessory contains a air quality sensor.
 Required Characteristics:
 - AIR_QUALITY
 
 Optional Characteristics:
 - NAME
 - STATUS_ACTIVE
 - STATUS_FAULT
 - STATUS_TAMPERED
 - STATUS_LOW_BATTERY
 - OZONE_DENSITY
 - NITROGEN_DIOXIDE_DENSITY
 - SULPHUR_DIOXIDE_DENSITY
 - PM25_DENSITY
 - PM10_DENSITY
 - VOC_DENSITY
 - CARBON_MONOXIDE_LEVEL
 - CARBON_DIOXIDE_LEVEL
 */
#define HOMEKIT_SERVICE_AIR_QUALITY_SENSOR HOMEKIT_APPLE_UUID2("8D")

來看看 AIR\_QUALITY 的Characteristics
.permissions 列出 read與notitfy
.value 是 0, 1, 2, 3, 4, 5,共六個有效值

#define HOMEKIT_CHARACTERISTIC_AIR_QUALITY HOMEKIT_APPLE_UUID2("95")
#define HOMEKIT_DECLARE_CHARACTERISTIC_AIR_QUALITY(_value, ...) \
    .type = HOMEKIT_CHARACTERISTIC_AIR_QUALITY, \
    .description = "Air Quality", \
    .format = homekit_format_uint8, \
    .permissions = homekit_permissions_paired_read \
                 | homekit_permissions_notify, \
    .min_value = (float[]) {0}, \
    .max_value = (float[]) {5}, \
    .min_step = (float[]) {1}, \
    .valid_values = { \
        .count = 6, \
        .values = (uint8_t[]) { 0, 1, 2, 3, 4, 5 }, \
    }, \
    .value = HOMEKIT_UINT8_(_value), \
    ##__VA_ARGS__

PM25\_DENSITY 的Characteristics
.permissions 列出 read與notitfy
.value 是 0~1000 的範圍

#define HOMEKIT_CHARACTERISTIC_PM25_DENSITY HOMEKIT_APPLE_UUID2("C6")
#define HOMEKIT_DECLARE_CHARACTERISTIC_PM25_DENSITY(_value, ...) \
    .type = HOMEKIT_CHARACTERISTIC_PM25_DENSITY, \
    .description = "PM25 Density", \
    .format = homekit_format_float, \
    .permissions = homekit_permissions_paired_read \
                 | homekit_permissions_notify, \
    .min_value = (float[]) {0}, \
    .max_value = (float[]) {1000}, \
    .value = HOMEKIT_FLOAT_(_value), \
    ##__VA_ARGS__

有上面這些資料,就可以變成我們的code了,範例如下

struct hap_characteristic air_quality[] = {
    {HAP_CHARACTER_AIR_QUALITY , (void *)air_quality_value,NULL, air_quality_read, NULL, air_quality_notify},
    {HAP_CHARACTER_PM2_5_DENSITY , (void *)pm25_ugm3_value,NULL, pm25_ugm3_read, NULL, pm25_ugm3_notify},
}  
hap_service_and_characteristics_add(acc, accessory_object, HAP_SERVICE_AIR_QUALITY_SENSOR , air_quality,ARRAY_SIZE(air_quality));


寫完,收工~~~~~~






2019年4月22日 星期一

單顆按鍵程式庫 OneButton

markdown
最近在開發的板子,因為當初僅設計一個按鍵,現在又需要進行更多的設定操作,結果外接的IO腳位不夠使用了,便上網搜尋了一下,找到了OneButton Library可以用,連結如下

https://github.com/mathertel/OneButton

它可以透過一個按鍵判斷Click、Double Click、Long Press的狀態,剛好可以滿足現在的應用了

下面是把所有OneButton的Function都列出,可以把需要的Function保留下來就好

#include "OneButton.h"
OneButton button1(GPIO_NUM_0, true);

void click1(){
......
}

void doubleclick1(){
......
}

void longPressStart1(){
......
}

void longPressStop1(){
......
}

void longPress1(){
......
}

void setup(){
    button1.attachClick(click1);
    button1.attachDoubleClick(doubleclick1);
    button1.attachLongPressStart(longPressStart1);
    button1.attachLongPressStop(longPressStop1);
    button1.attachDuringLongPress(longPress1);
}

在ESP32S3使用 Adafruit_TinyUSB 建立 HID 裝置進行讀寫

Adafruit_USBD_HID usb_hid; #define USB_VID 0xCafe #define USB_PID 0x4011 #define USB_MANUFACTURER "ESP32S3" #define USB_PRODUCT ...