/* 自定義代碼塊樣式 */

2026年2月9日 星期一

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

Adafruit_USBD_HID usb_hid;

#define USB_VID 0xCafe
#define USB_PID 0x4011
#define USB_MANUFACTURER "ESP32S3"
#define USB_PRODUCT "ESP32 HID"

#define HID_REPORT_SIZE 64

static const uint8_t hid_report_descriptor[] = {
  0x06, 0x00, 0xFF,        // Usage Page (Vendor)
  0x09, 0x01,              // Usage
  0xA1, 0x01,              // Collection (Application)

  0x09, 0x02,
  0x15, 0x00,
  0x26, 0xFF, 0x00,
  0x75, 0x08,
  0x95, HID_REPORT_SIZE,
  0x81, 0x02,              // Input

  0x09, 0x03,
  0x15, 0x00,
  0x26, 0xFF, 0x00,
  0x75, 0x08,
  0x95, HID_REPORT_SIZE,
  0x91, 0x02,              // Output

  0xC0
};

uint8_t hid_rx_buffer[HID_REPORT_SIZE];
uint8_t hid_tx_buffer[HID_REPORT_SIZE];

// PC → ESP32
void hid_set_report_cb(uint8_t report_id,
                       hid_report_type_t report_type,
                       uint8_t const* buffer,
                       uint16_t bufsize)
{
 
  memcpy(hid_rx_buffer, buffer, bufsize);

  Serial.print("RX: ");
  Serial.print(bufsize);
  Serial.print("  ");
  
  for(int ii=0;ii
在setup 中的設定
  // 初始化 HID
  TinyUSBDevice.setID(USB_VID, USB_PID);
  TinyUSBDevice.setManufacturerDescriptor("MattLab");
  TinyUSBDevice.setProductDescriptor("ESP32S3 MSC+HID");

  // ---------- HID ----------
  usb_hid.setReportDescriptor(hid_report_descriptor, sizeof(hid_report_descriptor));
  usb_hid.setPollInterval(2);
  usb_hid.setReportCallback(NULL, hid_set_report_cb);
  usb_hid.begin();
ESP32 → PC 將資料存放於 hid_tx_buffer 陣列中再送出
memset(hid_tx_buffer, 0, HID_REPORT_SIZE);
usb_hid.sendReport(0, hid_tx_buffer, HID_REPORT_SIZE);

2026年2月7日 星期六

ESP32-S3 使用 Adafruit SDFAT 控制 SD card

 

移除 SDFAT 相關的程式庫

安裝 Adafruit SdFat 版本的程式庫

Adafruit SdFat - Adafruit Fork of SdFat

完整code
#include 
#include 
#include 

#define SD_MISO 37
#define SD_MOSI 35
#define SD_SCK  36
#define SD_CS   38

#define SD_FAT_TYPE 1

SPIClass spiSD(FSPI);
SdFat32 SD;

void setup() {
  Serial.begin(115200);

  delay(2000);

  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);

  spiSD.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);

  SdSpiConfig spiConfig(
    SD_CS,
    SHARED_SPI,
    SD_SCK_MHZ(10),
    &spiSD
  );

  if (!SD.begin(spiConfig)) {
    Serial.println("SD init failed");
    while(1);
  }

  Serial.println("SD init OK");

  printCardInfo();
  listFiles();
}

void loop(){}


void printCardInfo() {
  uint32_t sizeMB = SD.card()->sectorCount() / 2048;
  Serial.print("Card size: ");
  Serial.print(sizeMB);
  Serial.println(" MB");
}


void listFiles() {
  char filename[255];
  Serial.println("\n📂 Files:");

  File32 root = SD.open("/");
  File32 file = root.openNextFile();

  while (file) {
    if (file.getName(filename, sizeof(filename))) {
      Serial.print(filename); // Successfully got the name
      Serial.print("  ");
      Serial.println(file.size());
      file = root.openNextFile();
    }
  }
}

輸出結果


2026年2月5日 星期四

SquareLine 在TextArea輸入時顯示鍵盤,未使用時隱藏鍵盤的設定

 1.選取 KEYBOARD WIDGE,並在Flags 中將 Hidden 打勾



2. 當按下鍵盤的確認鍵()就設定隱藏鍵盤

    增加 TextArea 的 EVENT,Action為MODIFY FLAG,Trigger 為READY


3. 當點選別的物件時隱藏鍵盤

    增加 TextArea 的 EVENT,Action為MODIFY FLAG,Trigger 為DEFOCUSED





SquareLine 一個鍵盤對應多個文字框 TextArea的設定方式

1. 配置版面範例,有兩個 TextArea 輸入欄位及一個Keyboard



2. 點擊TextArea,並在右下方EVENTS按下 ADD EVENT


3. Trigger 選擇 FOCUSED,Action 選擇 KEYBOARD SET TARGET 後按下 ADD 


4. Keyboard 選擇KEYBOARD WIDGE 的名稱,TextArea 選擇當下的TextArea名稱

5. 對所有文字框都重複以上步驟即可完成一個Keyboard對應多個TextArea的設定


2026年2月4日 星期三

Arduino GFX 增加 QSPI Read 功能

1. 在 Arduino_DataBus.h 中增加 virtual void read 宣告
  class Arduino_DataBus
    {
      public:
        Arduino_DataBus();
          virtual void read(uint8_t cmd, uint8_t addr, uint8_t *data, uint8_t len) = 0;
2. 在 Arduino_ESP32SPI.h 中增加 void read 宣告
  class Arduino_ESP32SPI : public Arduino_DataBus
    {
      public:
        void read(uint8_t cmd, uint8_t addr, uint8_t *data, uint8_t len);
3. 在 Arduino_ESP32QSPI.h 中增加 void read 宣告
  class Arduino_ESP32QSPI : public Arduino_DataBus
    {
      public:
        void read(uint8_t cmd, uint8_t addr, uint8_t *data, uint8_t len) override;;
4. 在 Arduino_ESP32QSPI.c 中增加 void Arduino_ESP32QSPI::read 作法
  void Arduino_ESP32QSPI::read(uint8_t cmd, uint8_t addr, uint8_t *data, uint8_t len)
{
  CS_LOW();
  
  spi_transaction_ext_t trans = {};
  trans.base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_MODE_QIO;
  trans.base.cmd = cmd;
  trans.base.addr = addr;
  trans.base.rxlength = len * 8; 
  trans.base.rx_buffer = data;

  trans.command_bits = 8;
  trans.address_bits = 8;  
  trans.dummy_bits = 8;
  
  spi_device_polling_transmit(_handle, (spi_transaction_t *)&trans);
	
  CS_HIGH();
}
  

2025年2月11日 星期二

定義Arduino Flash Partition

在Arduino 的工程目錄中,增加一個 partitions.csv 文字檔案,內容範例如下
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x140000,
font_hs20,data,      ,   0x150000,0x2250ac,
spiffs,   data, spiffs,  0x3C0000,0x30000,
coredump, data, coredump,0x3F0000,0x10000,

2025年2月7日 星期五

獨立編譯 LVGL 中文字庫並放置於Flash中並使用Arduino讀取

透過LVGL官方網站字體轉換網頁,轉換出需要的UNICODE字庫
Font converter
這邊取用 HarmonyOS_Sans_SC_Regular.ttf 作為TTF字體測試範例,可於此處下載字體 
因為要轉換字體大小為20,在Name欄位填寫 font_harmony_sans_20
TTF字體範圍: 0x20-0xBF,0x3000-0x301F,0x4E00-0x9FAF,0xFF00-0xFF64

按下Submit後開始進行轉換,完成後,會下載一個 font_harmony_sans_20.c 的檔案,裡面即為字型檔案,接著要將此檔案複製一份,將此檔案分別為兩個檔案,font_harmony_sans_20.c與font_harmony_sans_20_font.c
font_harmony_sans_20.c 是將 glyph_bitmap[] 與 glyph_dsc[] 兩個陣列移除後的檔案,font_harmony_sans_20_font.c 則相反,是將 glyph_bitmap[] 與 glyph_dsc[] 兩個陣列的所有資料及檔頭資訊保留下來的檔案,如下圖  (已將兩陣列資料摺疊收起)


將font_harmony_sans_20.c與font_harmony_sans_20_font.c 複製到 Arduino\libraries\lvgl\src\font 目錄下
修改 font_harmony_sans_20.c 檔案
1.修改引入檔案路徑 修改前
#include "lvgl/lvgl.h"
修改後
#include "../../lvgl.h"
2.增加ESP相關函數
#include <‍esp_partition.h‍>
#include <‍esp_err.h‍>
#include <‍esp_log.h‍>
#include <‍nvs_flash.h‍>

static const char *TAG = "lv_font_harmony_sans_20";
3.在font_harmony_sans_20.c 增加讀取MMU記憶體位址的函數,最後的 font_dsc.glyph_dsc 偏移量會在後面透過命令得到
 lv_port_font_harmony_sans_20_load(const char *partition_label)
{
    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, partition_label);
    if(partition == NULL) {
        ESP_LOGE(TAG, "Can't find %s partition!", partition_label);
        abort();
    }
	
	ESP_LOGE(TAG, "Find %s partition!", partition_label);

	const void *flash_offset;
    esp_partition_mmap_handle_t map_handle;
	
	// Map the partition to data memory
    ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &flash_offset, &map_handle));
    ESP_LOGE(TAG, "Mapped partition to data memory address %p\n", flash_offset);
    ESP_LOGE(TAG, "mapped %s@%1p", partition->label, flash_offset);
    
    font_dsc.glyph_bitmap            = flash_offset;
	font_dsc.glyph_dsc               = flash_offset+0x1d26dc;	//2bpp
}
並在 lv_font.h中增加
extern const lv_font_t font_harmony_sans_20;
void lv_port_font_harmony_sans_20_load(const char *partition_label);  
增加一個 rodata_gen_bin.ld 腳本檔案,確保 .rodata是從0x00的位置開始
SECTIONS {
    . = 0x0;
    .text : {
        *(.rodata)
    } = 0
}

開始編譯 font_harmony_sans_20_font.c 檔案,路徑會因安裝Arduino在不同位置而有所差異

1. 編譯 font_harmony_sans_20_font.c 產生.o 檔案
C:\Users\yyli\AppData\Local\Arduino15\packages\esp32\tools\esp-x32\2405\bin\xtensa-esp32-elf-gcc -c -D LV_CONF_SKIP -D LV_FONT_FMT_TXT_LARGE -I d:\Users\yyli\Documents\Arduino\\libraries\lvgl font_harmony_sans_20_font.c
2. 編譯 .o code
C:\Users\yyli\AppData\Local\Arduino15\packages\esp32\tools\esp-x32\2405\bin\xtensa-esp32-elf-ld -T rodata_gen_bin.ld .\font_harmony_sans_20_font.o -o  font_harmony_sans_20_font.out
3. 生成 .bin code
C:\Users\yyli\AppData\Local\Arduino15\packages\esp32\tools\esp-x32\2405\bin\xtensa-esp32-elf-objcopy --output-target elf-xtensa-le -O binary -S font_harmony_sans_20_font.out font_harmony_sans_20_font.bin
4. 查看字型陣列資料的偏移值
C:\Users\yyli\AppData\Local\Arduino15\packages\esp32\tools\esp-x32\2405\bin\xtensa-esp32-elf-objdump -t font_harmony_sans_20_font.out
Dump偏移量的結果,把結果回填到 font_harmony_sans_20.c 的 font_dsc.glyph_dsc 偏移值,在此例為 0x1d26dc
font_harmony_sans_20_font.out:     file format elf32-xtensa-le

SYMBOL TABLE:
00000000 l    d  .text  00000000 .text
00000000 l    d  .comment       00000000 .comment
00000000 l    d  .xtensa.info   00000000 .xtensa.info
00000000 l    d  .xt.prop       00000000 .xt.prop
00000000 l    df *ABS*  00000000 font_harmony_sans_20_font.c
00000000 l     O .text  001d26db glyph_bitmap
001d26dc l     O .text  000529d0 glyph_dsc
使用樂鑫官方的Flash downliad tool將font_harmony_sans_20_font.bin燒錄到 Font Flash 定義的為止即可,(定義Arduino flash partition) 上面產生的 font_harmony_sans_20_font.bin 在flash要預留glyph_bitmap + glyph_dsc 的大小,所以在partition.csv中定義 bin起始位址 0x150000,size為 0x2250ac 到此完成把字體bin燒錄到flash,在程式中要用到中文字時先呼叫 lv_port_font_harmony_sans_20_load("font_hs20"); 函數就能夠使用中文字了
  lv_init();
  lv_display_t * disp;
  
  /*TFT_eSPI can be enabled lv_conf.h to initialize the display in a simple way*/
  disp = lv_tft_espi_create(TFT_HOR_RES, TFT_VER_RES, draw_buf, sizeof(draw_buf));
  lv_display_set_rotation(disp, TFT_ROTATION);
 
  /* Create simple label */
  lv_obj_t *label = lv_label_create(lv_screen_active());

  lv_port_font_harmony_sans_20_load("font_hs20");
  lv_obj_set_style_text_font(label, &font_harmony_sans_20, 0);

  lv_label_set_text(label, "Hello Arduino! (V9.0) 中文版");
  lv_obj_align(label, LV_ALIGN_CENTER, 0, -50);

2023年10月2日 星期一

Free ERP on the Raspberry Pi (odoo)

 

#更新系統軟體

sudo apt update && sudo apt upgrade -y


#安裝資料庫

sudo apt install postgresql -y


#安裝py程序

sudo apt install python3-pip -y


#安裝odoo PDF工具

# for 32bit

wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.raspberrypi.bullseye_armhf.deb

sudo apt install ./wkhtmltox_0.12.6.1-2.raspberrypi.bullseye_armhf.deb -y


# for 64bit

wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.bullseye_arm64.deb

sudo apt install ./wkhtmltox_0.12.6.1-2.bullseye_arm64.deb -y


#安裝PDF工具中文字形

sudo apt install fonts-wqy-microhei ttf-wqy-microhei fonts-wqy-zenhei ttf-wqy-zenhei -y


#清理快取

fc-cache -f -v


# check Odoo service is running

sudo systemctl status odoo

2022年9月12日 星期一

DIY 簡易式數位電源供應器

一個小型桌上型的電源是很久前就想做的,但想了很久還是沒動手做

但,現在只要接幾條線,就可以完成了,先看成品吧




輸出 5V的時候,跟旁邊的硬幣比,就知道大小了

這是用兩個模組拼接起來的,一個是AC轉DC12V2A的電壓轉換模組


另一個模組是DC數位式降壓模組,按鍵與功能說明如下
把AC/DC模組的輸出接到降壓模組的輸入端,然後再於降壓模組的輸出端接上香蕉端子座,就完成了

電壓設定的範圍從功能圖上可以看到,為1.2V~32V,實際來操作一下
每按一次+或 - 的按鈕,就會有0.05V的變化,若是長按的話,變化量則為0.1V的變化,最後的最大值與最小值設定確實為1.2V與32V




但因為現在的輸入只有12V,所以超過12V的電壓實際上還是只有12V而已,僅僅是降壓模組可以支援到32V的設定,不等於實際上的輸出,所以若真的要輸出32V,就必須把輸入端的電壓再提高到32V以上,不過因為目前實驗都在12V以下,因此就目前的電壓來說已經很足夠我使用了

最後來看一下輸入端的電壓,實際是12.1V,改天需要再找個外殼給它穿上












2021年3月26日 星期五

設定Home Assistant

 安裝完成HA後,接著就是要進行設定的工作

在左邊選單列中,選擇Supervisor,再到右邊畫面,上方選擇附加元件商店,安裝我們需要的套件包



這邊是安裝四個套件包的畫面,File editor請一定要選擇,因後面有部分設定會需要用到它來進行;同時也將樹莓派當作 MQTT broker ,因此有安裝 Mosquitto broker



點選 MQTT broker ,並於上方選擇[設定]
這邊有變動到的就只有使用者帳號與密碼,都修改為tester,可依自己需要做修改



最後一步驟,點選左邊File editor的選單,編輯 /config/configuration.yaml 檔案
在在最後面加入

mqtt:
  discovery: true
  broker: 127.0.0.1
  username: tester
  password: tester

MQTT broker設定就算完成了






2021年3月25日 星期四

安裝 Home Assistant

 markdown

Home Assistant 我是用官方的映象檔安裝在樹莓派上使用,下載的檔案就直接燒錄在SD卡即可,這邊我使用的燒錄軟體是Rufus

但別急著插進樹莓派開機,還要設定WiFi連線,才能讓樹莓派連上網路

在SD卡根目錄下,新增一個CONFIG的目錄,裡面再新增一個network目錄

在network目錄內,增加一個文字檔案 my-network

[connection]
id=resin-wifi
type=wifi

[wifi]
hidden=true
mode=infrastructure
ssid=你的SSID名稱

[ipv4]
method=auto

[ipv6]
addr-gen-mode=stable-privacy
method=auto

[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=你的Wifi密碼

把ssid與wifi密碼修改完後,就可以插入樹莓派開機了

插入電源開機。第一次開機HA會自動下載最新版的 Home Assistant 並執行,耗時約 20 分鐘。

在等待更新的過程中,也可以打開瀏覽器輸入 http://hassio.local:8123 或是http://homeassistant.local:8123 看到HA的畫面

等待更新結束後,會看到建立帳號的畫面,就依照畫面指示,完成資料填寫即可






2020年10月23日 星期五

PL2303 傳輸線更換為 CH340N 晶片

手邊有兩個USB to Uart 的傳輸線都不能使用,可能是PL2303又掛了,所以這次不使用2303的IC,想要改裝成CH340的試試

從官網上查到有一個CH340N type,封裝只有8 pin,又不用外加振盪器,就入手了幾顆進行測試


首先當然是把PL2303從板子上移開,振盪器也卸除掉,如下圖


接著找看看有沒有相關的Pin 腳可以直接焊接就好


目前找到最好的擺法就是把 IC 反過來,背面朝上的方式,如下圖


焊接完後的結果


焊接的過程中,腦海中一直浮現一段話,「工程師沒什麼了不起的,只是比較會做手工藝而已」,這是一個業務朋友跟一個採購對話的內容,想想自己好像也是一個比較會做手工藝的工程師而已呀,哈

好了,焊接完成後,沒意外的話,應該就會在裝置管理員中看到COM Port了


後面再用 PUTTY 測試TXD/RXD是否正常,把TXD/RXD 短路在一起,Putty開啟 serial 模式,鍵盤敲什麼字元,Putty 終端機就應該要顯示什麼字元,如果都有顯示,代表正確焊接,收工啦













2020年10月20日 星期二

智能插座改造 -- 冷氣紅外線控制

markdown

一連買了好幾個智能插座後,一直用漆包線焊接也不是辦法,便動手layout一片板子,製做小量的PCB,汰換插座內的藍芽控制板,一樣是用 ESP8266 當主要控制器,還把未用到的pin也拉出,以備不時之需


因為機構的關係,所以 RXD pin 腳被犧牲了,背後還有個指示用的 LED 要跨接上去


焊接後的樣子如下,但下方的又被我改造了一番,我將本來控制繼電器的 pin 腳,改為紅外線發射 LED ,控制辦公室的冷氣,採用的是 Daikin 的Arduino 模組,也就是本來繼電器應該要ON 的時候,IR LED 會發射冷氣機ON的編碼,OFF時就發射OFF的編碼




紅線就只是壞掉的USB充電線,剪掉後僅使用5V電源,用膠帶黏在辦公室OA板上,使用著App 遠端開啟冷氣冷房,收工





智能插座 --- App篇

markdown

智能插座的硬體都改裝完成後,總是要能夠用手機操作吧,但我又不會寫App,這樣單有個插座硬體插座也是英雄無用武之地呀。

我自已是用 iPhone 手機,下載過好多個App都無法適用,某日不小心看到這個,安裝後,似乎可以滿足我要的功能


免費版只能使用10個 device,不過也夠用了,至少目前用不到那麼多,等超過了再購買App也行

下方左圖是正常使用畫面,右圖為 Edit 模式,預設的範例中有溫度曲線圖, 環狀溫度顯示方式,溫度設定等等的功能,更多功能可以自行研究,我們這邊只用到開關功能,圖中顯示在最下面的裝置 AC plug1,在Edit 編輯模式中,按下要修改的device 齒輪圖示,就進入了編輯模式


下圖左,首先看到的就是這個device的名稱(name),這邊示取名為AC plug1
然後把最下面 PUBLISH VALUES 中的 True與 False 分別改為 ON與OFF,
這意思表示當開關為【開】時,會在 Publish topic string 後面加上ON或OFF的字串,讓device去分析收到的訊息是要開啟裝置還是關閉裝置

接著要設定要發佈的訊息,按下 Publish 就進入設定畫面,如下圖右
把Topic string 填入發佈的訊息字串,這邊例子是填入 /devices/AC plug1/action
開啟 Allow publish,最下方的QoS選擇 At least once,也就是QoS1



接著要設定MQTT 主機,先按下主螢幕左上角的三藍線icon,再按下左下方的Settings,就可以看到如下圖左的設定畫面

點選 Configuration 組態設定,就會出現下圖右的 設定,在Host 端填入主機位址,若沒有,可以參考這裡  https://test.mosquitto.org/

設定完成後,回到主畫面,即完成設定了






至此算完成了,可以在回到家前,遠端把裝置開啟了









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年11月28日 星期四

遇見 LittlevGL

markdown



很久很久前,剛開始研究 ARM嵌入式系統時,就對圖形化介面吸引,希望能有一套開源、輕量、開機快速又能支援顯示中文的GUI,後來有找到一個名為ParaGUI的平台,不過基於沒太多時間研究,所以只稍稍碰了一下下,玩了幾個widge就沒再繼續了

這陣子在網上亂逛時,無意發現,原來還有一套能滿足我想要的GUI平台,LittlevGL,簡稱 LVGL

網頁寫的簡單明暸,有什麼功能,啪拉啪拉一籮筐,重點是體積小,80 kB Flash, 12 kB RAM就能執行起來了,這對一般的MCU來說,就是一大福音呀

在Github上,也已有提供 Arduino的lv\_arduino library,下載後直接使用即可,不過Arduino版的LVGL圖形顯示是建立在TFT\_eSPI library上,所以必須先讓TFT_eSPI能正確驅動 LCD螢幕,LVGL才能正常顯示

後續再慢慢介紹設定與使用方式,重點是中文字的顯示呀

(圖片來源:LittlevGL官網)

2019年8月2日 星期五

使用 MAX7219 驅動4個 8x8 矩陣式LED 顯示器



之前買了三個 6cm x 6cm 的MAX7219 白光LED點矩陣,把三個點矩陣串接起來並使用MaxMatrix Library做NTP時鐘,顯示都正常,所以就再加碼,買了比較小一點 4 in 1的,打算放在臥室



就在收到貨後,立馬更換,點亮了~,不過字體怎麼怪怪的,轉了90度,Google了一下,發現有MD_MAX72XX library 可以做轉向顯示,但是我已經用MaxMatrix 寫好code,不想大改了,所以只好捲起袖子,開始 trace MaxMatrix的code,看看能不能在最小幅度的修改下,達到文字旋轉90度的需求



下面是修改MaxMatrix.c,轉90度顯示所做的修改,有三個副程式需做修改

void MaxMatrix::setColumn(byte col, byte value)
{
    int xx = (col%8);   
    int yy = 0 ;   
   
    for (int row_i=0;row_i<8;row_i++){
        yy = (col/8)*8+row_i;
        setDot(xx, yy, bitRead(value, row_i));
    }
}

void MaxMatrix::setDot(byte col, byte row, byte value)
{
    int yy = 7-(col%8);
    int xx = (col/8)*8+row;
   
    bitWrite(buffer[xx], yy, value);
   
    int n = xx / 8;
    int c = (xx % 8);
    digitalWrite(load, LOW);
    for (int i=0; i<num; i++)
    {
        if (i == n)
        {
            shiftOut(data, clock, MSBFIRST, c + 1);
            shiftOut(data, clock, MSBFIRST, buffer[xx]);
        }
        else
        {
            shiftOut(data, clock, MSBFIRST, 0);
            shiftOut(data, clock, MSBFIRST, 0);
        }
    }
	digitalWrite(load, LOW);
	digitalWrite(load, HIGH);
}

void MaxMatrix::writeSprite(int x, int y, const byte* sprite)
{
	int w = sprite[0];
	int h = sprite[1];
	   
    for (int i=0; i<w; i++){
            for (int j=0; j<h; j++)
            {
                int c = x + i;
                int r = y + j;
                if (c>=0 && c<80 && r>=0 && r<8)
                    setDot(c, r, bitRead(sprite[i+2], j));
            }
    }
}


修改完結果如下,可正常顯示,但Scroll 移動的部分就沒有修改,所以若要捲動的話顯示會出問題的,這部份等有空再來改了






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

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