2010-01-25
秋月電子通商のラジオモジュールをArduinoで制御します。Arduinoではない素のATMEGA48で作ったものをArduinoに移植しました。
ArduinoのI2C通信はうまく使いこなせなかったので、自前のI2C関数を使用しました。12番ピンがSCL、13番ピンがSDAになっています。
モジュールからバーアンテナまでの距離は15cmくらいにしてください。長すぎると電波が減衰して音が小さくなります。短すぎるとデジタルノイズが乗ります。
RS-232Cで本機を接続します。ホストのPCは9600bps、8ビット、ノンパリティ、ストップ1ビット、でターミナルを開きます。
下の図はPuTTYを使用する場合の例です。接続先の指定で「シリアル」を選択し、「開く」をクリックします。
ターミナルが開いたら、まず「?[Enter]」と入力して、 「 RADIO 1.0」と表示されれば、通信は成功しています。
?[Enter] RADIO 1.0
周波数の数値を入力して、そのまま[Enter]を押します。
AM954kHzに設定する場合。kHz数をそのまま入力します。
954[Enter]
FM82.5MHzに設定する場合、MHz数を100倍して入力します。
8250[Enter]
2000未満の数値を入力した場合、AMの周波数。それ以上の数値の場合、FMの周波数の設定となります。
周波数を設定しただけでは、音は鳴りません。後述のバンドの選択をすることで、放送が聴けます。
AM放送を選択するコマンドは、amです。
am[Enter]
FM放送を選択するコマンドは、fmです。
fm[Enter]
このどちらかのコマンドを実行すると、ミュート状態が解除され、先に設定した周波数の放送が聴けます。
消音するには、muteコマンドを実行します。
mute[Enter]
再度、放送を聴くには、amコマンドまたはfmコマンドを実行します。
static const int I2C_SCL_PIN = 12; static const int I2C_SDA_PIN = 13; void wait10us() { delayMicroseconds(10); } void wait10ms() { delayMicroseconds(10000); } void wait100ms() { int i; for (i = 0;i < 10; i++) { wait10ms(); } } void wait1s() { int i; for (i = 0;i < 100; i++) { wait10ms(); } } // i2c void i2c_cl_0() { pinMode(I2C_SCL_PIN, OUTPUT); } void i2c_cl_1() { pinMode(I2C_SCL_PIN, INPUT); } void i2c_da_0() { pinMode(I2C_SDA_PIN, OUTPUT); } void i2c_da_1() { pinMode(I2C_SDA_PIN, INPUT); } int i2c_get_da() { return digitalRead(I2C_SDA_PIN); } void i2c_start() { i2c_da_0(); wait10us(); i2c_cl_0(); wait10us(); } void i2c_stop() { i2c_cl_1(); wait10us(); i2c_da_1(); wait10us(); } void i2c_repeat() { i2c_cl_1(); wait10us(); i2c_da_0(); wait10us(); i2c_cl_0(); wait10us(); } bool i2c_write(int c) { int i; bool nack; wait10us(); for (i = 0; i < 8; i++) { if (c & 0x80) { i2c_da_1(); } else { i2c_da_0(); } c <<= 1; wait10us(); i2c_cl_1(); wait10us(); i2c_cl_0(); wait10us(); } i2c_da_1(); wait10us(); i2c_cl_1(); wait10us(); nack = i2c_get_da(); i2c_cl_0(); return nack; } int i2c_read(bool nack) { int i, c; i2c_da_1(); wait10us(); c = 0; for (i = 0; i < 8; i++) { i2c_cl_1(); wait10us(); c <<= 1; if (i2c_get_da()) { c |= 1; } i2c_cl_0(); wait10us(); } if (nack) { i2c_da_1(); } else { i2c_da_0(); } wait10us(); i2c_cl_1(); wait10us(); i2c_cl_0(); wait10us(); return c; } // ns9542 void ns9542_write(int a, int c) { i2c_start(); i2c_write(0xc8); i2c_write(a); i2c_write(c); i2c_stop(); } int ns9542_read(int a) { int c; i2c_start(); i2c_write(0xc8); i2c_write(a); i2c_repeat(); i2c_write(0xc9); c = i2c_read(true); i2c_stop(); return c; } void ns9542_imf_adjust() { int bF, imf, fhm, g_fhm; bF = 0; g_fhm = 0xf0; ns9542_write(0x15, 0x0e); ns9542_write(0x3d, 0x27); for (fhm = 0; fhm < 4; fhm++) { bF = 0; for (imf = 0; imf < 3; imf++) { ns9542_write(0x37, fhm); ns9542_write(0x16, 22 + imf); wait10ms(); if ((ns9542_read(0x70) & 0x0c) == 0x0c) { bF++; if (imf == 1 && g_fhm == 0xf0) { g_fhm = fhm; } } } if (bF == 3) { g_fhm = fhm; break; } } ns9542_write(0x37, 0x80 | g_fhm); ns9542_write(0x16, 23); ns9542_write(0x3d, 0x37); wait100ms(); } void ns9542_best_iml(int iml) { ns9542_write(0x32, 0x00); while (iml < 16) { ns9542_write(0x17, 0xc0 | iml); wait10ms(); if (!(ns9542_read(0x70) & 0x08)) { break; } iml++; } iml--; ns9542_write(0x17, 0xc0 | iml); ns9542_write(0x32, 0x80); wait10ms(); ns9542_write(0xfe, 0x0a); wait10ms(); wait10ms(); } void ns9542_find_pg(int ialgn, int *fine_phase, int *fine_gain, int *result_pg) { int i, j; for (i = 0; i < 16; i++) { ns9542_write(0x15, 0x0a | (ialgn << 4)); ns9542_write(0x15, 0x0b | (ialgn << 4)); if (ns9542_read(0x05) & 0x08) { for (j = 0; j < 20; j++) { if (!(ns9542_read(0x05) & 0x08)) { int g = ns9542_read(0x65); int p = ns9542_read(0x66); if (g >= 103 && g <= 138 && 2 >= p && p <= 14) { *fine_gain = g; *fine_phase = p; *result_pg = 1; return; } } wait10ms(); } } } *result_pg = 0; } void ns9542_table_write(int *fine_p, int *fine_g) { int i, j, k, result; result = 0; for (i = 0; i < 4; i++) { ns9542_write(0x38, fine_g[i]); ns9542_write(0x39, fine_p[i] << 4); for (j = 0; j < 10; j++) { ns9542_write(0x15, 0x0e | (i << 4)); ns9542_write(0x15, 0x03 | (i << 4)); if (ns9542_read(0x05) & 0x08) { wait100ms(); for (k = 0; k < 10; k++) { if (!(ns9542_read(0x05) & 0x08)) { result++; goto L1; } wait10ms(); } break; } } L1:; if (result != i + 1) { break; } } } void ns9542_dsp_align_body() { int iml, imf, ialgn, cnt, fp, fg; int fine_p[5] = { 0, 0, 0, 0, 0 }; int fine_g[5] = { 0, 0, 0, 0, 0 }; iml = 5; for (ialgn = 0; ialgn < 4; ialgn++) { ns9542_write(0x15, 0x0a | (ialgn << 4)); wait100ms(); wait100ms(); ns9542_best_iml(iml); imf = 0; cnt = 0; fp = 0; fg = 0; for (cnt = 0; cnt < 5; cnt++) { int fine_phase, fine_gain, result_pg; ns9542_find_pg(ialgn, &fine_phase, &fine_gain, &result_pg); if (result_pg == 0) { return; } fp = fp + fine_phase; fg = fg + fine_gain; if (cnt == 2 && ialgn < 2) { cnt++; break; } } fine_p[ialgn] = fp / cnt; fine_g[ialgn] = fg / cnt; } ns9542_table_write(fine_p, fine_g); } void ns9542_mute(bool mute) { if (mute) { ns9542_write(0x00, ns9542_read(0x00) | 0x02); } else { ns9542_write(0x00, ns9542_read(0x00) & ~0x02); } } void ns9542_tune_am9(int freq) // freq = kHz { unsigned short psy; psy = freq; ns9542_write(0x00, 0x23); wait10ms(); wait10ms(); ns9542_write(0x04, 0x80); ns9542_write(0x0c, 0xf0); ns9542_write(0x10, 0x10); ns9542_write(0x02, psy & 0xff); ns9542_write(0x03, psy >> 8); ns9542_write(0x00, 0x21); } void ns9542_tune_fm(int freq) // freq = MHz * 100 { unsigned short psy; psy = freq / 5; ns9542_write(0x00, 0x03); ns9542_write(0x10, 0x10); ns9542_write(0x02, psy & 0xff); ns9542_write(0x03, psy >> 8); ns9542_write(0x00, 0x01); } void ns9542_reset() { ns9542_write(0xfe, 0xaa); } void ns9542_power_on() { static unsigned char power_on[] = { 0x01, 0x30, 0x0c, 0x80, 0x0e, 0x34, 0x15, 0xc4, 0x20, 0x3c, 0x21, 0x03, 0x22, 0x0a, 0x23, 0x0a, 0x30, 0xff, 0x3d, 0x07, 0x40, 0x1a, 0x41, 0x9a, 0x50, 0xe1, 0x54, 0xb0, 0x55, 0x36, 0x5c, 0xc8, 0x5d, 0x61, 0x5e, 0x88, 0x5f, 0xa5, 0x71, 0x2c, 0x72, 0x06, }; int i; for (i = 0; i < sizeof(power_on); i += 2) { ns9542_write(power_on[i], power_on[i + 1]); } ns9542_write(0x00, ns9542_read(0x00) | 0x03); } void ns9542_dsp_alignment() { ns9542_write(0x0e, ns9542_read(0x0e) & ~0x60 | 0x40); ns9542_write(0x01, 0x08); ns9542_write(0x15, 0x0c); ns9542_write(0x16, 0x17); ns9542_write(0x37, 0x82); ns9542_write(0x3d, 0x37); wait100ms(); ns9542_imf_adjust(); ns9542_dsp_align_body(); ns9542_write(0x01, 0x38); ns9542_write(0x0e, ns9542_read(0x0e) & ~0x60 | 0x20); ns9542_write(0x15, 0xc0); ns9542_write(0x17, 0x20); ns9542_write(0x32, 0x00); ns9542_write(0x37, 0x01); } boolean isdigit(int c) { return c >= '0' && c <= '9'; } int uart_get() { return Serial.read(); } int uart_put(int c) { Serial.write(c); } void uart_puts(char const *p) { while (*p) { uart_put(*p); p++; } } int freq_am = 594; // 594kHz int freq_fm = 8250; // 82.5MHz unsigned char buffer[16]; int length; void setup() { pinMode(I2C_SCL_PIN, INPUT); pinMode(I2C_SDA_PIN, INPUT); digitalWrite(I2C_SCL_PIN, 0); digitalWrite(I2C_SDA_PIN, 0); ns9542_reset(); ns9542_power_on(); ns9542_dsp_alignment(); Serial.begin(9600); // opens serial port, sets data rate to 9600 bps length = 0; uart_put('\r'); uart_put('\n'); } // the loop() method runs over and over again, // as long as the Arduino has power void loop() { int c = uart_get(); if (c >= 0) { if (c == '\r') { uart_put('\r'); uart_put('\n'); if (length > 0) { if (isdigit(buffer[0])) { int i, freq = 0; for (i = 0; i < length && isdigit(buffer[i]); i++) { freq = freq * 10 + (buffer[i] - '0'); } if (freq < 2000) { freq_am = freq; } else { freq_fm = freq; } goto done; } if (length == 1) { if (buffer[0] == '?') { uart_puts(" RADIO 1.0\r\n"); goto done; } } if (length == 2) { if (buffer[0] == 'a' && buffer[1] == 'm') { ns9542_tune_am9(freq_am); goto done; } if (buffer[0] == 'f' && buffer[1] == 'm') { ns9542_tune_fm(freq_fm); goto done; } } if (length == 4) { if (buffer[0] == 'm' && buffer[1] == 'u' && buffer[2] == 't' && buffer[3] == 'e') { ns9542_mute(true); goto done; } } } done:; length = 0; } else { uart_put(c); if (length < sizeof(buffer)) { buffer[length++] = c; } } } }