はじめに
- 電池駆動DSPラジオのその7。動作スケッチについての解説です。
- スケッチは4666バイト。ATTINY85でも若干余裕がありました。本記事の一番下に載せてあります。
- なるべく自前でスケッチを書きましたが、AQM0802Aへの出力につきましてはライブラリを利用させていただきました。
- 前記事(その1~その6)や過去記事も適宜ご参照ください。
ATTINY85への書き込みについて
- マイコンにATMEGA328を使うのであれば、ARDUINO UNOをそのまま使って、書き込み後にUNOから外せばよいですが、ATTINY85を利用する場合、書き込みを方法を用意しなければなりません。
- この点については、先達の記事が多数ありますので、ここでは触れません。本件ではATTINY85を3.3Vで利用しますので、書き込む際も3.3Vで書き込んだほうが良さそうです。
- 私は、一般的な方法である、UNOを書き込み器として利用する方法を用いました。書込み用のスケッチ(ArduinoISP)をUNOで読込 → ATTINY85を適宜接続 → 設定をATTINY85にして本件スケッチを書き込み。
- このページを参考にさせてもらいました。電圧は3.3Vに変更しました。
部品の構成
- スケッチを作成するにあたって、以下の部品構成を前提にしています。
- RDA5807FPのGPIO2から、STCトリガを出力させる。
- 上記の出力トリガをATTINY85のPin3(PB4)で受け、PCINT4割込みを発生させる。
- SEEK開始のタクトスイッチ → ATTINY85のPing2(PB3)
- +0.1MHZタクトスイッチ → ATTINY85のPing6(PB1)
- 音声出力はモノラル(スピーカー一つ)
- AQM0802Aはライブラリ使用
- ボリュームは可変抵抗器使用。スケッチではボリューム固定。
スケッチの構成
- 以下のような構成にしています。
- ライブラリの宣言: 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
- このページのライブラリを利用させていただきました。利用方法については同ページをご参照ください。「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を表示。他にも読み取れる情報はありますが、この2つだけにしています。
動作スケッチ
// 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については一区切りついた感じです。
- ちゃんとした回路図を作成していなかったので、時間を見つけて作成してみようと思います。