
写真1 AD9833 DDS MSOP 0.5ピッチ 変換基板に乗せる
それはさておき、
このチップは10ピンのMSOPで、写真にようにピンセットの先ほどの大きさです。
変換基板に取り付けましたが、ピンのピッチは0.5なので、半田付けにはちょっと技術が必要です。
まずチップをゲルタイプの瞬間接着剤で正確な位置に仮止めしておきます。
フラックスをほんのわずか塗って、すべてのピンにわざとまたがるくらい半田を盛ります。
半田吸い取り線で、余分な半田を吸い取って、出来上がり。
慣れれば簡単ですが、最初は数個パーにする覚悟がいります(笑)。
このDDSは、マスタクロック(MCLK)周波数は最高25MHzで、その場合最高発振周波数(ナイキスト周波数)は12.5MHzとなり、分解能は0.1Hzです。
今回は手持ち部品の関係で、20MHzのクリスタルを使用したので、10MHzまでのプログラマブルオシレータとして、実験してみました。この場合の分解能は約0.075Hzです。

写真1 時刻調整ボタンを追加したPSoClk ロータリーエンコーダとSDカードは関係ありません
赤ボタンで定常モードから時刻設定モードに入り、設定項目を指定します。選択された項目にカーソルが表示されます。押すたびに、時->分->秒->年->月->日の順でカーソルが移動し、変更できることを示します。
日が選択されているときに、さらに赤ボタンを押すと、定常モードに戻ります。
青ボタンを押すとカーソル位置の項目を+1します。定常モードでは効きません。
黄ボタンを押すとカーソル位置の項目を-1します。定常モードでは効きません。
+1, -1は有効な範囲(日なら1から31)をチェックせずuint8を単純に加減算しているので、0から255までの値をとりますが、設定には支障はありません。
緑ボタンは定常状態で効くボタンで、秒を0リセットします。年月日、時分を設定後、秒を0ジャスティファイするためのものです。最近は毎時の時報で合わせなくても、電波時計を見ながら毎分で合わせられるので、このようにしています。
各ボタンは押し続けると連続で機能します。
【Schematic】

今回追加したのは、4つのデジタル入力コンポーネントです。タクトスイッチを押すとグランドに落ちる負論理(LOW True)にしました。このためスイッチがオープンのときに確実にHighになるよう、プルアップに設定しておきます。
このようなスイッチは常にチャッタリングが起こる可能性があるので、防止方法としては簡易な方法ですが、数ms後再度レベルを確認して、Lowであれば押されたと認識するようにしています。
PSoC3を時計にしておくのは少々もったいないですね。データのロギング用タイマーや、ファイルシステムの時計、汎用タイマーなど、いろいろ応用できそうです。
【Program】
//main.c(今回変更部分のみ)
#define WAIT_MS 5 //チャッタリング防止用(要調整) 5 = 5ms
void RTC_Change(){
RTC_Stop();
RTC_WriteTime(RTC_Current);
RTC_WriteIntervalMask(RTC_INTERVAL_SEC_MASK);
RTC_Start();
}
void Set_CursorPos(uint8 pos){
switch (pos){
case 0: //normal
I2C_LCD_CursorOff();
break;
case 1: //hour
I2C_LCD_SetCursor(8, 0);
break;
case 2: //min
I2C_LCD_SetCursor(11, 0);
break;
case 3: //year
I2C_LCD_SetCursor(4, 1);
break;
case 4: //month
I2C_LCD_SetCursor(7, 1);
break;
case 5: //day
I2C_LCD_SetCursor(10, 1);
break;
default:
break;
}
}
void main(){
uint8 change_pos;
CyGlobalIntEnable;
RTC_Setup();
I2C_Start();
I2C_LCD_Init();
I2C_LCD_WriteString(0, 0, "PSoClk" );
I2C_LCD_WriteString(5, 1, "/" );
I2C_LCD_WriteString(8, 1, "/" );
I2C_LCD_WriteString(9, 0, ":" );
I2C_LCD_WriteString(12, 0, ":" );
change_pos = 0;
for ( ;; ){
if(interval_flag){
if(change_pos == 0) DispClock();
interval_flag = 0;
}
if(RED_SW_Read() == 0){
CyDelay(WAIT_MS);
if(RED_SW_Read() == 0) {
change_pos++;
if(change_pos == 6) change_pos = 0;
Set_CursorPos(change_pos);
}
}
if(change_pos != 0){
if(BLUE_SW_Read() == 0){ //+1
CyDelay(WAIT_MS);
if(BLUE_SW_Read() == 0) {
switch (change_pos){
case 1:
RTC_Current->Hour++;
break;
case 2:
RTC_Current->Min++;
break;
case 3:
RTC_Current->Year++;
break;
case 4:
RTC_Current->Month++;
break;
case 5:
RTC_Current->DayOfMonth++;
break;
default:
break;
}
}
}
if(YELLOW_SW_Read() == 0){ //-1
CyDelay(WAIT_MS);
if(YELLOW_SW_Read() == 0) {
switch (change_pos){
case 1:
RTC_Current->Hour--;
break;
case 2:
RTC_Current->Min--;
break;
case 3:
RTC_Current->Year--;
break;
case 4:
RTC_Current->Month--;
break;
case 5:
RTC_Current->DayOfMonth--;
break;
default:
break;
}
}
}
RTC_Change();
DispClock();
Set_CursorPos(change_pos);
}else{ //change_pos = 0
if(GREEN_SW_Read() == 0){ //sec justify
CyDelay(WAIT_MS);
if(GREEN_SW_Read() == 0) {
RTC_Current->Sec = 0;
RTC_Change();
DispClock();
}
}
}
CyDelay(100); //nothing to do
}
}
(JF1VRR)