Top Page 気象センサー&タイマーシールドの実装
自作工程のメモとして
27.Jun.2017


 前のページに 「Mighty CW Keyer のケースへの実装」を掲載しましたが、ケースの中身が大きく空洞になっており勿体ないので、ブレッドボードで実験していた気象センサー(AE-BME280)とタイマー(DS3231)を載せるシールドを作成しました。
CW-Keyerは、USBケーブルでパソコン(PC)に繋がっており、PCをONしている間は通電状態にあります。
私の場合は、交信を頻繁にするわけでも無く、日常的には温度・湿度・気圧・時刻を表示させておけば、購入したセンサー類を活用しながらブレッドボードを片付けることができることから作ってみました。
また、専用のPCBを作るほどでは有りませんが、最近FusionPCBへ発注する機会が多くなり、他のPCBと一緒に発注しました。




完成品1号機です。


Page edited by bluegriffon2.3.1


1.回路

 特別な回路ではなく、ブレッドボード上で組んでいたままを写しただけになります。
3.3V側と5V側にはプルアップ抵抗の回路も書きましたが、各センサー・タイマーにはプルアップ抵抗が入っていると思いますので、配線は不要です。(あまりに勿体ないのでパターンを描いてみただけです)


■ 回路図


クリックして拡大版(PDF)になります。




2.シールドの実装

 CW Keyer のケースの中にそのまま取り付けるだけです。
ただし、気象センサーは密閉状態ではおかしいので、後面のパネルに3.5Φの穴を開けています。

■ シールドを実装した状態の後面


気象センサー(AE-BME280)は、ブレッドボード上でテストしていたものを直付けしています。
もし、このように実装するならL型のピンコネクタを後面から刺せば、後面パネルにギリギリの位置まで近づけられたかもしれません。


■ 後面パネルに開けた穴

  
試しに、失敗作の後面パネルに穴を開け、センサーの穴(塞いではいけない穴)が見えるようにしました。
ケース内の温度上昇が影響するか心配しましたが、温度等は後面パネルを外した状態と変わらなかったため良しとしました。


■ CW Keyer に気象センサーと時刻を表示させた状態


スピードのボリュームを左に回し切った時に、気象センサーと時刻を表示するようにしています。
右に少し回すと、k3ng CW Keyer に切り替わります。(キーヤーの画面も復活)



3.スケッチの工夫(k3ng CW Keyer と 気象センサー&タイマーの同居)

 k3ng CW Keyer は更新の頻度が比較的高く、直接書き込むことを最小限にしようとヘッダファイルの形式で挿入・貼付けをすることにしました。
同居させるスケッチを5つのファイル(jlb_Insert_top.h ・ jlb_Insert_setup.h ・ jlb_Insert_loop.h ・ jlb_Insert_loopend.h ・ jlb_paste_end.h)に分割して、k3ng keyer本体の空白行に挿入していきます。(5つのファイルは、 k3ng_keyer.ino ファイルと同じフォルダーに入れます。)
ただし、最後のファイルは、ヘッダファイル形式で挿入するとコンパイル時にエラー(記述が見つからない??)が出たため、貼り付けています。
また、当然ですがk3ng Keyer の内容と重複するところは、削除しています。

k3ng_keyer.ino ファイルの挿入位置等は、20170514付での例です。

(1) jlb_Insert_top.h ファイルの挿入

■ 挿入位置


■ jlb_Insert_top.h ファイルの内容
// k3ng_keyer.ino  フィルの 1368 行に挿入

// 時間調整はM1 M2 ボタンを使う(プラス1秒=M1・マイナス1秒=M2)
// 注意:桁上がり桁下がりを考慮していないため、30秒前後の時に実行
// DS3231 を使用。ライブラリーは、DS1307
// k3ng CW Keyer と連携するときは、Keyerのloopエンドは、1538行目付近にある。
//

// #include <Wire.h>
// #include <TimeLib.h>
#include <DS1307RTC.h>

const char *monthName[12] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
// スイッチサイエンス社のBME280サンプスケッチ
#define BME280_ADDRESS 0x76
unsigned long int hum_raw, temp_raw, pres_raw;
signed long int t_fine;

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;

tmElements_t tm;

#define SerialOutFlag false  // シリアル出力する場合は true 、出力しない false
int b4sec;    // 前回表示した秒値を格納。

// -------------------------------------------




(2) jlb_Insert_setup.h ファイルの挿入

■ 挿入位置


■ jlb_Insert_setup.h ファイルの内容
// k3ng_keyer.ino  フィルの 1400 行に挿入
// -------------------------------------------

  pinMode(7, OUTPUT);

  //BME280初期設定
  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;

  // I2CのSETUP
  Wire.begin();

  writeReg(0xF2, ctrl_hum_reg);
  writeReg(0xF4, ctrl_meas_reg);
  writeReg(0xF5, config_reg);

  readTrim();

// -------------------------------------------




(3) jlb_Insert_loop.h ファイルの挿入

■ 挿入位置

■ jlb_Insert_loop.h ファイルの内容
// k3ng_keyer.ino  フィルの 1407 行に挿入
// -------------------------------------------
if (analogRead(0) < 5 )
{
  int SS;
    SS = analogRead(1);
  if (RTC.read(tm)) {    // RTCから時間が読み出せれば◆
    // 時間調整 プラス・マイナス1秒を M1+ M2- ボタンで調節する。
    // 注意:秒が30秒前後の時に実行すること
    // (簡易設定のため、桁上がり桁下がりを考慮せず)

      if ((SS > 70)&&(SS < 120)) { // M1ボタンなら +1秒
        tm.Second++;
        // and configure the RTC with this info
        RTC.write(tm);    // 時間をDS3231 へセットする
        beep();
        delay(500);
      }
      if ((SS > 150)&&(SS < 180)) { // M2ボタンなら -1秒
        tm.Second--;
        // and configure the RTC with this info
        RTC.write(tm);    // 時間をDS3231 へセットする
        beep();
        delay(500);
      }

  } else {    // RTCから時間が読み出せ無ければ◆
    if (RTC.chipPresent()) {
      lcd.setCursor(0, 0);
      lcd.print("run the SetTime");
    } else {
      lcd.setCursor(0, 0);
      lcd.print("DS1307 read error!");
    }
    delay(9000);
  }
  if (b4sec != tm.Second ) { // 取得した秒値が違えば、表示する
    b4sec = tm.Second;
    TempClockDisp();
  }
  // delay(1000);

}else{
// -------------------------------------------


まず、先頭行にある if (analogRead(0) < 5 ) でスピードのVRを読み出しています。
もし、左に回し切っている状態なら、気象・時刻の処理をするよう判断します。       
また、時間(秒単位)を調節できるよう、M1・M2ボタンを使っています。
M1・M2ボタンでの操作時に、 beep(); を入れてみました。



(4) jlb_Insert_loopend.h ファイルの挿入

■ 挿入位置



■ jlb_Insert_loopend.h ファイルの内容
// k3ng_keyer.ino  フィルの 1539 行に挿入
 }    // loop end



ここは、ループの終了位置 "}" を挿入するだけです。


(5) jlb_paste_end.h ファイルの貼付

■ 貼付け位置



■ jlb_paste_end.h ファイルの内容
// k3ng_keyer.ino  フィルの 17093 行(最下行)にこのファイル全体を貼り付ける。
// 編集は jlb_paste_end.h ファイルにて行い、その都度貼り付けること。
void TempClockDisp() {    // 温度・湿度・気圧・時間を表示

  // LCD へ出力する。
  // 時分秒
  lcd.setCursor(11, 0);
  lcd2digits(tm.Month);
  lcd.write('/');
  lcd2digits(tm.Day);
  lcd.write(' ');
  lcd.setCursor(8, 1);
  lcd2digits(tm.Hour);
  lcd.print(":");
  lcd2digits(tm.Minute);
  lcd.print(":");
  lcd2digits(tm.Second);

  /*
      // 年月日 表示エリヤの関係で使わない
      lcd.setCursor(0, 1);
      lcd.print(tmYearToCalendar(tm.Year));
      lcd.print("/");
      lcd2digits(tm.Month);
      lcd.print("/");
      lcd2digits(tm.Day);
      lcd.print(" ");
  */

  // 温度・湿度・気圧を表示
  double temp_act = 0.0, press_act = 0.0, hum_act = 0.0;
  signed long int temp_cal;
  unsigned long int press_cal, hum_cal;
  int aa;

  readData();

  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;
  //初期値が小数点以下2桁のため Serial.print(XXXXX,1); ,1 で
  //小数点以下2桁目を四捨五入し、小数点以下1桁出力とする。

  switch (tm.Second) {  // ■■■ 10秒毎に表示
    case 0:
    case 10:
    case 20:
    case 30:
    case 40:
    case 50:
      //LCD に表示する
      //初期値が小数点以下2桁のため lcd.print(XXXXX,1); ,1 で
      //小数点以下2桁目を四捨五入し、小数点以下1桁出力とする。
      lcd.setCursor(0, 0);
      temp_act = temp_act - 2.4;    // ■温度センサーの出力が高すぎるため -2.4度引く。
      lcd.print(temp_act, 1);
      lcd.print("c  ");
      lcd.setCursor(0, 1);
      if (press_act < 999.95) lcd.print(" ");
      lcd.print(press_act, 1);
      lcd.print("h ");
      lcd.setCursor(7, 0);
      lcd.print(hum_act, 0);
      lcd.print("% ");
  }
}

// ■◆■■これ以降、タイマーDS3231関係の記述

// LCDへの出力を2桁にする print2digits を参照して追加。
void lcd2digits(int number) {
  if (number >= 0 && number < 10) {
    lcd.print('0');
  }
  lcd.print(number);
}
// ■◆■■ここまで、タイマーDS3231関係の記述

////////////////////////////////////////////////////////////////
// ■■■これ以降、BME280 温度・湿度・気圧関係の記述
void readTrim()   // BME280の処理
{
  uint8_t data[32], i = 0;                   // Fix 2014/04/06
  Wire.beginTransmission(BME280_ADDRESS);
  Wire.write(0x88);
  Wire.endTransmission();
  Wire.requestFrom(BME280_ADDRESS, 24);      // Fix 2014/04/06
  while (Wire.available()) {
    data[i] = Wire.read();
    i++;
  }

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

  Wire.beginTransmission(BME280_ADDRESS);
  Wire.write(0xE1);
  Wire.endTransmission();
  Wire.requestFrom(BME280_ADDRESS, 7);       // Fix 2014/04/06
  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); // Fix 2014/04/06
  dig_H6 = data[31];                                   // Fix 2014/04/06
}
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);
  // ■■■ここまで、温度・湿度・気圧関係の記述
  /////////////////////////////////////////////////////////////////
}
このファイルだけは、ヘッダファイルとして挿入できず、その内容を貼り付けることにしています。







9.その他気づいたこと

(1)都度、追記します。





mighty-1284p mighty 1284p ATmega1284p
99.追記用(予備)