So-net無料ブログ作成
検索選択

Arduino DDS_VFO(1) [Aruduino]

 arduinoによるcolor_LCDとDDS、ロータリーエンコーダーを動かすことが出来たので、いよいよVFOを目指していく。
最初に仕様を決める。とはいっても初心者であるのであまり複雑なことは出来ない。基本的な機能とした。
【仕様】
 ・7Mhzシングルバンド
 ・周波数可変STEP(10,100,1K,10KHz)
 ・RIT(±10KHz)
 ・モード(LSB,CW)
 ・Sメータ表示

【ハードウェア】
arduino_VFO1.jpg 仕様を決めたら、其れに合わせてハードウェアを決定する必要がある。前回のものに、STEP変更スイッチ、RITスイッチ、モード変更スイッチの3つのスイッチが追加される。さらに送信状態の取り込みとモード(LSB,CW)の情報を出力ピンが必要となる。
 送信情報の取り込みは(A5)で、これをLOWにすることで送信状態となる。
モードはモードスイッチ(A1)でCWに変更されると、モード出力(A2)がHigh(5V)となる。これをデジトラに入力し、オープンコレクタで外部(キャリアOSC切替)に出力する。


【画面構成】

DSCN3569.JPG
 画面構成は大事であると思う。気に入った画面出なければ長く使う気にはなれない。しかしこれは個人のセンスによるものなので各人好みで製作されたい。今回以下の画面とした。どうもN6QWの影響が大きいため似たものとなってしまった。

 画面はイメージを作り上げるためにグラフィック的に描いただけで機能はまだ無い。ここまでは前回までのコマンドで作成できる。
 やはり実際に作ってみたほうがイメージが作りやすいと思う。

 ここで今までのコマンドでは描けないものが1つある。それは周波数表示の白枠や、STEP,RIT表示の角が丸くなった長方形である。
コマンドは、
tft.drawRoundRect(x1,y1,x2,y2,r,color) 塗りつぶし無し
tft.fillRoundRect(x1,y1,x2,y2,r,color)塗りつぶし有り
の2つ。実際の使用はスケッチを参考に。

 さてここまで決定したらいよいよプログラミングである。今回は周波数表示の改善である。というのは、前回のスケッチによる表示は、周波数を変更するたびに全体がチカチカして見にくい。そこでこれを改善する。とは言うもののこれは結構ハードなプログラミングとなってしまった。処理スピード等の懸念はあるが、取敢えずチャレンジしてみた。
 そもそもこの原因は、グラフィック表示ならではのものである。キャラクタLCDであれば上書きすれば書き換わるが、グラフィックLCDでは、一度前の表示を背景色で塗りつぶす必要がある。このため全体がチカチカしてしまう。
 ならばどうする。毎回書き直さず周波数変化があった時だけ書き換える。さらに変化のあった桁だけ修正することとした。
とはいうもののこれが大変な作業である。どうするかであるが、周波数数値をstring()というコマンドで文字に変換し、その文字で周波数の変化前と比較し変更になった文字部分のみ塗りつぶしと表示を行うという面倒な方法とした。面倒ではあるが、これによりドットを任意に追加できるようになった。詳細はスケッチを参考にしてください。特に苦心したのは1桁少なくなるときの消去(いわゆるゼロサプレッス) であった。このルーチンが出来たことにより999MHz~0Hzまでチカチカせず綺麗に表示出来るようになった。
 
DSCN3585.JPG
 尚、今回の修正に当たって数の読替宣言(#define)という命令を(const)命令に変更している。これは(const)命令のほうが厳密に管理されるとのことで、バグ等の原因 にならないようである。詳しくはリファレンス等を参照してください。色々な数値についても変数はいいのですが、定数(プログラム上で変更されない数値)は(const)命令としている。
 
 今回は周波数表示のみであり、表示は左の写真のようになる。
 チカチカせずきわめて綺麗に表示変更される(自画自賛)
 気になった処理スピードも問題なくエンコーダーに追随している。キャラクタLCDに比べてもきわめて処理が早いようだ。 
 
 
 
 
 
 
【スケッチ】
 
// Library include
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <TFT_ILI9163C.h>
#include <Rotary.h>
#include <EF_AD9850.h>

// Color definitions
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

/* 1.44inch color LCD using 4 wire SPI here, so:
 MOSI:  11//Teensy3.x/Arduino UNO
 MISO:  12//Teensy3.x/Arduino UNO
 SCK:   13//Teensy3.x/Arduino UNO
 */

// I/O setting 
  const byte __CS=10;
  const byte __DC=9;
  const byte __RST=8;
  const byte ddreset=4;
  const byte dddata=5;
  const byte ddfqup=6;
  const byte ddclock=7;
  const byte s_meter=A0;
  const byte modesw=A1;
  const byte modeout=A2;
  const byte stepsw=A3;
  const byte ritsw=A4; 
  const byte txsw=A5;
  const byte RE_A=2;
  const byte RE_B=3;
  
  TFT_ILI9163C tft=TFT_ILI9163C(__CS,__DC,__RST);  
  EF_AD9850 AD9850(ddclock,ddfqup,ddreset,dddata);
  Rotary r=Rotary(RE_A,RE_B);

// Variable setting
  long int freq =7100000; // 立上時の周波数
  long int freqold=0; // 変更前の周波数格納用変数
  String freqt=String(freq); // 周波数を文字変数に変換
  long int ddsfreq = 0; // DDSへ送る周波数(後にIFシフトを加味するため)
  char f100m,f10m,fmega,f100k,f10k,f1k,f100,f10,f1; //文字に変換された数値を桁毎に格納する変数
  int fstep=100; // 周波数変更ステップの初期値
  
//  初期設定
void setup() {
  tft.begin();
  tft.setRotation(1);
  PCICR |=(1<<PCIE2);
  PCMSK2 |=(1 << PCINT18) | (1 << PCINT19);
  sei();
  AD9850.init();
  AD9850.reset();
  screen01(); //基本画面の抽画
}

//Main Routine
void loop() {
    if (freq != freqold){ //周波数が変更されたか判定し異なれば以下を実行
      ddsfreq=freq; //変更後周波数を設定
      AD9850.wr_serial(0x00,ddsfreq); //DDSに命令を送る
      freqt=String(freq);  //周波数を文字に変換
      freqlcd(); //周波数表示ルーチンに飛びLCDに表示
      freqold=freq;  //旧周波数に現周波数を代入
    }
}

// Encoder Interrupt
ISR(PCINT2_vect) {
  unsigned char result = r.process();
     if(result) {
      if(result == DIR_CW){  
        freq=freq+fstep; // 周波数をSTEP分プラス
      }
      else{
        freq=freq-fstep; // 周波数をSTEP分マイナス
      }
    } 
}

//Main frequency screen 周波数表示ルーチン
void freqlcd(){
  int mojisuu=(freqt.length()); // 文字数を調べる
  tft.setTextSize(2); // 文字サイズを(2)に設定
  tft.setTextColor(GREEN); // 文字色を緑に設定
  if(freq>=100000000){ // 周波数が100MHz以上の時以下を処理
    if(f100m !=(freqt.charAt(0))){ // 100Mhz台が前回(f100m)と違うか判定し以下を処理
      tft.fillRect(4,13,12,14,BLACK); // 100Mhz台を黒で塗りつぶす
      tft .setCursor(4,13); // カーソルを100Mhzの位置にセット
      tft.print(freqt.charAt(0)); // 100MHz台を表示
      f100m = (freqt.charAt(0)); // 100Mhz台をf100mに格納 
    }
  } // 以下各桁同じような処理のためコメント省略
  if(freq<100000000){tft.fillRect(4,13,12,14,BLACK);}
  if (f10m !=(freqt.charAt(mojisuu-8))){
   tft.fillRect(16,13,12,14,BLACK);
   tft .setCursor(16,13);
   tft.print(freqt.charAt(mojisuu-8));
   f10m = (freqt.charAt(mojisuu-8));
  }

   if(freq<10000000){tft.fillRect(16,13,12,14,BLACK);}
   if(fmega !=(freqt.charAt(mojisuu-7))){
    tft.fillRect(28,13,12,14,BLACK);
    tft.setCursor(28,13);
    tft.print(freqt.charAt(mojisuu-7));
    fmega  = (freqt.charAt(mojisuu-7));
   }

  if(freq>=1000000){ //ドット表示(MHz台)
    tft.setTextSize(1);
    tft.setCursor(39,20); 
    tft.print(".");
    tft.setTextSize(2);
  }

  if(freq<1000000){tft.fillRect(28,13,18,14,BLACK);}
  if(f100k !=(freqt.charAt(mojisuu-6))){
    tft.fillRect(46,13,12,14,BLACK);
    tft.setCursor(46,13);
    tft.print(freqt.charAt(mojisuu-6));
    f100k = (freqt.charAt(mojisuu-6));
  }
    
  if(freq<100000){tft.fillRect(46,13,12,14,BLACK);}
  if(f10k !=(freqt.charAt(mojisuu-5))){
    tft.fillRect(58,13,12,14,BLACK);
    tft.setCursor(58,13);
    tft.print(freqt.charAt(mojisuu-5));
    f10k = (freqt.charAt(mojisuu-5));
  }
   
  if(freq<10000){tft.fillRect(58,13,12,14,BLACK);}
  if(f1k !=(freqt.charAt(mojisuu-4))){
    tft.fillRect(70,13,12,14,BLACK);
    tft.setCursor(70,13);
    tft.print(freqt.charAt(mojisuu-4));
    f1k  = (freqt.charAt(mojisuu-4));
  }
  
  if(freq>=1000){
    tft.setTextSize(1);
    tft.setCursor(81,20); 
    tft.print(".");
    tft.setTextSize(2);
  }
   
  if(freq<1000){tft.fillRect(70,13,18,14,BLACK);}
  if(f100 !=(freqt.charAt(mojisuu-3))){
    tft.fillRect(88,13,12,14,BLACK);
    tft.setCursor(88,13);
    tft.print(freqt.charAt(mojisuu-3));
    f100 = (freqt.charAt(mojisuu-3));
  }

  if(freq<100){tft.fillRect(88,13,12,14,BLACK);}
  if(f10 !=(freqt.charAt(mojisuu-2))){
    tft.fillRect(100,13,12,14,BLACK);
    tft.setCursor(100,13);
    tft.print(freqt.charAt(mojisuu-2));
    f10 = (freqt.charAt(mojisuu-2));
  }
   
  if(freq<10){tft.fillRect(100,13,12,14,BLACK);}
  if(f1 !=(freqt.charAt(mojisuu-1))){
    tft.fillRect(112,13,12,14,BLACK);
    tft.setCursor(112,13);
    tft.print(freqt.charAt(mojisuu-1));
    f1  = (freqt.charAt(mojisuu-1));   
  }
}

//Basic Screen
void screen01(){
  tft.drawRoundRect(0,5,128,30,4,WHITE);
  tft.setCursor(2,120);
  tft.setTextColor(YELLOW);
  tft.print(" Homeblew VFO JA2NKD");
}
 
次回はスイッチ関係の予定
 


nice!(1)  コメント(0) 
共通テーマ:趣味・カルチャー

nice! 1

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。

×

この広告は1年以上新しい記事の更新がないブログに表示されております。