目次

マイコン選定

 PLCを実現する関数が揃ったので、マイコンを選定します。

 入出力は、各8ビットを利用するとして合計16ビット
 なので、28ピン以上のマイコンが必要です。

 手元にはPIC、AVR、H8、ARM、78K等の40ピン以上のマイコン
 があります。どれも一長一短がありますが、ひとつのマイコン
 で動作するファームウエアを作成すれば、高レベル言語である
 Cで記述しているので、移植は簡単です。

 マイコンの選定条件を与えて、ひとつに絞ります。
  1. 40ピンDIP
  2. EEPROM内蔵
  3. シリアルインタフェース回路内蔵
  4. アルカリ乾電池2本で動作可能
  5. I/O数は多いほどよい
  6. GCCでファームウエアを開発可能
 これらの条件をすべて満たす手元のマイコンは、AVRだけでした。  マイコン決定後、パーツボックスの中にあるAVRを  調べてみると、次の種類がありました。  それぞれ特徴がありますが、PLC動作は単純なので  現在主流ではないAT90Sシリーズを利用することに  しました。  AT90S8515、AT90S8535ともにテストボードは作成して  あるので、AT90S8535で開発してみます。  AT90S8535の最高動作クロック周波数は、8MHzなので  8MHzで動作させています。  インタプリタは作成済みなので、通信処理とタイマー割込み  に分けて、動作を考えます。

通信処理

 通信処理は、次の2つのフェーズで必要になります。  通信にはプロトコルが必要なので、次のように決めました。  コマンドをS、Lにしたので、フォーマットを規定します。  Sコマンド   ラダー図情報は、16ビットデータでEEPROMに保存する   ので、アドレスとデータが必要です。   アドレス、データともに、16進4けたで指定します。   EEPROMのアドレス0100hに、9001hを設定する場合は   次のように記述します。    S01009001'\r'   通信内容をモニタできるように、文字で送信します。  Lコマンド   EEPROMに格納されている、ラダー図情報を取得します。   コマンドを示す1文字’L’を送信します。    L'\r'   マイコン側は、このコマンドを受信すると、0から   EEPROMの最終アドレスまで、内容を16進4けたで返信   します。  コマンドを決めたので、PLCファームウエア処理を修正します。 if ( mode == IDLE ) { if ( SFLAG == ON ) { SFLAG = OFF ; /* get command */ cmd = *(rbuf+0) ; /* set circuit infomation */ if ( cmd == 'S' ) { /* get address */ cadr = get_ad(OFF) ; /* get data */ cdat = get_ad(ON) ; /* save */ put_dat_eeprom( cadr , cdat ); } /* get circuit infomation */ if ( cmd == 'L' ) { *(xdat+2) = 0 ; for ( rom_address = 0 ; rom_address < 512 ; rom_address++ ) { tmp = read_eeprom( rom_address ) ; *(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ]; *(xdat+1) = asc_cha[ tmp & MASK0F ]; rs_puts( xdat ); } } } }  受信割込みから与えられたトリガーを使います。  トリガーが着たら、saveとloadを判断し、EEPROMの  アクセスを切り分けます。  プロトコルが確定したので、通信ブロック初期化と  受信割込みの内容を定義します。  通信ブロック初期化   データ転送速度を設定します。 #define FOSC 8000000 #define BAUD 38400 #define MYUBRR (FOSC/16/BAUD)-1 /* set Baud Rate Registers */ UBRR = MYUBRR ; /* Enable receive interrupt , receive module and transmit module */ UCR = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);   受信バッファが必要なので、配列で指定します。   また、格納データの位置を指定する変数を宣言します。 #define BUFSIZE 10 volatile UBYTE rbuf[BUFSIZE] ; volatile UBYTE rindex;  受信割込み   受信バッファに1文字ずつ格納し、デリミタで   あったなら、フラグSFLAGをセットします。 ISR(SIG_UART_RECV) { volatile UBYTE ch ; /* get 1 charactoer */ ch = UDR ; /* store */ *(rbuf+rindex) = ch ; rindex++ ; /* judge */ if ( ch == '\r' ) { SFLAG = ON ; rindex = 0 ; } }

タイマー割込み

 PLCでは、スキャン処理周期を10msとします。  10msごとに、スキャン処理開始のトリガーを  与えるため、タイマー割込みを使います。  10msごとにフラグTFLAGをセットします。  仕様を決めたので、初期設定と割込み処理を定義します。  初期設定   タイマー1を、コンペアマッチで動かします。 /* clear timer/counter */ TCNT1 = 0 ; /* set counter */ OCR1A = 9999 ; /* Control Register 1-B */ TCCR1B = (1 << CS10) ;   カウンタ用クロックは、8MHzを8分周して1MHzにします。   0〜9999まで、カウントとすると10msになります。  割込み処理   割込みでカウンタクリアとフラグ設定します。 ISR(SIG_OUTPUT_COMPARE1A) { /* clear timer/counter */ TCNT1 = 0 ; /* set flag */ TFLAG = ON ; }  シーケンス処理動作をさせるか、通信処理をさせるかを  トグルスイッチを利用して切り替えます。  スイッチを使うので、チャタリングが発生します。  チャタリング除去のために、20ms程度ごとにスイッチ状態  をシフトレジスタに読み込みます。  シフトレジスタに、スイッチ状態を入力するトリガーを  タイマー割込みで発生させます。  仕様を決めたので、初期設定と割込み処理を定義します。  初期設定   タイマー0を、オーバーフローで動かします。 /* clear timer/counter */ TCNT0 = 56 ; /* Control Register */ TCCR0 = (5 << CS00) ;   カウンタ用クロックは、8MHzを1024分周して入力します。   さらに、56〜256までカウントして25.6msごとに割込みが   発生するカラクリを作ります。  割込み処理   割込みでカウンタクリアとフラグ設定します。 ISR(SIG_OVERFLOW0) { /* clear timer/counter */ TCNT0 = 56 ; /* set flag */ MFLAG = ON ; }  2つのタイマーを動かすため、初期化後、次の命令を与えます。  TIMSK = (1 << OCIE1A) | (1 << TOIE0);
目次

inserted by FC2 system