Quantcast
Channel: JH7UBCブログ
Viewing all articles
Browse latest Browse all 440

PIC16F883 Si5351A VFO

$
0
0
 3チャンネル・クロックジェネレータSi5351Aを使ったVFOは、既にAeduinoやSTM32で製作済みです。

 今回は、MPLABX XC8の環境で、PIC16F883で7MHz VFOを作ってみました。

 Si5351Aの制御は、Arduinoのプログラムが、そのまま使えました。7MHzのVFOとしましたが、周波数は任意に設定できます。STEPは、ボタンを押すたびに1000Hz→100Hz→10Hz→1000Hzと循環します。

 回路図です。

 Si5351AとLCD AQM0602Aは、I2Cバスに接続します。プルアップ抵抗は、AQM0802Aモジュールに内蔵されています。

イメージ 1

 ブレッドボードです。

イメージ 2

 電源は、乾電池2本を使っています。

 プログラムです。ちょっと長いですが、参考までに掲載します。

 ロータリーエンコーダは、PORTBのピン変化割り込みを利用しています。PIC16F883では、RB0~RB7を利用できますが、割り込みを使うピンを
IOCB0 = 1;      //RB0を割り込みピンに指定
IOCB1 = 1;      //RN1を割り込みピンに指定
で指定しています。

 プログラムサイズは、メモリ4kワードの90%です。

--------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTRC_NOCLKOUT    //内蔵クロックを使う
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#pragma config LVP = OFF
// CONFIG2
#pragma config BOR4V = BOR40V
#pragma config WRT = OFF
#define _XTAL_FREQ 8000000
/* LCD AQM0802関係定義 */
#define LCD_addr 0x7C   //3E<<1
/* ロータリーエンコーダ関係定義*/
#define ECA RB0 //エンコーダA
#define ECB RB1 //エンコーダB
unsigned char curDat;
unsigned char befDat;
signed char count= 0;
/* SW関係定義 */
#define SW_step RB2
unsigned int Step = 1000;       //Step初期値
unsigned char step_val;
unsigned char step_old = 1;

/* Si5351A関係定義*/
#define Si5351_ADDR 0xC0    //60<<1
#define MSNA_ADDR 26
#define MS0_ADDR 42
#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
unsigned long Freq_old;         //周波数の前の値
const unsigned long XtalFreq = 25000000; //水晶発振器の周波数
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;
/* I2C関係関数*/
/* I2C 初期化*/
void I2C_init()
{
    SSPCON = 0x28;  //SSPEN = 1,I2C Master Mode
    SSPSTATbits.SMP = 1;    //標準速度モード(100KHz)
    SSPADD = 19;    //Fosc/(4*Clock)-1  Clock=100kHz,Fosc=8MHz
}
/* スタートコンディション */
void I2C_start()
{
    SEN = 1;
    while(SEN);
}
/* ストップコンディション */
void I2C_stop()
{
    SSPIF = 0;
    PEN = 1;
    while(PEN);
    SSPIF = 0;
}
/* I2Cに1byte送信 */
void  I2C_write(unsigned char dat)
{
    SSPIF = 0;
    SSPBUF = dat;
    while(!SSPIF);
}
/* 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){
    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
}
/* Clear Display */
void LCD_clear(){
    LCD_cmd(0x01);
    __delay_ms(1);
    __delay_us(80);
}
/* Return Home */
void LCD_home(){
    LCD_cmd(0x02);
    __delay_ms(1);
    __delay_us(80);
}
/* Cursor 2line top */
void LCD_2line(){
    LCD_cmd(0xC0);
}
/* write 1 charactor to LCD */
void putch(unsigned char ch){
    LCD_char(ch);
}
void Freq_disp(){
    LCD_home();
    printf("%8ld",Freq);
}
void Step_disp(){
    LCD_cmd(0xC4);  //cursol 4,1
    printf("%4d",Step);
}
void Step_change(){
    __delay_ms(10);
    if(Step==10){
        Step = 1000;
    }else{
        Step = Step / 10;
    }
    Step_disp();
    while(!SW_step);
    __delay_ms(10);
}
/* Si5351A関係関数*/
/* Si5351Aのレジスタにデータ送信*/
void Si5351_write(unsigned char Reg , unsigned char Data)
{
    I2C_start();
    I2C_write(Si5351_ADDR);
    I2C_write(Reg);
    I2C_write(Data);
    I2C_stop();
}
/* Si5351A初期化 */
void Si5351_init(){
    Si5351_write(OUTPUT_CTRL,0xFF); //Disable oll 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,0xA0); //Reset PLLA and PLLB
    Si5351_write(CLK0_CTRL,0b01001111); //CLOCK0 Power up 8mA
    Si5351_write(OUTPUT_CTRL,0xFE); //Enable CLOCK0
}
//レジスタにパラメータP1,P2,P3を書き込む。
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));
}
void PLLA_set()
{
    divider = 900000000 / Freq;
    divider >>= 1;  //dividerは整数かつ偶数
    divider <<= 1;
    PllFreq = divider * Freq;
    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);
}
void MS0_set()
{
    P1 = 128 * divider - 512;
    P2 = 0;
    P3 = 1;
    Parameter_write(MS0_ADDR,P1,P2,P3);
}
void interrupt isr(){
    RBIF = 0;   //RB割り込みフラッグクリア
    __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() {
    ANSEL = 0;  //アナログポートを使わない
    ANSELH = 0;
    OSCCON = 0x70;  //内蔵クロック8MHz
    TRISA = 0b00000000;
    TRISB = 0b00000111; //RB0,RB1,RB2 input
    TRISC = 0b00011000; //RC3(SCL),RC4(SDA)input
    PORTA = 0x00;
    PORTB = 0x00;
    PORTC = 0x00;
    OPTION_REGbits.nRBPU = 0;   //PORTB Pull up
   
    I2C_init();     //I2C initiatize
    LCD_init();     //LCD initialize
    Si5351_init();  //Si5351A initialize
   
    IOCB0 = 1;      //RB0を割り込みピンに指定
    IOCB1 = 1;      //RN1を割り込みピンに指定
    RBIE = 1;       //RBピン割り込み許可
    GIE = 1;        //全割り込み許可
   
    befDat = ECA + (ECB<<1);
   
    Freq_old = Freq;
    Freq_disp();
    PLLA_set();
    MS0_set();
    Step_disp();
       
    while(1){
        if(Freq != Freq_old){
        PLLA_set();
        MS0_set();
        Freq_disp();
        }
        Freq_old = Freq;
       
        step_val = SW_step;
        if((step_val == 0)&&(step_old == 1)){
            Step_change();
        }
        step_old = step_val;
    }
}
----------------------------------------------------
 

Viewing all articles
Browse latest Browse all 440

Trending Articles