PIC12F1840 Si5351A 7MHz VFO
2019.7.3 JH7UBC
3チャンネルクロックジェネレータSi5351AをPIC12F1840でコントロールして、7MHzのVFOを作ってみます。
周波数とSTEP表示用のLCD AQM0802AとSi5351Aは、I2Cバスでデータを送ります。
回路図です。
PIC12F1840のすべてのポートRA0〜RA5は、ウィークプルアップしています。
ブレッドボードです。
TX SWを押して7MHzを発振させています。
STEPボタンを押すたびにSTEPが1000Hz→100Hz→10Hz→1000Hzと循環します。
プログラムです。
MPLAB X IDE を使い、XC8 Ver2.05でコンパイルしました。
(Ver2.0では、プログラムサイズがオーバーしてしまいます)
割り込みサービスルーチンでエラーが出るときは、Project PropartiesでXC8 Global OptionのC standerdをC99からC90に変更してください。
/*
* 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; } } } |