====== 簡易ラジオ受信周波数表示ユニット(7セグ4桁) ======
===== 概要 =====
今迄に多くの「周波数カウンタ」を製作しました。
そして「周波数カウンタ」の機能の一部として、“ラジオ受信周波数表示<-455kHz>"を実装しました。
今回は、ラジオ受信周波数表示に特化したユニットを製作してみました。
<仕様>
* 表示周波数は、ラジオの中間周波数(455kHz)を差し引いた値(ラジオ受信周波数)とします。
* 表示周波数の単位は、kHzとし、1kHz未満は、四捨五入します。
* 簡素化を図るために、クロックはPIC内蔵の8MHzを使用します。
===== 動作原理 =====
<メイン処理>
* 周波数をカウントします。
* 校正スイッチがOFFの場合には、測定結果の補正、-455kHz、四捨五入、7セグ表示を行います。
* 校正スイッチがONの場合には、校正値の算出、保存、7セグ表示(1MHz時の周波数)を行います。
<セグメントデータ設定処理>
* 引数で渡されたカウント値(seg1,seg2,seg3,seg4)を、表示用変数(seg_dat)にセットします。
<割り込み処理>
* TIMER2を使用して、1msecの割り込みを発生させます。
* フラグ(fc_flg)が、“-1"であれば、何もしません。
* フラグ(fc_flg)が、“0"であれば、カウント用のゲートを開けて、フラグ(fc_flg)をインクリメントします。
* フラグ(fc_flg)が、“100"であれば、カウント用のゲートを閉じて、フラグ(fc_flg)を“-1"にします。
* フラグ(fc_flg)が、上記以外でであれば、フラグ(fc_flg)をインクリメントします。
* ダイナミック点灯処理を呼び出します。
<周波数カウント処理>
* カウント用のタイマー(TIMER1)を初期化します。
* フラグ(fc_flg)を、“0"にして、カウントを開始します。
* フラグ(fc_flg)が、“-1"になると、カウントを停止します。
<ダイナミック点灯処理>
* 呼び出される毎に、セグメントを順次切り替えて、表示用変数(seg_dat)の値を点灯させます。
<入力アンプ>
* C-MOSのインバータ 74HCU04を、抵抗で負帰還をかけてアナログアンプとして使用します。
<校正方法>
未校正でも使用可能ですが、校正をすることにより、精度を高めることが出来ます。
* 出来るだけ精度の高い、1MHzの信号を入力してください。
* 校正スイッチ(calibration)を押下します。
* 表示が1000kHz前後になることを確認します。
* 以降は、校正値で補正された値が表示されます。
* 校正値は、EEPROMに保存されるので、起動する度に校正をする必要はありません。
===== 回路図 =====
{{:imgpaste:202004:htmikan-20200430-142815.png}}
<5球スーパーラジオへの接続>
{{:imgpaste:202004:htmikan-20200430-142830.png}}
===== ソースコード =====
//**********************************************************************
/*
<簡易ラジオ受信周波数表示ユニット(7セグ4桁)>
※ラジオの局発から中間周波数(455kHz)を引いた値を表示する。
※つまり、ラジオの受信周波数を表示する。
*/
//**********************************************************************
//■■■関数&共有データ宣言■■■
extern void main();
extern long measurement();
extern void init_port();
extern void init_segment();
extern void init_timer();
extern void segment_disp();
extern void segment_set_data(short seg1, short seg2, short SEG3, short seg4);
extern void interrupt();
//**********************************************************************
//■■■マクロ定義■■■
//7SEG-SELECT
#define ACTIVE_LOW
//簡易接続、標準接続(B(2SA1015))
#ifdef ACTIVE_LOW
#define SEG_ON 0
#define SEG_OFF 1
#else
//標準接続(A(2SC1815))
#define SEG_ON 1
#define SEG_OFF 0
#endif
sbit SEG1 at PORTA.B1;
sbit SEG1_Direction at TRISA.B1;
#define SEG1_ON SEG1 = SEG_ON
#define SEG1_OFF SEG1 = SEG_OFF
sbit SEG2 at PORTA.B0;
sbit SEG2_Direction at TRISA.B0;
#define SEG2_ON SEG2 = SEG_ON
#define SEG2_OFF SEG2 = SEG_OFF
sbit SEG3 at PORTA.B7;
sbit SEG3_Direction at TRISA.B7;
#define SEG3_ON SEG3 = SEG_ON
#define SEG3_OFF SEG3 = SEG_OFF
sbit SEG4 at PORTA.B6;
sbit SEG4_Direction at TRISA.B6;
#define SEG4_ON SEG4 = SEG_ON
#define SEG4_OFF SEG4 = SEG_OFF
//7SEG-DATA
#define SEG_DATA PORTB
#define SEG_DATA_Direction TRISB
//switch
#define SW_CAL PORTA.B5
#define SW_ON 0
#define SW_OFF 1
//other
#define INPUT_MODE 1
#define OUTPUT_MODE 0
//**********************************************************************
//■■■メイン関数■■■
void main()
{
double freq;
long tmp;
char buf[16], tmp0, tmp1, tmp2, tmp3;
union {
double _double;
short _short[4];
} cal;
//
OSCCON = 0b01110000; //クロックを8MHzに設定します。
ANSEL = 0b00000000; //A/D変換モジュールは使用しません。
TRISA = 0b11111111;
TRISB = 0b11111111;
//
init_port();
init_segment();
init_timer();
// 校正データを読み込む
tmp0 = Eeprom_Read(0);
Delay_ms(20);
tmp1 = Eeprom_Read(1);
Delay_ms(20);
tmp2 = Eeprom_Read(2);
Delay_ms(20);
tmp3 = Eeprom_Read(3);
Delay_ms(20);
cal._short[0] = tmp0;
cal._short[1] = tmp1;
cal._short[2] = tmp2;
cal._short[3] = tmp3;
cal._double = ((cal._double < 0.5) || (cal._double > 1.5)) ? 1.0 : cal._double;
// 割り込みを許可します。
INTCON.PEIE = 1;
INTCON.GIE = 1;
//
while (1) {
//測定
freq = measurement();
//
if (SW_CAL == SW_OFF) {
//測定結果の補正、四捨五入、表示
tmp = freq / cal._double;
tmp -= 455000.0;
//
if ((tmp % 1000) >= 500) {
tmp = (tmp / 1000) + 1;
} else {
tmp = tmp / 1000;
}
//
LongWordToStr(tmp, buf);
buf[6] = (buf[6] == ' ') ? 0 : buf[6] - '0';
buf[7] = (buf[7] == ' ') ? 0 : buf[7] - '0';
buf[8] = (buf[8] == ' ') ? 0 : buf[8] - '0';
buf[9] = (buf[9] == ' ') ? 0 : buf[9] - '0';
segment_set_data(buf[6], buf[7], buf[8], buf[9]);
} else {
//校正値の算出、保存、表示(1MHz時の周波数)
cal._double = freq / 1000000.0;
//
Eeprom_Write(0, cal._short[0]);
Delay_ms(20);
Eeprom_Write(1, cal._short[1]);
Delay_ms(20);
Eeprom_Write(2, cal._short[2]);
Delay_ms(20);
Eeprom_Write(3, cal._short[3]);
Delay_ms(20);
//
LongWordToStr(cal._double * 1000.0, buf);
buf[6] = (buf[6] == ' ') ? 0 : buf[6] - '0';
buf[7] = (buf[7] == ' ') ? 0 : buf[7] - '0';
buf[8] = (buf[8] == ' ') ? 0 : buf[8] - '0';
buf[9] = (buf[9] == ' ') ? 0 : buf[9] - '0';
segment_set_data(buf[6], buf[7], buf[8], buf[9]);
}
Delay_ms(400);
}
}
//**********************************************************************
//■■■セグメント初期化関数■■■
void init_segment()
{
SEG1_Direction = OUTPUT_MODE;
SEG1_OFF;
SEG2_Direction = OUTPUT_MODE;
SEG2_OFF;
SEG3_Direction = OUTPUT_MODE;
SEG3_OFF;
SEG4_Direction = OUTPUT_MODE;
SEG4_OFF;
//
SEG_DATA_Direction = 0b01000000;
SEG_DATA = 0x00;
}
//**********************************************************************
//■■■入出力ポート初期化関数■■■
void init_port()
{
}
//**********************************************************************
//■■■タイマー初期化関数■■■
void init_timer()
{
T2CON.T2CKPS1 = 0;
T2CON.T2CKPS0 = 0;
T2CON.TOUTPS3 = 1;
T2CON.TOUTPS2 = 1;
T2CON.TOUTPS1 = 1;
T2CON.TOUTPS0 = 1;
TMR2 = 0;
PIE1.TMR2IE = 1;
PIR1.TMR2IF = 0;
PR2 = 125; //125=1msec/((1sec/8MHz)*4*16PS)
T2CON.TMR2ON = 1;
}
//**********************************************************************
//■■■セグメントデータ設定関数■■■
short seg_dat[4] = {0, 0, 0, 0};
//
void segment_set_data(short seg1, short seg2, short SEG3, short seg4)
{
seg_dat[0] = seg1;
seg_dat[1] = seg2;
seg_dat[2] = seg3;
seg_dat[3] = seg4;
}
//**********************************************************************
//■■■割り込み関数■■■
short fc_flg = -1;
void interrupt()
{
if (PIR1.TMR2IF == 1) {
PIR1.TMR2IF = 0;
//周波数カウンタ処理
switch (fc_flg) {
case -1:
break;
case 0:
T1CON.TMR1ON = 1; //ゲートを開ける。
fc_flg++;
break;
case 100:
T1CON.TMR1ON = 0; // ゲートを閉める。
fc_flg = -1;
break;
default:
fc_flg++;
break;
}
//
segment_disp();
}
}
//**********************************************************************
//■■■周波数測定関数■■■
long measurement()
{
long freq;
//
freq = 0;
PIE1.TMR1IE = 0;
PIR1.TMR1IF = 0;
T1CON.T1CKPS1 = 0;
T1CON.T1CKPS0 = 0;
T1CON.TMR1CS = 1;
T1CON.NOT_T1SYNC = 1;
TMR1H = 0;
TMR1L = 0;
fc_flg = 0;
while (fc_flg != -1) {
if (PIR1.TMR1IF == 1) {
PIR1.TMR1IF = 0;
freq++;
}
}
if (PIR1.TMR1IF == 1) {
PIR1.TMR1IF = 0;
freq++;
}
return (((freq * 65536) + ((long)TMR1H * 256) + (long)TMR1L) * 10);
}
//**********************************************************************
//■■■セグメントデータ表示関数■■■
short seg_tbl[10] = {
0b00111111, //0
0b00000110, //1
0b10011011, //2
0b10001111, //3
0b10100110, //4
0b10101101, //5
0b10111101, //6
0b00100111, //7
0b10111111, //8
0b10101111 //9
};
short seg_cnt = 0;
//
void segment_disp()
{
switch (seg_cnt) {
case 0:
SEG4_OFF;
SEG_DATA = seg_tbl[seg_dat[0]];
SEG1_ON;
seg_cnt = 1;
break;
case 1:
SEG1_OFF;
SEG_DATA = seg_tbl[seg_dat[1]];
SEG2_ON;
seg_cnt = 2;
break;
case 2:
SEG2_OFF;
SEG_DATA = seg_tbl[seg_dat[2]];
SEG3_ON;
seg_cnt = 3;
break;
case 3:
SEG3_OFF;
SEG_DATA = seg_tbl[seg_dat[3]];
SEG4_ON;
seg_cnt = 0;
break;
}
}
//**********************************************************************
===== 動作確認 =====
※入力アンプの74HCU04は、手持ち部品の関係で、74HC14を使用しています。
{{:imgpaste:202004:htmikan-20200430-143008.png?500}}
1121kHzを入力して、-455kHzした値(666kHz)が表示されることを確認してみました。
7セグLEDを、アクリル板で覆うことにより、表示が見やすくなります。
{{:imgpaste:202004:htmikan-20200430-143022.png}}{{:imgpaste:202004:htmikan-20200430-143026.png}}
手持ちの真空管ラジオに接続して、NHK第一放送(666kHz)を受信してみました。
{{:imgpaste:202004:htmikan-20200430-143036.png?500}}
このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。[[elechobby:picdic:picdic|詳細]]
This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.[[elechobby:picdic:picdic|Details]]