2014年6月28日土曜日

PICで正弦波を

またまたPICネタであります。

キーヤーは最後の詰めに入っていますが、その前にプログラムしたDDS-VFO トランシーバー制御システムにもサイドトーンをPIC内部で発生させようと考えています。ただ単にブザーオンオフではつまらないので、正弦波に近いトーンをPICから直接発生させるといいなと思いました。

波形発生方法としては、1つのポート系列をすべてつかってラダー抵抗で8bitD/A変換する方法とPIC内蔵のPWMモジュールを使う方法がありますが、ポート数の関係からPWMモジュールでやってみることにしました。専用のD/A変換ICを使うのもよいですが、PIC単独でやらせたいので今回は却下です。

 PWMモジュールを使う場合は搬送波の周波数を高くする必要があるためキーヤーのクロック周波数4MHzでは600Hzのまともな正弦波はつくれません(AFフィルター通せば正弦波になりますがそれではあまり面白くない(笑))。なのでキーヤープログラムのほうは搬送波そのものを600Hz周辺で発生させています。もちろん方形波ですがサウンダを鳴らす分には方形波でも問題ないのでこのままにしてます。今回は対象をDDS-VFOトランシーバー制御システムに使っている18F26K22 32MHzに想定して、同じPICを使って実験してみました。

 プログラムにあたってまず、搬送波周波数をどうするかです。PWMはある一定のパルス幅をもつ搬送波のデューティーサイクルをプログラムのデータに従って変化させることで出力レベルを変化させるという方法です。搬送波のタイミングで波形が分割される(サンプリングされる)というイメージで、ある正弦波の一周期に対する分割は細かいほど元の波形がより正確に再現できるというわけです。

どこかの情報ですと(出所失念^^;)出力したい最大周波数の20倍以上が必要とのこと。サイドトーンとして使われる周波数は400~800Hz程度なので搬送波周波数は最低16kHzということになります。それよりも高ければ高いほどよさそうですが、その分波形データが必要になるのとPWMのデューティーサイクルの階調が制限されます(PICのクロック周波数は一定なので)。っていうもろもろの要素を鑑みた結果大体32kHzあたりが妥当のようです。

そうなると、正弦波1周期分で800Hzなら40、400Hzなら80分割のデータを用意できればOKです。600Hzでは整数で分割できないので、近いところで約615kHzの52分割データ用意としました。

PWMの出力はDDS-VFOシステムでの空きピンを割り当てます。今回はPWM出力可能なRB4ピン(CCP1/P1D)とし、PWMタイムベースをTimer4に設定。この条件で各レジスタ設定値をメイン関数内の初期化プロセスに記述していきます。その後のループ処理内には、Timer4のタイミングフラグが立つごとにあらかじめ用意した正弦波のデータを順々に読み込ませてデューティーサイクル設定レジスタ(CCPR1L)にコピーするという処理を書き込みます。

正弦波データをプログラムで計算させるのは8ビットPICではきついので、あらかじめ表計算ソフトで算出したデータをromに入れておくことにします。計算方法は、1周期360度を分割数で割った角度ごとのsinまたはcos値を求めてそれぞれに1を加え(負の数をなくすため)階調(今回は250階調にしました)の半分を乗算し、小数点以下を四捨五入して整数化した値を1元配列におさめます。階調は10ビットまで指定できますが、上位2ビット分は別のレジスタになるのでデータを2元配列にするなど少々手間がかかります。
 
表計算ソフトでデータ作成 400Hzと800Hzは共通です なぜだかわかりますよね
 あとは、お決まりのconfigビットの設定文、クロック関連、ポート関連のレジスタを記述していきます。

そうやって出来上がったプログラムをPickit3で注入しました。

お城で観察。

RB4ポート出力波形 パルス幅が徐々に変化してますね

ポートから適当なRCフィルタを通した波形 ギザギザ^^;

スピーカーから出てくる音は正弦波に近い結構澄んだ音になってます。ギザギザは搬送波の成分なのでスピーカーでは出力されませんからね。

比較的簡単に正弦波もどきは出せるようです。18F26K22ではプログラムメモリ消費も微々たるものなので、DDS-VFOトランシーバー制御システムのサイドトーン発生プログラムに採用しようと思います。

以下サンプルプログラムです。出力周波数600Hz(正確には615Hz)

//
// 18F26K22 PWM Tone Generator
// JL1VNQ/HARU
//
// PWM base frequency 32kHz, Tone frequency 800Hz, 40 divisions = 9 degree
// PWM base frequency 32kHz, Tone frequency 600(615)Hz, 52 divisions = 6.92307 degree
// PWM base frequency 32kHz, Tone frequency 400Hz, 80 divisions = 4.5 degree
// resolution nearly 10bits (1000steps < 1024)
//

#include    <xc.h>

#pragma config FOSC = INTIO67, PLLCFG = ON, PRICLKEN = ON, FCMEN = OFF, IESO = OFF
#pragma config PWRTEN = OFF, BOREN = SBORDIS, BORV = 190
#pragma config WDTEN = OFF
#pragma config MCLRE = INTMCLR, HFOFST = OFF, PBADEN = ON
#pragma config XINST = OFF, STVREN = ON, LVP = OFF, DEBUG = OFF
#pragma config CP1 = OFF, CP0 = OFF, CP2 = OFF, CP3 = OFF
#pragma config CPB = OFF, CPD = OFF
#pragma config WRT1 = OFF, WRT0 = OFF, WRT2 = OFF, WRT3 = OFF
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF
#pragma config EBTR1 = OFF, EBTR0 = OFF, EBTR2 = OFF, EBTR3 = OFF
#pragma config EBTRB = OFF

#define EEPROM_SIZE     1024
#define _XTAL_FREQ      32000000

#define PWM_OUT PORTB,4        // CCS1/P1D

const unsigned char SIN400[80]={
    125,135,145,154,164,173,182,190,198,206,
    213,220,226,232,236,240,244,247,248,250,
    250,250,248,247,244,240,236,232,226,220,
    213,206,198,190,182,173,164,154,145,135,
    125,115,105,96,86,77,68,60,52,44,
    37,30,24,18,14,10,6,3,2,0,
    0,0,2,3,6,10,14,18,24,30,
    37,44,52,60,68,77,86,96,105,115
};

const unsigned char SIN600[52]={       // divisions number is "multiple of 4" recomended
    125,140,155,169,183,196,208,219,228,236,
    242,246,249,250,249,246,242,236,228,219,
    208,196,183,169,155,140,125,110,95,81,
    67,54,42,31,22,14,8,4,1,0,
    1,4,8,14,22,31,42,54,67,81,
    95,110
};

void main(void){
   
    OSCCON = 0x64;          // 8MHz internal clock, primary clock (IMPORTANT!! NOT SELECT "internal OSC" for PLL)
    OSCCON2 = 0x04;            // OSC drive circuit on
    OSCTUNE = 0x40;            // 4xPLL enable, calibration = 0

    ANSELA = 0x00;
    ANSELB = 0x00;
    ANSELC = 0x00;
   
    TRISA = 0x00;
    TRISB = 0x00;
    TRISC = 0x00;
    TRISE = 0x08;
   
    CCP1CON = 0x0C;            // PWM mode
    CCPTMRS0 = 0x01;           // TMR4 use for PWM time base
    PSTR1CON = 0x08;           // only P1D

    T4CON = 0x04;              // prescaler 0, postscaler 0, TMR4ON
    PR4 = 249;                 // 32kHz, resolution 1000steps
    CCPR1L = 125;              // Duty cycle initialize
   
    while(1){       
        static unsigned char i = 0;
        if(PIR5bits.TMR4IF){
            PIR5bits.TMR4IF = 0;
            i++;
            CCPR1L = SIN600[i];
            if(i > 51) i = 0;
        }
    }
}


2014年6月17日火曜日

PICで作るキーヤー

ここのところ週末の予定が空かず、移動運用もしばらくお休み中です。
そんな中各PICのプログラムをちまちまと進めています。

いま主に進めているのが、キーヤーのプログラムです。いまさら?って感じかもしれませんが、コンテストや移動運用のときにリグ内蔵のキーヤーでは機能的に十分でも即時に速度調整などが難しく、別によく使っているKD1JV TriBand CW transceiverやTX-136の内蔵キーヤーもフィーリングがどうも自分にはあわないため、ある程度機能も充実させたものを自分で作ろうというのが製作意図です。

ハード的には、PICは16F1827の1本でI2CキャラクタLCD表示器(AE-AQM0802)、設定用ロータリーエンコーダ、サイドトーン出力とPTT出力、メッセージメモリ選択ボタンつきで、単三乾電池2本の3V動作としました。


ソフトウエアによるキーヤーの仕様は、

・キーヤー動作モード:Iambic A, B, バグキーエミュレーション, メッセージメモリー
・長短点メモリあり(50%),長短点比3:1
・符号送出速度:10~60WPMで1WPMステップ可変
・PTT出力:セミ(200msec delay)/フルブレークイン
・パドル極性:ノーマル/リバース
・サイドトーン:PWMモジュールによる出力(周波数400,600,800Hz),ミュート
・メニュー呼び出し,ロータリーエンコーダによる各設定とEEPROMへ保存による設定値の保持
・60キャラクター(スペース除く)x 4chのメッセージメモリ記録,再生
・スリープ機能

とまぁ結構盛り沢山になりました。

ソフトウエアはCで記述し、Microchip社純正のXC8コンパイラで実行ファイルを作ってPickit3でPICに転送しています。

今のところメッセージ記録部分とスリープ機能の実装が残るだけとなっていますが、完成したら一部DDS-VFOシステムに取り込むほか、プログラムの流れや実行ファイルを後日公開してみようかなと思います。途中経過のソースファイルは、すでにGoogle+のコミュニティにぼちぼち公開していますので興味のある方は登録してみてください。

もっとプログラミングに慣れたら、オープン開発のサイトにも登録を考えてみたいのですが、果たしてどうなることやら...

ソースの一部 各スイッチ状態をタイマー0割り込みで1msec毎に監視して状態フラグを立てる

BBで仮組み状態 消費電流は無負荷動作時1.6mA

LCD付きでこの消費電流なら乾電池動作いけそうかな。スクイーズ動作も自分の感覚の基準では合格点といったところです。

2014年6月10日火曜日

やりたいことがいろいろあって

やりたいことがたくさんありすぎると、逆にどれも進まなくなってしまうという状態になりがちではないでしょうか。優先順位をつけるのもままならず、折角時間あってもただただ無為に過ごしてしまうという罠にはまっているようです。

そんなわけでとりあえずはやりたいこと、または現在やりかけていることをおさらいしてみることに。

まずは、

136kHz帯の24時間稼動グラバーの設置

アンテナは同調型Mini-whipとし、受信機はDC型のSDRを自作してUSBサウンドモジュールを接続したRaspberry Piで取り込みスナップショットをアップロードするという計画です。Linux用のQRSS受信ソフトはglferとLOPORAがありますが、LOPORAはスナップショットが撮れるので必要なライブラリとソフトをインストールして起動はできるところまでこぎつけましたが、サウンド入力がうまくできなくてそこで今はとまっています。

TX-136の汎用FSK対応について

WSQやJT-9などの多値FSKモード対応のためDDSの周波数レジスタを1bit単位で外部からコントロールできるようにTX-136のファームウエアを再度変更する必要があります。プログラム修正はできましたが、まだ本体のPICを書き換えて検証していません。ファームウエア更新に伴いコントローラー側にも修正が必要で、一応アセンブリで書きなおしましたがたぶんバグ取りなどに時間がかかりそうなので保留中です。

CWトランシーバー用DDS VFOシステムと新型キーヤー


DDS VFOシステムのプログラムはほぼ完成して、ユニバーサル基板にアナログ部分とともに試作はじめようという段階、新型キーヤーはメッセージメモリなど残った機能の実装に向けて目下プログラム中。いまのところこれが一番近々完成しそうな案件です。

136kHzアンテナ用の2代目ローディングコイルの製作

100円ショップで見つけた径高さともに12cmの円筒形プラスチック製お味噌入れをボビンにして、すでに取り寄せた1kg巻き1mm径PEWを3層ピラミッド巻きにして小型高インダクタンスなコイルを作って車を使わない136kHz移動運用を実現したいと思っていますが、PEWで3層ピラミッド巻きは難しそうです。2層巻きではボビンに両面テープを巻きつけて最下層の線を固定しながら巻くことができますが、3層では2層目の固定に逐一接着剤が必要そうです。

などなど、無線電子工作関連以外にもいくつかあります(苦笑)

自分がもう一人欲しいですhi