目次
前
次
システム拡張
タイマー割込みと受信割込みを利用し、PLCを実現する
C言語のコードを開発しました。
このPLCは、最低限の動作しかできません。
最近のPLCには、ほぼ標準で備わっている次の機能が
ありません。
- 入力メモリの状態表示
- 1ラインのステップ実行
- 出力メモリの状態表示
シミュレータでは、これらの機能は実現できています。
マイコンのファームウエアにも、これらの機能を組込み
ます。
RTOS(Real Time Operating System)利用
これまでのファームウエアは、タイマー割込みと受信割込みで
PLCの機能を実現してきました。
新たに機能を付加するには、ソースコードをすべて理解する
必要があります。それは、時間もかかり、面倒な作業です。
RTOS(Real Time Operating System)のUSO(Unvoiced Shadow Operating system)
を利用し、機能追加、削減が簡単にできるようにします。
必要な機能を考え、タスクに分割してみます。
- 通信処理(タスク0)
- EEPROMにデータ設定(タスク1)
- EEPROMの内容表示(タスク2)
- 入力からデータを取得し、入力メモリに展開(タスク3)
- スキャン処理(タスク4)
- 出力メモリから、出力へデータ転送(タスク5)
これらの6タスクで、PLCの機能は実現できます。
どこで機能拡張を担当するのかを検討していくと、
次のようになります。
タスク3は、入力と入力メモリ間の転送処理を担当します。
このタスクに、入力メモリの内容表示の機能を追加すると
機能拡張ができます。
タスク4は、スキャン処理を担当しています。
スキャン処理を全ラインで実現するのではなく、1ライン
ごとにステップ動作させるようにすれば、機能拡張できます。
タスク5は、出力と出力メモリ間の転送処理を担当します。
このタスクに、出力メモリの内容表示の機能を追加すると
機能拡張ができます。
タスクに分割すると、このように機能拡張が簡単になります。
通信処理で利用するコマンドを考えます。
これまでに、2つのコマンドを定義して使っています。
- Sコマンド EEPROMアドレスを指定し、16ビットデータ設定
- Lコマンド EEPROMから全ラダー情報を出力
付け加えるコマンドを考えます。
入力と入力メモリの内容を表示するように指定する
コマンドを考えます。入力の内容を表示するか否か
を指定するコマンドをIとします。
I1{enter}で、入力と入力メモリの内容表示開始
I0{enter}で、入力と入力メモリの内容表示停止
ステップ動作するかどうかを指定するコマンドを考えます。
このコマンドをPとします。
P1{enter}で、ステップ動作指定
P0{enter}で、ステップ動作停止
ステップ動作の場合は、1行ごとにラダー情報を実現
するので、実行する行の番号を増やすコマンドが必要
になります。
このコマンドをNとします。
N{enter}で、実行ラダー行の番号を+1する
出力と出力メモリの内容を表示するように指定する
コマンドを考えます。出力の内容を表示するか否か
を指定するコマンドをOとします。
O1{enter}で、出力と出力メモリの内容表示開始
O0{enter}で、出力と出力メモリの内容表示停止
コマンドをまとめます。
- Sコマンド EEPROMアドレスを指定し、16ビットデータ設定
- Lコマンド EEPROMから全ラダー情報を出力
- Iコマンド 入力と入力メモリの内容表示指定
- Pコマンド ステップ動作指定
- Nコマンド 処理対象の行番号を増やす
- Oコマンド 出力と出力メモリの内容表示指定
各タスクを定義します。
通信処理(タスク0)
コマンドをひとつ、ひとつ実装していきます。
ファームウエアとして定義した内容があるので
それを参考にしながら、動作を記述していきます。
if ( mode == IDLE ) {
if ( SFLAG == ON ) {
/* clear flag */
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 );
}
}
}
}
「Sコマンド EEPROMアドレスを指定し、16ビットデータ設定」は
タスク1に処理をまとめたので、このコマンドであれば、タスク1
をシステムコールを利用して、SUSPENDからREADYにします。
一応、必要な情報は、ここで取得しておきます。
if ( cmd == 'S' ) {
/* get address */
cadr = get_ad(OFF) ;
/* get data */
cdat = get_ad(ON) ;
/* wake up */
rsm_tsk( TSK_ID1 ) ;
}
「Lコマンド EEPROMから全ラダー情報を出力」はタスク2
に処理をまとめたので、このコマンドであれば、タスク2を
システムコールを利用して、SUSPENDからREADYにします。
if ( cmd == 'L' ) { rsm_tsk( TSK_ID2 ) ; }
「Iコマンド 入力と入力メモリの内容表示指定」は
タスク3が処理するとしたので、フラグを利用して
表示するか否かを指定します。
if ( cmd == 'I' ) {
IFLAG = OFF ;
if ( *(rbuf+1) == '1' ) {
IFLAG = ON ;
}
}
「Pコマンド ステップ動作指定」は、タスク4が処理する
としたので、フラグを利用して動作を指定します。
フラグをセットした場合に、ラダー行を指す変数pcntを用意
して0クリアします。
if ( cmd == 'P' ) {
PFLAG = OFF ;
if ( *(rbuf+1) == '1' ) {
PFLAG = ON ;
pcnt = 0 ;
}
}
「Nコマンド 処理対象の行番号を増やす」は、実際の動作を
タスク4が処理するとしたので、変数pcntの値を+2。
EEPROMは、1バイトごとにアドレスがついているので、ラダー
の1行が16ビットなので+2とします。
if ( cmd == 'N' ) { pcnt += 2 ; }
「Oコマンド 出力と出力メモリの内容表示指定」は、
実際の動作をタスク5が処理するとしたので、フラグ
を利用して動作指定します。
if ( cmd == 'O' ) {
OFLAG = OFF ;
if ( *(rbuf+1) == '1' ) {
OFLAG = ON ;
}
}
全コマンドの処理を決めたので、タスクとして定義します。
void tsk0_proc(void)
{
volatile UBYTE cmd ;
/* check flag */
if ( SFLAG == OFF ) return ;
/* clear flag */
SFLAG = OFF ;
/* get command */
cmd = *(rbuf+0) ;
/* judge */
if ( cmd == 'S' ) {
/* get address */
cadr = get_ad(OFF) ;
/* get data */
cdat = get_ad(ON) ;
/* wake up */
rsm_tsk( TSK_ID1 ) ;
}
if ( cmd == 'L' ) { rsm_tsk( TSK_ID2 ) ; }
if ( cmd == 'I' ) {
IFLAG = OFF ;
if ( *(rbuf+1) == '1' ) {
IFLAG = ON ;
}
}
if ( cmd == 'P' ) {
PFLAG = OFF ;
if ( *(rbuf+1) == '1' ) {
PFLAG = ON ;
pcnt = 0 ;
}
}
if ( cmd == 'N' ) { pcnt += 2 ; }
if ( cmd == 'O' ) {
OFLAG = OFF ;
if ( *(rbuf+1) == '1' ) {
OFLAG = ON ;
}
}
}
EEPROMにデータ設定(タスク1)
このタスクでは、EEPROMにデータを保存します。
必要な情報は、タスク0が設定してあるので、それらを
利用して、データ保存します。
一度処理すると、次にREADYにされるまで、システムコール
を利用して、自分自身でSUSPENDにします。
SUSPENDにします。
void tsk1_proc(void)
{
/* save */
put_dat_eeprom( cadr , cdat );
/* sleep */
slp_tsk();
}
EEPROMの内容表示(タスク2)
EEPROMには、情報が格納されているとして内容を
すべて転送します。一度処理すると、次にREADYに
されるまで、システムコールを利用して、自分自身
でSUSPENDにします。
void tsk2_proc(void)
{
UBYTE tmp;
UBYTE xdat[3];
/* set delimiter */
*(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 );
}
/* sleep */
slp_tsk();
}
入力からデータを取得し、入力メモリに展開(タスク3)
ファームウエアとして定義した内容があるので
それを基にして、動作を付加します。
void get_input_information(void)
{
/* send latch trigger */
PORTB |= (1 << ITRG);
PORTB &= ~(1 << ITRG);
/* enable nOEA */
PORTB &= ~(1 << OEA);
/* get lower data */
*(memory+0) = PINA ;
/* disable nOEA */
PORTB |= (1 << OEA);
/* enable nOEB */
PORTB &= ~(1 << OEB);
/* get upper data */
*(memory+1) = PINA ;
/* disable nOEB */
PORTB |= (1 << OEB);
}
フラグがセットされていれば、変数memoryの内容を通信回線に出力します。
void tsk3_proc(void)
{
UBYTE xdat[3];
UBYTE tmp ;
/* send latch trigger */
PORTB |= (1 << ITRG);
PORTB &= ~(1 << ITRG);
/* enable nOEA */
PORTB &= ~(1 << OEA);
/* get lower data */
*(memory+0) = PINA ;
/* disable nOEA */
PORTB |= (1 << OEA);
/* enable nOEB */
PORTB &= ~(1 << OEB);
/* get upper data */
*(memory+1) = PINA ;
/* disable nOEB */
PORTB |= (1 << OEB);
/* show input memory */
if ( IFLAG == ON ) {
*(xdat+2) = 0 ;
tmp = *(memory+0) ;
*(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ];
*(xdat+1) = asc_cha[ tmp & MASK0F ];
rs_puts( xdat );
tmp = *(memory+1) ;
*(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ];
*(xdat+1) = asc_cha[ tmp & MASK0F ];
rs_puts( xdat );
}
}
スキャン処理(タスク4)
スキャン処理は、2つのモードを考えなければなりません。
ステップ実行と一気に実行するのどちらかになります。
ステップ実行するか否かは、フラグPFLAGで判断します。
void tsk4_proc(void)
{
if ( PFLAG == ON )
{
} else
{
}
}
ステップ動作を実行する関数を定義して、その関数を
どう呼び出すのかを変えます。ステップ動作の関数を
定義します。
void doStep(UWORD radr)
{
/* get circuit infomation from EEPROM */
operand = get_circuit_infomation( radr );
/* get operational code */
opcode = (UBYTE)(operand >> 12);
operand &= 0x0fff ;
q = ((operand & 0xff) >> 3);
r = ((operand & 0xff) & 0x07);
/* END instruction */
if ( opcode == OP_END ) return ;
/* LD LDN instruction */
if ( opcode == OP_LD || opcode == OP_LDN ) {
push( reg );
reg = *(memory+q);
reg >>= r;
reg &= 1 ;
/* inverse */
if ( opcode == OP_LDN ) { reg ^= 1 ; }
}
/* OP_AND OP_ANDN OP_OR OP_ORN instruction */
if ( opcode == OP_AND || opcode == OP_ANDN ||
opcode == OP_OR || opcode == OP_ORN ) {
regx = *(memory+q);
regx >>= r;
regx &= 1;
/* inverse */
if ( opcode == OP_ANDN || opcode == OP_ORN ) { regx ^= 1 ; }
/* AND ANDN instruction */
if ( opcode == OP_AND || opcode == OP_ANDN ) { reg &= regx ; }
/* OR ORN instruction */
if ( opcode == OP_OR || opcode == OP_ORN ) { reg |= regx ; }
}
/* OP_ANDB OP_ORB instruction */
if ( opcode == OP_ANDB || opcode == OP_ORB ) {
regx = pull();
/* block AND */
if ( opcode == OP_ANDB ) { reg &= regx ; }
/* block OR */
if ( opcode == OP_ORB ) { reg |= regx ; }
}
/* OP_OUT instruction */
if ( opcode == OP_OUT ) {
/* shift bit data */
reg <<= r ;
/* clear target bit */
*(memory+q) ^= ~(1 << r);
/* store target bit */
*(memory+q) |= reg ;
}
}
}
ステップ動作では、関数doStepに変数pcntを渡します。
void tsk4_proc(void)
{
if ( PFLAG == ON ) {
doStep(pcnt);
} else {
}
}
ステップ動作でなければ、変数iを使い、EEPROMに
格納されている内容をすべて実行します。
void tsk4_proc(void)
{
UWORD i;
if ( PFLAG == ON ) {
doStep(pcnt);
} else {
for ( i = 0 ; i < 512 ; i += 2 ) {
doStep(i);
}
}
}
出力メモリから、出力へデータ転送(タスク5)
ファームウエアとして定義した内容があるので
それを基にして、動作を付加します。
void update_output(void)
{
/* output lower data */
PORTC = *(memory+2) ;
/* send latch pulse */
PORTB |= (1 << OTRGA) ;
PORTB &= ~(1 << OTRGA) ;
/* output upper data */
PORTC = *(memory+3) ;
/* latch upper data */
PORTB |= (1 << OTRGB) ;
PORTB &= ~(1 << OTRGB) ;
}
フラグがセットされていれば、変数memoryの内容を通信回線に出力します。
void tsk5_proc(void)
{
UBYTE xdat[3];
UBYTE tmp ;
/* output lower data */
PORTC = *(memory+2) ;
/* send latch pulse */
PORTB |= (1 << OTRGA) ;
PORTB &= ~(1 << OTRGA) ;
/* output upper data */
PORTC = *(memory+3) ;
/* latch upper data */
PORTB |= (1 << OTRGB) ;
PORTB &= ~(1 << OTRGB) ;
/* show output memory */
if ( OFLAG == ON ) {
*(xdat+2) = 0 ;
tmp = *(memory+2) ;
*(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ];
*(xdat+1) = asc_cha[ tmp & MASK0F ];
rs_puts( xdat );
tmp = *(memory+3) ;
*(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ];
*(xdat+1) = asc_cha[ tmp & MASK0F ];
rs_puts( xdat );
}
}
タスクの初期状態指定
RTOSでは、タスクの初期状態を決めておかないと
すべてのタスクが一度に動き出します。
EEPROMに関連するタスクをSUSPENDにしておき
コマンドが与えられたときにだけ、動作する
ように設定します。
- タスク0 READY 通信処理
- タスク1 SUSPEND EEPROMにデータ設定
- タスク2 SUSPEND EEPROMの内容表示
- タスク3 READY 入力からデータを取得し、入力メモリに展開
- タスク4 READY スキャン処理
- タスク5 READY 出力メモリから、出力へデータ転送
状態設定は、システムコールを利用して以下のようにします。
sta_tsk(TSK_ID0,TTS_READY);
sta_tsk(TSK_ID1,TTS_SUSPEND);
sta_tsk(TSK_ID2,TTS_SUSPEND);
sta_tsk(TSK_ID3,TTS_READY);
sta_tsk(TSK_ID4,TTS_READY);
sta_tsk(TSK_ID5,TTS_READY);
全ソースコード
RTOSのUSOを利用したPLCのCソースコードを次に示します。
システムクロック、I/O部分を変更すると、AVRではないマイ
コンに移植可能です。
#include <avr/io.h>
#include <avr/io8535.h>
#include <avr/interrupt.h>
#define TSK_ID_MAX 6
#define TSK_ID0 0
#define TSK_ID1 1
#define TSK_ID2 2
#define TSK_ID3 3
#define TSK_ID4 4
#define TSK_ID5 5
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
typedef signed char SBYTE ;
typedef signed short SWORD ;
typedef struct {
void (*tsk)(void);
UWORD wcount ;
} TCBP ;
typedef union {
struct {
unsigned char B0:1;
unsigned char B1:1;
unsigned char B2:1;
unsigned char B3:1;
unsigned char B4:1;
unsigned char B5:1;
unsigned char B6:1;
unsigned char B7:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP x_flags ;
#define SFLAG x_flags.BIT.B0
#define IFLAG x_flags.BIT.B1
#define PFLAG x_flags.BIT.B2
#define NFLAG x_flags.BIT.B3
#define OFLAG x_flags.BIT.B4
#define MFLAG x_flags.BIT.B4
#define BUFSIZE 10
volatile UBYTE rbuf[BUFSIZE] ;
volatile UBYTE rindex;
UBYTE asc_cha[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'} ;
#define OFF 0
#define ON 1
#define IDLE 0
#define RUN IDLE+1
#define LED_OFF (PORTD |= 0x10)
#define LED_ON (PORTD ^= 0xef)
#define LOWER_LATCH 1
#define UPPER_LATCH 2
#define MASKFF 0xff
#define MASK0F 0x0f
volatile UBYTE msft ;
volatile UBYTE memory[32] ;
volatile UBYTE mshift ;
volatile UWORD cadr ;
volatile UWORD cdat ;
volatile UBYTE stksft ;
volatile UBYTE opcode ;
volatile UBYTE operand;
volatile UBYTE q ;
volatile UBYTE r ;
volatile UBYTE cmd ;
volatile UWORD rom_address ;
volatile UBYTE reg ;
volatile UBYTE regx ;
volatile UWORD pcnt ;
#define TTS_SUSPEND 0
#define TTS_WAIT TTS_SUSPEND+1
#define TTS_READY TTS_SUSPEND+2
#define NO 0
#define YES 1
UBYTE ready ;
UBYTE suspend;
UBYTE vldtsk ;
UBYTE run_tsk;
TCBP tcb[TSK_ID_MAX];
/*------------------------*/
/* task function protoype */
/*------------------------*/
void tsk0_proc(void);
void tsk1_proc(void);
void tsk2_proc(void);
void tsk3_proc(void);
void tsk4_proc(void);
void tsk5_proc(void);
/*-----------------------*/
/* system call prototype */
/*-----------------------*/
void init_os(void);
void cre_tsk(UBYTE tid,void (*tsk)(void));
void sta_tsk(UBYTE tid,UBYTE sta);
void rsm_tsk(UBYTE tid);
void sus_tsk(UBYTE tid);
void slp_tsk(void);
void wai_tsk(UWORD x);
UBYTE is_tsk_ready(UBYTE tid);
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
#define ITRG 0
#define OEA 1
#define OEB 2
#define OEO 3
#define OTRGA 4
#define OTRGB 5
#define OP_END 0
#define OP_OUT 1
#define OP_LD 2
#define OP_LDN 3
#define OP_AND 4
#define OP_ANDN 5
#define OP_OR 6
#define OP_ORN 7
#define OP_ANDB 8
#define OP_ORB 9
void rs_putchar(UBYTE x);
void rs_puts(UBYTE *x);
void write_eeprom(UWORD adr,UBYTE dat);
UBYTE read_eeprom(UWORD adr);
void push(UBYTE x);
UBYTE pull(void);
UWORD get_circuit_infomation(UWORD x);
void doStep(UWORD radr);
void doScan(UWORD radr);
UBYTE get_hex(UBYTE x);
UWORD get_ad(UBYTE onoff);
void put_dat_eeprom(UWORD adr,UWORD dat);
/*------*/
/* main */
/*------*/
int main(void)
{
TCBP pcur_tsk ;
/* disable interrupt */
cli();
/* initialize monitor */
init_os();
cre_tsk(TSK_ID0,tsk0_proc);
cre_tsk(TSK_ID1,tsk1_proc);
cre_tsk(TSK_ID2,tsk2_proc);
cre_tsk(TSK_ID3,tsk3_proc);
cre_tsk(TSK_ID4,tsk4_proc);
cre_tsk(TSK_ID5,tsk5_proc);
sta_tsk(TSK_ID0,TTS_READY);
sta_tsk(TSK_ID1,TTS_SUSPEND);
sta_tsk(TSK_ID2,TTS_SUSPEND);
sta_tsk(TSK_ID3,TTS_READY);
sta_tsk(TSK_ID4,TTS_READY);
sta_tsk(TSK_ID5,TTS_READY);
user_initialize();
/* enable interrupt */
sei();
/* loop */
run_tsk = TSK_ID0 ;
while ( 1 ) {
pcur_tsk = tcb[run_tsk] ;
if ( is_tsk_ready( run_tsk ) == YES ) { (*(pcur_tsk.tsk))(); }
run_tsk++;
if ( run_tsk == TSK_ID_MAX ) { run_tsk = TSK_ID0 ; }
}
/* dummy */
return 0 ;
}
/*----------------*/
/* task functions */
/*----------------*/
void tsk0_proc(void)
{
/* mode switch handling */
LED_OFF ;
if ( MFLAG == ON ) { LED_ON ; }
/* check flag */
if ( SFLAG == OFF ) return ;
/* clear flag */
SFLAG = OFF ;
/* get command */
cmd = *(rbuf+0) ;
/* judge */
if ( cmd == 'S' ) {
/* get address */
cadr = get_ad(OFF) ;
/* get data */
cdat = get_ad(ON) ;
/* wake up */
rsm_tsk( TSK_ID1 ) ;
}
if ( cmd == 'L' ) { rsm_tsk( TSK_ID2 ) ; }
if ( cmd == 'I' ) {
IFLAG = OFF ;
if ( *(rbuf+1) == '1' ) { IFLAG = ON ; }
}
if ( cmd == 'P' ) {
PFLAG = OFF ;
if ( *(rbuf+1) == '1' ) { PFLAG = ON ; pcnt = 0 ; }
}
if ( cmd == 'N' ) { pcnt += 2 ; }
if ( cmd == 'O' ) {
OFLAG = OFF ;
if ( *(rbuf+1) == '1' ) { OFLAG = ON ; }
}
}
void tsk1_proc(void)
{
/* save */
put_dat_eeprom( cadr , cdat );
/* sleep */
slp_tsk();
}
void tsk2_proc(void)
{
UBYTE tmp ;
UBYTE xdat[3];
/* set delimiter */
*(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 );
}
/* sleep */
slp_tsk();
}
void tsk3_proc(void)
{
UBYTE xdat[3];
UBYTE tmp ;
/* send latch trigger */
PORTB |= (1 << ITRG);
PORTB &= ~(1 << ITRG);
/* enable nOEA */
PORTB &= ~(1 << OEA);
/* get lower data */
*(memory+0) = PINA ;
/* disable nOEA */
PORTB |= (1 << OEA);
/* enable nOEB */
PORTB &= ~(1 << OEB);
/* get upper data */
*(memory+1) = PINA ;
/* disable nOEB */
PORTB |= (1 << OEB);
/* show input memory */
if ( IFLAG == ON ) {
*(xdat+2) = 0 ;
tmp = *(memory+0) ;
*(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ];
*(xdat+1) = asc_cha[ tmp & MASK0F ];
rs_puts( xdat );
tmp = *(memory+1) ;
*(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ];
*(xdat+1) = asc_cha[ tmp & MASK0F ];
rs_puts( xdat );
}
}
void tsk4_proc(void)
{
UWORD i;
if ( PFLAG == ON ) {
doStep(pcnt);
} else {
for ( i = 0 ; i < 512 ; i += 2 ) { doStep(i); }
}
}
void tsk5_proc(void)
{
UBYTE xdat[3];
UBYTE tmp ;
/* output lower data */
PORTC = *(memory+2) ;
/* send latch pulse */
PORTB |= (1 << OTRGA) ;
PORTB &= ~(1 << OTRGA) ;
/* output upper data */
PORTC = *(memory+3) ;
/* latch upper data */
PORTB |= (1 << OTRGB) ;
PORTB &= ~(1 << OTRGB) ;
/* show output memory */
if ( OFLAG == ON ) {
*(xdat+2) = 0 ;
tmp = *(memory+2) ;
*(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ];
*(xdat+1) = asc_cha[ tmp & MASK0F ];
rs_puts( xdat );
tmp = *(memory+3) ;
*(xdat+0) = asc_cha[ (tmp >> 4) & MASK0F ];
*(xdat+1) = asc_cha[ tmp & MASK0F ];
rs_puts( xdat );
}
}
/*------------------*/
/* system call body */
/*------------------*/
void init_os(void)
{
ready = vldtsk = 0 ;
}
void cre_tsk(UBYTE tid,void (*tsk)(void))
{
if ( tid >= TSK_ID_MAX ) return ;
vldtsk |= (1 << tid) ;
tcb[tid].tsk = tsk;
tcb[tid].wcount = 0;
}
void sta_tsk(UBYTE tid,UBYTE sta)
{
if ( tid >= TSK_ID_MAX ) return ;
if ( sta == TTS_READY ) {
ready |= (1 << tid);
suspend &= ~(1 << tid);
}
if ( sta == TTS_WAIT ) {
ready &= ~(1 << tid);
suspend &= ~(1 << tid);
}
if ( sta == TTS_SUSPEND ) {
ready &= ~(1 << tid);
suspend |= (1 << tid);
}
}
void rsm_tsk(UBYTE tid)
{
if ( tid >= TSK_ID_MAX ) return ;
ready |= (1 << tid);
suspend &= ~(1 << tid);
}
void sus_tsk(UBYTE tid)
{
if ( tid >= TSK_ID_MAX ) return ;
ready &= ~(1 << tid);
suspend |= (1 << tid);
}
void slp_tsk(void)
{
sus_tsk(run_tsk);
}
void wai_tsk(UWORD x)
{
ready &= ~(1 << run_tsk);
suspend &= ~(1 << run_tsk);
tcb[run_tsk].wcount = x ;
}
UBYTE is_tsk_ready(UBYTE tid)
{
return( (ready >> tid) & 1 ) ;
}
/*-----------------------------*/
/* timer handler */
/* call from timer interrupt */
/*-----------------------------*/
void timer_handler(void)
{
UBYTE tmp;
UBYTE i ;
tmp = (ready ^ vldtsk) ^ suspend ;
for ( i = 0 ; i <= TSK_ID_MAX ; i++ ) {
if ( tmp & 1 ) {
tcb[i].wcount-- ;
if ( tcb[i].wcount == 0 ) { rsm_tsk(i); }
}
tmp >>= 1 ;
}
}
/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
#define FOSC 8000000
#define BAUD 38400
#define MYUBRR (FOSC/16/BAUD)-1
void user_initialize(void)
{
volatile UBYTE i ;
/* PORT A */
DDRA = 0b00000000 ; /* iiiiiiii */
PORTA = 0b00000000 ; /* 00000000 */
/* PORT B */
DDRB = 0b11111111 ; /* oooooooo */
PORTB = 0b00000000 ; /* 00000000 */
/* PORT C */
DDRC = 0b11111111 ; /* oooooooo */
PORTC = 0b00000000 ; /* 00000000 */
/* PORT D */
DDRD = 0b11110010 ; /* ooooiioi */
PORTD = 0b00010000 ; /* 00010000 */
/* initialize registers */
x_flags.DR = 0 ;
for ( i = 0 ; i < 32 ; i++ ) { *(memory+i) = 0 ; }
msft = 0 ;
/* initialize serial */
{
/* clear index */
rindex = 0 ;
/* clear buffer */
*(rbuf+0) = 0 ;
/* set Baud Rate Registers */
UBRR = MYUBRR ;
/* Enable receive interrupt , receive module and transmit module */
UCR = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);
}
/* initialize timer1 */
{
/* clear timer/counter */
TCNT1 = 0 ;
/* set counter */
OCR1A = 9999 ;
/* Control Register 1 B */
TCCR1B = (1 << CS10) ;
}
/* Enable interrupt */
TIMSK |= (1 << OCIE1A) | (1 << TOIE0);
}
/* UART receive interrupt */
ISR(SIG_UART_RECV)
{
UBYTE ch ;
/* get 1 charactoer */
ch = UDR ;
/* store */
*(rbuf+rindex) = ch ;
rindex++ ;
/* judge */
if ( ch == '\r' ) {
SFLAG = ON ;
rindex = 0 ;
}
}
/* timer1 interrupt */
ISR(SIG_OUTPUT_COMPARE1A)
{
/* clear timer/counter */
TCNT1 = 0 ;
/* get switch data */
msft <<= 1 ;
msft &= 0xfe ;
if ( PIND & 0x20 ) {
msft |= 1 ;
}
if ( msft == MASKFF ) {
MFLAG = ON ;
} else {
MFLAG = OFF ;
}
/* handling */
timer_handler();
}
void rs_putchar(UBYTE x)
{
while ( !(USR & (1 << UDRE)) ) {}
UDR = x ;
}
void rs_puts(UBYTE *x)
{
while ( *x != '\0' ) {
rs_putchar( *x ) ;
x++ ;
}
rs_putchar('\r');
rs_putchar('\n');
}
void write_eeprom(UWORD adr,UBYTE dat)
{
/* wait */
while ( EECR & (1 << EEWE) ) ;
/* set address */
EEARH = (UBYTE)((adr >> 8) & MASKFF);
EEARL = (UBYTE)(adr & MASKFF);
/* set data */
EEDR = dat ;
/* enable Master Write Enable */
EECR |= (1 << EEMWE) ;
/* enable Write Enable */
EECR |= (1 << EEWE);
}
UBYTE read_eeprom(UWORD adr)
{
/* wait */
while ( EECR & (1 << EEWE) ) ;
/* set address */
EEARH = (UBYTE)((adr >> 8) & MASKFF);
EEARL = (UBYTE)(adr & MASKFF);
/* enable Read Enable */
EECR |= (1 << EERE) ;
return EEDR ;
}
void push(UBYTE x)
{
stksft <<= 1 ;
stksft &= 0xfe ;
stksft |= x ;
}
UBYTE pull(void)
{
volatile UBYTE tmp ;
tmp = stksft ;
stksft >>= 1 ;
return(tmp & 1);
}
UWORD get_circuit_infomation(UWORD x)
{
volatile UBYTE dh;
volatile UBYTE dl;
volatile UWORD result ;
/* get upper byte */
dh = read_eeprom( x ) ;
/* get lower byte */
dl = read_eeprom( x+1 ) ;
/* concatenate */
result = dh ;
result <<= 8 ;
result |= dl ;
return result ;
}
void doStep(UWORD radr)
{
/* get circuit infomation from EEPROM */
operand = get_circuit_infomation( radr );
/* get operational code */
opcode = (UBYTE)(operand >> 12);
operand &= 0x0fff ;
q = ((operand & 0xff) >> 3);
r = ((operand & 0xff) & 0x07);
/* END instruction */
if ( opcode == OP_END ) return ;
/* LD LDN instruction */
if ( opcode == OP_LD || opcode == OP_LDN ) {
push( reg );
reg = *(memory+q);
reg >>= r;
reg &= 1 ;
/* inverse */
if ( opcode == OP_LDN ) { reg ^= 1 ; }
}
/* OP_AND OP_ANDN OP_OR OP_ORN instruction */
if ( opcode == OP_AND || opcode == OP_ANDN ||
opcode == OP_OR || opcode == OP_ORN ) {
regx = *(memory+q);
regx >>= r;
regx &= 1;
/* inverse */
if ( opcode == OP_ANDN || opcode == OP_ORN ) { regx ^= 1 ; }
/* AND ANDN instruction */
if ( opcode == OP_AND || opcode == OP_ANDN ) { reg &= regx ; }
/* OR ORN instruction */
if ( opcode == OP_OR || opcode == OP_ORN ) { reg |= regx ; }
}
/* OP_ANDB OP_ORB instruction */
if ( opcode == OP_ANDB || opcode == OP_ORB ) {
regx = pull();
/* block AND */
if ( opcode == OP_ANDB ) { reg &= regx ; }
/* block OR */
if ( opcode == OP_ORB ) { reg |= regx ; }
}
/* OP_OUT instruction */
if ( opcode == OP_OUT ) {
/* shift bit data */
reg <<= r ;
/* clear target bit */
*(memory+q) ^= ~(1 << r);
/* store target bit */
*(memory+q) |= reg ;
}
}
UBYTE get_hex(UBYTE x)
{
volatile UBYTE result ;
/* default */
result = 0 ;
/* select */
if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }
/* */
return result ;
}
UWORD get_ad(UBYTE onoff)
{
volatile UWORD result ;
/* get first byte */
result = get_hex( *(rbuf+1) );
/* get second byte */
result = (result << 4) | get_hex( *(rbuf+2) );
/* get third byte */
result = (result << 4) | get_hex( *(rbuf+3) );
/* get fourth byte */
result = (result << 4) | get_hex( *(rbuf+4) );
/* compute data */
if ( onoff == ON ) {
/* get first byte */
result = get_hex( *(rbuf+5) );
/* get second byte */
result = (result << 4) | get_hex( *(rbuf+6) );
/* get third byte */
result = (result << 4) | get_hex( *(rbuf+7) );
/* get fourth byte */
result = (result << 4) | get_hex( *(rbuf+8) );
}
/* */
return result ;
}
void put_dat_eeprom(UWORD adr,UWORD dat)
{
volatile UBYTE dhl ;
/* get upper data */
dhl = (UBYTE)((dat >> 8) & MASKFF) ;
/* store */
write_eeprom( adr , dhl );
/* get lower data */
dhl = (UBYTE)(dat & MASKFF) ;
/* store */
write_eeprom( adr+1 , dhl );
}
目次
前
次