ORANGE pico と GROVE - 高精度RTC でカレンダー付き時計を作ってみた。
プログラム
10 mptr 16
20 mdata 64,160,160,224,160,160,64,0,64,192,64,64,64,64,224,0,64,160,32,64,64,128,224,0,64,160,32,64,32,160
30 mdata 64,0,32,96,160,160,224,32,32,0,224,128,192,160,32,160,64,0,64,160,128,192,160,160,64,0,224,160,32,64
40 mdata 64,64,64,0,64,160,160,64,160,160,64,0,64,160,160,96,32,160,64,0
50 yearx=10:yeary=45:monthx=75:monthy=45:datex=10:datey=75:dayy=60:datedx=12:datedy=12
60 clockcx=220:clockcy=100:clockor=90:clockir=80:clocksr=70:clockmr=50:clockhr=30:clockmw=6:clockhw=10
70 white=rgb(255,255,255):yearcolor=white:monthcolor=white:dim daycolor(6)=[white,white,white,white,white,white,white]:ccolor=white:scolor=white:mcolor=white:hcolor=white
80 dim xydrawn(8,3):dim xytodraw(8,3):ydrawn=-1:mdrawn=-1:ddrawn=-1:csdrawn=-1:cmdrawn=-1:chdrawn=-1
90 cls:dpi!=atan(1)*8:dim daychars(6)=[&H93FA,&H8C8E,&H89CE,&H9085,&H96D8,&H8BE0,&H9379]
100 circle clockcx,clockcy,clockor,ccolor
110 for i=0 to 11
120 angle! = dpi!*i/12:cosine! = cos(angle!):sine! = sin(angle!)
130 odx=floor(clockor*sine!+0.5):ody=floor(clockor*cosine!+0.5):idx=floor(clockir*sine!+0.5):idy=floor(clockir*cosine!+0.5)
140 line clockcx+odx,clockcy-ody,clockcx+idx,clockcy-idy,ccolor
150 next
160 for i=0 to 6
170 cpeek daychars(i) & &HFFFF:gput datex+datedx*i,dayy,8,8000,daycolor(i) & &HFFFF
180 next
190 if i2cw(2,&H51,"\x00",0)<>0 then pause 500:goto 190
200 if i2cr(2,&H51,11,1)<>0 then pause 500:goto 190
210 rawyear=mpeek(10):year=2000 + ((rawyear & &HF0) >> 4) * 10 + (rawyear & &H0F)
220 rawmonth=mpeek(9):month=((rawmonth & &H10) >> 4) * 10 + (rawmonth & &H0F)
230 rawdate=mpeek(7):date=((rawdate & &H30) >> 4) * 10 + (rawdate & &H0F)
240 rawhour=mpeek(6):if mpeek(0) & 2 then hour=(((rawhour & &H10) >> 4) * 10 + (rawhour & &H0F) + ((rawhour & &H20) >> 5) * 12)%12 else hour=(((rawhour & &H30) >> 4) * 10 + (rawhour & &H0F))%12
250 rawminute=mpeek(5):minute=((rawminute & &H70) >> 4) * 10 + (rawminute & &H0F)
260 rawsecond=mpeek(4):second=((rawsecond & &H70) >> 4) * 10 + (rawsecond & &H0F)
270 if year==ydrawn && month==mdrawn && date==ddrawn && hour==chdrawn && minute==cmdrawn && second==csdrawn then goto 190
280 clt
290 if year==ydrawn && month==mdrawn && date==ddrawn then goto 530
300 zelleryear=year:zellermonth=month:if month<=2 then zelleryear=zelleryear-1:zellermonth=zellermonth+12
310 zellerc=zelleryear/100:zellery=zelleryear%100:zellergamma=5*zellerc+zellerc/4
320 day=(1+26*(zellermonth+1)/10+zellery+zellery/4+zellergamma+6)%7
330 if month==2 then finalday=28+(year%400==0 || (year%4==0 && year%100<>0)) else finalday=30+((month%2)^(month>=8))
340 for i=0 to 7
350 line yearx,yeary+i,yearx+32,yeary+i,0:line monthx,monthy+i,monthx+16,monthy+i,0
360 next
370 for i=-2 to datedy*5+8
380 line datex-2,datey+i,datex+datedx*7+8,datey+i,0
390 next
400 gprint yearx,yeary,format$("%4d",year),yearcolor:gprint monthx,monthy,format$("%2d",month),monthcolor
410 currenty=datey
420 for i=1 to finalday
430 currentx=datex+datedx*day:currentc=daycolor(day) & &HFFFF
440 if i>=10 then gput currentx,currenty,8,16+8*(i/10),currentc
450 gput currentx+4,currenty,8,16+8*(i%10),currentc
460 if i<>date then goto 490
470 line currentx-2,currenty-2,currentx+8,currenty-2,currentc:line currentx-2,currenty-2,currentx-2,currenty+8,currentc
480 line currentx+8,currenty+8,currentx+8,currenty-2,currentc:line currentx+8,currenty+8,currentx-2,currenty+8,currentc
490 day=day+1
500 if day>=7 then day=0:currenty=currenty+datedy
510 next
520 ydrawn=year:mdrawn=month:ddrawn=date
530 for i=0 to 8
540 line xydrawn(i,0),xydrawn(i,1),xydrawn(i,2),xydrawn(i,3),0
550 next
560 sangle! = dpi!*second/60:mangle! = dpi!*(minute+second/60.0)/60:hangle! = dpi!*(hour+minute/60.0+second/3600.0)/12
570 ssin! = sin(sangle!):scos! = cos(sangle!):msin! = sin(mangle!):mcos! = cos(mangle!):hsin! = sin(hangle!):hcos! = cos(hangle!)
580 sine! = hsin!:cosine! = hcos!:dx! = -clockhw/2.0:dy! = clockhr:gosub 910
590 xytodraw(0,0)=ox:xytodraw(0,1)=oy:xytodraw(1,0)=ox:xytodraw(1,1)=oy
600 dx! = clockhw/2.0:gosub 910
610 xytodraw(0,2)=ox:xytodraw(0,3)=oy:xytodraw(3,2)=ox:xytodraw(3,3)=oy
620 dy! = 0:gosub 910
630 xytodraw(2,0)=ox:xytodraw(2,1)=oy:xytodraw(3,0)=ox:xytodraw(3,1)=oy
640 dx! = -clockhw/2.0:gosub 910
650 xytodraw(1,2)=ox:xytodraw(1,3)=oy:xytodraw(2,2)=ox:xytodraw(2,3)=oy
660 sine! = msin!:cosine! = mcos!:dx! = -clockmw/2.0:dy! = clockmr:gosub 910
670 xytodraw(4,0)=ox:xytodraw(4,1)=oy:xytodraw(5,0)=ox:xytodraw(5,1)=oy
680 dx! = clockmw/2.0:gosub 910
690 xytodraw(4,2)=ox:xytodraw(4,3)=oy:xytodraw(7,2)=ox:xytodraw(7,3)=oy
700 dy! = 0:gosub 910
710 xytodraw(6,0)=ox:xytodraw(6,1)=oy:xytodraw(7,0)=ox:xytodraw(7,1)=oy
720 dx! = -clockmw/2.0:gosub 910
730 xytodraw(5,2)=ox:xytodraw(5,3)=oy:xytodraw(6,2)=ox:xytodraw(6,3)=oy
740 sine! = ssin!:cosine! = scos!:dx! = 0:dy! = clocksr:gosub 910
750 xytodraw(8,0)=clockcx:xytodraw(8,1)=clockcy:xytodraw(8,2)=ox:xytodraw(8,3)=oy
760 for i=0 to 3
770 line xytodraw(i,0),xytodraw(i,1),xytodraw(i,2),xytodraw(i,3),hcolor
780 next
790 for i=4 to 7
800 line xytodraw(i,0),xytodraw(i,1),xytodraw(i,2),xytodraw(i,3),mcolor
810 next
820 line xytodraw(8,0),xytodraw(8,1),xytodraw(8,2),xytodraw(8,3),scolor
830 for i=0 to 8
840 for j=0 to 3
850 xydrawn(i,j)=xytodraw(i,j)
860 next
870 next
880 t=tick():if t<55 then pause 1000*(55-t)/55
890 chdrawn=hour:cmdrawn=minute:csdrawn=second
900 goto 190
910 ox=clockcx+floor(dx!*cosine!+dy!*sine!+0.5):oy=clockcy+floor(dx!*sine!-dy!*cosine!+0.5):return
このプログラムは、CC BY 4.0 でライセンスする。
このプログラム (改造したものを含む) を公開の場で利用する際は、出典を示していただけると嬉しい。
これは、Qiitaの利用規約に基づくプログラムの利用を禁止するものではない。
実行結果例
解説
10~40行目:フォント定義
カレンダーで使用する美咲フォント (美咲ゴシック第2) の半角数字のフォントを用意している。
メモリー配列の先頭部分はRTCとのI2C通信で使用するので、少し後からデータを格納している。
50~70行目:パラメータ定義
描画に使用する座標や色を定義している。
パラメータの意味は以下の通りである。
パラメータ | 意味 |
---|---|
yearx, yeary | カレンダーの「年」を描画する左上の座標 |
month, monthy | カレンダーの「月」を描画する左上の座標 |
datex, datey | カレンダーの「日」を描画する左上の座標 |
dayy | カレンダーの「曜日」を描画する左上のy座標 (x座標はdatex) |
datedx, datedy | カレンダーの「日」1個あたりの横と縦の幅 |
clockcx, clockcy | 時計の中心の座標 |
clockor | 時計の外側の円の半径 |
clockir | 時計の目盛の内側の半径 |
clocksr | 時計の秒針の長さ |
clockmr, clockmw | 時計の分針の長さと幅 |
clockhr,clockhw | 時計の時針の長さと幅 |
yearcolor | カレンダーの「年」の描画色 |
monthcolor | カレンダーの「月」の描画色 |
daycolor | カレンダーの各曜日とその「日」の描画色 |
ccolor | 時計の外枠と目盛の描画色 |
scolor | 時計の秒針の描画色 |
mcolor | 時計の分針の描画色 |
hcolor | 時計の時針の描画色 |
80行目:描画状態を格納する変数の定義
描画を行った日時、および時計の針の描画の座標を格納する変数を用意する。
90~180行目:固定のUIの描画
画面の日時によって変化しない部分を描画する。
- 90行目:画面をクリアし、円周率の2倍
dpi!
および各曜日の文字コードを用意する。 - 100~150行目:時計の外枠を描画する。
- 160~180行目:カレンダーの曜日を描画する。
190~260行目:RTCからの日時の取得
I2C2バスに接続された高精度RTCから時刻データを取得する。
- 190~200行目:RTCと通信を行い、レジスタのデータを取得する。
- 210~260行目:取得したデータをデコードし、時刻情報を取り出す。
270~910行目:日時の描画
270~280行目:描画の準備
- 270行目:時刻が変わっていない場合、描画せず時刻のポーリングに戻る。
- 280行目:無駄な通信を減らすための待機のため、
tick()
の時刻を初期化する。
290~520行目:カレンダーの描画
- 290行目:日付が変わっていなければ、描画をスキップする。
- 300~320行目:ツェラーの公式を用いて、現在の月の最初の日の曜日を求める。
- 330行目:現在の月が何日まであるかを求める。
- 340~390行目:現在描画されているカレンダーを消去する。
- 400行目:年と月を描画する。
- 410~510行目:カレンダーを描画する。
- 430~450行目:日を描画する。
- 460~480行目:現在の日を四角で囲む。
- 490~500行目:描画位置を進める。
- 520行目:描画した日付を記録する。
530~910行目:時計の描画
- 530~550行目:前回描画した針を消去する。
- 560行目:それぞれの針の角度を求める。
- 570行目:それぞれの針の角度に対応する正弦と余弦を求める。
- 580~650行目:時針の描画位置を計算する。
- 660~730行目:分針の描画位置を計算する。
- 740~750行目:秒針の描画位置を計算する。
- 760~780行目:時針を描画する。
- 790~810行目:分針を描画する。
- 820行目:秒針を描画する。
- 830~870行目:描画した座標を記録する。
- 880行目:無駄な通信を減らすため、1秒弱待機する。
- 890行目:描画した時刻を記録する。
- 900行目:時刻のポーリングに戻る。
- 910行目:針の描画位置を計算するためのサブルーチン。