JH7UBCブログ

アマチュア無線 電子工作 家庭菜園など趣味のブログです

PIC12F1840 Si5351A 7MHz VFO

2019-06-28 12:12:13 | PIC12F1822/40

 PIC12F1840とSi5351Aを組み合わせて、7MHzのVFOを試作しました。

 回路図です。電源は3.3Vとします。(試作では電池2本3Vとしました。)

 3チャンネルクロックジェネレータSi5351Aと表示用のLCD AQM0802Aは、I2Cバスでコントロールします。

 RA0~RA5はすべてウィークプルアップして、プルアップ抵抗を省略しています。

 STEPボタンを押すたびに周波数ステップが1000Hz→100Hz→10Hz→1000Hzと循環します。

 TXボタンを押す(RA0が0になると)とCLK0に7MHzが出力されます。CWの場合は、KEYをここに接続します。

 TXボタンを押して、7MHzを出力しているところです。

 プログラムです。XC8Ver2.05でコンパイルしました。プログラムサイズは、3631wordsです。

 (v2.0でコンパイルするとプログラムサイズがオーバーしてしまいます)

/*
 * File:   main.c
 * Author: JH7UBC Keiji Hata
 * PIC12F1840 Si5351A VFO
 * Created on 2019/06/28
 */
 
#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
#define LCD_addr 0x7C   //3E+0
 
/* ロータリーエンコーダ関係定義*/
#define ECA RA5 //エンコーダA
#define ECB RA4 //エンコーダB
unsigned char curDat;
unsigned char befDat;
signed char count= 0;
 
/* Si5351A関係定義 */
#define Si5351_ADDR 0xC0    //60<<1
#define MSNA_ADDR 26
#define MS0_ADDR 42
#define MS1_ADDR 50
#define CLK0_CTRL 16
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define OUTPUT_CTRL 3
#define PLL_RESET 177
#define XTAL_LC 183
unsigned long Freq = 7000000;    //周波数初期値 7MHz
const int dF = 116;              //周波数補正値
unsigned long Freq_old;          //周波数の前の値
const unsigned long XtalFreq = 25000000; //PLL クリスタル周波数
unsigned long divider;
unsigned long PllFreq;
unsigned int mult;
unsigned long l;
float f;
unsigned long num;
const unsigned long denom = 1048575;
unsigned long P1;
unsigned long P2;
unsigned long P3;
 
/* STEP関係定義 */
unsigned int Step = 1000;
#define STEP_SW RA3
 
/* TX 関係定義 */
#define TX_SW RA0
unsigned char val=1;          //TX_SWの値
unsigned char old_val = 1;  //TX_SWの前の値
 
/* I2C intialize */
void I2C_init(){
    SSP1CON1 = 0x28;        //SSPEN = 1,I2C Master Mode
    SSP1STATbits.SMP = 1;   //standard mode(100KHz)
    SSP1ADD = 0x4F;         //Fosc/(4*Clock)-1  Clock=100kHz,Fosc=32MHz
}
 
/* start condition */
void I2C_start(){
    SEN = 1;
    while(SEN);
}
 
/* stop condition */
void I2C_stop(){
    SSP1IF = 0;
    PEN = 1;
    while(PEN);
    SSP1IF = 0;
}
 
/* write 1byte to I2C */
void I2C_write(unsigned char dat){
    SSP1IF = 0;
    SSP1BUF = dat;
    while(!SSP1IF);
}
 
/* write command */
void LCD_cmd(unsigned char cmd){
    I2C_start();          //start condition
    I2C_write(LCD_addr);  //send slave address
    I2C_write(0x00);      //send control byte
    I2C_write(cmd);       //send command
    I2C_stop();           //stop condition
}
 
/* write charactor */
void LCD_char(unsigned char dat){
    unsigned char ackn;
    I2C_start();          //start condition
    I2C_write(LCD_addr);  //send slave address
    I2C_write(0x40);      //send control byte
    I2C_write(dat);       //send data
    I2C_stop();           //stop condition
}
 
/* LCD initialize */
void LCD_init(){
    __delay_ms(40); //40ms wait
    LCD_cmd(0x38);  //8bit,2line
    LCD_cmd(0x39);  //IS=1 : extention mode set
    LCD_cmd(0x14);  //Internal OSC Frequency
    LCD_cmd(0x70);  //Contrast set
    LCD_cmd(0x56);  //Power/ICON/Contrast Control
    LCD_cmd(0x6C);  //Follower control
    __delay_ms(200);//200ms wait
    LCD_cmd(0x38);  //IS=0 : extention mode cancel
    LCD_cmd(0x0C);  //Display ON
    LCD_cmd(0x01);  //Clear Display
    __delay_ms(2);  //wait more than 1.08ms
}
 
/* Return Home `*/
void LCD_home(){
    LCD_cmd(0x02);
    __delay_ms(1);
    __delay_us(80);
}
 
/* Cursor x,y */
void LCD_cursor(unsigned char x,unsigned char y){
    if(y == 0){
        LCD_cmd(0x80 + x);
    }
    if(y == 1){
        LCD_cmd(0xC0 + x);       
    }
}
 
/* write 1 charactor to LCD  */
void putch(unsigned char ch){
    LCD_char(ch);
}
 
/* Si5351A関係関数*/
/* Send data to Si5351A register*/
void Si5351_write(unsigned char Reg , unsigned char Data)
{
    I2C_start();
    I2C_write(Si5351_ADDR);
    I2C_write(Reg);
    I2C_write(Data);
    I2C_stop();
}
 
/* Si5351A initialize */
void Si5351_init(){
    Si5351_write(OUTPUT_CTRL,0xFF); //Disable all output
    Si5351_write(CLK0_CTRL,0x80);   //CLOCK0 power down
    Si5351_write(CLK1_CTRL,0x80);   //CLOCK1 power down   
    Si5351_write(CLK2_CTRL,0x80);   //CLOCK2 power down   
    Si5351_write(XTAL_LC,0x80);     //Crystal Load Capasitance=8pF
    Si5351_write(PLL_RESET,0xAC); //Reset PLLA and PLLB
    Si5351_write(CLK0_CTRL,0b01001111); //CLOCK0 Power up 8mA
    Si5351_write(OUTPUT_CTRL,0xFF); //Disable CLK0?CLK2 output
}
 
/* Send parameter to register */
void Parameter_write(unsigned char REG_ADDR,unsigned long Pa1,unsigned long Pa2,unsigned long Pa3)
{
    Si5351_write(REG_ADDR + 0,(Pa3 & 0x0000FF00) >> 8);
    Si5351_write(REG_ADDR + 1,(Pa3 & 0x000000FF));
    Si5351_write(REG_ADDR + 2,(Pa1 & 0x00030000) >> 16);
    Si5351_write(REG_ADDR + 3,(Pa1 & 0x0000FF00) >> 8);
    Si5351_write(REG_ADDR + 4,(Pa1 & 0x000000FF));
    Si5351_write(REG_ADDR + 5,((Pa3 & 0x000F0000) >> 12) | ((Pa2 & 0X000F0000) >> 16));
    Si5351_write(REG_ADDR + 6,(Pa2 & 0x0000FF00) >> 8);
    Si5351_write(REG_ADDR + 7,(Pa2 & 0x000000FF));
}
 
/* Set frequency */
void VFO_set(unsigned long frequency){
    /* Set PLLA */
    frequency += dF;    //周波数補正
    divider = 900000000 / frequency;
    divider >>= 1;  //dividerは整数かつ偶数
    divider <<= 1;
    PllFreq = divider * frequency;
    mult = PllFreq / XtalFreq;
    l = PllFreq % XtalFreq;
    f = l;
    f *= denom;
    f /= XtalFreq;
    num = f;
    P1 = (unsigned long)(128 * ((float)num /(float)denom));
    P1 = (unsigned long)(128 * (unsigned long)mult + P1 - 512);
    P2 = (unsigned long)(128 * ((float)num / (float)denom));
    P2 = (unsigned long)(128 * num -denom * P2);
    P3 = denom;
    Parameter_write(MSNA_ADDR,P1,P2,P3);
    /* Set MS0 */
    P1 = 128 * divider - 512;
    P2 = 0;
    P3 = 1;
    Parameter_write(MS0_ADDR,P1,P2,P3);
}
 
/* Display Frequency */
void Freq_disp(unsigned long frequency){
    LCD_home();
    printf("%8ld",frequency);
}
 
/* Display Step */
void Step_disp(unsigned int stp){
    LCD_cursor(4,1);
    printf("%4d",stp);
}
 
/* STEP Change */
void Step_change(){
    __delay_ms(5);      // チャタリング待ち
    if(Step == 10){
        Step = 1000;
    }else{
        Step /= 10;
    }
    Step_disp(Step);
    while(!STEP_SW){
        __delay_ms(5);
    }
}
 
/* 割り込みサービスルーチン */
void __interrupt() isr(){
    IOCIF = 0;   //割り込みフラッグクリア
    IOCAF = 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 Tx_send(){
        if(val == 0){
            Si5351_write(OUTPUT_CTRL,0xFE);
        }else{   
            Si5351_write(OUTPUT_CTRL,0xFF);
        }
        __delay_ms(2);
    }
 
/* main program */
void main() {
    OSCCON = 0b01110000 ;       // クロック8MHz
    ANSELA = 0b00000000 ;       // アナログを使わない
    TRISA  = 0b00111111 ;       // RA0-RA5入力
    PORTA  = 0b00000000 ;       // PORTAクリア
    OPTION_REGbits.nWPUEN=0;    //ウィークプルアップ許可
    WPUA = 0b00111111;          //RA0-RA5をプルアップ
   
    /* 割り込み関係設定 */
    IOCIE = 1;                //状態変化割り込み許可
    IOCAP = 0b00110000;       //RA4,RA5立ち上がりエッジ検出
    IOCAN = 0b00110000;       //RA4,RA5立ち下りエッジ検出
    PEIE = 1;                 //周辺割り込み許可
    GIE = 1;                  //全割り込み許可
    I2C_init();
    LCD_init();
    Si5351_init();
 
   
    /* Rotary Encoder 初期値 */
    befDat = ECA + (ECB<<1);
   
 /*周波数とSTEP初期値表示*/
    Freq_disp(Freq);
    VFO_set(Freq);
    Freq_old = Freq;
    LCD_cursor(0,1);
    printf("STEP");
    Step_disp(Step);
      
    while(1){
        if(STEP_SW == 0){
            Step_change();
        }
       
        val = TX_SW;
        if(val != old_val){
            Tx_send();
        }
        old_val = val;       
              
        if(Freq != Freq_old){
            Freq_disp(Freq);
            VFO_set(Freq);
            Freq_old = Freq;
        }   
     }
}
 

ケールの収穫

2019-06-27 20:29:16 | 家庭菜園と花

 6月4日に植え付けたケールが大きく育ち収穫の時期を迎えました。

 大きくなった葉から順に切り取って収穫します。

 ケールは栄養満点で、青汁の主成分です。ジュースにして飲むのが一般出来ですが、我が家では、おひたしにして食べます。

 一方今年のナスは、ピンチです。

 14本苗を植えたのですが、3本は活着せずに枯れ、更に最近手前の3本の葉が黄色くなり始めました。

 うーーん。困った。今年はナスの収穫は期待できません。原因を探ってみます。


PIC12F1840 ロータリーエンコーダ テスト

2019-06-22 20:45:41 | PIC12F1822/40

 しばらくぶりに、PICの記事を書きます。

 先日製作した3.5MHz/7MHz用SDRフロントエンド+パソコンを受信機とし、簡単な7MHz CW送信機と組み合わせて交信してみたいと考えました。

 そこで、3チャンネルクロックジェネレータSi5351AをVFOとして使い、BS170 E級のファイナルとして、2~3Wの送信機を作ってみようと思います。

 Si5351Aのコントロールは、PIC12F1840を使うことにします。

 今日は、第一段階として、PIC12F1840でロータリーエンコーダを使うテストをしました。

 回路図です。ロータリーエンコーダの回転方向を判定して、シリアル通信でパソコンに結果を送り、TeraTermの「RIGHT」「LEFT」と表示します。シリアルUSB変換は、FT234モジュールを使用します。

 OPTION_REGのnWPUEN=0として、ウィークプルアップを有効にします。

 更にWPUA=0b00110000として、RA4とRA5をウィークプルアップします。これにより、プルアップ抵抗を省略しています。

 ロータリーエンコーダは、回転させると接点A,Bの状態(+か0)が変化し、RA4とRA5の状態が変化します。このピンの状態が変化したときに割り込みがかかるようにして(IOC割り込み)、回転方向を判定します。

 IOCIE=1として、ピン状態変化割り込みを有効にします。

 更に、IOCAP=0b00110000として、RA4とRA5のピン状態の立ち上がり検出を有効にし、IOCAN=0b00110000として、ピン状態の立下り検出も有効にします。

 回転方向に判定方法については、JH7UBCホームページのここを見てください。

 ブレッドボードです。

 プログラムです。

/*
 * File:   main.c
 * Author: JH7UBC Keiji Hata
 * PIC12F1840 Rotary Encoder test
 * Created on 2019/06/22
 */
#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
 
/* ロータリーエンコーダ関係定義*/
#define ECA RA5 //エンコーダA
#define ECB RA4 //エンコーダB
volatile unsigned char curDat;
volatile unsigned char befDat;
volatile signed char count= 0;
 
void serial_init(unsigned long BR){
    TXSTA = 0x24;   //SYNC=0 TXEN = 1 BRGH = 1
    BRG16 = 1;      //BRG 16bit mode
    RCSTA = 0x90;   //非同期、継続受信可
    unsigned int X= _XTAL_FREQ/BR/4 - 1;
    SPBRGH = X / 256;
    SPBRGL = X % 256;
}
 
void putch(unsigned char byte){
    while(!TXIF);
    TXREG = byte;
}
 
void __interrupt() isr(){
    IOCIF = 0;   //割り込みフラッグクリア
    IOCAF = 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){
        printf("RIGHT\r\n");
        count = 0;
    }else if(count <= -4){
        printf("LEFT\r\n");
        count = 0;
    }
}
 
void main() {
    OSCCON = 0b01110000 ;     // 内部クロック8MHz
    ANSELA = 0b00000000 ;     // アナログは使用しない
    TRISA  = 0b00110010 ;     // RA1,RA4,RA5は入力、他は出力
    PORTA  = 0b00000000 ;     // 出力ピンの初期化
    OPTION_REGbits.nWPUEN = 0;//ウィークプルアップ許可
    WPUA = 0b00110000;        //RA4,RA5をウィークプルアップ
   
    /* 割り込み関係設定 */
    IOCIE = 1;                //状態変化割り込み許可
    IOCAP = 0b00110000;       //RA4,RA5立ち上がりエッジ検出
    IOCAN = 0b00110000;       //RA4,RA5立ち下りエッジ検出
    PEIE = 1;                 //周辺割り込み許可
    GIE = 1;                  //全割り込み許可
   
    /* シリアル通信設定 */
    serial_init(9600);
   
    while(1){
    }
}
 
 TeraTernの画面です。時計方向に回転させると「RIGHT」、反時計回りに回転させると「LEFT」と表示されます。
 
 コンパイラは、xc8 Ver2.05を使っています。
 コンパイルエラーが出るときは、Project PropartiesでXC8 Global OptionのC standerdをC99からC90に変更してください。
 

2019-06-19 11:40:52 | 家庭菜園と花

 今、育てているいくつかの花を紹介します。

 夏に咲く小さな菊です。正確な名前を知らないのですが、畑の隅にどこかから飛んできた種が発芽し、2年目に開花したものを鉢に移しました。夏小菊とかぽんぽん小菊というらしい。

 妻が母の日にもらった寄せ植えの花の中に入っていたもので、カトレアクローバーといいます。

 一旦花が終わったのですが、鉢に植え替えて育てたら、再び花が咲き始めました。

 これも寄せ植えに入っていた花の一つで、カーネーションオスカーです。

 花を切り詰めたあと鉢に植え替えたら、たくさんの花が咲きました。

いずれも、梅雨明け頃まで楽しめそうです。


犯人はこいつだ

2019-06-10 12:47:23 | 家庭菜園と花

 先日植え付けたケールが、根元からポッキリ折られていました。

 周辺の土をていねいに掘って調べると、いました。ネキリムシです。

 ネキリムシを防ぐ方法は、いろいろあるようですが、見つけたら、捕殺するようにしています。

 

 バラ咲インパチェンスが、咲き始めました。きれいです。