目次

Renesas対策再考

 試走を続けながら、部屋を片付けているとトランジスタ技術の
 付録になったR8C/Tinyを実装した基板が出てきました。



 他にETで配布されていたオークス電子のR8C/Tiny基板も発掘されました。




 同じR8C/Tinyでも、オークス電子の基板は11/12シリーズで
 I/Oピンが多く、8ビットのタイマーもひとつ多くなって
 います。

 正方形の基板にマイコンチップが実装されているので
 手半田の基板を作ったとしても使いやすい基板を実現
 できそうです。

 センサーは、Game Boy Cameraに接続したArduinoが担当しているので
 4ビットで与えられる路面情報を利用するなら、R8C/Tinyを利用して
 マシンを移動させてもよいのではないのかと思うようになりました。

 R8C/Tinyはピン数が少ないので、MCR_VCマシンを動かすためには
 どのくらいのピン数があればよいかを見直しします。

 32ピンのR8C/Tinyでも対応できそうなので、もう少し考えます。

 R8C/Tinyの11/12シリーズには、8ビットタイマーはX、Y、Zの3種。
 16ビットタイマーはCで1種。これらのタイマーをすべて利用すると
 モータに関係するPWM波形生成は、簡単でしょう。

 GPIOを利用したいとすれば、次のピンを利用できます。

 データシートにあるピン配置を眺めてみます。



 ピン配置から、次のように考えました。

 路面情報は、ポート1の下位4ビットで入力。
 ポート3は2、3ビットをDCモータ制御出力。
 ポート3の7ビットをサーボモータ制御出力。
 ポート1の7ビットをスタートゲートの状態入力。
 路面情報は、ポート0をデータバスとして外部レジスタに渡す。
 路面情報表示に、ポート3の0ビットを出力で利用。
 内部情報は、ポート0をデータバスとして外部レジスタに渡す。
 内部情報表示に、ポート3の1ビットを出力で利用。

 制御基板は以下のものがあるので、ワイヤーコネクションを
 変えて対応。




 R8C/Tinyは、MITSUBISHIのM16CをCPUコアにもつので
 I/O部分の修正程度で、ファームウエアを完成させる
 ことが可能でした。

 C言語を動かす前に必要なスタートアップルーチンでは
 I/Oの入出力と初期値およびタイマー関係の設定を記述
 すれば、H8、ArduinoのCソースを活用できます。

 メインプロセッサにR8C/Tinyを利用するので、Renesas
 が後援する大会に出しても、規定に抵触することはない
 と判断しました。



ファームウエア

 R8C/Tinyを使う場合、最も頭を悩ませたのは、クロック  処理でした。3つのクロックソースがあるのはよいです  が、関連するレジスタが散在し、設定するビットがバラ  けていて、日立のデータシートに勝るとも劣らないほど  わかりにくかったです。  クロックは、次のように指定しました。 INIT_CLK: ; disable PROTECT bset #0,PRCR0 ; change Xin,Xout bset #3,CM1 ; enable Xin,Xout bclr #5,CM0 ; no divide bclr #6,CM0 ; wait stable nop nop nop nop ; select main clock bclr #2,OCD ; enable PROTECT bclr #0,PRCR0 ; rts  ポートの入出力と初期値を指定。  (ポート1の下位ニブルは、プルアップ。) INIT_IO: ; port values mov.b #00h,P0 ; port_0 value mov.b #00h,P1 ; port_1 value mov.b #00h,P3 ; port_3 value ; port directions mov.b #0FFh,PD0 ; port_0 direction mov.b #050h,PD1 ; port_1 direction mov.b #0FFh,PD3 ; port_3 direction ; P1 lower nibble pull up bset #2,PUR0 ; rts  システムタイマーを1ms周期として、タイマーZを利用。  タイマーZのブロック図は、以下。  8ビットプリスケーラと8ビットカウンタを使い、次の  4モードが可能となっています。  システムタイマーをインクリメントするだけなので  タイマーモードを使うことに。  プリスケーラに入力するクロックソースは、以下。  1msは1kHzなので、プリスケーラとカウンタの値を  組み合わせてみると、以下。 40x250=10,000 80x250=20,000  プリスケーラで250分周し、カウンタで40か80分周すると  f1、f2を利用できるとわかります。  利用するレジスタは、TYZMR、TZPR、PREZとなります。  初期化は以下。 INIT_TZ: ; select clock f1 and.b #11001111b,TCSS ; select timer Z mode and.b #10001111b,TYZMR ; prescalar mov.b #39,PREZ ; divider mov.b #79,TZPR ; enable interrupt mov.b #00001001b,TZIC ; start timer Z bset #7,TYZMR ; rts  1msごとにイベントフラグのセットとカウンタを  インクリメントします。 INT_TZ: ; set flag bset #0,FLAGS ; increment inc.w TIMCNT ; reit  割込みを使う場合、ヴェクター方式なので次のように  ROMエリアの一部に展開していきます。 dummy_int: reit .section VVECTOR,ROMDATA .org 0FF00h VVECTOR_ADR: .lword dummy_int ; vector 0 (BRK) .lword dummy_int ; vector 1 (reserved) .lword dummy_int ; vector 2 (reserved) .lword dummy_int ; vector 3 (reserved) .lword dummy_int ; vector 4 (reserved) .lword dummy_int ; vector 5 (reserved) .lword dummy_int ; vector 6 (reserved) .lword dummy_int ; vector 7 (reserved) .lword dummy_int ; vector 8 (reserved) .lword dummy_int ; vector 9 (reserved) .lword dummy_int ; vector 10(reserved) .lword dummy_int ; vector 11(reserved) .lword dummy_int ; vector 12(reserved) .lword dummy_int ; vector 13(Key Input) .lword dummy_int ; vector 14(A/D converter) .lword dummy_int ; vector 15(reserved) .lword dummy_int ; vector 16(Timer C compare 1) .lword dummy_int ; vector 17(UART0 transmitt) .lword dummy_int ; vector 18(UART0 receive) .lword dummy_int ; vector 19(UART1 transmitt) .lword dummy_int ; vector 20(UART0 receive) .lword dummy_int ; vector 21(INT2 interrupt) .lword dummy_int ; vector 22(Timer X interrupt) .lword dummy_int ; vector 23(Timer Y interrupt) .lword INT_TZ ; vector 24(Timer Z interrupt) .lword dummy_int ; vector 25(INT1 interrupt) .lword dummy_int ; vector 26(INT3 interrupt) .lword dummy_int ; vector 27(Timer C overflow) .lword dummy_int ; vector 28(Timer C compare 0) .lword dummy_int ; vector 29(INT0 interrupt) .lword dummy_int ; vector 30(reserved) .lword dummy_int ; vector 31(reserved) .lword dummy_int ; vector 32 .lword dummy_int ; vector 33 .lword dummy_int ; vector 34 .lword dummy_int ; vector 35 .lword dummy_int ; vector 36 .lword dummy_int ; vector 37 .lword dummy_int ; vector 38 .lword dummy_int ; vector 39 .lword dummy_int ; vector 40 .lword dummy_int ; vector 41 .lword dummy_int ; vector 42 .lword dummy_int ; vector 43 .lword dummy_int ; vector 44 .lword dummy_int ; vector 45 .lword dummy_int ; vector 46 .lword dummy_int ; vector 47 .lword dummy_int ; vector 48 .lword dummy_int ; vector 49 .lword dummy_int ; vector 50 .lword dummy_int ; vector 51 .lword dummy_int ; vector 52 .lword dummy_int ; vector 53 .lword dummy_int ; vector 54  MCR_VCマシンでは、DCモータとサーボモータを利用するので  1msか100us周期のタイマー割込みでカウンタをインクリメント  して、DUTY比かパルス幅を指定します。  DCモータでは、カウンタを0から100の範囲で動かし、指定した  DUTY比(0から99)と比較して、論理値の0か1を出力します。  DCモータを制御するためのPWM波形を、タイマーXを利用して  生成することを考えました。  カウンタをDCNTとして、タイマーのアンダーフローごとに+1し  100になったときに、0に戻るカラクリで、回します。  このカラクリを記述すると、以下。 INT_X: ; store pushm R0,R1 ; impress (copy counter values) mov.b DCNT,R1L mov.b R1L,R1H mov.b RXDUTY,R0L mov.b LXDUTY,R0H ; impress ( RXDUTY > DCNT ) cmp.b R0L,R1L jlt INT_X0 bclr #2,P3 jmp INT_X1 INT_X0: bset #2,P3 INT_X1: ; impress ( LXDUTY > DCNT ) cmp.b R0H,R1H jlt INT_X2 bclr #3,P3 jmp INT_X3 INT_X2: bset #3,P3 INT_X3: ; increment inc.b DCNT ; get value mov.b DCNT,R1H ; compare cmp.b #100,R1H ; if R1H = 100 , clear jne INT_X4 mov.b #0,DCNT ; copy mov.b RDUTY,RXDUTY mov.b LDUTY,LXDUTY INT_X4: ; resume popm R0,R1 ; return reit  タイマーXを利用すると仮定して、コードを書いたので  割込み周期を1msとしてみます。  タイマーXのブロック図を見て、初期化処理を考えます。  1msを生成するには、タイマーXのプリスケーラ、カウンタを  利用してf1(20MHz)あるいはf2(10MHz)を分周。またモードは  タイマーモードで利用すれば、充分でしょう。  この仕様を、アセンブリ言語コードにすると、以下。 INIT_TX: ; select clock f1 and.b #11111100b,TCSS ; select timer X mode and.b #11111100b,TXMR ; prescalar mov.b #39,PREX ; divider mov.b #79,TX ; enable interrupt mov.b #00001001b,TXIC ; start timer X bset #3,TXMR ; rts  タイマーXの割込みを使うので、ヴェクターにアドレスを指定。 .section VVECTOR,ROMDATA .org 0FF00h VVECTOR_ADR: .lword dummy_int ; vector 0 (BRK) .lword dummy_int ; vector 1 (reserved) .lword dummy_int ; vector 2 (reserved) .lword dummy_int ; vector 3 (reserved) .lword dummy_int ; vector 4 (reserved) .lword dummy_int ; vector 5 (reserved) .lword dummy_int ; vector 6 (reserved) .lword dummy_int ; vector 7 (reserved) .lword dummy_int ; vector 8 (reserved) .lword dummy_int ; vector 9 (reserved) .lword dummy_int ; vector 10(reserved) .lword dummy_int ; vector 11(reserved) .lword dummy_int ; vector 12(reserved) .lword dummy_int ; vector 13(Key Input) .lword dummy_int ; vector 14(A/D converter) .lword dummy_int ; vector 15(reserved) .lword dummy_int ; vector 16(Timer C compare 1) .lword dummy_int ; vector 17(UART0 transmitt) .lword dummy_int ; vector 18(UART0 receive) .lword dummy_int ; vector 19(UART1 transmitt) .lword dummy_int ; vector 20(UART0 receive) .lword dummy_int ; vector 21(INT2 interrupt) .lword INT_TX ; vector 22(Timer X interrupt) .lword dummy_int ; vector 23(Timer Y interrupt) .lword INT_TZ ; vector 24(Timer Z interrupt) .lword dummy_int ; vector 25(INT1 interrupt) .lword dummy_int ; vector 26(INT3 interrupt) .lword dummy_int ; vector 27(Timer C overflow) .lword dummy_int ; vector 28(Timer C compare 0) .lword dummy_int ; vector 29(INT0 interrupt) .lword dummy_int ; vector 30(reserved) .lword dummy_int ; vector 31(reserved)  サーボモータの角度をタイマーYを使って、制御します。  サーボモータは、20mの周期で、パルス幅を1msから2msに  変化させると、角度が追従する仕様となっています。  カウンタを0から2000まで変化させて、2000になったなら  0に戻し、カウンタを10usごとにインクリメントすること  を考えます。  カウンタをSCNTとして、タイマーのアンダーフローごとに+1し  2000になったときに、0に戻るカラクリで、回します。  このカラクリを記述すると、以下。 INT_Y: ; store pushm R0,R1 ; impress (copy counter values) mov.w SCNT,R1 mov.w SXVAL,R0 ; impress ( SXVAL > SCNT ) cmp.w R0,R1 jlt INT_Y0 bclr #7,P3 jmp INT_Y1 INT_Y0: bset #7,P3 INT_Y1: ; increment inc.w SCNT ; get value mov.w SCNT,R1 ; compare cmp.b #2000,R1 ; if R1 = 2000 , clear jne INT_Y2 mov.w #0,SCNT ; copy mov.w SVAL,SXVAL INT_Y2: ; resume popm R0,R1 ; return reit  タイマーYを利用すると仮定して、コードを書いたので  割込み周期を1msとしてみます。  タイマーYのブロック図を見て、初期化処理を考えます。  10usは100kHzなので、f1(20MHz)を使うとすれば、プリスケーラ  とカウンタの値の組み合わせは、以下。 200 = 100x2 = 50x4 = 25x8  プリスケーラで25分周し、カウンタで8分周すると  f1を利用できるとわかります。  利用するレジスタは、TYZMR、TYPR、PREYとなります。  初期化は以下。 INIT_TY: ; select clock f1 and.b #11110011b,TCSS ; select timer Y mode and.b #11111000b,TYZMR ; prescalar mov.b #24,PREY ; divider mov.b #7,TYPR ; enable interrupt mov.b #00001001b,TYIC ; start timer Y bset #3,TYZMR ; rts  タイマーYの割込みを使うので、ヴェクターにアドレスを指定。 .section VVECTOR,ROMDATA .org 0FF00h VVECTOR_ADR: .lword dummy_int ; vector 0 (BRK) .lword dummy_int ; vector 1 (reserved) .lword dummy_int ; vector 2 (reserved) .lword dummy_int ; vector 3 (reserved) .lword dummy_int ; vector 4 (reserved) .lword dummy_int ; vector 5 (reserved) .lword dummy_int ; vector 6 (reserved) .lword dummy_int ; vector 7 (reserved) .lword dummy_int ; vector 8 (reserved) .lword dummy_int ; vector 9 (reserved) .lword dummy_int ; vector 10(reserved) .lword dummy_int ; vector 11(reserved) .lword dummy_int ; vector 12(reserved) .lword dummy_int ; vector 13(Key Input) .lword dummy_int ; vector 14(A/D converter) .lword dummy_int ; vector 15(reserved) .lword dummy_int ; vector 16(Timer C compare 1) .lword dummy_int ; vector 17(UART0 transmitt) .lword dummy_int ; vector 18(UART0 receive) .lword dummy_int ; vector 19(UART1 transmitt) .lword dummy_int ; vector 20(UART0 receive) .lword dummy_int ; vector 21(INT2 interrupt) .lword INT_TX ; vector 22(Timer X interrupt) .lword INT_TY ; vector 23(Timer Y interrupt) .lword INT_TZ ; vector 24(Timer Z interrupt) .lword dummy_int ; vector 25(INT1 interrupt) .lword dummy_int ; vector 26(INT3 interrupt) .lword dummy_int ; vector 27(Timer C overflow) .lword dummy_int ; vector 28(Timer C compare 0) .lword dummy_int ; vector 29(INT0 interrupt) .lword dummy_int ; vector 30(reserved) .lword dummy_int ; vector 31(reserved)  2種のモータのために、値の初期化が必要。  DCモータのDUTY比は0%として、回転なしにしておき  サーボモータへは、1.5msのパルス幅を与えるように  指定します。 INIT_VAL: ; clear mov.w #0,R0 mov.w #0,R1 ; DC motor mov.b R0L,DCNT mov.b R0H,LDUTY mov.b R1L,RDUTY mov.b R1H,LXDUTY mov.b R0L,RXDUTY ; servo motor mov.w R0,SCNT mov.w #150,SVAL mov.w #150,SXVAL ; rts  モータを使うには、パラメータを変更できるように  サブルーチンを用意。APIを設計しているので、2種  のモータのパラメータ変更用サブルーチン名は、以下  のように決めます。 SEND_DC SEND_SERVO  アセンブリ言語では、パラメータを渡すときにレジスタ  を利用するのが、お約束なので2種のAPIは次のように  レジスタR0を使うことに。 SEND_DC: ; store push.w R0 ; put left duty ratio mov.b R0H,LDUTY ; put right duty ratio mov.b R0L,RDUTY ; resume pop.w R0 ; rts SEND_SERVO: ; store push.w R0 ; put parameter mov.w R0,SVAL ; rts  DCモータのDUTY比は、左右で各8ビットなので  レジスタR0が16ビットという特徴を利用。  モータの制御に関係する階層構造は、以下。  スタートゲートの状態を監視するためのサブルーチンを  用意して、処理を単純にします。ポート1の7ビットを  スタートゲートのOPENED、CLOSEDに割り当てると以下の  処理でよいはず。 GET_START: ; store push.w R1 ; default (clear flag) bclr #2,FLAGS ; get start gate state mov.b P1,R1H ; judge btst #7,R1H jeq GET_START1 bset #2,FLAGS GET_START1: ; resume pop.w R1 ; rts  スタートゲートの状態を監視して、OPENEDになった  ならば、フラグをセット。状態フラグを使い、移動  処理を実行するのは、サブルーチンを使う側の問題  に変換してしまいます。  APIには時間待ちもあるので、これをサブルーチンで用意。 DELAY_MS: ; store pushm R2,R3 ; get now system timer count mov.w TIMCNT,R3 ; calculate add.w R2,R3 ; compare DELAY_MS1: cmp.w TIMCNT,R3 jlt DELAY_MS1 ; resume popm R2,R3 ; rts  レジスタR2に遅延したい時間のカウント値を格納して  サブルーチンコールします。  ライントレースするには、路面状態を取得しなければ  なりません。ポート1の下位ニブルからセンサー出力  の路面状態を取得。 GET_SENSOR: ; store push.w R0 ; set pattern mov.b #00001111b,R0H ; get nibble from port 1 mov.b R1,R0L ; mask add.b R0H,R0L ; store mov.b R0L,ROAD ; resume pop.w R0 ; rts  ここまでで、利用する変数が確定したので  まとめて、表形式に。 .section VARIABLE,DATA .org 0400h FLAGS: .blkb 1 ROAD: .blkb 1 TIMCNT: .blkw 1 DCNT: .blkb 1 LDUTY: .blkb 1 RDUTY: .blkb 1 LXDUTY: .blkb 1 RXDUTY: .blkb 1 SCNT: .blkw 1 SVAL: .blkw 1 SXVAL: .blkw 1 STATE: .blkb 1  内部状態を持っておいた方が、ファームウエアを  作成しやすいので、1バイトのSTATEを用意。  内部状態を指定するために、STATEを用意しますが  代入する値(状態値)を、次のように割当てます。  マイコンのファームウエアでは、状態値をみて  状態遷移をするか否かを決定します。  走行時は、以下の状態遷移に。   NORMAL -> CRANK -> ROTATE -> NORMAL   NORMAL -> LANE -> CHANGE -> BLIND -> NORMAL  スタートトリガーを使い、STATE=0からSTATE=1に  遷移させます。また、タイムアップしたときには  STATE=10として、即座にSTATE=0に戻します。  路面と内部の状態をLEDで表示します。  8ビットのレジスタICを利用して、LEDを点灯、消灯  すれば簡単に実現できると判断。  回路図は以下。  路面と内部の状態は、ひとつのサブルーチンで一度に  表示できるようにします。  表に値を格納しておき、表から値を引き出して設定する  方法を採用。 DISPLAY: ; store pushm A0,R0 ; set pointer mova RDTBL,A0 ; calculate address mov.b #0,R0H mov.b ROAD,R0L add.w R0,A0 ; impress code mov.b [A0],P0 ; set trigger bset #0,P3 ; clear trigger bclr #0,P3 ; set pointer mova STTBL,A0 ; calculate address mov.b #0,R0H mov.b STATE,R0L add.w R0,A0 ; impress code mov.b [A0],P0 ; set trigger bset #1,P3 ; clear trigger bclr #1,P3 ; resume popm A0,R0 ; rts  表に値を格納するサブルーチンは、以下。 RDTBL: .blkb 13 STTBL: .blkb 8 INIT_TABLE: ; store push.w A0 ; set pointer mova RDTBL,A0 ; ALL_BLACK mov.b #0,[A0] ; ALL_WHITE mov.b #0FFh,1:8[A0] ; LEFT_WHITE mov.b #0F0h,2:8[A0] ; RIGHT_WHITE mov.b #00Fh,3:8[A0] ; CENTER mov.b #38h,4:8[A0] ; TINY_RIGHT mov.b #0Ch,5:8[A0] ; RIGHT mov.b #06h,6:8[A0] ; BIG_RIGHT mov.b #03h,7:8[A0] ; TINY_LEFT mov.b #30h,8:8[A0] ; LEFT mov.b #60h,9:8[A0] ; BIG_LEFT mov.b #0C0h,10:8[A0] ; BOTH_WHITE mov.b #81h,11:8[A0] ; ILLEAGAL mov.b #0A5h,12:8[A0] ; set pointer mova STTBL,A0 ; STATE = 0 mov.b #01h,[A0] ; STATE = 1 mov.b #02h,1:8[A0] ; STATE = 2 mov.b #04h,2:8[A0] ; STATE = 3 mov.b #08h,3:8[A0] ; STATE = 4 mov.b #10h,4:8[A0] ; STATE = 5 mov.b #20h,5:8[A0] ; STATE = 6 mov.b #40h,6:8[A0] ; STATE = 7 mov.b #80h,7:8[A0] ; resume pop.w A0 ; rts  必要なサブルーチンを定義したので、移動処理を考えます。  実際の移動に関わらない部分だけを定義。 WST .EQU 0 NORMAL .EQU 1 CRANK .EQU 2 ROTATE .EQU 3 LANE .EQU 4 CHANGE .EQU 5 BLIND .EQU 6 TIME_UP .EQU 7 MAIN: ; get sensor state jsr GET_SENSOR mov.b ROAD,R0H ; show internal state and road state jsr DISPLAY ; judge STATE mov.b STATE,R0L cmp.b WST,R0L jgt MAIN1 ; get start gate jsr GET_START btst #0,FLAGS jz MAIN1 ; 1 -> STATE inc.b STATE MAIN1: ; get system timer count mov.w TIMCNT,R3 cmp.w #60000,R3 jlt MAIN2 mov.b #TIME_UP,STATE jmp MAIN10 MAIN2: ; ??? ; ??? ; ??? MAIN10: mov.b #WST,STATE ; MAINL: ; jmp MAIN  R8C/Tinyはピン数も少ないので、スタートゲートの状態と  タイムアップの情報を、同一のピンで共有することに。  回路は、以下。  スタートゲートセンサーの開閉情報をシフトレジスタで  受けておき、タイムアップの情報とデータセレクタで  区別して対応。  パワーオンリセットで、出力CLRに'1'を出力しておき  スタートゲートが開いたなら、CLRを'0'にします。  シフトレジスタもカウンタも1Hzのクロックを使い  スタートゲートの状態とタイムアップを出力。どちら  の情報を使うのかは、マイコン次第に。  マイコンの2ピンを使うだけで、スタートゲートと  タイムアップの情報を指定できます。タイムアップ  を内蔵タイマーで扱わないだけ、ファームウエアの  テストが楽です。  スタートゲートセンサーの開閉情報は、センサーにより  論理値が異なるので、シフトレジスタの出力を反転する  か否かをデバイス出力で選択できるようにと考えました。  1Hzの精度は、それほどいらないので、8ピンのPICで  生成するだけです。  試走で利用するカウンタに使っているので、手持ちの  PIC12F1501にファームウエアを転送するだけ。  1Hzと10Hzのクロックを生成するファームウエアは、以下。 /* redefine data type */ typedef unsigned char UBYTE ; typedef unsigned int UWORD ; #define OFF 0 #define ON OFF+1 #define MASK0F 0x0f #define OUT10 GPIO.B0 #define OUT1 GPIO.B1 #define OUTM GPIO.B2 #define OUTX GPIO.B4 #define CNTBEGIN 6 #define XCNTMAX 25 #define YCNTMAX 250 volatile UBYTE eflag ; volatile UBYTE tmp ; volatile UBYTE xcnt ; volatile UBYTE ycnt ; volatile UBYTE zcnt ; volatile UBYTE cnt10 ; volatile UBYTE cnt ; /* function prototype */ void init_usr(void); /* interrupt handler */ void interrupt(void) { /* generate 500Hz */ if ( INTCON.T0IF == ON ) { /* clear flag */ INTCON.T0IF = OFF ; /* initialize (/250) */ TMR0 = CNTBEGIN ; /* set flag */ eflag = ON ; } } void main(void) { /* user initialize */ init_usr(); /* endless loop */ while ( ON ) { /* generate 10Hz and 1Hz */ if ( eflag == ON ) { /* clear flag */ eflag = OFF ; /* counter increment */ xcnt++ ; ycnt++ ; zcnt++ ; /* generate 20Hz */ if ( xcnt == XCNTMAX ) { xcnt = 0 ; cnt10 = cnt10 + 1 ; } /* generate 2Hz */ if ( ycnt == YCNTMAX ) { ycnt = 0 ; cnt++ ; } /* impress */ OUT10 = cnt10 & ON ; OUT1 = cnt & ON ; OUTX = zcnt & ON ; } /* manual clock generator */ { /* get and mask */ tmp = GPIO & (1 << 5); /* shift */ tmp >>= 5 ; /* impress */ OUTM = !(tmp & ON) ; } } } /* define function body */ void init_usr(void) { /* I/O state */ GPIO = 0x00 ; /* I/O directions */ TRISIO = 0x28 ; /* bit0,1,2,4 as output , others as input */ /* disable compare module */ CMCON = 0x07 ; /* pull-up */ WPU = 0x20 ; /* initialize Timer 0 */ { /* 4MHz/4 = 1MHz -> 1MHz/8 = 125kHz prescaler = 1:8 */ OPTION_REG = 0x02 ; /* 256 - 6 = 250 */ TMR0 = CNTBEGIN ; /* enable timer0 overflow interrupt */ INTCON.T0IE = ON ; } /* enable general interrupt */ INTCON.GIE = ON ; /* clear flag */ eflag = OFF ; /* others */ xcnt = 0 ; ycnt = 0 ; zcnt = 0 ; cnt10 = 0 ; cnt = 0 ; }

目次

inserted by FC2 system