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;
}
}
}
}