配線図のとおり金属がつながっている。(ゆがんでいるのは耐熱試験でやられているから)


Interface7月号のラズパイPicoでゼロから作るOSを試そうとしたら環境構築で手間取ったのでメモ。
Interface記載の各ダウンロード先最新のもので環境構築をするとpicoprobeのデバックが動かない。対処としてxpmで入れたopenocdを使用すると動いた。
インストール方法
node/npm/xpmが入っている環境で
cd my-project
xpm init # Only at first use.
xpm install @xpack-dev-tools/openocd@latest --verbose
手順通りだとエラー。エラーメッセージを取り損ねているけどlocalhost:3333がtimeoutとかの類だったはず。
cmsis-dap.cfgを修正しadapter speed 5000を追記するという手順をしても以下エラー。
Error: Sequence 4 not supported.
Info : DAP init failed
Error: Sequence 3 not supported.
Error: Sequence 4 not supported.
Interface記載のopenocdだと今のpicoprobeの処理に対応していない。こちらのリンク先のパッチが未適用。(公式だと取り込まれていた。)Interface記載の段階では動いたようなのでおそらくpicoprobeのバージョンアップで動作が変わったと思う。(が、picoprobe側の変更履歴は確認していない。)
多分直接関係するのはopenocdとpicoprobeだけだと思う
C:\Users\kitam>node -v
v18.17.1
C:\Users\kitam>npm -v
9.6.7
C:\Users\kitam>xpm --version
0.16.3
picoprobe-cmsis-v1.0.3
"xpack": {
"minimumXpmRequired": "0.16.3",
"dependencies": {},
"devDependencies": {
"@xpack-dev-tools/arm-none-eabi-gcc": {
"specifier": "12.3.1-1.1.1",
"local": "link",
"platforms": "all"
},
"@xpack-dev-tools/windows-build-tools": {
"specifier": "4.4.0-1.1",
"local": "link",
"platforms": "all"
},
"@xpack-dev-tools/openocd": {
"specifier": "0.12.0-2.1",
"local": "link",
"platforms": "all"
}
},
Eclipse IDE for Embedded C/C++ Developers (includes Incubating components)
Version: 2023-06 (4.28.0)
Build id: 20230608-1333
秋月で販売開始になったCH32V003J4M6(マイコン本体)とWCH-LinkEエミュレーター(書き込み/デバック装置)で書き込みができたのでそこまでのメモ。
基本的にはこちらの記事をトレースしてわからなかったことを追記した感じ
「いつも通り Workspace の場所を決めて Launch をクリックします。」は出なかった。後で選べる。
「File⇒Open Procets from File System をクリックします。」は「Open Procets from File System」のとこが微妙に名前変わっていた
「コンパイル」のトンカチアイコンは見当たらず、ビルドアイコンがツールバーの左寄りにあった。ダウンロードアイコンもツールバーの左寄り。
サンプルソースはGPIO_Pin_0でLチカしているけどSOP8のだとPD0は出ていないのでGPIO_Pin_6(PD6の1番ピン)に変更
書き込みのたびに、MounRiver Studioにて以下操作
PCのUSBにPCのUSBにWCH-LinkEエミュレーター接続
| WCH-LinkEエミュレーター | CH32V003 |
| GND | 2番ピン(VSS) |
| 3V3 | 4番ピン(VDD) |
| SWDIZO | 8番ピン() |
CH32V003の1番ピン – Lチカ用のLED – 1KΩ抵抗 – CH32V003の2番ピン(VSS)
CH32V003の2番ピン(VSS) – 0.1uFコンデンサ – CH32V003の4番ピン(VDD)
ほぼそのままだけど下の
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/08/08
* Description : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*
*@Note
GPIO routine:
PD0 push-pull output.
*/
#include "debug.h"
/* Global define */
/* Global Variable */
/*********************************************************************
* @fn GPIO_Toggle_INIT
*
* @brief Initializes GPIOA.0
*
* @return none
*/
void GPIO_Toggle_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
/*********************************************************************
* @fn main
*
* @brief Main program.
*
* @return none
*/
int main(void)
{
u8 i = 0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n", SystemCoreClock);
printf("GPIO Toggle TEST\r\n");
GPIO_Toggle_INIT();
while(1)
{
Delay_Ms(250);
GPIO_WriteBit(GPIOD, GPIO_Pin_6, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET));
}
}
ここのやつ。
5mのオレンジで12Vで約1.2A。
明るさとしては室内の照明だと十分目立つけど昼の屋外だとほぼわからないぐらい。屋外で使うならやや日が傾きだしたぐらいからかな。晴れた6月の京都で18時ぐらいで見えるぐらい。
なお開封直後はゴム臭がけっこうした。



チューブに黒い点がついていてそこから切り離せるはずだけど試していない。
看板に使用したいので曲げてみた。折り目はつかないのでターンのきついところでは接着剤等で角度保持してやらなくてはならない。
ちなみに看板は最初トリマーで掘り込もうと思ったけど丁寧にやるのは時間がかかるのであきらめた。大きいCNCがあったら楽そうだけどCNC事態を持っていないのでレーザーカッターでアクリルを切り抜いたやつで作る予定。
SG90をPlatformIOで入れたライブラリで0,90,180度で動かそうとしたところそれぞれ0,45,90度ぐらいしか動かなかった
ソースは以下
#include <Arduino.h>
#include <Servo.h>
#define SERVO_PIN 12
Servo servoMotor;
void setup() {
Serial.begin(115200);
delay(100);
digitalWrite(LED_PIN, HIGH);
servoMotor.attach(SERVO_PIN);
}
int count = 0;
int angle[] = {0,90,180};
void loop() {
servoMotor.write(angle[count%3]);
Serial.printf("%s - run %d %d \n",__func__,count,servoMotor.readMicroseconds());
count++;
delay(1000);
}
[env:esp_wroom_02]
platform = espressif8266
board = esp_wroom_02
framework = arduino
monitor_speed = 115200
upload_port = COM9
servoMotor.readMicroseconds()でみてみると本来500,1450,2400(ms)ぐらいであってほしい数値が1000,1500,2000ぐらいになっていた。
サーボモーターの初期化をするときに以下のように明示的に0度と180度(データシート的には-90度と90度)の値を指定してやったら動いた。
servoMotor.attach(SERVO_PIN,500,2400);
PlatformIOだとplatform を切り替えるとそれぞれのマイコンに応じたライブラリが読み込まれるみたい。そしてそこ(Servo.h)にあるデフォルト値が欲しい値じゃなかった
#define DEFAULT_MIN_PULSE_WIDTH 1000 // uncalibrated default, the shortest duty cycle sent to a servo
#define DEFAULT_MAX_PULSE_WIDTH 2000 // uncalibrated default, the longest duty cycle sent to a servo
#define DEFAULT_NEUTRAL_PULSE_WIDTH 1500 // default duty cycle when servo is attached
読み込まれているライブラリはPIOホーム -> Libraries -> Built-inから(必要なら検索で絞って)Servoを選んでRevealを押すと確認可能。
12/29-1/3は予約が必要です。
12/26 通常営業(18:00-23:00)
12/27 通常営業(14:30-23:00)
12/28 通常営業(14:30-23:00)
12/29 1時間程度前まで予約必要で終日営業(10:00-23:00)
12/30 前日まで予約必要で終日営業(10:00-23:00)
12/31 前日まで予約必要で短縮営業(10:00-19:00)
1/1 前日まで予約必要で短縮営業(13:00-22:00)
1/2 前日まで予約必要で短縮営業(11:00-22:00)
1/3 前日まで予約必要で終日営業(10:00-23:00)
1/4 通常営業再開(14:30-23:00)
連絡先 090-3524-7416 または 075-632-8978
携帯の方がつながりやすいと思います
先日入手したWinsenのダストセンサーZH06を触ってみた。先日ZPH02というのを触ったけどそれより少し良い奴。ZPHはDuty比しか返してくれないので換算が面倒だけどこっちはI2Cでug/m3で返してくれる。ただしPWMは二つの値を順次返してくれるようでマイコンなしで扱うのは大変そう。
コネクタはオスオスのがついてきた。メスのコネクターはなかったので半分に切ってピンヘッダーに半田した。

NanoとPCはUSB接続
| ZH06 | Nano |
| #1 VDD | 5V |
| #2 GND | GND |
| #3 Reserved | 未接続 |
| #4 RXD Serial receive pin | D3(スケッチで指定) |
| #5 TXD Serial send pin | D2(スケッチで指定) |
| #6 Reserved | 未接続 |
| #7 Reserved | 未接続 |
| #8 PWM output | 未接続 |
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);
#define LED_PIN 13
#define BUFFER_SIZE 31
#define START_BIT 0x42
unsigned char inBuffer[BUFFER_SIZE];
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
mySerial.setTimeout(1500);
}
void loop() {
bool readFlg = false;
int bufIndx = 0;
if(mySerial.find(START_BIT)){
mySerial.readBytes(inBuffer,BUFFER_SIZE);
}
if (checkSum()) {
writeData();
}
delay(100);
}
bool checkSum() {
int dataSum = 0;
for ( int i = 0; i < (BUFFER_SIZE-2) ; i++) {
dataSum += inBuffer[i];
}
dataSum += START_BIT;
Serial.print("calc=");
Serial.print(dataSum, HEX);
Serial.print(" checksum=");
Serial.print( (inBuffer[29] << 8) + inBuffer[30], HEX);
Serial.print(" ");
bool isGoodChecksum = (dataSum == ((inBuffer[29] << 8) + inBuffer[30]));
if(!isGoodChecksum){
Serial.println("チェックサムエラー");
}
return isGoodChecksum;
}
void writeData() {
for ( int i = 0; i < BUFFER_SIZE; i++ ) {
Serial.print(inBuffer[i], HEX);
Serial.print(",");
}
Serial.print("[pm1.0 ");
Serial.print((inBuffer[9] << 8) + inBuffer[10]);
Serial.print("]");
Serial.print("[pm2.5 ");
Serial.print((inBuffer[11] << 8) + inBuffer[12]);
Serial.print("]");
Serial.print("[pm10 ");
Serial.print((inBuffer[13] << 8) + inBuffer[14]);
Serial.print("]");
Serial.println("");
}
問い合わせモードにするコマンドもあるけど試していない。データシートのリンクないけどこれで動いた
先日入手したWinsenのダストセンサーZPH02を触ってみた。検索でv1.2のデータシートがかかったけど公式からデータシートにリンクが張られているV1.0のほうだった。(公式の写真だとピンヘッダーが1*4だけど1*5のが届いたので微妙に違うものかも)なお、ピンヘッダーについてはデータシートにアサイン等記載なかった。少なくともコネクタと並び順は違う。
コネクタ(EH2.54-5P terminal socket)に関してはケーブルが付属していなかった。とりあえずジャンパーのメスと同じサイズなのでそれで引きさした。
出力は粒子数直接ではなくて粒子数に応じて出力LowのDuty比がかわる。データシート参照。
NanoとPCはUSB接続
| PHZ02 | Nano |
| #1 Control pin | GND |
| #2 Output OUT2/RXD | 未接続 |
| #3 Power positive (VCC) | 5V |
| #4 Output OUT1/TXD | D2(スケッチで指定) |
| #5 GND | GND |
#1をGNDにするか未接続かでPHZ02の出力がUARTになるかPWMになるかが切り替えられる。GNDだとUARTモードになる。UARTだと#4がTXになるのでそれをNanoのRXを割り当てたGPIOで受け取る。もともとのハードウェアなRX端子はPCとのやりとりで使いたいのでSoftwareSerialにて割り当てた。
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3);
#define LED_PIN 13
#define BUFFER_SIZE 9
unsigned char inBuffer[BUFFER_SIZE];
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
}
void loop() {
bool readFlg = false;
int bufIndx = 0;
while (mySerial.available() > 0) {
unsigned char readValue = mySerial.read();
if (bufIndx > BUFFER_SIZE) {
continue;
}
inBuffer[bufIndx] = readValue;
bufIndx++;
readFlg = true;
}
delay(10); // 少し待ってあげないと配列がちゃんと読み込めない
if (readFlg && checkSum()) {
writeData();
}
delay(100);
}
bool checkSum() {
unsigned char tempq = 0;
for ( int i = 1; i < 8 ; i++) {
tempq += inBuffer[i];
}
tempq = (~tempq) + 1;
if(!(tempq == inBuffer[8] )){
Serial.println("チェックサムエラー");
}
return (tempq == inBuffer[8] );
}
void writeData() {
for ( int i = 0; i < BUFFER_SIZE; i++ ) {
Serial.print(inBuffer[i], HEX);
Serial.print(",");
}
Serial.print("[");
Serial.print(inBuffer[3]);
Serial.print(".");
Serial.print(inBuffer[4]);
Serial.print("]");
Serial.println("");
}
ZPH02の通信速度(Baud Rate)は9600なのでソフトシリアルで指定。コンストラクタでD2を指定。
コメント入れてあるdelay(10)がないと配列ちゃんと読み込めなかった。
チェックサムは1~7バイト。スタートバイトはいらない。
for ( int i = 1; i < 8 ; i++) {
なにか、チェックサムがおかしな値しか返らなくなって再起動しなくてはいけない事象があった。(まだ詳しく見られていない。)
精度はパルス幅0.1%までの模様。値は結構上下するみたいなのでそのまま使うと上下に振れすぎて読みにくいかも。
スタートビットちゃんとみてデータ取得していない拾っていない途中まで読み込んでいるのは次回捨てている。
| PHZ02 | Nano |
| #1 Control pin | 未接続 |
| #2 Output OUT2/RXD | PWM出力(計測用にオシロの+に) |
| #3 Power positive (VCC) | 5V |
| #4 Output OUT1/TXD | 未接続 |
| #5 GND | GND(計測用にオシロの-に) |
#1をGNDにするか未接続かでPHZ02の出力がUARTになるかPWMになるかが切り替えられる。未接続だとPWMモードになる。
1秒サイクルでLow(0V)の割合が濃度。
メジャーなCO2センサー(ZGm053U)の値を拾おうとしたらHIDで通信しているということでPC版のChrome・Edge(あとOperaも?)なら使用できるWeb HID APIを使ってみた。なお、新しめの読み込みが公開されているタイプのみ対応。(古いタイプだと値が暗号化されて読み込み機能が公開されているわけではないので自重。読み方はネットに落ちてはいる)
日本だとCO2miniとして売られている大人気のモデル。
読み込み用のページはこちら
人気CO2センサーZGm053Uの値をブラウザ(PC版のChrome/Edge限定)で見れる便利ページ暫定公開しました。
使う人多そうだったら適宜バージョンアップします
使い方はpcにusb繋げて値取得開始ボタン押すだけ。 終了はおもむろに閉じてください。
コード的にはシンプルで、
if (“hid” in navigator) にてWebHIDが使用できるか確認。
const [device] = await navigator.hid.requestDevice({ filters }); にて対象デバイスを取得。CO2センサーのvendorId: 0x04d9,productId: 0xa052は少し上で指定。Windowsだとデバイスマネージャーのヒューマンインターフェースマネージャーにそれっぽいのがいるはず。
await device.open().then(() => { の中で接続時の処理を指定。
中でやっているのはdevice.addEventListener(“inputreport”, handleInputReport);とdevice.sendFeatureReport(0, new Uint8Array([0,0,0,0,0,0,0,0]));
sendFeatureReportはしないとセンサーが動かない。このCO2センサーに必要な送信の起動条件だと思う。
The
https://developer.mozilla.org/en-US/docs/Web/API/HIDDevice/sendFeatureReportsendFeatureReport()method of theHIDDeviceinterface sends a feature report to the HID device. Feature reports are a way for HID devices and applications to exchange non-standardized HID data.
addEventListenerで登録したfunction内で受信したReport(HIDの通信単位らしい)を適宜処理。ZGm053Uの場合は、0バイト目にデータの種類、received[1] * 256 + received[2]で値。チェックサムとかも入っているけどちゃんと見てはいない。
<script>
const filters = [
{
vendorId: 0x04d9,
productId: 0xa052
},
];
function handleInputReport(e) {
let received = new Uint8Array(e.data.buffer);
console.log(received);
if(received[0]==80){ // ID 80 がCO2
let resultValue = received[1] * 256 + received[2]; // 値をそのまま信じる(チェックサム等は未確認)
document.getElementById("co2value").innerText = resultValue;
document.getElementById("ppm").innerText = "ppm";
}
}
async function checkHID() {
if ("hid" in navigator) {
const [device] = await navigator.hid.requestDevice({ filters });
await device.open().then(() => {
device.addEventListener("inputreport", handleInputReport);
device.sendFeatureReport(0, new Uint8Array([0,0,0,0,0,0,0,0])); // 値取得コマンド送信が必要な模様
})
} else {
alert("USB接続を確認してください");
}
}
</script>
データ送信はしていないけどこんな感じらしい。
const enableVibrationData = [1, 0, 1, 64, 64, 0, 1, 64, 64, 0x48, 0x01];
await device.sendReport(0x01, new Uint8Array(enableVibrationData));
// Then, send a command to make the Joy-Con device rumble.
// Actual bytes are available in the sample below.
const rumbleData = [ /* … */ ];
await device.sendReport(0x10, new Uint8Array(rumbleData));
あとクローズも
await device.close();
そのまま切っても大丈夫のものが多いと思うけど行儀は悪いのでちゃんとクローズしたほうが良い。(けど作ったソースではやっていない)
ちなみに、ブラウザでのボタン操作等必須。自動(onloadとか)で接続しようとすると以下のように怒られる。
zyco2.html:52 Uncaught (in promise) DOMException: Failed to execute 'requestDevice' on 'HID': Must be handling a user gesture to show a permission request.
とPM1.0/ PM10/ PM2.5ダストセンサー ZH06とPM2.5ダストセンサーZPH02が届いた。AliのWinsen公式で買って13日。

ZH06はケーブルついていた。ZPH02は付属ケーブル無し。
使い方はこれから調べる
データシートはこちら
出力はPWMとUART。コネクタは1.25t-8a、入手しにくいから公式で一緒に売ってくれないかな。データシートのFig9あたりに置き方書いてあるけど通気口ふさいだらよくないし置く確度とかも意識しろと。この間かったDSM501Aにも書いてあったけど通気関係は結構シビアっぽい。
湿度は80%まで。ちょいちょい引っかかりそうね。
想定寿命は10000時間以上。連続稼働だと1年ちょいなので短めは短めね。モジュール本体はケーブル接続なので交換部品だけ買えるようにしておけばよいか。 そして油/煙のある環境はあかんと。
数値の計算式”Please refer the document of ZH06 I-IV Series Communication Protocol.”とか書いているけど、そのドキュメントどこにあるんだ?どりあえず旧バージョンのデータシートにそれっぽいのがのっているのできっとこれでよいだろう。あとでサポートにきかなくては。あいかわらずWinsenのドキュメント類はうち並みの整備状況っぽい。
データシートはこちら(V1.0で公式の製品情報からリンクがある物)とこちら(V1.2でGoogle検索で出ててきたもの)が見つかった。届いたものは、UARTのレスポンスbyte[6]が1でbyte[7]が0なのでどちらのデータシートとも微妙に違う。サポートに確認しようと思ったけど、ドキュメント大体なのでbyte[7]が0というのが現在の動作なのだろう。(売るならちゃんと聞く) 公式からリンクが張られている方だった。よくみたらVOCセンサーがない場合はbyte6が0x00と補足に書いてあった。
PIN5をグランドにするかどうかでPWMモードかUARTモードかを切り替えるとのこと。
UARTは5Vで1秒ごとの受信のみ。
コネクター以外にピンヘッダー付きそうな端子があるけどデータシートに記載なし。同じものが引き出されていそうなきはするけど、少なくとも並び順はコネクターと違う。後で調べる。