PIC16F883とAD9834DDSを組み合わせてVFOを試作してみました。
周波数表示は前の記事で実験したI2Cインターフェース付きのLCD1602です。
ロータリーエンコーダのプログラムは、PIC16F88で実験したものを使います。(割り込みを使わない方法)
AD9834DDSのコントロールは、Arduinoで実験済みのこちらのプログラムを若干変更して使います。コントロールの方法も書いてあります。
回路図です。
AD9834のクロックは、67.108864MHzのクリスタルオシレータSG8002DBを使っています。
AD9834に周波数データを送るフォーマットは、次の図のとおりです。
周波数データの計算方法は、次の図の通りです。マスタクロックの周波数を67108864Hz=2^26とすることにより、計算が非常に簡単になります。
ブレッドボードと発生させた信号を自作周波数カウンタで測定している様子です。電源は、FT234Xから供給しています。
プログラムのメモリ占有率は、38%です。
------------------------------------------------------
/*
* File: main.c
* Author: Keiji
* PIC16F883 AD9834DDS VFO
* clock = 67.108864MHz
* Created on 2019/01/15, 13:12
*/
* File: main.c
* Author: Keiji
* PIC16F883 AD9834DDS VFO
* clock = 67.108864MHz
* Created on 2019/01/15, 13:12
*/
#include <stdio.h>
#include <stdlib.h>
#include <xc.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
#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
/* AD9834DDS関係定義 */
#define FSYNC RA0
#define SCLK RA1
#define SDATA RA2
unsigned long Freq = 7000000; //周波数初期値
unsigned long Freq_old; //周波数の前の値
unsigned int Step = 1000; //周波数STEP初期値
#define FSYNC RA0
#define SCLK RA1
#define SDATA RA2
unsigned long Freq = 7000000; //周波数初期値
unsigned long Freq_old; //周波数の前の値
unsigned int Step = 1000; //周波数STEP初期値
//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 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 RB0
#define ECB RB1
unsigned char curDat;
unsigned char befDat = 0;
unsigned char rotDir = 0;
unsigned char inputMatch;
unsigned char matchCnt;
unsigned char rotPat = 0;
signed char val;
unsigned int STEP = 1000; //周波数ステップ初期値
#define ECA RB0
#define ECB RB1
unsigned char curDat;
unsigned char befDat = 0;
unsigned char rotDir = 0;
unsigned char inputMatch;
unsigned char matchCnt;
unsigned char rotPat = 0;
signed char val;
unsigned int STEP = 1000; //周波数ステップ初期値
/* SW定義 */
#define SW_step RB2
#define SW_rit RB3
unsigned char step_val;
unsigned char step_old = 1;
#define SW_step RB2
#define SW_rit RB3
unsigned char step_val;
unsigned char step_old = 1;
/* 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_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_start(){
SEN = 1;
while(SEN);
}
/* ストップコンディション */
void I2C_stop(){
SSPIF = 0;
PEN = 1;
while(PEN);
SSPIF = 0;
}
void I2C_stop(){
SSPIF = 0;
PEN = 1;
while(PEN);
SSPIF = 0;
}
/* I2Cに1byte送信 */
unsigned char I2C_write(unsigned char dat){
SSPIF = 0;
SSPBUF = dat;
while(!SSPIF);
return ACKSTAT;
}
unsigned char I2C_write(unsigned char dat){
SSPIF = 0;
SSPBUF = dat;
while(!SSPIF);
return ACKSTAT;
}
/* LCDにデータを送る */
void Write_data(unsigned char data){
unsigned char ackn;
I2C_start();
ackn = I2C_write(LCD_addr);
ackn = I2C_write(data | LCD_EN | LCD_BL);
ackn = I2C_write(data | LCD_BL);
I2C_stop();
__delay_us(100);
}
void Write_data(unsigned char data){
unsigned char ackn;
I2C_start();
ackn = I2C_write(LCD_addr);
ackn = I2C_write(data | LCD_EN | LCD_BL);
ackn = I2C_write(data | LCD_BL);
I2C_stop();
__delay_us(100);
}
/* LCDにコマンドまたは文字を送る */
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_write(unsigned char bits,unsigned char mode){
//send High 4bits
Write_data((bits & 0xF0) | mode);
//send Low 4bits
Write_data(((bits << 4) & 0xF0) | mode);
}
/* LCD初期化 */
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_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);
}
LCD_write(0x01,LCD_CMD);
__delay_ms(1);
}
void LCD_home(){
LCD_write(0x02,LCD_CMD);
__delay_ms(1);
}
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);
}
}
if (y == 0){
LCD_write(LCD_LINE1+x,LCD_CMD);
}
if (y == 1){
LCD_write(LCD_LINE2+x,LCD_CMD);
}
}
void LCD_char(unsigned char byte){
LCD_write(byte,LCD_CHR);
}
LCD_write(byte,LCD_CHR);
}
void putch(unsigned char ch){
LCD_char(ch);
}
LCD_char(ch);
}
/* 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;
}
}
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 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;
}
/*エンコーダの回転方向判定*/
signed char CheckEnc(unsigned dat){
rotPat <<=2; //左に2bitシフト
rotPat |= (dat & 0x03);//datの下位2bitを加える
if(rotPat == 0x4B){
return 1; //時計回り(CW))
}else if(rotPat == 0x87){
return -1; //反時計回り(CCW)
}else{
return 0; //どちらでもない
}
}
signed char CheckEnc(unsigned dat){
rotPat <<=2; //左に2bitシフト
rotPat |= (dat & 0x03);//datの下位2bitを加える
if(rotPat == 0x4B){
return 1; //時計回り(CW))
}else if(rotPat == 0x87){
return -1; //反時計回り(CCW)
}else{
return 0; //どちらでもない
}
}
/* 周波数表示 */
void Freq_disp(unsigned long f){
LCD_cursor(3,0);
printf("%5d",f/1000);
printf(".");
printf("%03d",f%1000);
}
void Freq_disp(unsigned long f){
LCD_cursor(3,0);
printf("%5d",f/1000);
printf(".");
printf("%03d",f%1000);
}
/* STEP表示 */
void Step_disp(unsigned int stp){
LCD_cursor(4,1);
if(stp == 1000){
printf(" 1K");
}else if(stp == 100){
printf("100");
}else{
printf(" 10");
}
}
void Step_disp(unsigned int stp){
LCD_cursor(4,1);
if(stp == 1000){
printf(" 1K");
}else if(stp == 100){
printf("100");
}else{
printf(" 10");
}
}
/* STEP変更 */
void Step_change(){
__delay_ms(10);
if(STEP == 10){
STEP = 1000;
}else{
STEP /= 10;
}
Step_disp(STEP);
}
void Step_change(){
__delay_ms(10);
if(STEP == 10){
STEP = 1000;
}else{
STEP /= 10;
}
Step_disp(STEP);
}
void main() {
ANSEL = 0; //アナログポートを使わない
ANSELH = 0;
OSCCON = 0x70; //8MHz
TRISA = 0b00000000;
TRISB = 0b00000111; //RB0 RB1 RB2input
TRISC = 0b00011000; //RC3(SCL),RC4(SDA)input
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
OPTION_REGbits.nRBPU = 0;//PORTB Pull up
I2C_init(); //I2C初期化
LCD_init(); //LCD初期化
//周波数初期値表示
Freq_disp(Freq);
Freq_old = Freq;
//周波数STEP表示
LCD_cursor(0,1);
printf("STEP");
Step_disp(STEP);
//DDS制御信号初期化
FSYNC = 1;
SCLK = 1;
//初期周波数設定
Fnc_DDS(Freq);
/*ロータリーエンコーダ初期値設定*/
curDat = 0;
if(ECA){
befDat |= 2;
}
if(ECB){
befDat |= 1;
}
ANSEL = 0; //アナログポートを使わない
ANSELH = 0;
OSCCON = 0x70; //8MHz
TRISA = 0b00000000;
TRISB = 0b00000111; //RB0 RB1 RB2input
TRISC = 0b00011000; //RC3(SCL),RC4(SDA)input
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
OPTION_REGbits.nRBPU = 0;//PORTB Pull up
I2C_init(); //I2C初期化
LCD_init(); //LCD初期化
//周波数初期値表示
Freq_disp(Freq);
Freq_old = Freq;
//周波数STEP表示
LCD_cursor(0,1);
printf("STEP");
Step_disp(STEP);
//DDS制御信号初期化
FSYNC = 1;
SCLK = 1;
//初期周波数設定
Fnc_DDS(Freq);
/*ロータリーエンコーダ初期値設定*/
curDat = 0;
if(ECA){
befDat |= 2;
}
if(ECB){
befDat |= 1;
}
while(1){
/* STEP SWが押されたらSTEPを変更 */
step_val = SW_step;
if((step_val == 0)&&(step_old == 1)){
Step_change();
}
step_old = step_val;
/*ロータリーエンコーダ処理*/
curDat = 0;
if(ECA){
curDat |= 2;
}
if(ECB){
curDat |= 1;
}
if(befDat == curDat){
//befDatとcurDatが一致したときの処理
if(!inputMatch){
matchCnt++;
if(matchCnt >=2){ //2回以上一致したらフラッグを立てる
inputMatch = 1;
val = CheckEnc(curDat); //回転方向判定
if(val == 1){
Freq += STEP;
}
if(val == -1){
Freq -= STEP;
}
if(Freq != Freq_old){ //周波数が変化したらDDSに周波数データを送り周波数を更新
Fnc_DDS(Freq);
Freq_disp(Freq);
Freq_old = Freq;
}
}
}
}else{
//befDatとcuDatが一致しなかった時の処理
__delay_ms(1);//1ms待つ
befDat = curDat;
matchCnt = 0;
inputMatch = 0;
}
}
}
/* STEP SWが押されたらSTEPを変更 */
step_val = SW_step;
if((step_val == 0)&&(step_old == 1)){
Step_change();
}
step_old = step_val;
/*ロータリーエンコーダ処理*/
curDat = 0;
if(ECA){
curDat |= 2;
}
if(ECB){
curDat |= 1;
}
if(befDat == curDat){
//befDatとcurDatが一致したときの処理
if(!inputMatch){
matchCnt++;
if(matchCnt >=2){ //2回以上一致したらフラッグを立てる
inputMatch = 1;
val = CheckEnc(curDat); //回転方向判定
if(val == 1){
Freq += STEP;
}
if(val == -1){
Freq -= STEP;
}
if(Freq != Freq_old){ //周波数が変化したらDDSに周波数データを送り周波数を更新
Fnc_DDS(Freq);
Freq_disp(Freq);
Freq_old = Freq;
}
}
}
}else{
//befDatとcuDatが一致しなかった時の処理
__delay_ms(1);//1ms待つ
befDat = curDat;
matchCnt = 0;
inputMatch = 0;
}
}
}
----------------------------------------------------