
- >
- コンピュータとインターネット
- >
- インターネット
- >
- その他インターネット
全体表示
[ リスト | 詳細 ]
|
PIC16F1827を使って、周波数カウンタを作ってみました。
これまで、PIC16F88,PIC16F628Aなどで製作した「電子工作etc」というサイトで紹介された「周波数カウンタV7」と基本的には同じアルゴリズムです。
残念ながら「電子工作etc」というサイトは既に見えなくなっているようです。
PIC 1個で、どのようにして周波数カウンタを作るかを簡単に説明します。
周波数カウンタを作るには、周波数を測定するカウンタとカウント時間(普通は1秒)を発生するタイムベースが必要です。
PICは、内部に複数のタイマー(カウンタ)を持っています。そのうち16bitタイマーであるTimer1(TMR1)を周波数を測定するカウンタに使い、8bitタイマーTimer2(TMR2)を使って1秒を発生させます。
TMR2を利用したタイムベースからの1秒の合図で、TMR1へのゲートを開けたり閉めたりして、周波数をカウントします。
詳細は、JH7UBCホームページのここを見てください。
回路図です。
入力信号は、2SC1815GRの簡単なアンプを通して、T1CKI(RB6)に加えます。 クロックは、正確に測定するために20MHzのクリスタルオシレータを使い、外部クロック入力CLKIN(RA7)に入れます。
周波数表示は、I2Cアダプタ付きのLCD1602を使いました。
動作確認のために、TMR1のゲートが開いている間点灯するLEDをつけました。
ブレッドボードです。自作SGからの1MHz(1000000Hz)の信号を測定しています。
プログラムです。 ------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <xc.h> // CONFIG1
#pragma config FOSC = ECH //外部クロック CLKIN (4-32MHz) #pragma config WDTE = OFF #pragma config PWRTE = ON #pragma config MCLRE = OFF #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config CLKOUTEN = OFF #pragma config IESO = OFF #pragma config FCMEN = OFF // CONFIG2
#pragma config WRT = OFF #pragma config PLLEN = OFF #pragma config STVREN = ON #pragma config BORV = HI #pragma config LVP = OFF #define _XTAL_FREQ 20000000 //クロック20MHz
#define LED RA4 //LCD関係定義
#define LCD_EN 0b00000100 //Enable #define LCD_BL 0b00001000 //Back Light #define LCD_CMD 0x00 #define LCD_CHR 0x01 #define LCD_LINE1 0x80 #define LCD_LINE2 0xC0 #define LCD_addr 0x4E //0x27<<1 /* I2C 初期化*/
void I2C_init(){ SSP1CON1 = 0x28; //SSPEN = 1,I2C Master Mode SSP1STATbits.SMP = 1; //標準速度モード(100KHz) SSP1ADD = 0x31; //Fosc/(4*Clock)-1 Clock=100kHz,Fosc=20MHz } /* スタートコンディション */
void I2C_start(){ SSP1CON2bits.SEN = 1; while(SSP1CON2bits.SEN); } /* ストップコンディション */
void I2C_stop(){ SSP1IF = 0; SSP1CON2bits.PEN = 1; while(SSP1CON2bits.PEN); SSP1IF = 0; } /* I2Cに1byte送信 */
void I2C_write(unsigned char dat){ SSP1IF = 0; SSP1BUF = dat; while(!SSP1IF); } void Write_data(unsigned char data){
I2C_start(); I2C_write(LCD_addr); I2C_write(data | LCD_EN | LCD_BL); I2C_write(data | LCD_BL); I2C_stop(); __delay_us(100); } void LCD_write(unsigned char bits,unsigned char mode){
//send High 4bits Write_data((bits & 0xF0) | mode); //send Low 4bits Write_data(((bits << 4) & 0xF0) | mode); } void LCD_init(){ LCD_write(0x33,LCD_CMD); LCD_write(0x32,LCD_CMD); LCD_write(0x06,LCD_CMD); LCD_write(0x0C,LCD_CMD); LCD_write(0x28,LCD_CMD); LCD_write(0x01,LCD_CMD); __delay_ms(1); } void LCD_clear(){
LCD_write(0x01,LCD_CMD); __delay_ms(1); } void LCD_home(){
LCD_write(0x02,LCD_CMD); __delay_ms(1); } void LCD_cursor(unsigned char x,unsigned char y){
if (y == 0){ LCD_write(LCD_LINE1+x,LCD_CMD); } if (y == 1){ LCD_write(LCD_LINE2+x,LCD_CMD); } } void putch(unsigned char ch){
LCD_write(ch,LCD_CHR); } static unsigned int MeassuremmentCnt;
/*TMR2のオーバーフロー割り込み*/
void interrupt isr(){ TMR2IF = 0;//TMR2割り込みフラッグクリア MeassuremmentCnt --; if (MeassuremmentCnt == 0){ TMR1ON = 0;//ゲートを閉める。 TMR2ON = 0;//TMR2を停止する。 } } /*周波数測定*/
unsigned long FreqMeassurement(){ static unsigned long freq; /*TIMERの初期化*/ TMR1IF = 0; //TMR1割り込みフラッグクリア TMR1L = 0; //TMR1クリア TMR1H = 0; /*TMR2の初期化*/ TMR2IF = 0; //TMR2割り込みフラッグクリア MeassuremmentCnt = 1221; TMR2 = 0x4C; /*counter 初期化*/ freq = 0; /*割り込み許可*/ PEIE = 1; GIE = 1; //count start TMR2ON = 1; /*gate time調整 NOP 25*/ NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); /*ゲートを開ける*/ TMR1ON = 1; while(TMR2ON){ if(TMR1IF == 1){ TMR1IF = 0; freq ++; } } if(TMR1IF == 1){ TMR1IF = 0; freq ++; } /*換算*/ freq = freq * 65536; freq = freq + ((unsigned)TMR1H * 256) + (unsigned)TMR1L; return(freq); } void main() { ANSELA = 0b00000000 ; // AN0-AN4は使用しない ANSELB = 0b00000000 ; // AN5-AN11は使用しない TRISA = 0b10000000 ; // RA7は入力 他は出力(RA5は入力) TRISB = 0b01010010 ; // RB1(SDA),RB4(SDA),RB6は入力他は出力 PORTA = 0b00000000 ; // PORTA初期化 PORTB = 0b00000000 ; // PORTB初期化 I2C_init(); LCD_init(); LCD_cursor(12,0); printf("Hz"); /*TMR2の設定*/ TMR2IE = 1; //TMR2割り込み許可 TMR2IF = 0; //TMR2割り込みフラッグクリア T2OUTPS0 = 0; //TMR2 output poststscaler 1:1 T2OUTPS1 = 0; T2OUTPS2 = 0; T2OUTPS3 = 0; TMR2ON = 0; //TMR2 off T2CKPS0 = 0; //TMR2 prescaler 1:16 T2CKPS1 = 1; TMR2 = 0; //TMR2 clear /*TMR1の設定*/ TMR1IE = 0; //TMR1割り込み禁止 TMR1IF = 0; //TMR1割り込みフラッグクリア T1CKPS0 = 0; //TMR1 prescaler 1:1 T1CKPS1 = 0; T1OSCEN = 0; //TMR1 Clock source = T1CKI TMR1CS1 = 1; TMR1CS0 = 0; nT1SYNC = 1; TMR1ON = 0; //TMR1 stop TMR1L = 0; //TMR1 clear TMR1H = 0; while(1){ /*周波数の測定*/ LED = 1;//RA4 LED ON unsigned long frequency = FreqMeassurement(); LED = 0;//RA4 LED OFF LCD_cursor(2,0); printf("%9ld",frequency); __delay_ms(500); } }
|

- >
- コンピュータとインターネット
- >
- コンピュータ
- >
- その他コンピュータ
|
2月9日〜10日に開催されたKCJトップバンドコンテストの結果が、今朝メールで届きました。
届いたのは、当局の照合結果ですが、KCJのホームページに全体の結果が発表されていました。
当局JH7UBCの結果は、全国23位(171局中)、福島県1位(5局中)でした。
初めての参加でしたので、まずまずの結果だと思います。
しかし、当局が相手局コールサインをミスコピーしたのが3局ありました。
まだまだですね。
来年も頑張ろうと思います。
|
|
PIC16F1827は、CCP1からCCP4の4つのMWP出力を持っています。
PWMのPeriod(周期)とDuty Cycle、Duty比は、次の式で設定します。
テストとして、CCP3に1000Hz(周期1ms=1×10^-3s) デューティ比50%のPWM信号を出力してみます。 PICのクロックは、内臓クロック8MHz(Tosc=1/8×10^6)とし、Timerは、Timer2を使います
上記の式からPWM周期を決定するTimer2のPR2の値は
PR2 = Period / (4×Tosc × TMR2Prescale Value) - 1= 1×10^-3/(4×(1/8×10^6)×TMR2 Prescale Value) -1
= 2×10^3/TMR2 Prescale Value となります。
TMR2のプリスケーラの値によってPR2の値は次のようになります。
Prescale Value PR2
1 1999
4 499
16 124
PR2レジスタは8bitですから0〜255の値でなければなりませんので
Prescale Value = 16 PR2 = 124 となります。
デューティ比を50%としますので、CCPR3L = (PR2 + 1)/2 = 125/2 = 62 となります。
プログラムです。
CCP3CONレジスタのbit3:2=11でPWM modeに設定し、bit1:0=00で出力をactive highに設定します。
CCPTMRSレジスタのbit5:4=00でCCP3にTMR2を割り当てます。
T2CONレジスタのbit1:0=10でプリスケーラ値を1:16に設定します。同じT2CONレジスタのbit2=1とするとTMR2が有効になり、PWM信号が出力されます。
実際に出力されたPWM信号の周波数を測定してみました。
998Hzでした。誤差2%というところです。 #include <stdio.h>
#include <stdlib.h> #include <xc.h> // CONFIG1
#pragma config FOSC = INTOSC #pragma config WDTE = OFF #pragma config PWRTE = ON #pragma config MCLRE = OFF #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config CLKOUTEN = OFF #pragma config IESO = OFF #pragma config FCMEN = OFF // CONFIG2
#pragma config WRT = OFF #pragma config PLLEN = OFF #pragma config STVREN = ON #pragma config BORV = HI #pragma config LVP = OFF #define _XTAL_FREQ 8000000 //クロック8MHz
void main() {
OSCCON = 0b01110010 ; // 内蔵クロック8MHz ANSELA = 0b00000000 ; // AN0-AN4は使用しない。全てデジタルポート ANSELB = 0b00000000 ; // AN5-AN11は使用しない。全てデジタルポート TRISA = 0b00000000 ; // PORTAは全て出力( RA5は入力のみ) TRISB = 0b00000000 ; // RORTBは全て出力 PORTA = 0b00000000 ; // PORTA初期化 PORTB = 0b00000000 ; // PORTB初期化 /* PWMに関する設定 * CCP3(RA3,2番ピン)を使う * PWMの周波数は、1000Hz(周期は1ms) * デューティ比は、50%とする */ CCP3CON = 0b00001100; //PWM mode P3A,P3C active high,P3B,P3D active high CCPTMRS = 0b00000000; //bit5-bit4=00,CCP3にTimer2を割り当てる PR2 = 124; //Timer2の周期を設定 CCPR3L = 62; //デューティ比 50% T2CON = 0b00000110; //prescale 1:16 Timer2 start while(1){ } }
|

- >
- コンピュータとインターネット
- >
- コンピュータ
- >
- その他コンピュータ
|
先日製作した3.5/7MHz SDRフロントエンドと組み合わせて実際の交信をしてみようと思い、7MHzのCW送信機を作ろうと思います。
まず、AD9834DDSをPIC16F1827でコントロールして7MHz VFOを作ります。
PIC16F883+AD9834 VFOのプログラムをPIC16F1827用に若干変更し、ロータリーエンコーダは、IOC割り込みを利用した方法にしました。
回路図です。
ブレッドボードです。 AD9834DDSの出力の波形です。 参考までに、プログラムです。 -----------------------------------------
/*
* File: main.c * Author: JH7UBC Keiji Hata * PIC16F1827_AD9834_VFO * Created on 2019/03/27 */ #include <stdio.h>
#include <stdlib.h> #include <xc.h> // CONFIG1
#pragma config FOSC = INTOSC #pragma config WDTE = OFF #pragma config PWRTE = ON #pragma config MCLRE = OFF #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config CLKOUTEN = OFF #pragma config IESO = OFF #pragma config FCMEN = OFF // CONFIG2
#pragma config WRT = OFF #pragma config PLLEN = ON #pragma config STVREN = ON #pragma config BORV = HI #pragma config LVP = OFF #define _XTAL_FREQ 32000000 //クロック32MHz
//LCD関係定義
#define LCD_EN 0b00000100 //Enable #define LCD_BL 0b00001000 //Back Light #define LCD_CMD 0x00 #define LCD_CHR 0x01 #define LCD_LINE1 0x80 #define LCD_LINE2 0xC0 #define LCD_addr 0x4E //0x27<<1 /* ロータリーエンコーダ関係定義*/
#define ECA RB6 //エンコーダA #define ECB RB7 //エンコーダB unsigned char EA; unsigned char EB; volatile unsigned char curDat; volatile unsigned char befDat; volatile signed char count= 0; /* STEP関係設定 */
unsigned int Step = 1000; //STEP初期値 #define STEP_SW RB5 /* AD9834DDS関係定義 */
#define FSYNC RA0 #define SCLK RA1 #define SDATA RA2 unsigned long Freq = 7000000; //周波数初期値 unsigned long Freq_old; //周波数の前の値 const unsigned long Fre_Hi = 7200000; //周波数上限 const unsigned long Fre_Lo = 7000000; //周波数下限 /* I2C 初期化*/
void I2C_init(){ SSP1CON1 = 0x28; //SSPEN = 1,I2C Master Mode SSP1STATbits.SMP = 1; //標準速度モード(100KHz) SSP1ADD = 0x4F; //Fosc/(4*Clock)-1 Clock=100kHz,Fosc=32MHz } /* スタートコンディション */
void I2C_start(){ SSP1CON2bits.SEN = 1; while(SSP1CON2bits.SEN); } /* ストップコンディション */
void I2C_stop(){ SSP1IF = 0; SSP1CON2bits.PEN = 1; while(SSP1CON2bits.PEN); SSP1IF = 0; } /* I2Cに1byte送信 */
void I2C_write(unsigned char dat){ SSP1IF = 0; SSP1BUF = dat; while(!SSP1IF); } void Write_data(unsigned char data){
I2C_start(); I2C_write(LCD_addr); I2C_write(data | LCD_EN | LCD_BL); I2C_write(data | LCD_BL); I2C_stop(); __delay_us(100); } void LCD_write(unsigned char bits,unsigned char mode){
//send High 4bits Write_data((bits & 0xF0) | mode); //send Low 4bits Write_data(((bits << 4) & 0xF0) | mode); } void LCD_init(){ LCD_write(0x33,LCD_CMD); LCD_write(0x32,LCD_CMD); LCD_write(0x06,LCD_CMD); LCD_write(0x0C,LCD_CMD); LCD_write(0x28,LCD_CMD); LCD_write(0x01,LCD_CMD); __delay_ms(1); } void LCD_clear(){
LCD_write(0x01,LCD_CMD); __delay_ms(1); } void LCD_home(){
LCD_write(0x02,LCD_CMD); __delay_ms(1); } void LCD_cursor(unsigned char x,unsigned char y){
if (y == 0){ LCD_write(LCD_LINE1+x,LCD_CMD); } if (y == 1){ LCD_write(LCD_LINE2+x,LCD_CMD); } } void putch(unsigned char ch){
LCD_write(ch,LCD_CHR); } void Freq_disp(unsigned long frequency){
LCD_home(); printf("%8ld",frequency); } void Step_disp(unsigned int stp){
LCD_cursor(4,1); printf("%4d",stp); } void Step_change(){
__delay_ms(5); if(Step == 10){ Step = 1000; }else{ Step = Step/10; } Step_disp(Step); while(!STEP_SW){ __delay_ms(5); } } /* AD9834DDSに16ビット送信 */
void Data_send(unsigned long data){ for(unsigned char i = 0;i<16;i++){ if(data & 0x8000){ SDATA = 1; }else{ SDATA = 0; } __delay_us(1); SCLK = 0; __delay_us(1); SCLK = 1; data <<= 1; } } /* AD9834DDSに周波数データを送る */
void Fnc_DDS(unsigned long frequency){ unsigned long wrk = frequency << 2; unsigned int wrk1,wrk2,wrk3; wrk1 = 0x2000; //コントロールワード wrk2 = wrk & 0x3fff; //周波数データ下位 wrk2 = wrk2 | 0x4000; wrk3 = wrk >> 14; wrk3 = wrk3 & 0x3fff; //周波数データ上位 wrk3 = wrk3 | 0x4000; SCLK = 1; FSYNC = 0; Data_send(wrk1); Data_send(wrk2); Data_send(wrk3); FSYNC = 1; } void interrupt isr(){
IOCIF = 0; //割り込みフラッグクリア IOCBF6 = 0; IOCBF7 = 0; __delay_ms(2); curDat = ECA + (ECB<<1); if (befDat != curDat){ unsigned char d = ((befDat<<1)^curDat) & 3; //回転方向判定 if(d < 2){ count++; }else{ count--; } befDat = curDat; } if(count >= 4){ Freq += Step; count = 0; }else if(count <= -4){ Freq -= Step; count = 0; } } void main(){
OSCCON = 0b01110000 ; // 内部クロック8MHz ANSELA = 0b00000000 ; // AN0-AN4は使用しない ANSELB = 0b00000000 ; // AN5-AN11は使用しない TRISA = 0b00000000 ; // PORTAは全て出力(RA5は入力) TRISB = 0b11110010 ; // RB1(SDA),RB4(SDA),RB5,RB6(REA),RB7(REB)は入力他は出力 PORTA = 0b00000000 ; // PORTA初期化 PORTB = 0b00000000 ; // PORTB初期化 OPTION_REGbits.nWPUEN=0; // ウィークプルアップ許可 WPUB = 0b11100000; // RB5,RB6,RB7をプルアップ /* IOC割り込み設定 */ IOCBN = 0b11000000; //RB6,RB7立下り割り込み設定 IOCBP = 0b11000000; //RB6,RB7立ち上がり割り込み設定 IOCIE = 1; //IOC割り込み許可 GIE = 1; //全割り込み許可 I2C_init(); //I2C初期化 LCD_init(); //LCD初期化 /* Roatry Encoder 初期値 */ EA = ECA; EB = ECB; befDat = EA + (EB<<1); /* 初期表示と初期周波数設定 */ LCD_cursor(9,0); printf("Hz"); Freq_disp(Freq); Fnc_DDS(Freq); LCD_cursor(0,1); printf("STEP"); Step_disp(Step); while(1){ if(STEP_SW == 0){ Step_change(); } if(Freq != Freq_old){ if(Freq < Fre_Lo)Freq = Fre_Lo; if(Freq > Fre_Hi)Freq = Fre_Hi; Fnc_DDS(Freq); Freq_disp(Freq); Freq_old = Freq; } } } |

- >
- コンピュータとインターネット
- >
- コンピュータ
- >
- その他コンピュータ



