0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ORANGE picoAdvent Calendar 2023

Day 11

ORANGE pico + RTC でカレンダー付き時計

Posted at

ORANGE picoGROVE - 高精度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行目:針の描画位置を計算するためのサブルーチン。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?