H8/3664FでタイマA割り込みできたよ!!!やったね!!!
何がいけなかったのか?
昨日上げたソースコードから1行ずつコメントを外して検証した結果、Count関数を用いないと(NOP();を一定回数ループさせないと)7セグメントLEDが点灯しないことが判明した。ただし判明した時点での点灯状況は数字が表示されるというものではなく、ただランダムに点灯しているような状況だった。この時は、グローバル変数の値を参照して数値を表示させるようにしており、割り込み関数内でそのグローバル変数をインクリメントしている状態だった。その後、割り込みはできたが数字として表示されない状態に。
隣の班と情報交換をし、どうやらグローバル変数が悪さをしているようだが、構造的にグローバル変数を用いずに実現させるのは難しいと考え、別の解決策をググった。
コンパイル時に、プログラムは最適化される。しかし組み込み用途では、最適化が思わぬ動作を引き起こすことがあり、無効化することが望ましい場合があるとのこと。google:h8 volatile
そこでグローバル変数をvolatile修飾子を付けて宣言しなおしたところ、正常に動作するようになった。
長い
グローバル変数にはvolatile付けろ。配列はダメな。
現時点でのソースコード
動いたver
時計表示のための60進数実現部分でif文が入れ子になっており、これ、なんとか短くできそう。関数化するとか。
/* * H8/3664F 7セグメントLEDのダイナミック点灯制御実験 */ #include "3664.h" //7セグメントLEDの各数字表示 #define ZERO 0x80 //10000000 //0 #define ONE 0xF1 //11110001 //1 #define TWO 0x44 //01001000 //2 #define THREE 0x60 //01100000 //3 #define FOUR 0x31 //00110001 //4 #define FIVE 0x22 //00100010 //5 #define SIX 0x2 //00000010 //6 #define SEVEN 0xB0 //10110000 //7 #define EIGHT 0x0 //00000000 //8 #define NINE 0x20 //00100000 //9 //7セグメントLEDの格桁に対応するポート #define DIGIT0 0x1 #define DIGIT1 0x2 #define DIGIT2 0x4 #define DIGIT3 0x8 #define DIGIT4 0x10 #define DIGIT5 0x20 #define DIGIT6 0x40 //タイマAの割り込み要求フラグが立っている状況 #define IRRTA 0x70 //タイマAの割り込み要求を許可するflug #define IENTA 0x40 //グローバル変数(最適化対象でない) volatile short int disp0; volatile short int disp1; volatile short int disp2; volatile short int disp3; /*入力された数値に対応する7セグメントLEDを *負論理で点灯させるポート出力用の数値を返す */ int LightNumber( int num ) { int led[10] = { ZERO , ONE , TWO , THREE , FOUR , FIVE , SIX , SEVEN , EIGHT , NINE , }; return led[num]; } /*入力された数値に対応する桁をトランジスタのスイッチングによって *点灯させるようにポートをセットする */ int LightDigit( int num ) { int dig[] = { DIGIT0 , DIGIT1 , DIGIT2 , DIGIT3 , DIGIT4 , DIGIT5 , DIGIT6 , }; return dig[num]; } /*ダイナミック点灯を行う関数 *表示する数値はグローバル変数と割り込みで更新 */ void Count( void ) { int wait; //1桁目の点灯 PDR5 = LightDigit( 0 ); PDR8 = LightNumber( disp0 ); //僅かな時間点灯させる for( wait = 0; wait < 10000; wait++ ) { NOP(); } //2桁目の点灯 PDR5 = LightDigit( 1 ); PDR8 = LightNumber( disp1 ); //僅かな時間点灯させる for( wait = 0; wait < 10000; wait++ ) { NOP(); } //3桁目の点灯 PDR5 = LightDigit( 2 ); PDR8 = LightNumber( disp2 ); //僅かな時間点灯させる for( wait = 0; wait < 10000; wait++ ) { NOP(); } //4桁目の点灯 PDR5 = LightDigit( 3 ); PDR8 = LightNumber( disp3 ); //僅かな時間点灯させる for( wait = 0; wait < 10000; wait++ ) { NOP(); } } /*タイマーAを使用して1秒毎に割り込みを行う関数 *これにより1秒毎にカウントアップができるようになった *できた *まあまあ理解した *帰れた */ #pragma interrupt void int_timera( void ) { IRR1 &= ~IRRTA; //タイマAの割り込み要求をクリア disp0++; } /*7セグメントLEDを0から9の順に点灯させるプログラム*/ int main() { CLI(); //初期化操作のため割り込みを禁止 disp0 = 0; disp1 = 0; disp2 = 0; disp3 = 0; /*ポート1は7セグメントLEDの数値表示に用いる ポート1は接触不良のため使用不可 PMR1 = 0x00; //汎用入出力ポートに設定 PCR1 = 0xff; //ポート1を全ビット出力用に使用 PDR1 = 0x00; //ポート1をクリア */ //ポート5はどの7セグメントLEDを点灯させるかのトランジスタでのスイッチングに用いる PMR5 = 0x00; /*汎用入出力ポートに設定*/ PCR5 = 0xff; /*全ビット出力用に設定*/ PDR5 = 0x00; /*ポート5をクリア*/ //ポート8は7セグメントLEDの数値表示に用いる //PMR8 = 0x00; /*ポートBは出力専用なのか?*/ PCR8 = 0xff; /*ポートBを全ビット出力用に使用*/ PDR8 = 0x00; /*ポートBをクリア*/ TMA = 0x8; //タイマーAを低速時計用クロック、速度は1秒間隔に設定 STI(); //初期化操作終了とともに割り込みを許可 IENR1 |= IENTA; //タイマAの割り込みを許可 IRR1 &= ~IRRTA; //タイマAの割り込み要求をクリア for( ; ; ) { //60進数制御if文の羅列 //もっとスマートな書き方があるはず。関数化してしまうとか。 if( disp0 > 9 ) { disp0 = 0; disp1++; if( disp1 > 5 ) { disp0 = 0; disp1 = 0; disp2++; if( disp2 > 9 ) { disp0 = 0; disp1 = 0; disp2 = 0; disp3++; if( disp3 > 5 ) { disp0 = 0; disp1 = 0; disp2 = 0; disp3 = 0; } } } } //ダイナミック点灯 Count(); } }
あとはレポート書くだけ