DSP FMラジオ RDA5807FP+ATTINY85+AQM0802A　その7　動作コード

#はじめに
* 電池駆動DSPラジオのその7。動作スケッチについての解説です。
* スケッチは4666バイト。ATTINY85でも若干余裕がありました。本記事の一番下に載せてあります。
* なるべく自前でスケッチを書きましたが、AQM0802Aへの出力につきましてはライブラリを利用させていただきました。
* [前記事（その1～その6）や過去記事](https://qiita.com/dabodabo)も適宜ご参照ください。

#ATTINY85への書き込みについて
* マイコンにATMEGA328を使うのであれば、ARDUINO UNOをそのまま使って、書き込み後にUNOから外せばよいですが、ATTINY85を利用する場合、書き込みを方法を用意しなければなりません。
* この点については、先達の記事が多数ありますので、ここでは触れません。本件ではATTINY85を3.3Vで利用しますので、書き込む際も3.3Vで書き込んだほうが良さそうです。
* 私は、一般的な方法である、UNOを書き込み器として利用する方法を用いました。書込み用のスケッチ（ArduinoISP)をUNOで読込　→　ATTINY85を適宜接続　→　設定をATTINY85にして本件スケッチを書き込み。
* [このページ](http://miraluna.hatenablog.com/entry/tinyshield)を参考にさせてもらいました。電圧は3.3Vに変更しました。

#部品の構成
* スケッチを作成するにあたって、以下の部品構成を前提にしています。
    1. RDA5807FPのGPIO2から、STCトリガを出力させる。
    2. 上記の出力トリガをATTINY85のPin3(PB4)で受け、PCINT4割込みを発生させる。
    3. SEEK開始のタクトスイッチ →　ATTINY85のPing2(PB3)
    4. +0.1MHZタクトスイッチ →　ATTINY85のPing6(PB1)
    5. 音声出力はモノラル（スピーカー一つ）
    6. AQM0802Aは[ライブラリ](https://n.mtng.org/ele/arduino/i2c.html)使用
    7. ボリュームは可変抵抗器使用。スケッチではボリューム固定。

#スケッチの構成
* 以下のような構成にしています。
    * ライブラリの宣言：　Wire、I2CLiquidCrystal
    * VOLATILE変数の宣言
        * 以下SETUP()
    * LCD初期化
    * PB4、PB3、PB1のINPUT_PULLUP
    * RDA5807の条件設定、GPIO2の設定
    * PCINT4を利用するための設定
    * SEEK機能開始
        * 以下LOOP()
    * STCフラグの監視　→　データ表示
    * SEEK開始ピンの監視　→　SEEK開始
    * +0.1MHZピンの監視　→　+0.1MHZ周波数セット
        * 以下サブルーチン（関数）
    * 割込みで飛ぶ関数：　STCフラグの変更
    * SEEK開始関数：　RDA5807FPのレジスタに書き込み
    * +0.1MHZ周波数セット関数：　現在の周波数+0.1MHZをレジスタに書き込み
    * データ表示関数：　周波数、RSSIをレジスタから呼び込み、LCDに表示

#スケッチ詳細
* I2CLiquidCrystal
    * [このページ](https://n.mtng.org/ele/arduino/i2c.html)のライブラリを利用させていただきました。利用方法については同ページをご参照ください。「ST7032iタイプ」を参照しています。外部プルアップ抵抗は用いず、ATTINY85の内部プルアップ抵抗を利用しています。
* volatile変数
    * 割込み関数で利用する変数（stc）を宣言しています。freq10の方はvolatileでなくてもよいかも。
* lcd.begin(8,2)
    * 上記のライブラリに従っています。
* pinMode
    * 本件で使うピンを宣言して、内部プルアップ抵抗を利用します。何も起きていないときはこれらのピンはHighになります。
* レジスタ03,05,04への書き込み
    * 種々の条件を設定。過去記事、RDA5807FPのデータシートなどご参照ください。
* GIMASK, PCMSK
    * PCINT4を利用するための設定です。
* レジスタ02への書き込み
    * seek bitを1にして書き込み　→　SEEK開始
* if(stc==1)
    * stcフラグが1になったらデータ表示関数(infodisplay())を実行。
* if(digitalRead(3)==0)
    * PB3（SEEK開始ボタン）が0になったら、”Sup”を表示して、SEEK開始関数（seekset02H()）を実行
* if(digitalRead(1)==0)
    * PB1（+0.1MHZボタン）が0になったら、”+01”を表示して、+0.1MHZ周波数セット関数（setfreq()）を実行
* ISR(PCINT0_vect)
    * PB4でPCINTが発生（選局完了）した場合に処理される関数。ここでstcが1となり、loop文の中でデータ表示関数が実行されます。
    * 1回目のPCINT（High → Low)の時だけstcを1とするようにしています。
* void seekset02H()
    * SEEK開始関数。レジスタ02に書き込みことによって、seekを開始（再開）します。RDA5807FPの仕様では現在の周波数からseekを再開することになっています。
* void setfreq()
    * +0.1MHZ周波数セット関数。「現在の周波数+0.1MHZ」を計算し、レジスタ03に書き込むことによって、その周波数を選局します。Tuneビットを1にする必要あり。
* void infodisplay()
    * データ表示関数。レジスタ0Aと0Bから情報を読み込み、適当に変換してLCDに表示しています。
    * 選局している周波数とRSSIを表示。他にも読み取れる情報はありますが、この２つだけにしています。

#動作スケッチ

```
// ATTINY85,AQM0802,Mono,Seek,+0.1MHZ

#include <Wire.h>
#include <I2CLiquidCrystal.h>
// initialize the library
I2CLiquidCrystal lcd(32, (bool)false);
//  contrast (0-63)
//  set true if the power suply is 5V, false if it is 3.3V

volatile bool stc=0;
volatile int freq10=0;

void setup()
{
lcd.begin(8,2);

pinMode(4,INPUT_PULLUP);//STC PCInterupt
pinMode(3,INPUT_PULLUP);//Tact Switch seekup
pinMode(1,INPUT_PULLUP);//Tact Switch +100khz

Wire.begin();
  delay(20);
  Wire.beginTransmission(0X11);
   Wire.write(0X03);
   Wire.write(0x00); //CHAN0  
   Wire.write(0b00001000); //TUNE0 BAND10 SPACE00
  Wire.endTransmission();
  Wire.beginTransmission(0X11);
   Wire.write(0X05);
   Wire.write(0b00000100); //INT_MODE1 SeekTh 0100  
   Wire.write(0b10001111); // vol1111
  Wire.endTransmission();
  Wire.beginTransmission(0X11);
   Wire.write(0X04);
   Wire.write(0b01001010); //STCINT1,DE50 
   Wire.write(0b00000100); //GPIO2:01 
  Wire.endTransmission();

GIMSK = B00100000; //PCINT ENABLE
PCMSK = B00010000; //PCINT4 ONLY
  Wire.beginTransmission(0X11);
   Wire.write(0X02);
   Wire.write(0b11100011); //mono seek up, seek on  
   Wire.write(0x05); //seekmode0(wrap)
  Wire.endTransmission();
}

void loop() {
  if(stc==1){
  infodisplay();
  stc=0;  
  }
  delay(10);
  
  if(digitalRead(3)==0){
      lcd.setCursor(0, 0);
      lcd.print("Sup");
    seekset02H();
    delay(50);
  }
  if(digitalRead(1)==0){
      lcd.setCursor(0, 0);
      lcd.print("+01");
    setfreq();
    delay(50);
   }
  delay(100);
}

ISR(PCINT0_vect){
 if(digitalRead(4)==0)
      stc=1;
}

void seekset02H(){
  Wire.beginTransmission(0X11);
   Wire.write(0X02);
   Wire.write(0b11000011); //seek up, seek on  
   Wire.write(0b00000101); //seekmode0(wrap)
  Wire.endTransmission();
}

void setfreq(){
int chan = freq10 - 760+1; //周波数+0.1MH
byte h3 = chan >>2; //Highbyte03
byte l3 = chan & 0b00000011;
l3 = l3<<6;
l3 = l3 | 0b00011000; //Lowbyte03 TUNE1 BAND10 SPACE00
  Wire.beginTransmission(0X11);
   Wire.write(0X03);
   Wire.write(h3); //03h freq  
   Wire.write(l3); //03l Tune1
  Wire.endTransmission();
}

void infodisplay(){
//Serial.begin(9600);
  delay(50);   //RSSIが安定するまでdelay
  Wire.begin();
  Wire.beginTransmission(0X11);
  Wire.write(0X0a);
  Wire.endTransmission(false);
  Wire.requestFrom(0x11,4); //reading 5807
  byte bufferAH= Wire.read();
  byte bufferAL= Wire.read();
  byte bufferBH= Wire.read();

freq10= 760 + 512*bitRead(bufferAH,1)+ 256*bitRead(bufferAH,0)+ bufferAL;
unsigned char freq = freq10/10 ;
byte rssi = bufferBH>>1;
    lcd.clear(); 
    lcd.setCursor(0, 0);
    lcd.print("STC");
    lcd.print(freq); 
    lcd.print("."); 
    lcd.print(freq10 - 10*freq); 
    lcd.setCursor(0, 1);
    lcd.print("RSSI:");
    lcd.print(rssi);
}

```
#おまけ
* 昔はラジオ工作と言えばAMラジオのことで、FMラジオを自作するのは難しかったと思います。しかし、DSPラジオチップは、マイコンと組み合わせれば、取り扱いも簡単かつ安価で、むしろFMラジオの方が作りやすいと感じました。
* 今はAM放送もFMバンドで放送していますし、民放ラジオ局はFM放送にシフトする意向、というのも聞いたことがあります。なのでFMラジオで十分、とは言えると思います。
* とは言え、今はradikoもありますから、今回作成したラジオも実用性があるかと言えば疑問です。乾電池だけで動くので災害時には使えるかもしれませんが…
* ATMEGA328を使えば、もっと高機能なステレオラジオも作れそうですが、とりあえずDSPラジオCHIPについては一区切りついた感じです。
* ちゃんとした回路図を作成していなかったので、時間を見つけて作成してみようと思います。