PLL方式FMラジオの製作

[公開:any]

[電子工作/ラジオの製作]
[電子工作/AVR]
[AVR,ATmega88,PLL,TC9256P,ラジオ,TA7358P]

origin 2010-01-05



 「FMラジオ用PLL-VFOの実験」で試したPLL-ICのTC9256Pを使用してFMラジオを製作します。PLL制御以外のFMラジオの回路は、「高周波回路の設計・製作(CQ出版社)」をほぼそのままコピーしました。この本、基礎的な解説も多く、とてもわかりやすくてお勧めです。

高周波回路の設計・製作

 FMラジオの回路図です。・・・といっても、書籍の回路を除く部分です。書籍の回路をそのまま掲載するのは問題あるので省略します。FMのIF増幅、検波するTA7303PというICが古くて入手性が悪いのですが、通販ショップのイーエレで入手できます。その他は、入手に苦労する部品はありませんでした。もっとも、PLL-ICのTC9256Pを入手するのが一番大変ですが・・・・・。

2010年1月現在、TC9256Pもイーエレで取り扱いがあります。

PLL方式FMラジオ回路図

 フロントエンドは、FMフロントエンド用のTA7358Pを使用して全面アースの基板に組み立てます。最初に普通の基板で組み立てたのですが、VCOが目的周波数で安定して発振しませんでした。全面アースの基板で作ると安定して動作しました。TA7303PのIF増幅・検波部分とLM386のAF部分は普通のユニバーサル基板に組み立てました。


 AVRやTC9256PのPLL制御部分はブレッドボードに組み立ててFMラジオの動作試験を行いました。安定して動作します。受信音もクリアです。屋内でも短いワイヤーアンテナで十分な感度です。


 AVRのPLL制御回路とループフィルタ回路をユニバーサル基板に作成しました。3端子レギュレータを使用した9Vと5Vの電源回路も載せました。AVRのプログラムは、実験で使用したTC9256Pの制御に「PLL-VFOを使った短波受信機の製作」と同じ周波数メモリ機能などを追加搭載しました。


 全体をバラックでテストしました。「FMラジオの製作」で作ったものは、ボディエフェクトが大きく受信周波数が変動したのですが、PLL方式はさすがに周波数が安定しています。むき出しの基板を触っても受信周波数がふらつくことはありません。


 ケースは100円ショップのディスプレイ用プラスチックケースです。・・が、基板が3枚もあるためこれまで使用したケースには入りません。100円ショップで一回り大きなケースを購入してきました。・・・・並べて比較すると体積で4倍ほどありそうです。


 基板は3段重ねとしました。ACトランスもケース内に内蔵しました。基板間の干渉を心配しましたがFM方式の受信ということもありノイズ等の影響は特に気になりません。動作も安定しています。


 市販のラジオと比較しましたが、受信感度や安定度はまったく同等です。回路を参考にした書籍では、FMステレオ・マルチプレクス復調回路を使ったFMステレオラジオまでの解説になっています。ステレオ・マルチプレクス復調ICが入手できるならFMステレオラジオにするのもよさそうです。

 ソースプログラムです。

AVRの入出力ポートが回路図とあっていません。このコンテンツを参考に製作される場合は、実作の回路にあわせるようにプログラム変更をお願いします。(2012-07-07)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/**********************************************************************
    AVR PLL-VFO control for FM Radio
     PLL device : TC9256P (Toshiba Co.)
     7.200MHz(Xtal) / 720(preset prescaler) = 10KHz(minimam step)
 
    2010/01/05  www.henteko.org
**********************************************************************/
#include <avr/io.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <math.h>

#include "lcd.h"

#define cbi(addr, bit)     addr &= ~(1<<bit)
#define sbi(addr, bit)     addr |=  (1<<bit)

#define PLL_PORT    PORTD
#define PLL_CLOCK    PD1
#define PLL_DATA        PD0
#define PLL_LE        PD2

FILE *fp;                            // File descriptor for LCD
unsigned long pcd;                // frequency
unsigned int diff;                    // frequency step
unsigned int mem;
unsigned char mode;
unsigned char renc_now, renc_old;     // value of rotary encoder
static unsigned int fm[12] __attribute__((section(".eeprom")));


/**********************************************************************
    milisecond order delay
**********************************************************************/
void delay_ms(unsigned int t) {    while(t--)  _delay_ms(1); }

/**********************************************************************
    PLL control: pll data send (LSB first)
        data: data set
        bit : bit length
**********************************************************************/
void pll_dataset(unsigned long data, unsigned int bit)
{
    unsigned int i;
    unsigned int tmp;

    cbi(PLL_PORT, PLL_LE);

    for(i = 0; i < bit ; i++) {
        tmp = (data >> i) & 0x00000001;
        if(tmp % 2)
            sbi(PLL_PORT, PLL_DATA);
        else
            cbi(PLL_PORT, PLL_DATA);
        _delay_us(2);
        cbi(PLL_PORT, PLL_CLOCK);
        _delay_us(2);
        sbi(PLL_PORT, PLL_CLOCK);    
        _delay_us(2);
        if(i == 2)
            sbi(PLL_PORT, PLL_LE);
    }
    _delay_us(2);
    cbi(PLL_PORT, PLL_LE);
    _delay_us(2);
    sbi(PLL_PORT, PLL_LE);
}

/**********************************************************************
    Pin change interrupt
    Frequency Up & Down by Rotary encorder input
**********************************************************************/
ISR(SIG_PIN_CHANGE1)
{
    if(bit_is_set(PINC, PC3)){
        if(bit_is_clear(PINC, PC4))
            renc_now = 0;
        else 
            renc_now = 1;
    } else {
        if(bit_is_set(PINC, PC4))
            renc_now = 2;
        else
            renc_now = 3;
    }

    if((renc_now + 3 + 1) % 3 == renc_old) {
        if(mode == 0) {
            if(pcd > 6500)
                pcd -= diff;
        } else {
            if(mem > 0)
                mem -= 1;
        }
    }
    if((renc_now + 3 - 1) % 3 == renc_old) {
        if(mode == 0) {
            if(pcd < 8000)
                pcd += diff;
        } else {
            if(mem < 9)
                mem += 1;
        }
    }
    renc_old = renc_now; 
    if(mode == 1) {
        eeprom_busy_wait();
        pcd = eeprom_read_word(&fm[mem]);
        if(pcd > 8000 || pcd < 6500)
            pcd = 6930;
    }
    pll_dataset(0xd0 + ((unsigned long)pcd<<8) + ((unsigned long)0x9a<<24), 32);
}

/**********************************************************************
    main routine
**********************************************************************/
void main(void)
{
    unsigned char sw0_state, sw1_state;
    unsigned long     freq;
    unsigned int    tim;
    unsigned long     ftmp;

     
     DDRB = 0b11111111;        // LCD
    DDRC = 0b00000000;        // PC3 sw input, PC4,5 routary encoder input 
    DDRD = 0b11111111;        // PD0-2 PLL serial output

    PORTC = 0b00111110;        // PC3,4,5 pull up

    PCICR = _BV(PCIE1);
      PCMSK1 = _BV(PCINT12)|_BV(PCINT11);

    sbi(PLL_PORT, PLL_LE);
    sbi(PLL_PORT, PLL_CLOCK);
    sbi(PLL_PORT, PLL_DATA);

    lcd_init();
    lcd_cls();
    fp = fdevopen(lcd_putch, NULL);        // Open File descriptor for LCD

    sw0_state = sw1_state = 0;
    pcd = 7080;        // default frequency 80.00MHz
    diff = 10;    
    mode = 0;
    mem = 0;
    tim = 0;

    pll_dataset(0xd0 + ((unsigned long)pcd<<8) + ((unsigned long)0x9a<<24), 32);

    sei();

    while(1) {
        if(bit_is_clear(PINC, PC2)) {    // frequency step change
            sw0_state = 1;            
            delay_ms(15);
        }
        if(sw0_state && bit_is_set(PINC, PC2)) {
            sw0_state = 0;
            if(diff == 1) {
                diff = 10;                // 100kHz step
                pcd = pcd / 10 * 10;
            } else {
                diff = 1;                // 10kHz step
            }
        }
        if(bit_is_clear(PINC, PC1)) {
            sw1_state = 1;            
            delay_ms(10);
            tim++;
        }
        if(sw1_state && bit_is_set(PINC, PC1)) {
            sw1_state = 0;
            tim = 0;
            if(mode == 0) {
                mode = 1;
                ftmp = pcd;
                eeprom_busy_wait();
                pcd = eeprom_read_word(&fm[mem]);
                if(pcd > 8000 || pcd < 6500)
                    pcd = 6930;
            } else {
                mode = 0;
                pcd = ftmp;
            }
            pll_dataset(0xd0 + ((unsigned long)pcd<<8) + ((unsigned long)0x9a<<24), 32);
        }
        if(tim > 60) {
            sw1_state = 0;
            tim = 0;
            if(mode == 0) {
                eeprom_busy_wait();
                eeprom_write_word(&fm[mem], pcd);
                lcd_goto(0, 0);
                fprintf(fp, "VFO->MEM");
            } else {
                eeprom_busy_wait();
                pcd = eeprom_read_word(&fm[mem]);
                if(pcd > 8000 || pcd < 6500)
                    pcd = 6930;
                lcd_goto(0, 0);
                fprintf(fp, "MEM->VFO");
                mode = 0;
                pll_dataset(0xd0 + ((unsigned long)pcd<<8) + ((unsigned long)0x9a<<24), 32);
            }                
            loop_until_bit_is_set(PINC, PC1);
        }

        freq = pcd + 1070;
        lcd_goto(0, 0);
        if(diff == 1)
            fprintf(fp, "%2d.%02dMHz", (unsigned int)(freq * 0.01),
                                 freq - (unsigned int)(freq * 0.01) * 100);
        else {
            freq = freq * 0.1;
            fprintf(fp, "%2d.%01d MHz", (unsigned int)(freq * 0.1),
                                 freq - (unsigned int)(freq * 0.1) * 10);
        }
        lcd_goto(1, 0);
        if(mode == 0) {
            fprintf(fp, "VFO Ch:%d", mem);
        } else {
            fprintf(fp, "MEM Ch:%d", mem);
        }
    }
}

▲ページ Top へ...