元プログラムはこちらです⇒: PIC/16F1705のDAC(DAコンバータ)を使ってみた(ソース付き)
プログラム本体はダウンロードできるようにいつものところにおいてあります。zip解凍にパスコードが必要です。
あまり解説は要らないのかも知れませんが少しだけ。追加したところのみ。
FOSC=ECH で外部クロック(高速High)を指定。
PLLEN=ON でソフトウェア内部でクロック4倍を指定。
・asm("OPCODE xx"); を使ってアセンブラを書きます。
・コンパイル時にワーニングが出ますが、バンクセレクトの問題です。
・配列の値を直接DAC1CON1に書き込むようにすると(WREGにイミディエット値ロードとDAC1CON1へのストア)2命令で済みます。
・ループの最後から先頭に戻るGOTO命令が2命令サイクル分かかるので、最後の書き込み以外は仕方なくNOPを2つ追加しています。
・以上4命令を1セットとして64個書きます(ただし最後の64番目はNOPなしの2命令)
・正弦波の上端か下端部分の電圧設定を端折って、63書き込み(上記は64書き込み)NOPなしにすれば周波数はさらに2倍上げることができます。GOTO分が命令2サイクル長なので。
・可変抵抗を1MΩにすればさらに低い周波数も出せるようになりますが、その分、微調整が難しくなると思います。
・PLLENをConfigurationBitで指定しないようにして、ディップスイッチで外部で4倍、1倍を切り替えられるようにできるかも(まだ思いつきレベル)
-----------追記----------
#define マクロを使って4命令をまとめると短く書くことができるようになります。
VOUT(x)というのを定義してパラメータが渡せるようにしました。
ダウンロードしたものとHEXファイルは違いがないはずですが、こちらのほうが見通しがよくなります。
-----------プログラムはここから----------
プログラム本体はダウンロードできるようにいつものところにおいてあります。zip解凍にパスコードが必要です。
あまり解説は要らないのかも知れませんが少しだけ。追加したところのみ。
#pragma config WDTE=OFF,FOSC=ECH,PLLEN=ON
FOSC=ECH で外部クロック(高速High)を指定。
PLLEN=ON でソフトウェア内部でクロック4倍を指定。
void main()
{
asm("MOVLB 0x02"); // バンクセレクトレジスタでDAC1CON1のバンクを指定
{
OSCCON = 0b11110000;
DAC1CON0 = DAC1EN | DAC1OE2 | DAC1PSS_VDD | DAC1NSS_VSS;
OPA2CON = OPAxEN | OPAxSP_Low | OPAxUG_ON | OPAxCH_DAC;
while(1) {
asm("MOVLW 0x80"); // いわゆるインライン展開^^;
asm("MOVWF DAC1CON1"); // テーブルジャンプだと5サイクル必要なところ
asm("NOP"); // 即値で書けば命令は2サイクルで済みます
asm("NOP"); // NOPが2つあるのはループ最後のGOTO分のサイクル長
:
:
asm("MOVLW 0x76");
asm("MOVWF DAC1CON1"); // この後ろにNOP2つが無いのでぴったり4サイクルで1電圧設定
}
}
・asm("OPCODE xx"); を使ってアセンブラを書きます。
・コンパイル時にワーニングが出ますが、バンクセレクトの問題です。
・配列の値を直接DAC1CON1に書き込むようにすると(WREGにイミディエット値ロードとDAC1CON1へのストア)2命令で済みます。
・ループの最後から先頭に戻るGOTO命令が2命令サイクル分かかるので、最後の書き込み以外は仕方なくNOPを2つ追加しています。
・以上4命令を1セットとして64個書きます(ただし最後の64番目はNOPなしの2命令)
・正弦波の上端か下端部分の電圧設定を端折って、63書き込み(上記は64書き込み)NOPなしにすれば周波数はさらに2倍上げることができます。GOTO分が命令2サイクル長なので。
・可変抵抗を1MΩにすればさらに低い周波数も出せるようになりますが、その分、微調整が難しくなると思います。
・PLLENをConfigurationBitで指定しないようにして、ディップスイッチで外部で4倍、1倍を切り替えられるようにできるかも(まだ思いつきレベル)
-----------追記----------
#define マクロを使って4命令をまとめると短く書くことができるようになります。
VOUT(x)というのを定義してパラメータが渡せるようにしました。
ダウンロードしたものとHEXファイルは違いがないはずですが、こちらのほうが見通しがよくなります。
-----------プログラムはここから----------
#include <xc.h>
#include <math.h>
//#define _XTAL_FREQ 500000 // delay用クロック設定は今回不要
// DAC1CON0
#define DAC1EN 0x80
#define DAC1OE2 0x10
#define DAC1PSS_VDD 0x00
#define DAC1NSS_VSS 0x00
// OPAxCON
#define OPAxEN 0x80
#define OPAxSP_High 0x40 // 扱う周波数が高いときはこちらの方が安全でしょう。
#define OPAxSP_Low 0x00
#define OPAxUG_ON 0x10
#define OPAxCH_DAC 0x02
#define VOUT(x) asm("MOVLW "#x); asm("MOVWF DAC1CON1"); asm("NOP"); asm("NOP")
#pragma config WDTE=OFF,FOSC=ECH,PLLEN=ON
void main()
{
OSCCON = 0b11110000;
DAC1CON0 = DAC1EN | DAC1OE2 | DAC1PSS_VDD | DAC1NSS_VSS;
OPA2CON = OPAxEN | OPAxSP_Low | OPAxUG_ON | OPAxCH_DAC;
asm("MOVLB 0x02"); // バンクセレクトレジスタでDAC1CON1のバンクを指定
while(1) {
VOUT(0x80); VOUT(0x89); VOUT(0x93); VOUT(0x9D);
VOUT(0xA6); VOUT(0xAF); VOUT(0xB7); VOUT(0xBF);
VOUT(0xC6); VOUT(0xCD); VOUT(0xD3); VOUT(0xD8);
VOUT(0xDC); VOUT(0xDF); VOUT(0xE2); VOUT(0xE3);
VOUT(0xE4); VOUT(0xE3); VOUT(0xE2); VOUT(0xDF);
VOUT(0xDC); VOUT(0xD8); VOUT(0xD3); VOUT(0xCD);
VOUT(0xC6); VOUT(0xBF); VOUT(0xB7); VOUT(0xAF);
VOUT(0xA6); VOUT(0x9D); VOUT(0x93); VOUT(0x89);
VOUT(0x80); VOUT(0x76); VOUT(0x6C); VOUT(0x62);
VOUT(0x59); VOUT(0x50); VOUT(0x48); VOUT(0x40);
VOUT(0x39); VOUT(0x32); VOUT(0x2C); VOUT(0x27);
VOUT(0x23); VOUT(0x20); VOUT(0x1D); VOUT(0x1C);
VOUT(0x1B); VOUT(0x1C); VOUT(0x1D); VOUT(0x20);
VOUT(0x23); VOUT(0x27); VOUT(0x2C); VOUT(0x32);
VOUT(0x39); VOUT(0x40); VOUT(0x48); VOUT(0x50);
VOUT(0x59); VOUT(0x62); VOUT(0x6C);
asm("MOVLW 0x76");
asm("MOVWF DAC1CON1");
}
}