fc2ブログ

三軸加速度センサーMMA8452Qを使う(1)

 四月の異動後のストレス?で現実逃避の「電子工作」を継続しています・・。ブログも四月以降、電子工作ネタで今回が13件目です。手を動かしていないとダメなんでしょうね。ただ、最近、半田付けの時に細かいものにピントが合いにくく、しんどいですね・・。

 振動の分析をしてみようと、秋月でNXP製の加速度センサーMMA8452Qを実装したモジュールキットを買いました。I2C通信で簡単にデータが取れるタイプです。
【K-12069】 MMA8452Q使用3軸加速度センサーモジュールキット
 配線図は以下の通りです。周辺に転がっていた部品類を掻き集めて実装しました。MMA8452Q配線図_190629AE-ATMEGA328-MINIとMMA8452Q間のSDA、SCL信号端子間には330Ωの抵抗を入れるようにマニュアルに書かれていましたが、手持ちがなかったので、240Ωで代用しました。実装した写真はこんな感じです。MMA8452Q実装写真_190629
 また、マニュアルに以下のArduino用のI2C通信のサンプルスケッチがありましたので、そのままコピペして、動作確認です。
#include <Wire.h>
#define MMA8452_ADRS 0x1D

#define MMA8452_OUT_X_MSB 0x01
#define MMA8452_XYZ_DATA_CFG 0x0E
#define MMA8452_CTRL_REG1 0x2A
#define MMA8452_CTRL_REG1_ACTV_BIT 0x01
#define MMA8452_G_SCALE 2

void setup() {
byte tmp;

Serial.begin(38400);
Wire.begin();

tmp = MMA8452_ReadByte(MMA8452_CTRL_REG1);
MMA8452_WriteByte(MMA8452_CTRL_REG1, tmp & ~(MMA8452_CTRL_REG1_ACTV_BIT));

MMA8452_WriteByte(MMA8452_XYZ_DATA_CFG, (MMA8452_G_SCALE >> 2));

tmp = MMA8452_ReadByte(MMA8452_CTRL_REG1);
MMA8452_WriteByte(MMA8452_CTRL_REG1, tmp | MMA8452_CTRL_REG1_ACTV_BIT);

}

void loop() {
byte buf[6];
float g[3];

MMA8452_ReadByteArray(MMA8452_OUT_X_MSB, 6, buf);
g[0] = -(float((int((buf[0] << 8) | buf[1]) >> 4)) / ((1 << 11) / MMA8452_G_SCALE));
g[1] = -(float((int((buf[2] << 8) | buf[3]) >> 4)) / ((1 << 11) / MMA8452_G_SCALE));
g[2] = -(float((int((buf[4] << 8) | buf[5]) >> 4)) / ((1 << 11) / MMA8452_G_SCALE));

Serial.print(g[0], 4);
Serial.print("\t");
Serial.print(g[1], 4);
Serial.print("\t");
Serial.print(g[2], 4);
Serial.println("\t");

delay(10);
}

void MMA8452_ReadByteArray(byte adrs, int datlen, byte *dest){
Wire.beginTransmission(MMA8452_ADRS);
Wire.write(adrs);
Wire.endTransmission(false);

Wire.requestFrom(MMA8452_ADRS, datlen);

while(Wire.available() < datlen);

for(int x = 0; x < datlen; x++){
dest[x] = Wire.read();
}
}

byte MMA8452_ReadByte(byte adrs){
Wire.beginTransmission(MMA8452_ADRS);
Wire.write(adrs);
Wire.endTransmission(false);

Wire.requestFrom(MMA8452_ADRS, 1);

while(!Wire.available());
return(Wire.read());
}

void MMA8452_WriteByte(byte adrs, byte dat){
Wire.beginTransmission(MMA8452_ADRS);
Wire.write(adrs);
Wire.write(dat);
Wire.endTransmission();
}
x、y、zの各方向のみに揺らしてデータを採取しました。MMA8452Q数値結果_190629Arduinoのシリアルモニタでは数値だけの表示でピント来ないので、シリアルプロッタで可視化します。Arduinoシリアルプロッタ_190629これはなかなか便利です。いまさらですが、たまたま見つけた機能でした・・。MMA8452Q結果X方向_190629MMA8452Q結果Y方向_190629MMA8452Q結果Z方向_190629x、y、zの各方向のみに揺らしたデータが素直に反映されていました。へぇーうまく出るもんだなと納得です。

次回は、きちんとプリント基板に半田付けして、モータの振動(加速度)でも取ってみようと思います。
スポンサーサイト



LED Cubeを作る

 YouTubeのリコメンド動画の中に、複数のLEDを立方体形状に配線し、各LEDをプログラムでON/OFFさせる「LED Cube」がありました。面白そうだなと思い、早速作ってみました。
 5×5×5のLED Cubeを目指したかったのですが、まずはトライアルで3×3×3を作製して味見をしました。ネット上に作り方が多数出回っているので、詳細は割愛しますが、まずは準備からスタートです。

 LEDを整然と並べるためのベースプレートを準備しました。base_plate_190627.pngホームセンターから廃材の板(@50円)を購入し、25mmピッチでドリルで穴開けをしました。将来の5×5×5を見越して25個開けました。

今回使った部品類は以下の通りです。①〜③は秋月で購入し、④⑤は手持ちのものを利用しました。
① LED 青色 200個 (3×3×3は27個、5×5×5は125個)
 【I-11334】 3mm青色LED 470nm 70° OSB5YU3Z74A (100個入)
② LED光拡散キャップ 150個
 【I-07614】 LED光拡散キャップ(3mm) 青 (50個入)
③ AEーATMEGA328-MINI
 【K-10347】 AE-ATMEGA328-MINI (Arduino Pro Mini上位互換)
④ NPNトランジスタ 3 pcs
⑤ 抵抗 10kΩ × 3、 240Ω × 9

 配線図は以下の通りです。LED_Cube配線図_190627AEーATMEGA328-MINIの0〜8番(D0〜D8ピン)を9個のLEDの制御に、14〜16番(A0〜A2ピン)を上・中・下段のLEDのダイナミック点灯の制御に利用しました。

 ベースプレートにLEDをセットしてカソード側を半田付けしてつなぐ際、完成品の見栄えを良くするために(LEDが綺麗に整列するように)、以下の通り、足を曲げる方向を3パターン変えました。LED足曲げ_190627結線図はこんな感じです。細かいこだわりですが・・。LED足_配線図_190627 9個のLEDを平面実装できた所で、動作確認を行いました。[広告]

点灯/消灯動作に問題ないことを確認して、もう2セット作製し、立体的に組み上げ、アノード側を半田付けして完成です。完成品を動かすプログラムはこのサイトを参考にさせていただきました。ありがとうございます。[広告]

なかなかいい感じで出来上がりました。また、いろいろなパターンを登録して遊んでみようと思います。

Raspberry Pi Zeroをアクセスポイントとして使う(5)

 前回の続きです。今回はESP8266に接続している温湿度気圧センサ(BME280)のデータをRaspi Zeroに飛ばすお話です。
 プログラムは以下の通りで、132〜258行目はセンサからのデータ収集部分、266行目以降は前回お話ししたFTP通信部分です。センサデータ収集プログラムは以前のblogでお話しした内容、FTP通信プログラムは前回の内容をそのまま参考にしました。機能ごとにソースコードを分けずに引っ付けて長くなってしまいましたが、まずは動作検証まで。
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <FS.h>

#define AP_SSID "Raspi_AP"
#define AP_PW "drbobt123"
#define BME280_ADDRESS 0x76

WiFiServer server( 80 );

//FTPサーバーと接続するための設定_
#define FTP_TO "192.168.4.1" // FTP 送信先のIPアドレス
#define FTP_USER "pi" // FTP ユーザ名
#define FTP_PASS "raspberry" // FTP パスワード
#define FTP_DIR "/home/pi/Common" // FTP ディレクトリ
#define FILENAME "/mes.csv" // FTPサーバーに送るファイル名(保存するファイル名)

unsigned long int hum_raw,temp_raw,pres_raw;
signed long int t_fine;
double temp_act = 0.0, press_act = 0.0,hum_act=0.0;
int sec, minute, hr, mintemp;
char temperature[16];
char atmospheric_pressure[16];
char humidity[16];
char uptime[16];
char filename[16];

uint16_t dig_T1;
int16_t dig_T2;
int16_t dig_T3;
uint16_t dig_P1;
int16_t dig_P2;
int16_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int16_t dig_P6;
int16_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;
int8_t dig_H1;
int16_t dig_H2;
int8_t dig_H3;
int16_t dig_H4;
int16_t dig_H5;
int8_t dig_H6;

void setup()
{
// For STA use
WiFi.mode(WIFI_STA);
WiFi.begin(AP_SSID, AP_PW);
while (WiFi.status() != WL_CONNECTED) { // 接続に成功するまで待つ
Serial.print(".");
delay(500); // 待ち時間処理
}
server.begin();

uint8_t osrs_t = 1; //Temperature oversampling x 1
uint8_t osrs_p = 1; //Pressure oversampling x 1
uint8_t osrs_h = 1; //Humidity oversampling x 1
uint8_t mode = 3; //Normal mode
uint8_t t_sb = 5; //Tstandby 1000ms
uint8_t filter = 0; //Filter off
uint8_t spi3w_en = 0; //3-wire SPI Disable

uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
uint8_t config_reg = (t_sb << 5) | (filter << 2) | spi3w_en;
uint8_t ctrl_hum_reg = osrs_h;

mintemp = -1;

// Sensor data Communication
Serial.begin(115200);
Wire.begin(4,5);
writeReg(0xF2,ctrl_hum_reg);
writeReg(0xF4,ctrl_meas_reg);
writeReg(0xF5,config_reg);
readTrim();

SPIFFS.begin();
}

void loop()
{
signed long int temp_cal;
unsigned long int press_cal,hum_cal;

delay(60000);
readData();
sec = millis() / 1000;
minute = sec / 60;
hr = minute / 60;

temp_cal = calibration_T(temp_raw);
press_cal = calibration_P(pres_raw);
hum_cal = calibration_H(hum_raw);
temp_act = (double)temp_cal / 100.0;
press_act = (double)press_cal / 100.0;
hum_act = (double)hum_cal / 1024.0;
sprintf(uptime,"%02d:%02d",hr, minute % 60);
Serial.print(uptime);
Serial.print("->");
Serial.print("TEMP : ");
Serial.print(temp_act);
Serial.print(" DegC PRESS : ");
Serial.print(press_act);
Serial.print(" hPa HUM : ");
Serial.print(hum_act);
Serial.println(" %");

File f = SPIFFS.open(FILENAME, "a");
f.print(uptime);
f.print(",");
f.print(temp_act);
f.print(",");
f.print(press_act);
f.print(",");
f.println(hum_act);
f.close();

if(minute!=mintemp){
mintemp = minute;
byte ret = doFTP(FILENAME); // FTPで送信する
if (ret) {
Serial.print("FTP Err :");
Serial.println(ret);
delay(3000);
}
}
}

void readTrim()
{
uint8_t data[32],i=0;
Wire.beginTransmission(BME280_ADDRESS);
Wire.write(0x88);
Wire.endTransmission();
Wire.requestFrom(BME280_ADDRESS,24);
while(Wire.available()){
data[i] = Wire.read();
i++;
}

Wire.beginTransmission(BME280_ADDRESS);
Wire.write(0xA1);
Wire.endTransmission();
Wire.requestFrom(BME280_ADDRESS,1);
data[i] = Wire.read();
i++;

Wire.beginTransmission(BME280_ADDRESS);
Wire.write(0xE1);
Wire.endTransmission();
Wire.requestFrom(BME280_ADDRESS,7);
while(Wire.available()){
data[i] = Wire.read();
i++;
}
dig_T1 = (data[1] << 8) | data[0];
dig_T2 = (data[3] << 8) | data[2];
dig_T3 = (data[5] << 8) | data[4];
dig_P1 = (data[7] << 8) | data[6];
dig_P2 = (data[9] << 8) | data[8];
dig_P3 = (data[11]<< 8) | data[10];
dig_P4 = (data[13]<< 8) | data[12];
dig_P5 = (data[15]<< 8) | data[14];
dig_P6 = (data[17]<< 8) | data[16];
dig_P7 = (data[19]<< 8) | data[18];
dig_P8 = (data[21]<< 8) | data[20];
dig_P9 = (data[23]<< 8) | data[22];
dig_H1 = data[24];
dig_H2 = (data[26]<< 8) | data[25];
dig_H3 = data[27];
dig_H4 = (data[28]<< 4) | (0x0F & data[29]);
dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F);
dig_H6 = data[31];
}

void writeReg(uint8_t reg_address, uint8_t data)
{
Wire.beginTransmission(BME280_ADDRESS);
Wire.write(reg_address);
Wire.write(data);
Wire.endTransmission();
}

void readData()
{
int i = 0;
uint32_t data[8];
Wire.beginTransmission(BME280_ADDRESS);
Wire.write(0xF7);
Wire.endTransmission();
Wire.requestFrom(BME280_ADDRESS,8);
while(Wire.available()){
data[i] = Wire.read();
i++;
}
pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
hum_raw = (data[6] << 8) | data[7];
}

signed long int calibration_T(signed long int adc_T)
{

signed long int var1, var2, T;
var1 = ((((adc_T >> 3) - ((signed long int)dig_T1<<1))) * ((signed long int)dig_T2)) >> 11;
var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T>>4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14;

t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return T;
}

unsigned long int calibration_P(signed long int adc_P)
{
signed long int var1, var2;
unsigned long int P;
var1 = (((signed long int)t_fine)>>1) - (signed long int)64000;
var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long int)dig_P6);
var2 = var2 + ((var1*((signed long int)dig_P5))<<1);
var2 = (var2>>2)+(((signed long int)dig_P4)<<16);
var1 = (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((signed long int)dig_P2) * var1)>>1))>>18;
var1 = ((((32768+var1))*((signed long int)dig_P1))>>15);
if (var1 == 0)
{
return 0;
}
P = (((unsigned long int)(((signed long int)1048576)-adc_P)-(var2>>12)))*3125;
if(P<0x80000000)
{
P = (P << 1) / ((unsigned long int) var1);
}
else
{
P = (P / (unsigned long int)var1) * 2;
}
var1 = (((signed long int)dig_P9) * ((signed long int)(((P>>3) * (P>>3))>>13)))>>12;
var2 = (((signed long int)(P>>2)) * ((signed long int)dig_P8))>>13;
P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4));
return P;
}

unsigned long int calibration_H(signed long int adc_H)
{
signed long int v_x1;

v_x1 = (t_fine - ((signed long int)76800));
v_x1 = (((((adc_H << 14) -(((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) +
((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) *
(((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) *
((signed long int) dig_H2) + 8192) >> 14));
v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4));
v_x1 = (v_x1 < 0 ? 0 : v_x1);
v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);
return (unsigned long int)(v_x1 >> 12);
}

void sleep() {
Serial.println("F Err"); // ファイルを呼び出せなかった時のエラー表示
}

// FTP Communication

#define FTP_WAIT 1
#define BUFFER_SIZE 128

byte doFTP(char *filename){
char ftpBuf[BUFFER_SIZE];
WiFiClient client;
WiFiClient dclient;
int i;

File file = SPIFFS.open(FILENAME,"r");
if(!file){
Serial.println("SPIFFS open fail");
return 11;
}
Serial.println("SPIFFS opened");
if (client.connect(FTP_TO,21)) {
Serial.println("Command connected");
}
if(eRcv(client,ftpBuf)) return 21;

sprintf(ftpBuf,"USER %s\r\n",FTP_USER);
client.print(ftpBuf);
delay(FTP_WAIT);
Serial.print(ftpBuf);
if(eRcv(client,ftpBuf)) return 22;

sprintf(ftpBuf,"PASS %s\r\n",FTP_PASS);
client.print(ftpBuf);
delay(FTP_WAIT);
Serial.println("PASS");
if(eRcv(client,ftpBuf)) return 23;

client.print("Type I\r\n");
delay(FTP_WAIT);
Serial.println("Type i");
if(eRcv(client,ftpBuf)) return 25;

client.print("PASV\r\n");
delay(FTP_WAIT);
Serial.println("PASV");
delay(100);
if(eRcv(client,ftpBuf)) return 26;

char *tStr = strtok(ftpBuf,"(,");
if(tStr == NULL) return 27;
int array_pasv[6];
for (i = 0; i < 6; i++) {
tStr = strtok(NULL,"(,");
array_pasv[i] = atoi(tStr);
if(tStr == NULL){
Serial.println("Bad PASV Answer");
return 28;
}
}

unsigned int hiPort,loPort;
hiPort = array_pasv[4] << 8;
loPort = array_pasv[5] & 255;
Serial.print("Data port: ");
hiPort = hiPort | loPort;
Serial.println(hiPort);
if (dclient.connect(FTP_TO,hiPort)) {
Serial.println("Data connected");
}else{
Serial.println("Data connection failed");
client.stop();
file.close();
return 31;
}
sprintf(ftpBuf,"STOR %s%s\r\n",FTP_DIR,filename);
client.print(ftpBuf);
delay(FTP_WAIT);
Serial.print(ftpBuf);
if(eRcv(client,ftpBuf)){
dclient.stop();
file.close();
return 32;
}
Serial.println("Writing");
i=0;
while(file.available()){
ftpBuf[i]=file.read();
i++;
if(i >= BUFFER_SIZE){
if(!dclient.connected()) break;
dclient.write( (byte *)ftpBuf, BUFFER_SIZE);
i=0;
Serial.print(".");
delay(1);
}
}
if(i > 0){
if(dclient.connected()){
dclient.write((byte *)ftpBuf, i);
}
}
dclient.stop();
Serial.println("Data disconnected");
if(eRcv(client,ftpBuf)) return 33;
client.print("QUIT\r\n");
delay(FTP_WAIT);
Serial.println("QUIT");

client.stop();
Serial.println("Command disconnected");
file.close();
Serial.println("SPIFFS closed");

return 0;
}

byte eRcv(WiFiClient &client,char *ftpBuf){
byte thisByte,i=0,len=0;

while(!client.available()){
delay(FTP_WAIT);
if(!client.connected()){
Serial.println("FTP:eRcv:disC");
return 11;
}
i++;
if(i>1000){ // 200ms以上必要
Serial.println("FTP:eRcv:noRes");
return 12;
}
}
while(client.connected()){
if(!client.available()){
delay(FTP_WAIT);
if(!client.available()) break;
}
thisByte = client.read();
if(thisByte==(byte)'\r');
else if(thisByte==(byte)'\n'){
Serial.write('>');
Serial.println(ftpBuf);
if(ftpBuf[0] >= '4'){
client.print("QUIT\r\n");
delay(FTP_WAIT);
Serial.println("QUIT");
return 1;
}
if(len>3 && ftpBuf[3] == ' '){
return 0;
}
len = 0;
}else if(len < BUFFER_SIZE - 1 ){
ftpBuf[len] = thisByte;
len++;
ftpBuf[len] = 0;
}
}
return 0;
}

void efail(WiFiClient &client){
byte thisByte = 0;
client.print("QUIT\r\n");
delay(FTP_WAIT);
while(!client.available()){
if(!client.connected()) return;
delay(1);
}
while(client.available()){
thisByte = client.read();
Serial.write(thisByte);
}
client.stop();
Serial.println("Command disconnected");
}
実行時のArduinoのシリアルモニタはこんな感じです。1分おきにデータ収集して、そのデータをSPIFFSに追加書き込みし、そのファイルをRaspi ZeroにFTPで飛ばします。Arduino_SerialMonitor_190602.pngRaspi Zeroには確実にファイル転送され、保存されていました。Raspi_server_datafolder_190602.pngファイルの中身は以下の通り。左側から経過時間(1分おき)、温度、気圧、湿度の順番です。Raspi_server_data_190602.pngファイル保存されるのは、現時刻ではなく経過時間ですが、Raspi Zeroにファイル保存された時刻と経過時間から、データ収集した時刻を計算できました。採取したデータを表計算ソフトでグラフ化すると以下の通りです。TemperatureGraph_190602.pngAtomosphericPressureGraph_190602.pngHumidityGraph_190602.pngCSVファイルがRaspi Zeroにリアルタイムに入ってくるので、Webアプリでグラフ化するのも容易にできそうです。今回は行いませんが・・。センサの数を増やして、それらのデータをRaspi Zeroに集約すると面白いかもしれません。「簡便な自宅IoTシステム」のできあがりです。

Raspberry Pi Zeroをアクセスポイントとして使う(4)

 前回の続きです。今回はESP8266からRaspberry Pi ZeroへのFTP通信のお話をします。前回説明したESP8266のSPIFFS内にファイルを作成し、その後、FTPでRaspberry Pi Zero(アクセスポイント)に転送するプログラムを作成しました。とはいえ、ネット情報を頼りに、ほとんど丸ごとコピペです・・。ありがとうございました。

 アクセスポイント名はRaspi_AP、Raspi Zero内に共有フォルダ(/home/pi/Common)にspiffs.csv(今回のファイルの中身にはカンマはないですが・・)を飛ばします。1回目にお話しましたが、このデータ飛ばしはIoT network内の話です。
 SPIFFSにファイルを書き込む所は29〜31行目です。50行目以降は、FTP転送に関する部分で処理の流れがよく分かり、どこでエラーを吐いているか分かり易かったです。
#include <ESP8266WiFi.h>                      // ESP8266用ライブラリ
#include <FS.h>

#define SSID "Raspi_AP" // 無線LANアクセスポイントのSSID
#define PASS "drbobt123" // 無線LANアクセスポイントのパスワード

//FTPサーバーと接続するための設定_
#define FTP_TO "192.168.4.1" // FTP 送信先のIPアドレス
#define FTP_USER "pi" // FTP ユーザ名
#define FTP_PASS "raspberry" // FTP パスワード
#define FTP_DIR "/home/pi/Common" // FTP ディレクトリ
#define FILENAME "/spiffs.csv" // FTPサーバーに送るファイル名(保存するファイル名)

File file;
WiFiServer server(80); // Wi-Fiサーバ(ポート80=HTTP)定義

void setup() {

SPIFFS.begin();
Serial.begin(115200); // 動作確認のためのシリアル出力開始
WiFi.mode(WIFI_STA); // 無線LANをSTAモードに設定
WiFi.begin(SSID, PASS); // 無線LANアクセスポイントへ接続
while (WiFi.status() != WL_CONNECTED) { // 接続に成功するまで待つ
Serial.print(".");
delay(500); // 待ち時間処理
}
server.begin(); // サーバを起動する

File f = SPIFFS.open(FILENAME, "a"); // 保存のためにファイルを開く(追記モードでオープン)
f.println("From SPIFFS to Raspberry Pi Zero"); // 書き込みデータ
f.close(); // ファイルを閉じる

byte ret = doFTP(FILENAME); // FTPで送信する
if (ret) {
Serial.print("FTP Err :");
Serial.println(ret);
delay(3000);
}
Serial.println("finish"); // 終了表示
}

void loop() {
//
}

void sleep() {
Serial.println("F Err"); // ファイルを呼び出せなかった時のエラー表示
}

#define FTP_WAIT 1
#define BUFFER_SIZE 128

byte doFTP(char *filename){
char ftpBuf[BUFFER_SIZE];
WiFiClient client;
WiFiClient dclient;
int i;

File file = SPIFFS.open(filename,"r");
if(!file){
Serial.println("SPIFFS open fail");
return 11;
}
Serial.println("SPIFFS opened");
if (client.connect(FTP_TO,21)) {
Serial.println("Command connected");
}
if(eRcv(client,ftpBuf)) return 21;

sprintf(ftpBuf,"USER %s\r\n",FTP_USER);
client.print(ftpBuf);
delay(FTP_WAIT);
Serial.print(ftpBuf);
if(eRcv(client,ftpBuf)) return 22;

sprintf(ftpBuf,"PASS %s\r\n",FTP_PASS);
client.print(ftpBuf);
delay(FTP_WAIT);
Serial.println("PASS");
if(eRcv(client,ftpBuf)) return 23;

client.print("Type I\r\n");
delay(FTP_WAIT);
Serial.println("Type i");
if(eRcv(client,ftpBuf)) return 25;

client.print("PASV\r\n");
delay(FTP_WAIT);
Serial.println("PASV");
delay(100);
if(eRcv(client,ftpBuf)) return 26;

char *tStr = strtok(ftpBuf,"(,");
if(tStr == NULL) return 27;
int array_pasv[6];
for (i = 0; i < 6; i++) {
tStr = strtok(NULL,"(,");
array_pasv[i] = atoi(tStr);
if(tStr == NULL){
Serial.println("Bad PASV Answer");
return 28;
}
}

unsigned int hiPort,loPort;
hiPort = array_pasv[4] << 8;
loPort = array_pasv[5] & 255;
Serial.print("Data port: ");
hiPort = hiPort | loPort;
Serial.println(hiPort);
if (dclient.connect(FTP_TO,hiPort)) {
Serial.println("Data connected");
}else{
Serial.println("Data connection failed");
client.stop();
file.close();
return 31;
}
sprintf(ftpBuf,"STOR %s%s\r\n",FTP_DIR,filename);
client.print(ftpBuf);
delay(FTP_WAIT);
Serial.print(ftpBuf);
if(eRcv(client,ftpBuf)){
dclient.stop();
file.close();
return 32;
}
Serial.println("Writing");
i=0;
while(file.available()){
ftpBuf[i]=file.read();
i++;
if(i >= BUFFER_SIZE){
if(!dclient.connected()) break;
dclient.write( (byte *)ftpBuf, BUFFER_SIZE);
i=0;
Serial.print(".");
delay(1);
}
}
if(i > 0){
if(dclient.connected()){
dclient.write((byte *)ftpBuf, i);
}
}
dclient.stop();
Serial.println("Data disconnected");
if(eRcv(client,ftpBuf)) return 33;
client.print("QUIT\r\n");
delay(FTP_WAIT);
Serial.println("QUIT");

client.stop();
Serial.println("Command disconnected");
file.close();
Serial.println("SPIFFS closed");

return 0;
}

byte eRcv(WiFiClient &client,char *ftpBuf){
byte thisByte,i=0,len=0;

while(!client.available()){
delay(FTP_WAIT);
if(!client.connected()){
Serial.println("FTP:eRcv:disC");
return 11;
}
i++;
if(i>1000){ // 200ms以上必要
Serial.println("FTP:eRcv:noRes");
return 12;
}
}
while(client.connected()){
if(!client.available()){
delay(FTP_WAIT);
if(!client.available()) break;
}
thisByte = client.read();
if(thisByte==(byte)'\r');
else if(thisByte==(byte)'\n'){
Serial.write('>');
Serial.println(ftpBuf);
if(ftpBuf[0] >= '4'){
client.print("QUIT\r\n");
delay(FTP_WAIT);
Serial.println("QUIT");
return 1;
}
if(len>3 && ftpBuf[3] == ' '){
return 0;
}
len = 0;
}else if(len < BUFFER_SIZE - 1 ){
ftpBuf[len] = thisByte;
len++;
ftpBuf[len] = 0;
}
}
return 0;
}

void efail(WiFiClient &client){
byte thisByte = 0;
client.print("QUIT\r\n");
delay(FTP_WAIT);
while(!client.available()){
if(!client.connected()) return;
delay(1);
}
while(client.available()){
thisByte = client.read();
Serial.write(thisByte);
}
client.stop();
Serial.println("Command disconnected");
}

 実行してみますが「Permission denied」エラーが発生し、早速つまづきました。設定が足りませんでした。急ぎ過ぎました・・。
 まず、Raspi Zero側のCommonフォルダのパーミッションをchmodで変更しました。CommonFolder_190601.png次にこのサイトを参考に、Raspi Zeroの「vsftpd.conf」ファイルの設定を変更しました。ターミナルから以下のコマンドを入力し、
sudo nano /etc/vsftpd.conf
該当パラメータを次の通りに変更し、vsftpd_setting_190601.png次のコマンドで再スタートさせました。
sudo /etc/init.d/vsftpd restart
稼働状態を確認し、
sudo /etc/init.d/vsftpd status
問題ないことを確認しました。FTP_status_check_190601.png
 ここで、1回目にお話ししたHome networkのMacBook AirからFTPアクセスできるかを確認してみました。SafariからRaspi ZeroのIPアドレスを指定して、
ftp://192.168.11.30
を実行すると、以下のメッセージが出るので「許可」しました。FTP_Access_From_Mac1_190601.png次に、ユーザ名、パスワードを入力して、接続しました。FTP_Access_From_Mac2_190601.png問題なく接続でき、Commonフォルダを確認できました。FTP_Access_From_Mac3_190601.png
 それでは仕切り直しでプログラムの再実行です。program_run_190601.png進行経過を見る限り、問題はないようです。file_check_190601.pngRaspi Zero側のCommonフォルダを確認すると、正しく書き込まれていることが分かりました。

 次回は、最終回でESP8266に接続している温湿度気圧センサ(BME280)のデータをRaspi Zeroに飛ばすお話をします。

ご訪問者数

(Since 24 July, 2016)

タグクラウド


プロフィール

Dr.BobT

Author: Dr.BobT
興味のおもむくままに生涯考え続けるエンジニアでありたい。

月別アーカイブ

メールフォーム

名前:
メール:
件名:
本文: