目次
前
次
計測器エミュレータ
Personal Computer上のアプリケーションソフトを
開発したときに、対象となる計測器の代用にPICを
利用しました。シリアルインタフェースで接続して
使います。
仕様は、次のように単純です。
- コマンドで'?'を入力すると、ヘルプ関連文字列を転送
- コマンドで'C'を入力すると、計測値を1レコードごとに転送開始
- コマンドで'c'を入力すると、計測値レコードの転送終了
- コマンドで'N'を入力すると、機械番号を10進数2けたで転送
エミュレータのハードウエアブロック図は
次のようにしました。
外付けでDIPスイッチを用意し、アナログスイッチで
0から255の2進数でリードできるようにします。
これを機械番号とします。
LEDは、機械番号確認用です。
コマンドインタプリタから作成していきます。
ヘルプ処理
if ( cmd == '?' ) {
show_help() ;
}
利用する関数を定義します。
void show_help()
{
rs_puts("? help");
rs_puts("C begin measure");
rs_puts("c stop measure");
rs_puts("N show number");
}
計測値転送開始
if ( cmd == 'C' ) {
eflag = ON ;
}
フラグがセットされているときだけ
計測値を端末に送るようにします。
計測値出力処理は、後で定義します。
計測値転送停止
if ( cmd == 'c' ) {
eflag = OFF ;
}
機械番号表示
if ( cmd == 'N' ) {
/* get number from DIP switch */
xnum = 0 ;
for ( loop = 0 ; loop < 8 ; loop++ ) {
/* shift */
xnum <<= 1 ;
/* transmitt address */
PORTC &= ~0x07 ;
PORTC |= (7-loop) & 0x07 ;
/* update LSB */
if ( PORTC.B3 == ON ) { xnum |= ON ; }
}
/* show LEDs */
PORTB = xnum ^ 0xff ; /* inverted */
/* send number to terminal */
rs_putchar( (xnum / 100) + '0' ); xnum %= 100 ;
rs_putchar( (xnum / 10 ) + '0' );
rs_putchar( (xnum % 10 ) + '0' );
crlf();
}
コマンドインタプリタを考えたので
シリアル処理で使う関数を定義します。
1文字出力
送信バッファにデータがないことを確認後
レジスタに文字を設定します。
void rs_putchar(UBYTE x)
{
/* judge */
while ( !TXSTA.TRMT ) ;
/* set data */
TXREG = x ;
}
1文字列出力
送信文字列の先頭アドレスを渡して
'\0'を検出するまで、1文字ずつ
送信します。
void rs_puts(UBYTE *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++ ;
}
crlf();
}
改行
端末画面で改行できるように、改行
コードを送信します。
void crlf(void)
{
rs_putchar('\r');
rs_putchar('\n');
}
文字列受信
1文字受信すると、受信バッファに保存
していきます。'\r'を検出するとコマンド
インタプリタに通知します。
void interrupt(void)
{
UBYTE chx ;
/* receive interrupt */
if ( PIR1.RCIF == ON ) {
/* clear flag */
PIR1.RCIF = OFF ;
/* get 1 charactor */
chx = RCREG ;
/* store */
*(sbuf+sindex) = chx ;
/* increment */
sindex++ ;
/* judge */
if ( chx == '\r' ) {
sindex = 0 ;
rflag = ON ;
}
}
}
受信バッファは、リングバッファで構成するのが
定石ですが、今回はコマンドが1文字でパラメータ
がないので、単純な配列にします。
配列のどこに文字を格納するかを指定する変数も
用意します。
typedef unsigned char UBYTE ;
UBYTE sbuf[4] ;
UBYTE sindex ;
計測値は、温度、生値、換算値の3種を1レコードで
構成しています。温度は、小数第1位までですが10倍
して整数にします。生値は4けたの整数、換算値は
浮動小数点つきですが、小数第2位までで全体で5桁
です。
(例) 234 1025 30.55
エミュレーションすればよいので、5レコードを
文字列で用意して、それを順次送信します。
フラグがセット中に送信します。
if ( eflag == ON ) {
switch ( state ) {
case 1 : rs_puts("123 1128 31.23") ; break ;
case 2 : rs_puts("234 1256 32.34") ; break ;
case 3 : rs_puts("456 1384 34.56") ; break ;
case 4 : rs_puts("789 1512 37.89") ; break ;
default : rs_puts("012 1000 30.00") ; break ;
}
state++ ;
if ( state == 5 ) { state = 0 ; }
}
時間経過がわからないのでタイマー割込みから
1秒経過をフラグ通知し、5レコード中の指定
文字列を表示します。
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* update state */
state++ ;
if ( state == 5 ) { state = 0 ; }
/* enable send */
sflag = ON ;
}
if ( eflag == ON && sflag == OFF ) {
/* clear flag */
sflag = OFF ;
/* show */
switch ( state ) {
case 1 : rs_puts("123 1128 31.23") ; break ;
case 2 : rs_puts("234 1256 32.34") ; break ;
case 3 : rs_puts("456 1384 34.56") ; break ;
case 4 : rs_puts("789 1512 37.89") ; break ;
default : rs_puts("012 1000 30.00") ; break ;
}
}
割込みは、タイマー、受信の2種でよいので
ハンドラとして関数にまとめます。
void interrupt(void)
{
UBYTE chx ;
/* generate 1ms */
if ( INTCON.TMR0IF == ON ) {
/* clear flag */
INTCON.TMR0IF = OFF ;
/* initialize */
TMR0 = 6 ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0x3ff) == 1000 ) { TFLAG = ON ; }
}
/* receive interrupt */
if ( PIR1.RCIF == ON ) {
/* clear flag */
PIR1.RCIF = OFF ;
/* get 1 charactor */
chx = RCREG ;
/* store */
*(sbuf+sindex) = chx ;
/* increment */
sindex++ ;
/* judge */
if ( chx == '\r' ) {
sindex = 0 ;
RFLAG = ON ;
}
}
}
フラグを利用する場合、1ビットでよいので
1バイト中の各ビットにフラグを割当てます。
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define RFLAG xflags.BIT.B0
#define EFLAG xflags.BIT.B1
#define TFLAG xflags.BIT.B2
#define SFLAG xflags.BIT.B3
利用するクロックは4MHzとして、通信条件等を指定。
void init_usr(void)
{
/* disable A/D converter */
ADCON1 = 0x07 ;
/* disable Analog comparator */
CMCON = 0x07 ;
/* I/O initial state */
PORTA = 0xff ;
PORTB = 0x00 ;
PORTC = (1 << RX_BIT);
/* I/O direction */
TRISA = 0 ;
TRISB = 0 ;
TRISC = (1 << RX_BIT) | (1 << PM_BIT) ;
/* initialize serial interface */
{
sindex = 0 ;
/* BAUD rate */
SPBRG = 25 ; /* 9600bps */
/* TxD */
TXSTA.TXEN = ON ;
TXSTA.SYNC = OFF ;
TXSTA.BRGH = ON ;
/* RxD */
RCSTA.SPEN = ON ;
RCSTA.CREN = ON ;
/* enable receive interrupt */
PIE1.RCIE = ON ;
}
/* initialize Timer 0 */
{
/*
4MHz/4 = 1MHz -> 1MHz/4 = 250kHz prescaler = 1:4
all inputs are pull-up .
*/
OPTION_REG = 0x01 ;
/* 256 - 250 = 6 */
TMR0 = 6 ;
/* enable timer0 overflow interrupt */
INTCON.TMR0IE = ON ;
}
/* enable peripheral interrupt */
INTCON.PEIE = ON ;
/* enable general interrupt */
INTCON.GIE = ON ;
/* clear flags */
xflags.DR = 0 ;
/* others */
timcnt = 0 ;
state = 0 ;
}
以上からソースコードを定義します。
/* redefine data type */
typedef unsigned char UBYTE ;
typedef unsigned int UWORD ;
typedef unsigned long ULONG ;
#define OFF 0
#define ON OFF+1
#define RX_BIT 7
#define TX_BIT 6
#define PM_BIT 3
#define MASKFF 0xff
#define MASK30 0x30
#define MASK0F 0x0f
#define MASK07 0x07
#define MASK03 0x03
#define MASK3FF 0x3ff
typedef union {
struct {
unsigned B7:1;
unsigned B6:1;
unsigned B5:1;
unsigned B4:1;
unsigned B3:1;
unsigned B2:1;
unsigned B1:1;
unsigned B0:1;
} BIT ;
unsigned char DR ;
} FLAGSP ;
volatile FLAGSP xflags ;
#define RFLAG xflags.BIT.B0
#define EFLAG xflags.BIT.B1
#define TFLAG xflags.BIT.B2
#define SFLAG xflags.BIT.B3
volatile ULONG timcnt ;
volatile UBYTE sbuf[4] ;
volatile UBYTE sindex ;
volatile UBYTE cmd ;
volatile UBYTE xnum ;
volatile UBYTE loop ;
volatile UBYTE state ;
/* function prototype */
void init_usr(void);
void rs_putchar(UBYTE x);
void rs_puts(UBYTE *ptr);
void crlf(void);
void show_help(void);
/* interrupt handler */
void interrupt(void)
{
UBYTE chx ;
/* generate 1ms */
if ( INTCON.TMR0IF == ON ) {
/* clear flag */
INTCON.TMR0IF = OFF ;
/* initialize */
TMR0 = 6 ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0x3ff) == 1000 ) { TFLAG = ON ; }
}
/* receive interrupt */
if ( PIR1.RCIF == ON ) {
/* clear flag */
PIR1.RCIF = OFF ;
/* get 1 charactor */
chx = RCREG ;
/* store */
*(sbuf+sindex) = chx ;
/* increment */
sindex++ ;
/* judge */
if ( chx == '\r' ) {
sindex = 0 ;
RFLAG = ON ;
}
}
}
void main(void)
{
/* user initialize */
init_usr();
/* endless loop */
while ( ON ) {
/* command interpreter */
if ( RFLAG == ON ) {
/* clear */
RFLAG = OFF ;
/* new line */
crlf();
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help() ; }
/* begin */
if ( cmd == 'C' ) { EFLAG = ON ; }
/* suspend */
if ( cmd == 'c' ) { EFLAG = OFF ; }
/* show machine number */
if ( cmd == 'N' ) {
/* get number from DIP switch */
xnum = 0 ;
for ( loop = 0 ; loop < 8 ; loop++ ) {
/* shift */
xnum <<= 1 ;
/* transmitt address */
PORTC &= ~MASK07 ;
PORTC |= (7-loop) & MASK07 ;
/* update LSB */
if ( PORTC.B3 == ON ) { xnum |= ON ; }
}
/* show LEDs */
PORTB = xnum ^ MASKFF ; /* inverted */
/* send number to terminal */
rs_putchar( (xnum / 100) + '0' ); xnum %= 100 ;
rs_putchar( (xnum / 10 ) + '0' );
rs_putchar( (xnum % 10 ) + '0' );
crlf();
}
}
/* 1second pass */
if ( TFLAG == ON ) {
/* clear flag */
TFLAG = OFF ;
/* update state */
state++ ;
if ( state == 5 ) { state = 0 ; }
/* enable send */
SFLAG = ON ;
}
/* show measure recode */
if ( EFLAG == ON && SFLAG == OFF ) {
/* clear flag */
SFLAG = OFF ;
/* show */
switch ( state ) {
case 1 : rs_puts("123 1128 31.23") ; break ;
case 2 : rs_puts("234 1256 32.34") ; break ;
case 3 : rs_puts("456 1384 34.56") ; break ;
case 4 : rs_puts("789 1512 37.89") ; break ;
default : rs_puts("012 1000 30.00") ; break ;
}
}
}
}
/* define function body */
void init_usr(void)
{
/* disable A/D converter */
ADCON1 = 0x07 ;
/* disable Analog comparator */
CMCON = 0x07 ;
/* I/O initial state */
PORTA = 0xff ;
PORTB = 0x00 ;
PORTC = (1 << RX_BIT);
/* I/O direction */
TRISA = 0 ;
TRISB = 0 ;
TRISC = (1 << RX_BIT) | (1 << PM_BIT) ;
/* initialize serial interface */
{
sindex = 0 ;
/* BAUD rate */
SPBRG = 25 ; /* 9600bps */
/* TxD */
TXSTA.TXEN = ON ;
TXSTA.SYNC = OFF ;
TXSTA.BRGH = ON ;
/* RxD */
RCSTA.SPEN = ON ;
RCSTA.CREN = ON ;
/* enable receive interrupt */
PIE1.RCIE = ON ;
}
/* initialize Timer 0 */
{
/*
4MHz/4 = 1MHz -> 1MHz/4 = 250kHz prescaler = 1:4
all inputs are pull-up .
*/
OPTION_REG = 0x01 ;
/* 256 - 250 = 6 */
TMR0 = 6 ;
/* enable timer0 overflow interrupt */
INTCON.TMR0IE = ON ;
}
/* enable peripheral interrupt */
INTCON.PEIE = ON ;
/* enable general interrupt */
INTCON.GIE = ON ;
/* clear flags */
xflags.DR = 0 ;
/* others */
timcnt = 0 ;
state = 0 ;
}
void rs_putchar(UBYTE x)
{
/* judge */
while ( !TXSTA.TRMT ) ;
/* set data */
TXREG = x ;
}
void rs_puts(UBYTE *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++ ;
}
crlf();
}
void crlf(void)
{
rs_putchar('\r');
rs_putchar('\n');
}
void show_help(void)
{
rs_puts("? help");
rs_puts("C begin measure");
rs_puts("c stop measure");
rs_puts("N show number");
}
回路図は、以下。
目次
前
次