2019年6月18日火曜日

SR-FRS FMトランシーバ

SR-FRS1WVを使った2m FMトランシーバ(2m FM 1W出力)。写真のシールドされた部分が、SR-FRSモジュールである。このモジュールは、中華の数社から販売されており、DRA818、SA818、SR-FRSなどのキーワードで探すことが出来る。SR-FRSを除き殆ど、12.5kHzまたは25kHzステップとなっており、国内では使いづらい。SR-FRSは、20kHzステップとして動作させられるので、音声FMに適している。




BK4811

SR-FRSの回路である。BK4811(DSP)とRF AMP,マイコンから構成されている。このBK4811は、70cmも対応しているが残念ながら、DSPにコマンドを与えない限り、70cmは動作しない様だ。










トランシーバ回路

周波数設定にロータリーエンコーダを使い、oled表示器を備えた回路図である。注意しなければいけない事は、SR-FRSの定格電圧が低いことである。電源電圧を4.5V以下で使うのが良いであろう。











PCB設計

PCBEを使ってPCB設計し、KicadのViewerでチェックを行った。マイク入力とRF出力が近接している為、RF回り込みを心配したが、全く問題なく動作した。









ハンディタイプ


ハンディタイプ トランシーバとして纏めた例である。リチュームイオン電池(3.7V)と充電器を内蔵。人間工学からメーカ製とは考え方の異なる配置とした。

















スケッチ

バンドプランによる運用周波数制限、スケルチoff、自動メモリー書込みの機能がある。
JA2GQP's Download siteのSR-FRSフォルダからダウンロード可能。Ver1.00での既知のバグは、1kHz台の表示が誤表示する事がある。誤表示は、電源offまたは運用周波数範囲外チェック後の希望周波数への移動などにより回避できる。この下1桁誤表示は、Ver1.01で確認試験を行っていたが、誤表示する事は無かった。下記の黄色部分は、Downloadサイトに反映されてアップロード済み。

//////////////////////////////////////////////////////////////////////
//  SR-FRS1W VHF TRX program ver.1.01
//    Copyright(C)2019.JA2GQP.All rights reserved.
//
//                                                2019/06/18
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.encoeder STEP 20kHz
//    2.Squelch on/off(SQ SW)
//    3.Auto save memory(frequency)
//    4.Voltmeter
//////////////////////////////////////////////////////////////////////

#include "src/Rotary.h"               // http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
#include "src/SSD1306AsciiAvrI2c.h"   // https://github.com/greiman/SSD1306Ascii
#include <EEPROM.h>

////////////////////////////////
// Set Device
////////////////////////////////
Rotary r = Rotary(2, 3);
SSD1306AsciiAvrI2c oled;

////////////////////////////////
// I/O Port
////////////////////////////////
const byte SW_SQ = 4;                 // SQ SW

////////////////////////////////
// EEPROM Memory Address
////////////////////////////////
const byte  Eep_Init = 0x00;          // Eep Init(1byte*1)
const byte  Eep_Freq = 0x10;          // Frequency(4byte*8)
const byte  Int_End = 73;             // Initial end code

////////////////////////////////
// Constant Memory
////////////////////////////////
const char Call[9] = "JA2GQP";        // Display Call sign
const unsigned long DEF_FREQ =145000; // Default
const unsigned long BAND_L =144600;   // Low limit
const unsigned long BAND_H =145800;   // High limit

////////////////////////////////
// Variable Memory
////////////////////////////////
unsigned long frq;                    // Frequency data
unsigned long frqb;                   //           old data
const unsigned int STEP = 20;         // STEP 20kHz

String GBW = "0";                     // Bandwidth(0:Nallow 1:Wide)
unsigned long  TFV;                   // Transmit frequency
unsigned long  RFV;                   // Receive frequency
String RXCXCSS = "00";                // CICSS/CDCSS(00-121)
String SQ = "1";                      // Squelch level(0:Monitor mode)
String TXCXCSS = "00";                // CICSS/CDCSS(00-121)
String FLAG = "0";                    // Bit0(Busy),Bit1(Compression),Bit2(Power)

float v;                              // volt data
float vb = 0;                         //           old
byte Flg_freq = 0;
byte Flg_sq = 0;
byte Flg_eepWT = 0;                   // EEP Write Flag
long Time_Passd = 0;                  // int to hold the arduino miilis since startup

//----------- setup -----------------------------------------------------

void setup(){
  pinMode(SW_SQ,INPUT_PULLUP);

  attachInterrupt(0,rotary_encoder,CHANGE);
  attachInterrupt(1,rotary_encoder,CHANGE);

  analogReference(INTERNAL);          // Internal 1.1V set
  oled.begin(&Adafruit128x64,0x3C);

  Serial.begin(9600);
  if(EEPROM.read(Eep_Init) != Int_End){    // Eep initialaz
    delay(10);
    eep_init();
  }

  eep_rdata();
  frs_init();
  frs_set();

  volt_disp();
  freq_disp(frq);
  call_disp();
}

//---------- loop -------------------------------------------------------

void loop(){
  if(frq != frqb){
    frq = constrain(frq,BAND_L,BAND_H);
    frs_set();
    freq_disp(frq);
    frqb = frq;
    volt_disp();

    Time_Passd = millis();
    Flg_eepWT = 1;
  }

  if (digitalRead(SW_SQ) == LOW) {
    sq_set();
    frs_set();
  }

  if(Flg_eepWT == 1){                       // EEPROM auto Write
    if(Time_Passd+2000 < millis()){
      eep_wdata();
      Flg_eepWT = 0;
    }
  } 
}

//----------  Rotaly Encorder  -----------------------------------------

void rotary_encoder() {                     // rotary encoder events
  uint8_t result = r.process();

  if (result) {
    Flg_freq = 1;
    if (result == DIR_CW)
      frq = frq + STEP;
    else
      frq = frq - STEP;
  }
}

//----------  Band set  ------------------------------------------------

void sq_set(){
  if(Flg_sq == 0){
    SQ = "0";
    Flg_sq = 1;
  }
  else{
    SQ = "1";
    Flg_sq = 0;
  }
  while(digitalRead(SW_SQ) == LOW);
}

//----------  EEPROM Initialization ------------------------------------

void eep_init(){
  int i;

  for (i=0;i<128;i++)                       // 0 clear(128byte)
    EEPROM.write(i, 0);

  eep_write4(DEF_FREQ,Eep_Freq);
  EEPROM.write(Eep_Init,Int_End);           // Init end set(73)
}

//----------  Write EEPROM 4byte  --------------------------------------

void eep_write4(long value,int address){
  address += 3;
  for(int i = 0;i < 4;i++){
    byte toSave = value & 0xFF;
    if(EEPROM.read(address) != toSave){
      EEPROM.write(address,toSave);
      }
    value = value >> 8;
    address--;
  }
}

//----------  Read EEPROM 4byte  ---------------------------------------

long eep_read4(int address){
  long value = 0;

  for(int i = 0;i < 4;i++){
    value = value | EEPROM.read(address);
    if( i < 3){
      value = value << 8;
      address++;
    }
  }
  return value;
}

//----------  EEPROM Dat Read  -----------------------------------------

void eep_rdata(){
  frq = eep_read4(Eep_Freq);
}

//----------  EEPROM Dat Write  ----------------------------------------

void eep_wdata(){
  eep_write4(frq,Eep_Freq);
}

//---------- callsign display ------------------------------------------

void call_disp() {
  oled.setFont(Arial_bold_14);
  oled.setCursor(56, 6);
  oled.print(Call);
}

//----------  Frequency Display  ---------------------------------------

void freq_disp(uint32_t sf_rx) {
  unsigned int wk;

  oled.setFont(lcdnums14x24);
  oled.setCursor(16, 2);
  wk = sf_rx / 1000;
  oled.print(wk);
  oled.print('.');
  wk = sf_rx % 1000;
  if (wk < 100)
    oled.print('0');
  if (wk < 10)
    oled.print('0');
  oled.print(wk/10*10);
}

//---------- SR-FRS Initialize ----------------------------------------

void frs_init(){
  Serial.println("AT+DMOCONNECT");    // Se connecter au module
  Serial.println("");
  Serial.println("");
  delay (500);
}

//---------- SR-FRS data set ------------------------------------------

void frs_set(){
  TFV = RFV = frq;

  Serial.print("AT+DMOSETGROUP=");    // Commencer un message
  Serial.print(GBW);
  Serial.print(',');
  Serial.print((float)TFV / 1000, 4);
  Serial.print(',');
  Serial.print((float)RFV / 1000, 4);
  Serial.print(',');
  Serial.print(RXCXCSS);
  Serial.print(',');
  Serial.print(SQ);
  Serial.print(',');
  Serial.print(TXCXCSS);
  Serial.print(',');
  Serial.println(FLAG);
  delay(20);
}

//---------- Volt Meter -----------------------------------------------

void volt_disp(){
  v = analogRead(A1) * 1.1;
  v = v / 1023;
  v = v / 2200;
  v = v * 12200;

  if(vb != v){
    oled.setFont(Arial_bold_14);
    oled.setCursor(1, 0);
    oled.print("        ");
    oled.setCursor(1, 0);
    oled.print(v,2);
    oled.print('V');
    vb = v;
  }
}




5 件のコメント:

  1. 初めまして、いつも大変に参考にさせて頂いております。
    本記事を見る前に当方も価格に釣られSA808のU/Vを購入しテストコマンドで動かしてみましたが殆ど本SR-FRSと同じコマンドで動くようです。
    周波数ステップの件でお聞きしたいのですが特定の送受信周波数セットは特に気にせず10khzでも20khzでも設定可能なようです。
    ここで言うのはBWは送信時の占有周波数帯域幅がと思うのですが、当方のスペアナでは、分解能が悪く、12.5k/25k切換えてモニターしても、違いがわかりませんでした。
    12.5khzにしておけば、国内でも使えると思うのですが、もし何かお分かりでしたら、お教えください。

    返信削除
  2. JN3TFI OM 
    はじめまして。
    早速ですが、私の知っているモジュールはDRA818、SA818、SR-FRSがあります。DRAとSAは型番が示す通り同じものの様です。SR-FRSは類似してますが唯一10kHzステップが可能です。
    周波数カウンターで測定しましたが、設定通りの表示がでます。SA818とDRA818はWeb検索でも多くヒットします。SR-FSRはデータシートも暫定版なども出回っており、万民向けでは有りません。モジュール自体、西洋、欧州などの仕様に合わせ12.5kHz、25kHzが基本になってます。jarl.comにメールが設定して有れば、データシート送ります。他のメールアドレスでもOKなので返事ください。

    返信削除
  3. OMありがとうございます。
    やはり周波数ステップが異なるようですね。

    先ほど此方からメールを送らせて頂きました。宜しくお願いします。

    返信削除
  4. Unknown
    Download SR-FRS1W_oled.zip from the Download site.
    Unzip SR-FRS1W_oled.zip to create the SR-FRS1W_oled folder.
    Sketch files, schematics, and src folders are generated in the SR-FRS1W_oled folder. You can modify the sketches in this folder as needed and compile them.
    The sketch uses the library in the src folder.

    返信削除