デジタルノギスの測長データをPCに取り込む
デジタルノギスには、謎の4ピン端子がついています.この端子はミツトヨの商標で「デジマチック」と呼ばれるそうです.
今回はこの端子から出てくる信号をPCに取り込んでみます.
デジマチックについてネットを探してみましたが、仕様が見つからなかったので、以下はわたしが解析した結果ですので、誤り・不足があるかもしれません.
右上に謎の4ピン端子があります.
バラしたプリント基板から、GND,DATA,CLK,VCCであることが判明.
オシロで観測すると、 次が判りました.赤がclock、青がdataです.
●振幅1.5V
●clockのHIGHの最短時間は160uSec
●clockの立ち上がりエッジでdataをラッチすればいい.
●24bitがバースト送信される.LSB first.
●バースト間隔は約250mSec
データ構造は、
[23] 0ならmm表示 1ならインチ表示
[22:21] 0固定 何の意味なのか不明
[20] 符号ビット 0:正数 1:負数
[19:0] 距離の絶対値 (2の補数ではありません)
距離の絶対値をインチまたはmmに換算するには、
X[mm] = data[19:0] ÷ 100
X[インチ]=data[19:0] ÷ 2000
上図の波形は、[14:0]の範囲が見えている.[14:0]=000_0000_0011_0010
=32H=50になっている.この50とは、デジタル表示LCDの 0.50mm
を表している.つまり1LSB=0.01mmの意味の23bitの2進数と、符号が1bit送信されているわけです.
HOST PC側からノギスに対してゼロリセット要求を与えるような仕組みになっているとは思えませんでした.
以上を知っていれば、STM8S-DISCOVERYで受信し、値をPCに送信できます.
ハードウエアの準備
全体写真はこんな感じです.この写真にはこの回路とは無関係の余計なものもついてますのでご注意のほど.
@回路図
ノギスが出力するパルスは1.5Vしかありませんので、STM8Sはそれを受信できませんでした.
なので、2SC1815で電圧を3.3V振幅に変換せざるを得ませんでした.
そのため、clock,dataともに論理反転されていますので、clockの立ち上がりエッジでデータをサンプルするようなプログラムにしてあります.
clockは、TLIのピンであるPD7へ配線、dataはPD4へ配線します.
AUSBシリアル変換回路
まず、UARTをUSBに変換する回路を、STM8S-DISCOVERYにどうやって取り付けるかを説明します.
秋月のUSBシリアル変換基板をSTM8S-DISCOVERYに取り付けます.
回路図は下記です.
●STM8SのPD5とPD6には、UARTの送信信号と受信信号が出てきますので、それをUSBシリアル基板に配線しています.
●STM8S-DISCOVERYでは、電源はFLASH焼き回路から5V or 3.3Vが供給されますが、これを切断し、USBシリアル変換基板から3.3Vが供給されるようにします.ただし5Vじゃダメってことではありません.3.3Vにしたのはなんとなくです.
そのために、ジャンパーをつぎの1)2)のように設定 してください.
1) USBシリアル変換基板のジャンパーピンは、下図の赤色の位置にします.
2) STM8S-DISCOVERYのJP1のジャンパーピンは、外しておきます.
USBシリアル変換基板の取付完了状態はこのようになります.
右の黄色の囲いがUSBシリアル変換回路です.同基板に刺さっているMini-USBがPCのUSBへ行きます.
中央の水色の囲いがSTM8Sマイコンです.USBシリアル変換回路と配線されています.
左の赤い囲いは、ブロック図には描きませんでしたがSTM8Sを焼くために必須な回路です.同基板に刺さっているUSBケーブルは、STM8Sを焼くためのケーブルです.やはりPCに接続します.
この回路は、PCのUSBポートを都合2ヶ占有することになります.
プログラムを焼いてしまえば、焼き用のUSBケーブルは不要になるわけで、下図のようにUSBを外してしまいたくなるのが人情です.
ところが、USBケーブルを外しただけでは、STM8Sにリセットがかかってしまって動かなくなってしまいます.
そこで、下の写真の丸の中にあるSB1とSB2をハンダごてでOPENにしてやればリセット線が切断されるので、STM8Sが動きます.
この方法は憶えておきましょう.
AリセットSW
これは適当につけてください.
プルアップ抵抗は不要で、対GNDへ落とす形式でOKです.
ソフトウエア
こちらからprojectファイルをダウンロードできます.
#include "stdio.h" printf()など
#include "stdlib.h" 文字列操作
#include "string.h" 文字列操作
#include "math.h" 数式を使うかも
#include "stm8s.h" STM8S standard libraryを使うため
#include "usrlib-uart.h" UARTを使うため
void main(void)
{
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1 );
CLK_SYSCLKConfig( CLK_PRESCALER_CPUDIV1 );
clockの設定です.内部clock16MHzにしてます.clockの解説はこちら.
// GPIO
GPIO_DeInit(GPIOD);
GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_HIGH_FAST); // PD0 LED
GPIO_Init(GPIOD, GPIO_PIN_4, GPIO_MODE_IN_PU_NO_IT); // PD4 DATA
GPIO_Init(GPIOD, GPIO_PIN_7, GPIO_MODE_IN_PU_IT); // TLI CLK
GPIOの設定をしてます.
PD0をノギスからの受信の度に(250msごとに)点滅させてindicatorとします.
PD4にはノギスからのdataを入力します.
PD7にはノギスからのclockを入力します.PD7はTopLevelInterrupt(TLI)の端子です.
clock割り込みを最上位割り込みにすることで、dataの取りこぼしを防ごうとしています.
GPIOについての解説はこちら.
// UART initialization
// 115200 bps
// data 8bit + parity 1bit
// stop bit 1bit
// odd parity
UART_Init((u32)115200, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_NO);
UARTを、15200bps、8bit、stop1bit、parityなし、に設定しました.UARTの解説はこちら.
// clock interrupt
EXTI_DeInit();
EXTI_SetTLISensitivity( EXTI_TLISENSITIVITY_FALL_ONLY );
TLIに接続されたclockで割り込みするように設定しています.TLIの解説はこちら.
ノギスのclockは立ち上がりエッジでdataをサンプルする意図で出力されていますが、レベル補正のためのトランジスタによって極性が反転してしまいましたので、立ち下がりエッジで割り込みをかけるようにしてあるので、ご注意のほど.
// time out timer 1msec
TIM4_DeInit();
TIM4_TimeBaseInit( TIM4_PRESCALER_128, 124 ); // 16MHz/128/125=1000Hz
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
TIM4_Cmd(ENABLE);
タイマ4で1ms割り込みを作っています.あとでタイマ4割り込みルーチンでその意図を説明します.タイマ4の解説はこちら.
enableInterrupts();
割り込み開始.
while(1) { } 無限ループ
} 以上でmainルーチンはおしまい
// data recieve and trigger UART
// when TLI high, this routine is invoked
// [23] 1:inch 0:mm
// [22:21]
// [20] 1:negative
// [19:0] absolute length
int length=0; 受信したdata[19:0]を格納します
int length_old=9999999; 一つ前に受信したdata[19:0]を格納します
int i=0; // serial data bit index [23:0]のbitを数えるカウンタ
int timeout_cnt=0; タイマ4で使います
void TLI_interrupt(void) interrupt 0
TLIすなわちclock割り込みルーチンです.TLIの割り込み番号は最上位のゼロ番です.
{
BitStatus PD4; data portの読み込み値
int pd4; data
char L[80]; // ascii length UARTに表示する文字列
float length_float; data[19:0]をfloatに変換した値
timeout_cnt=0; // timeout counter clear タイマ4によるtimeoutチェックをリセットする
PD4 = GPIO_ReadInputPin( GPIOD, GPIO_PIN_4 ); // PD4 is reversed data portを読む
pd4 = (PD4==RESET) ? 1 : 0; 反転してるのを元に戻す
if(i<=19 && pd4==1) length = length + (pd4<<i); [19:0]は2進数距離データなのでlengthに格納する
else if(i==20 && pd4==1) length=(-1)*length; [20]は符号なので1ならマイナス値にする
else if(i==23) [23]が最後のbit
{
GPIO_WriteReverse(GPIOD, GPIO_PIN_0); LED indicstorを点滅させる
if(pd4==1) { インチ表示かミリ表示か?
length_float = (float)length/2000; インチなら÷2000
sprintf(L,"%4.4f inch\r\n",length_float); UART文字列作成
}
else {
length_float = (float)length/100; ミリなら÷100
sprintf(L,"%3.2f mm\r\n",length_float); UART文字列作成
}
// UART transfer
if(length_old!=length) 距離に変化があった場合のみUARTに表示
{
UART_PutString(L); UARTに表示
}
// next bit
i=0; bitクリア
length_old=length; 旧距離をセーブ
length=0; 距離=ゼロリセット
}
i++; bit位置をインクリメント
}
// time out timer
void TIM4_interrupt(void) interrupt 23
ノギスのコネクタが外れたりして、バーストデータの途中で中断したときにデータが化けないように、150msecの間clockが来なかったらデータをチャラにするための150msecのタイムアウトカウンタ
{
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
timeout_cnt++;
if(timeout_cnt>150) i=0; // when past 150mSec then clear recieved data
}
#ifdef USE_FULL_ASSERT
void assert_failed(u8* file, u32 line)
debug functionですが有効活用はしてません
{
while (1) { }
}
#endif
動作結果
ノギスを動かすと、terminal softには次のような測定結果が表示されます.
14.53 mm
20.07 mm
14.32 mm
13.33 mm
10.58 mm
9.86 mm
0.3880 inch
0.3545 inch
0.1680 inch
0.0285 inch
-0.0010 inch
-0.1030 inch
-0.3180 inch
-0.5985 inch
-0.6785 inch
-17.23 mm
-0.6785 inch
-17.23 mm
-0.6785 inch