jl7gmnのblog

yahooブログから移行してきました。アマチュア無線を中心としたブログです。

Arduino

RDA5708Mモジュール50MHz受信器その1

FMラジオの受信用として、とても安い価格のRDA5807Mモジュールをアマゾンで3個のものを注文し入手してあったので、試しにArduinoNANOで50MHzのFM受信機をスケッチし作製してみることにしました。
この価格でも安いですが、以前はこれよりもかなり安かったようです。

rdm5807-amazon

元々FMラジオ用として使用するものですが、データシートを確認してみると、レジスターアドレス03Hの2ビットめ3ビットめの2つのビットの設定でバンドセレクト(各国のFM周波数帯選択)ができるようになっています。下記のなかの11の設定で試してみるという方法で確認しました。結果から言うと、実際の受信できる周波数範囲はバンドセレクトの仕様とは異なり、受信感度も問題なく45.60MHzから119.60MHzと言う仕様よりも広範囲な受信周波数範囲で受信ができました。FMのインプットレンジが全部対応という事です。(仕様ではMIN:50MHzーMAX:115MHz)また、感度も50MHzではS/N=26dBで標準で1.4μV(EMF)という仕様の様です。びっくりです。

00:87-108MHz(US/Europe)
01:76-91MHz(Japan)
10:76-108MHz(World wide)
11:65-76MHz(East Europe) or 50-65MHz

このモジュールの取り付けピッチは2mmで通常の2.54mmのピッチに変換すると
ボードで使用できるので変換用に蛇の目基板を使い変換しています。時間をかけて半田ゴテをあててしまい、1個はモジュール側のメッキ部が取れて半田付けができなくなり失敗してしまいました。注意点として、早めの半田付のテクニックがいるかと思います。Hi!
RDA5708M-1

ArduinoNANOを使いましたがArduinoUnoでも問題なく使用できます。
RDA5708M-FM-ArduinoNANO

50MHz帯は51MHzからFMバンド帯なので起動時の周波数は51.00MHzに設定してあります。
ロータリーエンコーダ1クリックアップ時では、ステップ10KHzで、51.01MHzとなります。
RDA5708M-OLED-Display

今回のアマチュア無線バンドの50MHz帯の受信器の実験の参考にしたホームページは下記です。


面白いのは、レジスター60Hに書き込むとRDA5807Mで50MHzでも動かせるというものです。この隠しコマンドがあるということで、50MHz帯が受信できるように設定できるというものです。
他、スケッチのフレームとしてロータリーエンコーダ化も必要なので外国のアマチュア無線家 PU2CLR 局が作製してるデータを参考にしました。この局は他のDSPハード(SI4732)でSSB受信化できるライブラリを作った作者で、NETには数多くのDSPライブラリを使用した受信機の制作ページがありました。とても興味をそそる記事がたくさんあるようです。いつか試しにハードウェアを注文し確認してみたいと思います。ライブラリは基本的なもので改良、改変はOKとのことです。Hi! 今回はハードウェアはRDM5807なのでGithubに数多くデータを公開している中の、RDA5807_07_NANO_OLEDを参考に使用しました。また、表示DISPLAYは異なるものでしたので、手持ちのOLEDタイプのSD1306ASCiiのI2cタイプに変更してあります。


今回は単純にロータリーエンコーダーで周波数を10KHzステップで受信する機能のみです。ArduinoNANOにつなぐSWポートのD4、D5、D6、D14、D7の各ポートは設定のみです。スケッチはまだありません。(機能を付けてません。)ハード上追加できる機能としては上記のポートに対応してボリュームUP、ボリュームDOWN、オーディオMUTE、受信信号スキャン、オーディオBASSセットなどがあるのですが、他のハード用(ATtiny84)でしたので、今回の使用のハード用に下記のWireコマンドでソフトウェア設定する必要があります。機能追加するには、RDA5807Mのデータシートを確認しながらテストする必要があります。今後の検討課題としてあります。

Wire.beginTransmission(0x**);
Wire.write(0x**);
Wire.endTransmission();

下記は50MHz帯のFM信号をロータリーエンコーダで10KHzステップで変えて受信するという機能のみのスケッチです。メインとなっているのは、アップダウンのスケッチ部です。
PU2CLR局が使用したハード(ATtiny84)がArduinoNANOと異なるのでスケッチで変えたところはレム化し、残してあります。また使用していない変数設定も一部アリます。Hi!

/*
  Test and validation of RDA5807 on UNO/NANO or other ATMEGA328 based device.
  It is FM receiver with

   Nano and RDA5807 wireup

  Wire up on Arduino UNO, Nano or Pro mini

  | Device name      | Device Pin / Description  |  Arduino Pin  |
  |-----------------------|-----------------------------------|------------ |
  | OLED - I2C        |                                          |               |
  |                           |  SDA                                 |     A4      |
  |                           |  SCLK                               |     A5      |
  | ----------------------|-----------------------------------|-------------|
  | RDA5807           |                                          |               |
  |                           | SDA/SDIO                        |     A4      |
  |                           | SCLK (Clock)                   |     A5      |
  | ----------------------| ----------------------------------|-------------|
  | Buttons              |                                          |                |
  |                           | Volume Up                        |      4        |
  |                           | Volume Down                   |      5        |
  |                           | Mute                                 |      6        |
  |                           | Bass                                 |      7        |
  |                           | SEEK (encoder button)    |  D14/A0  |
  | --------------------------| ------------------------------|-------------|
  | Encoder             |                                          |               |
  |                           | A                                       |       2      |
  |                           | B                                       |       3      |

   By Ricardo Lima Caratti, 2020.
*/

#include "src/SSD1306AsciiAvrI2c.h"
#include "src/SSD1306Ascii.h"
SSD1306AsciiAvrI2c oled;
#define I2C_ADDRESS 0x3C  //0x3C,0x3A

#define FIX_VOLUME 4

#include <Wire.h>
#include <TEA5767Radio.h>
TEA5767Radio rx;

//#include <Tiny4kOLED.h>
//#define RDA_FM_BAND_SPECIAL 3    //!< 65 –76 MHz(East Europe) or 50 - 65MHz(see bit 9 of gegister 0x07)
#include "Rotary.h"

// Please, check the ATtiny84 physical pins

#define VOLUME_UP     4
#define VOLUME_DOWN   5
#define AUDIO_MUTE    6
#define AUDIO_BASS    7
#define SEEK_STATION 14 // A0 = D14

// Enconder PINs
#define ENCODER_PIN_A 2
#define ENCODER_PIN_B 3

bool bBass = false;
bool bMute = false;

volatile int encoderCount = 0;
int encorderCount = 0;
uint8_t seekDirection = 1; // 0 = Down; 1 = Up. This value is set by the last encoder direction.
long elapsedTimeEncoder = millis();

// Encoder control
Rotary encoder = Rotary(ENCODER_PIN_A, ENCODER_PIN_B);

unsigned char frequencyH=0;
unsigned char frequencyL=0;
unsigned int frequencyB;
double frequency=0;
double freq_available=0; //receivef
int b=0;
int c=0;
int d=0;
int e=0;
int f=0;

void setup()
{
  pinMode(ENCODER_PIN_A, INPUT_PULLUP);
  pinMode(ENCODER_PIN_B, INPUT_PULLUP);

  // Push button pin
//#define VOLUME_UP 4
//#define VOLUME_DOWN 5
//#define AUDIO_MUTE  6
//#define AUDIO_BASS  7
#define SEEK_STATION 14 // A0 = D14
 
  pinMode(VOLUME_UP, INPUT_PULLUP);     //D4
  pinMode(VOLUME_DOWN, INPUT_PULLUP);   //D5
  pinMode(AUDIO_MUTE, INPUT_PULLUP);    //D6
  pinMode(AUDIO_BASS, INPUT_PULLUP);    //D7
  pinMode(SEEK_STATION, INPUT_PULLUP);  //D14
  oled.begin(&Adafruit128x64,I2C_ADDRESS);
  //oled.begin();
  oled.clear();
  //oled.on();
   
  oled.setFont(Adafruit5x7);
 // oled.setFont(FONT8X16);
 
  oled.set2X();
  oled.setCursor(0, 10);
  oled.println("RDA5807OLED");
 
  oled.setCursor(0,40);
  oled.println("By PU2CLR   ");
  oled.setCursor(0,90);
  oled.println("Modefy By");
  oled.setCursor(0,140);
  oled.println("  JL7GMN");
  delay(3000);
  oled.clear();
/*
    Reads encoder via interrupt
    Use Rotary.h and  Rotary.cpp implementation to process encoder via interrupt
*/
  // Encoder interrupt
  attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), rotaryEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_B), rotaryEncoder, CHANGE);

// frequency initialize -------------------------------------------------
  frequency=51.00; //starting frequency ABALABLE MIN 45.60MHz TO MAX 119.60MHz
  frequencyB=4*(frequency*1000000+225000)/32768; //calculating PLL word
  frequencyH=frequencyB>>8;
  frequencyL=frequencyB&0XFF;
  delay(100);
//tune set to 0
  Wire.beginTransmission(0X10); //continuous write
                              //no need to specify register
  Wire.write(0X00); // 02h(HighByte02) DMUTE0
  Wire.write(0X00); // 02l(LowByte02)
  Wire.write(0X00); // 03h
  Wire.write(0X00); // 03l TUNE0 ENABLE0
  Wire.endTransmission();

  Wire.beginTransmission(0x60);   //writing TEA5767
  Wire.write(frequencyH);
  Wire.write(frequencyL);
  Wire.write(0xB0);
  Wire.write(0x00);// F0->10
  Wire.write(0x00);
  Wire.endTransmission();

/*
  Wire.beginTransmission(0X11); //normal i2c
  Wire.write(0X05); // specify register 05h
  Wire.write(0X88); // 05h
  Wire.write(0b10001000); // 05l VOLUMExxxx
 Wire.endTransmission();  
*/
 
  //radio.setVolume(15);
  //oled.setFont(Adafruit5x7);
  oled.setFont(X11fixed7x14B);
 
  oled.clear();
  oled.setCursor(1, 0);
  ;
 
  delay(10);
//----------------------------------------------------------
  showStatus();
}



void rotaryEncoder()
{ // rotary encoder events
  uint8_t encoderStatus = encoder.process();
  if (encoderStatus)
    encoderCount = (encoderStatus == DIR_CW) ? 1 : -1;
}

void showStatus()
{
  ;
  oled.set2X();
  oled.setCursor(0, 0);
  oled.println("FM ");

  oled.setCursor(0, 95);
  oled.println("       ");
  oled.setCursor(0, 95);
  oled.set2X();
  oled.print(frequency);
 
  oled.setCursor(75, 75);
  oled.println("MHz");

}

void loop()
{
  oled.set1X();

  // Check if the encoder has moved.
  if (encoderCount != 0)
  {
    if (encoderCount == 1)
    {
      //  seekDirection = RDA_SEEK_UP;
      //frequency=(freq_available/1000000)+0.05; //f=receivef+0.05
      frequency=(frequency+(freq_available/1000000)+0.01); //f=receivef+0.05
      frequencyB=4*(frequency*1000000+225000)/32768+1;
      frequencyH=frequencyB>>8;
      frequencyL=frequencyB&0XFF;   

    //tune set to 0
      Wire.beginTransmission(0X10); //continuous write
                              //no need to specify register
      Wire.write(0X00); // 02h(HighByte02) DMUTE0
      Wire.write(0X00); // 02l(LowByte02)
      Wire.write(0X00); // 03h
      Wire.write(0X00); // 03l TUNE0 ENABLE0
      Wire.endTransmission();
     
      Wire.beginTransmission(0x60);   
      Wire.write(frequencyH);
      Wire.write(frequencyL);
      Wire.write(0xB0);
      Wire.write(0x00);//Wire.write(0x1F);
      Wire.write(0x00);
    //Wire.write(0x88); // 05h
    //Wire.write(0x81); // 05l volulme001
      Wire.endTransmission();
      //////////////////////
      b=100;
    }
    else
    {
    //  seekDirection = RDA_SEEK_DOWN;
      //frequency=(freq_available/1000000)-0.05; //f=receivef-0.05
      frequency=(frequency+(freq_available/1000000)-0.01); //f=receivef-0.05
      frequencyB=4*(frequency*1000000+225000)/32768+1;
      frequencyH=frequencyB>>8;
      frequencyL=frequencyB&0XFF;

    //tune set to 0
      Wire.beginTransmission(0X10); //continuous write
                                    //no need to specify register
      Wire.write(0X00); // 02h(HighByte02) DMUTE0
      Wire.write(0X00); // 02l(LowByte02)
      Wire.write(0X00); // 03h
      Wire.write(0X00); // 03l TUNE0 ENABLE0
      Wire.endTransmission();
      
      Wire.beginTransmission(0x60);   
      Wire.write(frequencyH);
      Wire.write(frequencyL);
      Wire.write(0x30);
      Wire.write(0x00);//Wire.write(      
    // rx.setVolume(15);
    //TEA5767Radio::setVolume(15);0x1F);
      Wire.write(0x00);
    //Wire.write(0x88); // 05h
    //Wire.write(0x81); // 05l volulme001
      Wire.endTransmission();
      c=100;

    }
    showStatus();
    encoderCount = 0;
  }
 
  else if (digitalRead(VOLUME_UP) == LOW)     // D4
   {;// rx.setVolumeUp();
    
   }
  else if (digitalRead(VOLUME_DOWN) == LOW)   // D5
   {;// rx.setVolumeDown();

   }
  else if (digitalRead(AUDIO_MUTE) == LOW)    // D6
   {;// rx.setMute(bMute = !bMute);  

   }
  else if (digitalRead(SEEK_STATION) == LOW)  //D14
  { ; // rx.seek(RDA_SEEK_WRAP, seekDirection, showStatus); // showFrequency will be called by the seek function during the process.
    
    delay(200);
  }
  else if (digitalRead(AUDIO_BASS) == LOW)    //D7
  {;//  rx.setBass(bBass = !bBass);
    
    delay(50);
  }
}

上記のArduinoNANOスケッチで50MHz帯のFMが受信できました。
なおSSGで受信を確認してみたところ、FM受信は仕様上のチャンネルスペースの設定範囲が200KHz,100KHz,50KHz,25KHの中からの設定です。最低でも25KHz間隔です。なので見かけ上スケッチにて10KHz間隔で周波数表示対応できてはいますが選択したスペースで受信されているようです。やはりFM放送受信用ということでしょうか?
FM受信周波数にしてFMラジオとして使うのが一番無難なのかもしれません。Hi!

つづく?


ESP32DevKitCでのカラーグラフィックSメータその6

Sメータの画像表示で使用したLovyanGFXライブラリでの画像データを直接TFT液晶に書き込み表示するやり方とスプライト画面に書き込んでから表示する方法をまとめてみました。

■オフラインスプライトcanvasに書き込む方法

//#define LGFX_AUTODETECT //no need this one
#include <LovyanGFX.hpp>
#include "LGFX_ESP32_ST7735S.hpp" // add needing
#include "smeter.h"
#include "needle.h"

static LGFX lcd;
static LGFX_Sprite canvas(&lcd); // off screen draw buffer
static LGFX_Sprite smeter(&canvas);// myBitmap (128x160)
static LGFX_Sprite needle(&canvas);// hari     (5x100)

const uint16_t imgWidth = 128;
const uint16_t imgHeight = 160;

uint16_t signalLevel;  //角度に変換するのA/D値(0から4095)
uint16_t avtimes = 16 ;   //16 analoginput avaraging times

#define SW_TX  32                // A/D port 32   original sketch D0

void setup() {
  pinMode(SW_TX,INPUT);          

  lcd.init();
  lcd.setColorDepth(16);
  lcd.setSwapBytes(true);

  smeter.setColorDepth(16);
  needle.setColorDepth(16);

  canvas.fillScreen(TFT_WHITE); 
  canvas.setPivot(lcd.width() >>1,lcd.height() >>1);
  canvas.setColorDepth(16);
  canvas.setSwapBytes(true);
  canvas.setRotation(1);
  canvas.setBuffer((void*)myBitmap,128,160,16);
  canvas.createSprite(lcd.width(),lcd.height());
  canvas.pushImage(0,0,128,168,myBitmap);
  canvas.pushSprite(0,0);

  needle.createSprite(5,100);
  needle.setPivot((imgWidth/2),(imgHeight/3));
  needle.setBuffer((void*)hari,5,100,16);
  
}
void loop() {
 
    long d = 0 ;
  //*********************************************************
  // averaging settingtimes avtimes now setting 16
    for(int i=0;i<avtimes;i++){
      d += analogRead(32);
    }
    signalLevel = d/avtimes;

   Serial.println(signalLevel);
   //********************************************************

   //********************************************************
   // mapping to degree value
    signalLevel = map(signalLevel, 0, 4095, -64 , 80);
   //********************************************************
    
   //****************************************************************************************
 //エイリアス処理なし
   //needle.pushRotateZoom(&lcd,(imgWidth/1.55),(imgHeight/1),signalLevel,1.0,2.8);
   //エイリアス処理あり
    needle.pushRotateZoomWithAA(&lcd,(imgWidth/1.55),(imgHeight/1),signalLevel,1.0,2.8);
   // needleスプライト表示 
    needle.pushSprite(imgWidth/1.55,imgHeight/1); 
   //****************************************************************************************
    delay(200); //needle 表示時間調整用
   //スプライト書き込みしたcanvasを表示
   canvas.pushSprite(0,0);
   delay(1);

}

■直接lcdに画像データを書き込む方法
//#define LGFX_AUTODETECT //no need this one
#include <LovyanGFX.hpp>
#include "LGFX_ESP32_ST7735S.hpp" // add needing
#include "smeter.h"
#include "needle.h"

static LGFX lcd;
static LGFX_Sprite smeter(&lcd);// myBitmap (113x160) (128x160)
static LGFX_Sprite needle(&lcd);// hari     (5x100)

const uint16_t imgWidth = 128;
const uint16_t imgHeight = 160;

uint16_t signalLevel;  //角度に変換するのA/D値(0から4095)
uint16_t avtimes = 16 ;   //16 analoginput avaraging times

#define SW_TX  32                // A/D port 32   original sketch D0

void setup() {
  pinMode(SW_TX,INPUT);          

  lcd.init();
  lcd.setColorDepth(16);
  lcd.setSwapBytes(true);

  smeter.setColorDepth(16);
  needle.setColorDepth(16);
   
  lcd.setRotation(1); //角度設定1
  lcd.pushImage(0,0,128,160,myBitmap); //指針表示
  lcd.setRotation(0);   //角度設定0に戻す 指針の位置設定に合わせる
  lcd.pushImage((imgWidth/1.6),(imgHeight/7),5,100,hari);
   
  needle.createSprite(5,100);
  needle.setPivot((imgWidth/2),(imgHeight/3));
  needle.setBuffer((void*)hari,5,100,16);
  
}
void loop() {

    long d = 0 ;
  //**************************************************
  // averaging 100times
    for(int i=0;i<avtimes;i++){
      d += analogRead(32);
    }
    signalLevel = d/avtimes;
  Serial.println(signalLevel);
  
  //*********************************************************
  // mapping to degree value
    signalLevel = map(signalLevel, 0, 4095, -64 , 80);
  //*********************************************************
 
  //******************************************************************************************************
  //エイリアス処理なし
  //needle.pushRotateZoom(&lcd,(imgWidth/1.55),(imgHeight/1),signalLevel,1.0,2.8);
  //エイリアス処理あり
    needle.pushRotateZoomWithAA(&lcd,(imgWidth/1.55),(imgHeight/1),signalLevel,1.0,2.8);
    
    needle.pushSprite(imgWidth/1.55,imgHeight/1); //指針スプライト表示
  //******************************************************************************************************
    delay(200);//needle 表示時間調整用

    lcd.setRotation(1); //角度設定1
    lcd.pushImage(0,0,128,160,myBitmap); // Sメータ画像表示
    lcd.setRotation(0); //角度設定0に戻す。指針の位置表示に合わせる

   delay(1);
}

直接lcdに書き込む方法とオフラインバッファ画面に書き込んでから表示するのと同じ動作ですが、指針表示時間調整のディレータイムの値設定にもよると思いますが、若干ですが、lcd直接書き込みのほうがチラつきが少ないように思えます。これは、実際に動作させてみて、良いほうを使うのが常道のようです。必ずしも、オフラインで画像書き込みしたのを表示するスプライト処理がチラつきがないとは言えないこともあるようです。(書き込みの画像データ量も関係あるかと思います。)

いずれにしても、スプライト処理は画像のみならず、文字でも同様に処理できますので、覚えておいてよい表示方法かと思います。

つづく?

ESP32DevKitCでのカラーグラフィックSメータその5

気が向いたので、Sメータのパネルを最初から作り直してみました。
画像編集用のアプリは例のごとく、Inkscape とWindows10のペイントアプリ、そして、画像変換アプリの LCD-Image-Converterです。

Inkscapeはレイヤー処理で重ねる順番も自由に設定できるので、パネルの赤塗処理はとても簡単にきれいに作成できます。他、文字はコピーで、単に文字を書き換えて作成が簡単です。前のSメータパネルで一番気になっていたのは文字盤の目盛りと針の重なった時の一致していないことでした。今回はほぼ指針と重なるようにできましたので、すっきりしました。

■Inkscapeで作成したSメータパネル
できるだけ大きなページサイズで作成しておきます。サイズ変更はペイントアプリが便利です。
幅:1000px 、 高さ:680px
エクスポートで名前を適当に決めて、jpegで保存します。

inkscape-smeter


■ペイントアプリで編集します。
最初にサイズを目的の128x160pcになるように横の160pcは固定で縦の128pcになるように下側のページ位置を下げたり上げたりして変換値を確認し丁度128x160のサイズになったら変換します。
ESPのスケッチでは画像を左に90度回転しての取り込み仕様なので、ペイントで左回転90度で下記の画像にしてjpegで保管です。


paint-smeter-size-rotate

■ESP32DevKitC用の取り込みデータ用に変換するLCD-Image-Conveterで変換します。

LCD-image-converter-main

OptionでPreviewしデータを確認します。右側のデータをすべてを選択し、コピーしてESP32DevKitCのSメータスケッチのSメータ用データ取り込みファイルにコピー貼り付けします。
LCD-image-converter

■ESP32DevKitCのSメータスケッチをコンパイルしてTFT液晶に表示されることを確認します。出来上がったのが下記の画像です。
Homebrew1

Homebrew2


前のSメータパネルより、インジケータ指針とSメータパネルの目盛りのバランスはよくなったと思います。目盛りとインジケータ指針の重なりもうまく一致してバランスの悪かった違和感がなくなり見やすくなったと思います。粗削りの要素多く、まだいろいろと問題があるかと思いますが、最初から作成したのは今回が初めてなので、次の作成時はもっと、よくできるかと! ただ、デザインやスケッチのセンスが、かなり影響がでるので、私の場合は、もしかしたらこの程度が限界かもしれません。Hi !


ついでに動画も取りました。カメラを手で持ってるので、フォーカスとブレがありますが、まずまず動作は確認できると思います。



既存の画像を利用してうまく加工できればいいのですが、やはり、納得のいくものは、自分で作成するのが一番です。
LovyanGFXライブラリではSPIライブラリ(従来のスプライト処理)を継承し、たくさんのコマンドが用意されています。その中のコマンドでで指針の元画像を拡大、伸長できる調整パラメータがあるので、あとからでも指針のバランス調整が自由にできます。

通常表示
needle.pushRotateZoom(&lcd,(imgWidth/1.55),(imgHeight/1),signalLevel,2.3,2.8);
OR
アンチエイリアス付き回転と拡大縮小
needle.pushRotateZoomWithAA(&lcd,(imgWidth/1.55),(imgHeight/1),signalLevel,2.3,2.8);

目盛り版としての画像データは作り直しでないとできませんが!
LCD-image-Converterは各種のTFT液晶のサイズも対応しているので、もう一回りサイズの大きなTFT液晶を用意すれば、既存の受信機のSメータをデジタル式に入れ替えできますね。指針のカラーや、目盛り装飾などアイデア次第で、自由に目盛り版も作成できるので、楽しく自作できるデジタル式Sメータとしてアマチュア無線家の醍醐味の一つにもなると思います。Hi !

つづく?

ESP32DevKitCでのカラーグラフィックSメータその4

カラーグラフィック画像を使ったSメータをLovyanGFXライブラリのスプライト機能を使い作成しましたが、元のSメータ画像の目盛りの赤色が青色で表示されてしまっていました。この青色となってしまう原因を探ってみました。
青色の目盛りカラー写真を撮るのを忘れたので、先の動画で青色の情報確認です。



元の画像ではSで9から上は赤色で塗られています。この画像の変換データが現状のSメータの画像表示では青色で表示されてしまっています。

signal.bmp_Image

Lang-ship

上記リンクのなかのLovyanGFXとは?には、AdafruitGFXやTFT_eSPIと一定の互換性をもちつつカリカリにチューニングされているグラフィックライブラリです。とあります。

この色数に関してのLovyanGFXライブラリの使用上の注意ということで説明しているサイトです。
これに基づいて、実際に確認もしてみたいと思います。

やはり、ライブラリのインクルード状態だけでスプライトを使う上での初期設定がされていないための問題であることが、なんとなく原因であろうことがわかってきました。
基本デフォルトで16ビットの色数らしいのですが、設定したTFT、と各スプライト事に宣言をしていなかったのが色が正常ではなかった原因ではないかと思います。この確認のため、スケッチ上に色数の初期設定を追加してみることにしました。緑色文字が追加した色数の初期設定箇所です。

void setup() {
  pinMode(SW_TX,INPUT);          

  lcd.init();
  lcd.setColorDepth(16);
  lcd.setSwapBytes(true);
  smeter.setColorDepth(16);
  needle.setColorDepth(16);
(以下省略)

実際にコンパイルして動作させてみると、目盛り上の赤色部が正常な色で表示されました。

color16setting

LovyanGFXライブラリではTFTの色数の初期設定は必ず行う必要があるということです。合わせて、使用したスプライトも色数の初期設定をしておくと違った色で表示されてしまうことがなくなります。
ちなみに、今回使用したLovyanGFXライブラリは、先のJF3HZB uebo氏の新しいバージョンのVFOsys2_00では240x320のサイズにも他の種類のTFTの各ダイアル項目の任意設定用ファイル上でもインクルードして使用しているようです。前のVFOsysよりも、LovyanGFXライブラリやオリジナルのフォントなどを使うことでさらに動作スピードの向上となっていると思われます。

つづく?

続きを読む

ESP32DevKitCでのカラーグラフィックSメータその3

前のSメータはラインの描画コマンドによる線でのSメータの針でした。太くしようとしても、画面の端ではうまく均一に太さが表示されないため、1本のラインのSメータとしていました。ESPのサンプルのSメータでも同じで、太くする処理がされていましたが、TFT上の位置によって太さが変わるのはいただけません。ということで、針をグラフィック画像で作成し対応してみることにしました。針の太さの事が気にならないSメータの検討を開始しました。今回このSメータで使用するのは、スプライト処理ですが、最初の描画ラインでも一部<TFT_eSPI.h>および、<SPI.h>ライブラリを使ったスプライト処理でした。がネットで調べてゆくと、最近のスプライト処理は<LovyanGFX.h>ライブラリを使うのが主流のようです。処理スピードも改善されている云々とありましたので、このライブラリをSメータのスプライト処理でためしに使ってみることにしました。
最初にやることはArduino IDE 2.1.1(最新にしました。)にライブラリをインストールです。この処理は他のWebページにお任せして、要点は、自分のTFT液晶の型番に合わせたTFT用のライブラリを設定し作成する必要があります。私のTFTは1.8inch(128x160ピクセル)で型はST7735Sです。
このやり方もこの元のライブラリファイル内にファイル名作成についてとかも記載あります。私は設定したファイルのファイル名を "LGFX_ESP32_ST7735.hpp"として用意しました。作成したら動作確認として、サンプルプログラムが動作し、TFTに表示されるかを確認しておきます。問題なければLovyanGFX.hpp と一緒に今後TFTのST7735S専用ライブラリとして利用してゆけます。

おまけ:なお、LovyanGFXサンプルスケッチでは次の定義はコメント化または、削除する必要があリました。
//#define LGFX_AUTODETECT


最初にスケッチ上にライブラリとしてインストールした<LovyanGFX.hpp>ライブラリをインクルードします。

#include <LovyanGFX.hpp>

次に設定してファイル名を付けて保存したTFT設定用のライブラリをインクルードします。

#include "LGFX_ESP32_ST7735S.hpp"

TFT設定用のライブラリをインクルードします。上記を行いスケッチをしてゆきます。ネットには詳しくスプライトの使用方法があるので、練習してみるのもよいかと思います。自分のTFT用のライブラリをインクルードするのを忘れないことです。"LGFX_ESP32_ST7735S.hpp"

作成のスケッチよりも使う画像のサイズをキチンと確認しておく必要があります。また、自分のTFT液晶のサイズもそうです。あとは手順通りにスケッチしてゆくのですが、初めてなので、何度も躓きましたが。何とか2日ぐらいで作成することができました。とにかく実際に試すことも含めいろいろとやってみることです。久々に新しいライブラリのコマンドで悩み、時々、”なんでうごかないの!” そして最後に落ち着くのは、基本に忠実にです。暗中模索はいけません。時間の浪費になるだけです。仕様通りにスケッチすることですべて解決します。特に動作しているサンプルスケッチをみて同じコマンドが使われてないかを含め、確認できる動作サンプルを見つけることも完成への近道かと思います。
【スケッチの概要】
Sメータの画像をLCDに取り込みスプライト処理の針の中心位置を needle.setPivotで決め、画面の回転表示をlcd.setRotation(1)と設定し最初にSメータ画像を(0,0)のポジションに取り込みます。
次にはスプライトのバッファ確保のneedle.setBuffer((void*)hari,2,100,16); とし セットアップ終了し
次のvoid loop()につなげます。

Sメータへの直流電圧をESP32DevKitCのポート32にから取り込みしA/D変換しその値をmap関数で角度へ変換します。ここでSメータの指針のセットを行います。入力には半固定を用いて、電圧値を調整します。4095は最大時なので、入力電圧値で要調整します。最後にmap角度範囲にて微調整します。

long d = 0 ;
  //**************************************************
  for(int i=0;i<avtimes;i++){
    d += analogRead(32);
  }
  signalLevel = d/avtimes;
   // mapping to degree value
  signalLevel = map(signalLevel, 0, 4095, -64 , 80);
  //**************************************************
 
針を表示しますが、針の画像の位置関係よりlcd.setRotation(0);でSメータ画像にうまく位置が合うようにします。あとはスプライト処理での針をTFTへ表示させます。表示の際には元の針の画像データのサイズを拡大して表示しています。signalLevel, 2.0,2.85 で2.0は針の幅を2倍にしています。簡単に針の太さを変えることができます。2.85は針のサイズを中心位置から拡大(長さ)倍率値です。これも調整して設定しています。

表示は2つあげましたが、最初は画像のエッヂ処理なしです。あとはアンチエイリアス処理付きのコマンドでの表示です。アンチエイリアス処理ではエッジをきれいに処理し表示させることができる処理のようです。動作スピードと相談して設定が必要のようです。

■通常処理の場合

needle.pushRotateZoom(&lcd,(imgWidth/1.55),(imgHeight/1),
signalLevel,2,2.85);

アンチエイリアス処理の場合(処理が少し重くなるそうです。)
needle.pushRotateZoomWithAA(&lcd,(imgWidth/1.55),(imgHeight/1),
signalLevel,2.0,2.85);

Sメータの元画像を縮小縮小で作成したため、荒くなってしまいました。あとできれいになるように工夫してSメータ画像データを用意したいと思います。



今回は<LovyanGFX.hpp>ライブラリを使ったスプライト処理での画像データによるSメータ作成でした。

Twitterへも投稿したところ、ニュースで言っていた通りロゴⅩに変わっていました。



つづく?



アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード
アーカイブ
  • ライブドアブログ