2015年11月15日日曜日

Solidarite


人は愚かだ。

しかし、英知は何物も乗り越えることができる。


#include "mbed.h"
#include "neopixel.h"
// This must be an SPI MOSI pin.
#define DATA_PIN dp2
#define N_COL 8
#define N_ROW 8
#define N_LED (N_COL * N_ROW)
#define N_WAVE 128
float wave[N_WAVE];
int gSpeed;
void generate(neopixel::Pixel * out, uint32_t index, uintptr_t extra)
{
uint8_t red, green, blue;
int x = index % N_COL;
red = green = blue = 0;
uint8_t val = 8.0 * wave[((x+extra)*gSpeed) % N_WAVE] + 16.0 * wave[extra % N_WAVE] + 16.0;
val = val / 2;
if (x <= 2) {
blue = val;
} else if (x <= 5) {
red = green = blue = val / 2;
} else {
red = val;
}
out->red = red;
out->green = green;
out->blue = blue;
}
int main()
{
// Create a temporary DigitalIn so we can configure the pull-down resistor.
// (The mbed API doesn't provide any other way to do this.)
// An alternative is to connect an external pull-down resistor.
DigitalIn(DATA_PIN, PullDown);
// The pixel array control class.
neopixel::PixelArray array(DATA_PIN);
for (int i = 0; i < N_WAVE; i++) {
wave[i] = sin((float)i / (float)N_WAVE * 3.14159265 * 2.0) * 0.5 + 0.5;
}
int offset = 0;
gSpeed = 8;
while(1) {
array.update(generate, N_LED, offset++);
if (offset >= N_WAVE) {
offset = 0;
gSpeed = (rand() % 8) + 4;
}
wait_ms(20);
}
}
mbed, LPC1114FN28使用。ライブラリはJacob Bramley氏のPixelArrayを使用しました。

Thanks, Jacob!

このライブラリはBurstSPIを利用しています。SPI/MOSI端子を出力ピンとして使用し、WS2811/2812のDin端子と接続してください。Din信号は周波数特性に敏感なので、なるべく配線を短くしてつなぎます。誤動作するとLED全点灯側に振れますので、電源がヤバいです。配線を長くしなくてはいけない場合は両端にSN751768などを入れてRS485信号に変換し、ツイステッドペアのシールド線で配線すれば少し安心だと思います。

今日の秋月:NchMOSFET 2SK4033 (60V5A) (5個入)

(秋月のサイトから)

Nch MOSFET 2SK4033、本当に今のMOSFETはVth低くてもRds小さくてスゴいですね(データシートから転記)

  • Vdss 60V
  • Vgss ±20V
  • Rds 0.07Ω
  • Id 5A
  • Pd 20W
  • Ciss 730pF
  • Coss 95pF
  • Crss 60pF

Arduinoはもちろん、mbedからでも十分スイッチできます。電子工作の定番MOSFETの2N7000とは桁が違う(秋月のサイトから引用)

  • VDSS 60V
  • VGSS ±20V
  • RDS(ON) 標準1.8Ω 最大5.1Ω(@VGS=4。5V)
  • ID 200mA
  • PD 400mW
  • Ciss 標準20pF 最大50pF
  • Coss 標準11pF 最大25pF
  • Crss 標準4pF 最大5pF


値段もあまり変わらないし、もう2SC1815や2N7000は買わなくて良いんじゃね?と思うくらいなのですが…2SK4033の方が入力容量がデカいので、マイコン直結だと高速でスイッチングするのは厳しいですね。

ところで、表面実装部品を直接ピンヘッダにハンダ付けして使うのがマイブーム(笑)なのですが、2SK4033は表面実装だけど端子間隔が2.54mmなのでピンヘッダに直接ハンダ付けするのが楽だし、そうすれば普通に使える。

よし何個か買って置こうか…と思ったのですが。

電気的特性の同じ2SK4017↓を買えばいいんだよな、と直前に気づきましたw

NchパワーMOSFET 2SK4017(Q) (60V5A)

2015年11月14日土曜日

今日の秋月:DS1307 I2Cリアルタイムクロックモジュール(RTC)

(秋月のサイトより)

サインスマートのI2C接続RTCモジュール、750円。

RTCのDS1307と32kbitシリアルEEPROM 24C32と電池ホルダーを一つにまとめたモジュール。5V版。

自分でデジタル時計を作る時にはDIP版のDS1307+をよく使います。外付けなしで動いて値段が手頃でI2Cの扱いも簡単、何よりバックアップ電源端子が別になっているのでリチウム一次電池を直結するだけでバックアップできて便利なんですよね。このモジュールには充電回路もついているのでどっちにしろ気にしなくて良いですが。

1307に限らないですが、RTCは通電当初はあんまり精度が良くなくて「まぁ…値段相応かな」と思うんですが、数日経つと普通のクォーツ程度の精度に落ち着いてきます。

あ、今気づいたけど、このモジュールって温度センサーDS18B20用のパターンもついてるんですね。ただ、DS18B20は別売り。I2Cとは別に1 wireで接続する必要があるので、温度計が必要なら少し高いけど湿度も測れるHDC1000を使った方が良いんじゃないかなー。熱慣性小さくて好き。

今日の秋月:液晶表示ミニ周波数カウンター(1MHz~500MHz)

(秋月のサイトより)

サインスマート製で006P電池と同じようなサイズの周波数カウンター、2750円。

私が電子工作に興味をもった小学生の頃(うわ40年前だ)、テスターは持っていましたが、周波数カウンターは超憧れの計測器でした。当時いくらぐらいだったっけなぁ。10万とか30万とか、とにかく小学生には雲の上というか銀河系の外レベルの話でした。それも一番安いやつは30Mhzが上限。

これは2750円で500Mhzまで計れちゃうんですね(遠い目

// 「今日の」には多少の誤差を含みますw

2015年11月13日金曜日

自作補聴器への樹状迷路orz

(秋月電子通商のWebより)

おお、こんなのがあるんですね(上写真および下記仕様は秋月電子通商のWebから)。

オーディオコーデックIC VS1063A
  • 対応方式:MP3/AAC/WMA/FLAC/Ogg/G.711/G.722等
  • 低消費電力DSPコア(VS_DSP4プロセッサ)搭載
  • マイコン制御またはスタンドアローン動作でMP3録音/再生をワンチップで簡単に実現できます
  • ストリーミング対応
  • ライン入力(2ch)/マイクアンプ(1ch)/ヘッドフォンアンプ(ステレオ)内蔵
  • LQFP48(48ピンフラットパッケージ)
  • DAC分解能:18bit(2ch)
  • ダイナミックレンジ:100dB ・SN比:94dB
  • エンコード:MP3、Ogg Vorbis、RIFF WAV
  • デコード:MP3、MP2、Ogg Vorbis、AAC、WMA、FLAC、RIFF WAV
  • GPIO×12、UART、SPI Bus、I2C ・トーンコントロール(低音/高音)、イコライザ(5バンド)

オーディオ機器、例えばMP3プレイヤーなんかをワンチップで作れちゃうチップ。

デジタル信号処理音痴でアナログ音痴の私が補聴器を作ろうと思って今ひとつすっきりいかないのが多チャンネルのイコライザとアンプ系なのですが、「マイクアンプ」「イコライザ(5バンド)」「ヘッドフォンアンプ」などが揃っているので、あとはFFTで帯域ごとのパワーを求めてイコライザを制御すれば、補聴器の基本機能である帯域ごとの圧縮・増幅、なんてのがサクっと出来てしまいます。

しかも600円で低消費電力。うは。

…なんてことばかり考えていると、ぜんぜん進まないし中途半端に試作をしたチップやモジュールやボードの山ができるだけです。

まずSTM32 F7を何とかして、次にMSP432R401をどうにかした後で、VS1063Aで何かプログラムをビルドできてから買おう。

2015年11月11日水曜日

「机ドン!」検出デバイス改良@Arduino


■暫定仕様でした■

前バージョンは「とりあえず動けばいいや」で、各軸どれかがボリュームでセットした値を超えたら2段階の明るさでランプを明滅させる、という安易な仕様でした。

これだと一度、例えば閾値ギリギリの信号で点滅が始まるとその後に強い衝撃が来ても無視されてしまいます。幸い、滅多にそういうケースはないのですが、可能性としては排除できません。

■改良版■

まず、加速度を各軸ごとの値ではなくスカラー値として処理します。各軸値自乗の総和の平方根ですね(sqrt(x*x + y*y + z*z))。スカラー値はセンサーの向きが変わっても一定のはずなので、起動時に値を保持しておけば、あとは初期スカラー値と瞬間のスカラー値の差をとれば、どの方向であれ掛かった加速度の大きさがわかります。なお、255を超える値を自乗した時に整数だとオーバーフローしてしまうので、floatに直しています。

それと、少し簡略版ですが、加速度の最大値でランプのピークの明るさを決めるようにしました。ピークかどうかを検出するのは、一定の時間ごとにサンプルした今回の値が前回の値よりも下がったら前回がピークだった、ということになります。本当ならそのピーク値が前回のピーク値より上かどうかを調べれば、大きな山から下っていくところに出来た小さなピークを誤認することがなくなるのですが、今回は「ドン!」という比較的単純な衝撃の検出なのでそこまで凝ったことはしませんでしたm(_ _)m 

この辺は本当にこり始めるとキリがないですし、味付けというか装置の賢さを感じる要素だったりするんですが…とりあえず週末までに何か考えます。

なお、ハードウェアには一切手を加えていません。

■結果■

以下2点の問題が解決しました。

  • 水平に置いて起動した後、傾けて置いても点滅しっぱなしにならない。
  • 大きな衝撃を与えた場合にきっちり強くランプが点灯する。

■ソース■


#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <ADXL345.h>
#include <Time.h>
//
// NeoPixel
//
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 2
#define NUMPIXELS 1
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//
// ADXL345
//
ADXL345 adxl; //variable adxl is an instance of the ADXL345 library
#define MaxWaves 64
int wave[MaxWaves];
int aveX, aveY, aveZ, aveScalar;
void setup() {
Serial.begin(115200);
//
// NeoPixels
//
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
// End of trinket special code
pixels.begin(); // This initializes the NeoPixel library.
//
// sine curve
//
for (int i = 0; i < MaxWaves; i++) {
wave[i] = sin((float)i * 3.14159265 / (float)MaxWaves) * 255;
}
//
// ADXL345
//
adxl.powerOn();
adxl.setActivityX(1);
adxl.setActivityY(1);
adxl.setActivityZ(1);
adxl.setInactivityX(1);
adxl.setInactivityY(1);
adxl.setInactivityZ(1);
delay(1000);
int sumX = 0, sumY = 0, sumZ = 0, sumS = 0;
const int times = 10;
for (int i = 0; i < times; i++) {
int x,y,z, scalar;
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables x,y,z
sumX += x;
sumY += y;
sumZ += z;
sumS += calcScalar(x, y, z);
delay(100);
}
aveX = sumX / times;
aveY = sumY / times;
aveZ = sumZ / times;
aveScalar = sumS / times;
Serial.print("Test calcScalar=");
Serial.println(calcScalar(10, -20, 250));
}
// loop counter
int xStep = -1;
int yStep = -1;
int zStep = -1;
// max loop counter
const int MaxSteps = MaxWaves * 5;
// minimum movement
int sensitive;
// range of brightness
int magX, magY, magZ;
//
// calc brightness by range and step in loop
//
int brightness(int inMag, int inStep) {
int ret = wave[inStep % MaxWaves] * inMag / 100;
if (ret < 0) ret = 0;
if (ret > 255) ret = 255;
return ret;
}
//
// set brightness range
//
int calcMag(int inDiff) {
int ret = 10;
if (inDiff > sensitive * 2) {
ret = 100;
} else if (inDiff > sensitive * 2) {
ret = 20;
}
return ret;
}
// peek of scalar
int maxScalar;
//
// calc scalar
//
int calcScalar(int inX, int inY, int inZ) {
float x = inX;
float y = inY;
float z = inZ;
return sqrt(x*x + y*y + z*z);
}
// average value of volume
int aveVol = 0;
void loop() {
//
// RGB each brightness
//
int red = 0, green = 0, blue = 0;
//
// read volume and set sensitivity
//
aveVol = (aveVol * 9 + analogRead(20) / 8) /10;
sensitive = aveVol / 10;
//
// read accelometer and detect movement
//
int x,y,z, scalar;
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables x,y,z
scalar = calcScalar(x, y, z);
aveX = (aveX * 9 + x) / 10;
aveY = (aveY * 9 + y) / 10;
aveZ = (aveZ * 9 + z) / 10;
int diffX = abs(aveX - x);
int diffY = abs(aveY - y);
int diffZ = abs(aveZ - z);
int diffS = abs(aveScalar - scalar);
//
// if movement is harder than expected, start flashing!
//
if (diffS > maxScalar) {
maxScalar = diffS;
} else if (maxScalar != 0 && maxScalar > diffS) {
Serial.print("ave scalar=");
Serial.print(aveScalar);
Serial.print("diff scalar=");
Serial.print(diffS);
Serial.print("max scalar=");
Serial.print(maxScalar);
Serial.print("sensitive=");
Serial.print(sensitive);
Serial.print("x=");
Serial.print(diffX);
Serial.print("y=");
Serial.print(diffY);
Serial.print("z=");
Serial.println(diffZ);
if (maxScalar > sensitive) {
if (diffX > sensitive) {
// if (xStep == -1) {
xStep = 0;
magX = calcMag(diffX);
// }
}
if (diffY > sensitive) {
// if (yStep == -1) {
yStep = 0;
magY = calcMag(diffY);
// }
}
if (diffZ > sensitive) {
// if (zStep == -1) {
zStep = 0;
magZ = calcMag(diffZ);
// }
}
maxScalar = 0;
}
}
//
// manage flashing
//
if (xStep != -1) {
if (xStep > MaxSteps) {
xStep = -1;
} else {
green = brightness(magX, xStep++);
}
}
if (yStep != -1) {
if (yStep > MaxSteps) {
yStep = -1;
} else {
blue = brightness(magY, yStep++);
}
}
if (zStep != -1) {
if (zStep > MaxSteps) {
zStep = -1;
} else {
red = brightness(magZ, zStep++);
}
}
//
// controll WS2811
//
pixels.setPixelColor(0, pixels.Color(green, red, blue));
pixels.show();
// wait for 5mSec
//
delay(5);
}

2015年11月10日火曜日

mbed最強:STM32 F7 Discovery



Cortex-M7@216Mhz、64Mbit SDRAM、という基本スペックもスゴいけど、個人的には液晶がタッチパネル付き、それもコストの高い静電式ってところに萌えます。

シリコンマイクも2個搭載しているので、そのままレコーディング可能。ライン入出力あり、コーデックはハイレゾにも対応。



ないのはWiFiとBluetoothぐらいだけど、EtherついてるしUSBも3ポートあるからどうにでもなっちゃう(はず

とりあえず、各種搭載モジュールについてはmbed用ライブラリが提供されたみたいだし、…これで補聴器作れなかったら、技術屋の看板下ろすわw

MSP432R401も忘れてませんよw
#でもマイクやアンプ壊したりでなかなか進まないのよ@アナログ音痴

2015年11月8日日曜日

「机ドン!」検出デバイス@ESP-WROOM版



■ESP版■

というわけで前回のArduino版をESP-WROOM-02でも動かしてみました。

AdafruitによるWS2811最新版ライブラリはESP8266にも対応しています。

ただ、うちのWS2811がNeoPixelではなく安物なのがいけないのか、指示した通りに光ってくれません。Greenだけは良い感じなんですが、Red/Blueについては意図した信号になっていません。トランジスタで3.3->5vへのレベルコンバータをはさんでみたのですが変わりませんでした。うーん。

400khzに切り替えても同じ。うーん。

光り方をみていると最上位ビットがズレているような感じ。

ということでLEDの点滅が意図したパターンとは違いますが、ESPでも動作させることができました。加速度センサーの値に応じてLEDを点滅させるところまではArduino版と同じですが、1分ごとにThingSpeak.comあてに各軸ごとの最大加速度を送信するようにしました。

■配線など■

相変わらずプルアップ/プルダウン/GND接続が多くて面倒くさい。

ESP-WROOM-02接続先
3V33V3
GND(すべて)GND
EN10kΩ経由で3V3
IO14ADXL345のSCL
IO12WS2811のDin
IO13N.C.
IO1510kΩ経由でGND
IO210kΩ経由で3V3
IO010kΩ経由で3V3 およびISPスイッチ※
IO16N.C.
TOUTN.C.
RST10kΩ経由で3V3 およびRSTスイッチ※
IO5N.C.
TxdFTDIのRxへ
RxdFTDIのTxへ
IO4ADXL345のSDAへ

※ISPスイッチ/RSTスイッチはノーマリーオープンのタクトスイッチで、他方をGNDにつないでください。これによりRSTとISPは常時Highレベルでスイッチを押した時にLowレベルになります。

レベル変換回路はこちらのページ(3.3V 5V レベル変換)に記載されていた「3.FETによる3.3V 5Vレベル変換」と「4.トランジスタによる3.3V 5Vレベル変換」回路を試しました。このページ上の写真にうつっているのはトランジスタによる回路です。なお、WS2811の場合は流れ込む電流が多いのか5V側のプルアップ抵抗は10kΩでは電圧が上がらなかったので1kΩを使いました。出力側の回路に応じて使い分ける必要があります。

それとFTDIを接続する際には、GND同士の接続をお忘れなく。

ADXL345接続先
SCLESPのIO14
SDAESPのIO4
SDOGND
CS3.3v
Vs3.3v
GNDGND
Vdd3.3v

WS2811接続先
DinESPのIO12
Vcc5V
GNDGND
DoutN.C.

M78AR033-0.5接続先
Vin5V
GNDGND
Vout3V3ライン

この他、ESPの3V3近くとADXL345のVccに0.1μFのパスコン、WS2811のVccとGNDの間に470uFのアルミ電解コンデンサを入れてます。

■ADXL345ライブラリの修正■

Android Citiさんのライブラリは Wire.begin(); でI2Cを初期化しているので、これを接続したピンに合わせて Wire.begin(4, 14); に変えます。ただそのままだと後日このライブラリをArduinoで使った時に動かなくて苦しみそうなので、
#ifdef ESP8266
  Wire.begin(4,15);
#else
  Wire.begin();
#endif
と書いておきます。

■ソース■

Arduino版との違いはボリューム読み込みをしていないのとThingSpeak.comへの送信処理を行っている点です。ThingSpeakへは1分ごとにその間の最高値を送るようにしています。

ESPからThingSpeak.comへの送出には鳩退治デバイスに使ったsendなどの処理をほぼそのまま使ってます。楽だわー。

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <ADXL345.h>
#include <Time.h>
//
// Wifi
//
const char *ssid = "***********";
const char *password = "***********";
WiFiClient client;
//
// NeoPixel
//
#define PIN 12
#define NUMPIXELS 1
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//
// ADXL345
//
ADXL345 adxl; //variable adxl is an instance of the ADXL345 library
#define MaxWaves 64
int wave[MaxWaves];
int aveX, aveY, aveZ;
void setup() {
Serial.begin(115200);
//
// NeoPixels
//
pixels.begin(); // This initializes the NeoPixel library.
//
// Wifi
//
WiFi.begin ( ssid, password );
// Wait for connection
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 );
Serial.print ( "." );
}
Serial.println("Wifi Connected");
//
// ADXL345
//
adxl.powerOn();
adxl.setActivityX(1);
adxl.setActivityY(1);
adxl.setActivityZ(1);
adxl.setInactivityX(1);
adxl.setInactivityY(1);
adxl.setInactivityZ(1);
int sumX = 0, sumY = 0, sumZ = 0;
const int times = 10;
for (int i = 0; i < times; i++) {
int x, y, z;
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables x,y,z
sumX += x;
sumY += y;
sumZ += z;
delay(100);
}
aveX = sumX / times;
aveY = sumY / times;
aveZ = sumZ / times;
//
// others
//
for (int i = 0; i < MaxWaves; i++) {
wave[i] = sin((float)i * 3.14159265 / (float)MaxWaves) * 255;
}
}
// loop counter
int xStep = -1;
int yStep = -1;
int zStep = -1;
// max loop counter
const int MaxSteps = MaxWaves * 5;
// minimum movement
int sensitive;
// range of brightness
int magX, magY, magZ;
//
// calc brightness by range and step in loop
//
int brightness(int inMag, int inStep) {
int ret = wave[inStep % MaxWaves] * inMag / 100;
if (ret < 0) ret = 0;
if (ret > 255) ret = 255;
return ret;
}
//
// set brightness range
//
int calcMag(int inDiff) {
int ret = 10;
if (inDiff > sensitive * 2) {
ret = 100;
} else if (inDiff > sensitive * 2) {
ret = 20;
}
return ret;
}
// average value of volume
int aveVol = 0;
// to get max number
int maxX = 0, maxY = 0, maxZ = 0;
int prevMinute = -1;
void loop() {
//
// RGB each brightness
//
int red = 0, green = 0, blue = 0;
//
// read volume and set sensitivity
//
aveVol = 150; // (aveVol * 9 + analogRead(20)) /10;
sensitive = aveVol / 10;
//
// read accelometer and detect movement
//
int x, y, z;
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables x,y,z
int diffX = abs(aveX - x);
int diffY = abs(aveY - y);
int diffZ = abs(aveZ - z);
if (diffX > maxX) maxX = diffX;
if (diffY > maxX) maxY = diffY;
if (diffZ > maxX) maxZ = diffZ;
if (second() == 0 && prevMinute != minute()) {
sendAxises(maxX, maxY, maxZ);
maxX = maxY = maxZ = 0;
prevMinute = minute();
}
//
// if movement is harder than expected, start flashing!
//
if (diffX > sensitive) {
if (xStep == -1) {
xStep = 0;
magX = calcMag(diffX);
}
}
if (diffY > sensitive) {
if (yStep == -1) {
yStep = 0;
magY = calcMag(diffY);
}
}
if (diffZ > sensitive) {
if (zStep == -1) {
zStep = 0;
magZ = calcMag(diffZ);
}
}
//
// manage flashing
//
if (xStep != -1) {
if (xStep > MaxSteps) {
xStep = -1;
} else {
green = brightness(magX, xStep++);
}
}
if (yStep != -1) {
if (yStep > MaxSteps) {
yStep = -1;
} else {
blue = brightness(magY, yStep++);
}
}
if (zStep != -1) {
if (zStep > MaxSteps) {
zStep = -1;
} else {
red = brightness(magZ, zStep++);
}
}
//
// controll WS2811
//
pixels.setPixelColor(0, pixels.Color(red, blue, green));
pixels.show();
// wait for 5mSec
//
delay(5);
}
void sendAxises(int inX, int inY, int inZ) {
String postStr = "";
if (inX > 0 && inX < 255) postStr = postStr + "&field1=" + String(inX);
if (inY > 0 && inY < 255) postStr = postStr + "&field2=" + String(inY);
if (inZ > 0 && inZ < 255) postStr = postStr + "&field3=" + String(inZ);
send(postStr);
Serial.println(postStr);
}
void send(String inPostStr) {
String apiKey = "**************";
Serial.print("Connecting...");
if (client.connect("184.106.153.149", 80)) { // api.thingspeak.com
Serial.print("Connected....");
String postStr = apiKey + inPostStr + "\r\n\r\n";
client.print("POST /update HTTP/1.1\n");
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
Serial.println("posted.");
}
client.stop();
}

2015年11月7日土曜日

「机ドン!」検出デバイスw


■追記■

ESP-WROOM-02にも対応しました(リンク)。

■原因はWindows/Excel■

どっちも嫌い。Excelは使い慣れているGoogle SpreadsheetやNumbersと比べてUI特にモード遷移が不自然で違和感の塊だし、ASCIIキーボード愛用マカーなので日本語切り替えキーが変なところにあるのもイヤ。

そんなこんなで職場でのイライラは募るばかり。

そのせいか、ついついキーボードを「バン!」と叩いていたようで、同僚氏からクレームが来ましたです。辛く当たってごめんよ、Apple Wireless keyboard(自腹購入)。

しかし、気をつけていても直らず。

ということで、振動を検出・通知するデバイスを作りました。

■仕様■

手っ取り早くArduino nanoと加速度センサーADXL345マイコン内蔵LEDを使う。

一定以上の衝撃を検出したら、各軸に対応した色のLEDをペカペカ点滅させる。「一定以上」の値についてはボリュームで設定する。

手持ちで単純なRGB入りLEDもあるのでシリアルRGBを使う必要はないんだけど、当初ピンの少ないESP8266上で動かそうとしていたのです。しかしArduino用ライブラリでは動いてくれないので挫折、nanoにしました。

初めての秋月版、きれいにまとまったのに
なお、上の写真でADXL345(赤い基板)のハンダがすごく汚いですが、これは電子工作を再開した直後に作ったもの。隣の秋月ESPに免じて許してやってください。少しはきれいになったのは昔の勘を取り戻したというのもあるけど、大きなものでもルーペ使ってハンダ付けするようになったのが大きな要因だと思います。

■接続など■

Nano接続先
3.3v出力ブレッドボードの+ライン
GNDブレッドボードの-ライン
5v出力マイコン内蔵LEDのVdd
D2マイコン内蔵LEDのDin
A4ADXL345のSCL
A5ADXL345のSDA
A610KΩ半固定抵抗の真ん中

ADXL345接続先
SCLArduino A4
SDAArduino A5
SDOGND
CS3.3v
Vs3.3v
GNDGND
Vdd3.3v

その他、半固定抵抗の一端をGND, 他端を3.3v、マイコン内蔵LEDのGNDをGNDに接続します。あ、またパスコン入れ忘れた。

標準のArduinoだとA6って使えないんでしたっけ。その場合はA0-A3どれでも結構です。そしてソース上のanalogReadで指定しているピン番号をそれに合わせて変えてください…A0の場合は14です。

nanoではなくnanoパチ

■ソフトについて■

ADXL345のライブラリはAndroid Citiさんのライブラリ、マイコン内蔵LEDについてはAdafruitさんのライブラリを使用させていただきました。ありがとうございます。

あ、そろそろ年末だからAdafruitさんに何か注文しなきゃ(注:いつも同社が提供しているライブラリを他社製品でばかり使っているので、年に一度お礼代わりに何か買うことにしています)。

コードはsetupで各デバイスを初期化、点滅に必要なサインカーブ用テーブルを用意、装置の傾きなどを補正するために各軸からの値の平均値を取ってます。loopはぐるぐる回りながら加速度を読み込んで初期値との差分が一定値を超えていたら点滅用のカウンタをセットし、あとはカウンタをインクリメントしながら各軸の値をテーブルに従って変えています。無駄な演算多いけど許してください。

うーん、本当は「ドン!」のピーク値を算出し、それを元にして最大照度などを決定すべきなんですが・・・面倒くさいからやってません。また、現在は加速度で検出していますけど、重力加速度の影響で傾けたりしても誤動作してしまいます。それこそ毎度お馴染みFFTを実行して数Hz以上の加速度成分が一定値を超えたら作動する…って処理にすれば完璧だと思いますが・・・・面倒すぎるのでやってません。


#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <ADXL345.h>
#include <Time.h>
//
// NeoPixel
//
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 2
#define NUMPIXELS 1
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//
// ADXL345
//
ADXL345 adxl; //variable adxl is an instance of the ADXL345 library
#define MaxWaves 64
int wave[MaxWaves];
int aveX, aveY, aveZ;
void setup() {
Serial.begin(115200);
//
// NeoPixels
//
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
// End of trinket special code
pixels.begin(); // This initializes the NeoPixel library.
//
// ADXL345
//
adxl.powerOn();
adxl.setActivityX(1);
adxl.setActivityY(1);
adxl.setActivityZ(1);
adxl.setInactivityX(1);
adxl.setInactivityY(1);
adxl.setInactivityZ(1);
int sumX = 0, sumY = 0, sumZ = 0;
const int times = 10;
for (int i = 0; i < times; i++) {
int x,y,z;
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables x,y,z
sumX += x;
sumY += y;
sumZ += z;
delay(100);
}
aveX = sumX / times;
aveY = sumY / times;
aveZ = sumZ / times;
//
// others
//
for (int i = 0; i < MaxWaves; i++) {
wave[i] = sin((float)i * 3.14159265 / (float)MaxWaves) * 255;
}
}
// loop counter
int xStep = -1;
int yStep = -1;
int zStep = -1;
// max loop counter
const int MaxSteps = MaxWaves * 5;
// minimum movement
int sensitive;
// range of brightness
int magX, magY, magZ;
//
// calc brightness by range and step in loop
//
int brightness(int inMag, int inStep) {
int ret = wave[inStep % MaxWaves] * inMag / 100;
if (ret < 0) ret = 0;
if (ret > 255) ret = 255;
return ret;
}
//
// set brightness range
//
int calcMag(int inDiff) {
int ret = 10;
if (inDiff > sensitive * 2) {
ret = 100;
} else if (inDiff > sensitive * 2) {
ret = 20;
}
return ret;
}
// average value of volume
int aveVol = 0;
void loop() {
//
// RGB each brightness
//
int red = 0, green = 0, blue = 0;
//
// read volume and set sensitivity
//
aveVol = (aveVol * 9 + analogRead(20)) /10;
sensitive = aveVol / 10;
Serial.println(sensitive);
//
// read accelometer and detect movement
//
int x,y,z;
adxl.readAccel(&x, &y, &z); //read the accelerometer values and store them in variables x,y,z
int diffX = abs(aveX - x);
int diffY = abs(aveY - y);
int diffZ = abs(aveZ - z);
//
// if movement is harder than expected, start flashing!
//
if (diffX > sensitive) {
if (xStep == -1) {
xStep = 0;
magX = calcMag(diffX);
}
}
if (diffY > sensitive) {
if (yStep == -1) {
yStep = 0;
magY = calcMag(diffY);
}
}
if (diffZ > sensitive) {
if (zStep == -1) {
zStep = 0;
magZ = calcMag(diffZ);
}
}
//
// manage flashing
//
if (xStep != -1) {
if (xStep > MaxSteps) {
xStep = -1;
} else {
green = brightness(magX, xStep++);
}
}
if (yStep != -1) {
if (yStep > MaxSteps) {
yStep = -1;
} else {
blue = brightness(magY, yStep++);
}
}
if (zStep != -1) {
if (zStep > MaxSteps) {
zStep = -1;
} else {
red = brightness(magZ, zStep++);
Serial.print(zStep);
Serial.print(",");
Serial.println(red);
}
}
//
// controll WS2811
//
pixels.setPixelColor(0, pixels.Color(green, red, blue));
pixels.show();
// wait for 5mSec
//
delay(5);
}
view raw ADXL_WS2811.cpp hosted with ❤ by GitHub

2015年11月5日木曜日

表面実装立体化シリーズ:MOSFET

老眼鏡でも見えない件

最新のMOSFETはすっごいですよね。毎度お馴染みの2N7000あたりと比べるとオン抵抗、スイッチング速度、ドレイン電流、どの特性も一桁違う感じです。

しかし、残念ながら新しいのはみんな表面実装か大型パッケージ。

というわけで、またピンヘッダに直付けしてみましたw

以前のチップ抵抗/コンデンサは大変うまくいったのですが、今回は2個つくるのに30分もかかりました。最初はピンヘッダを内側にまげて、GDS配列のまま取り付けようとしたのですが、どーにも細かすぎて私のスキルでは無理。

なので、1と2を隣接するヘッダにハンダ付けし、3はジャンパで飛ばしました。試してみたらちゃんとスイッチングしているので、一応生きてはいるようです。

ちょっとゴツいけど、初期の点接触トランジスタみたいでちょっと萌えるw

ブレイクアウト基板ならもう少し簡単だけど、ディスクリート部品にはちょっと大げさになってしまうので、こういう作業を簡単にできるブレイクアウト・ピンヘッダみたいなのがあれば、それなりに売れるんじゃないかな。

おお起業ロマン!…と一瞬思ったのですが、こういうプラスチック型が必要で初期投資大きく、単価が安いものはリスクが大きいよね。

夢は見ないで大人しく寝ます。みなさんも良い夢を。