目次

reduce circuit

 ディスクリート回路を小さな基板でも
 使えるように、PICを利用してICの数を
 減らしてみました。

 元の回路は、以下。



 2個のプッシュスイッチのチャタリング除去のため
 ヒステリシスインバータを使っています。

 スイッチ入力の'H'を、論理和回路に入れて出力の'H'を
 反転し、NE555のトリガーとします。

 NE555は、規定時間だけ'H'を出力。

 タイミングチャートで見ると、以下。



 この回路をPIC12F1501を利用して、エミュレートする
 ならば、以下でよいでしょう。



 ディスクリートICを減らすのと同時に、次の部品を
 使わないで済ませられます。

 抵抗とキャパシタの数を減らし、抵抗3本だけに。

 抵抗を減らしたので、PIC12F1501の該当ピンに
 内部で、プルアップ抵抗を接続。

  WPUA = 0x30 ;

 初期化を考えると、次の関数でまとまるでしょう。

void setup(void)
{
  /* select 2MHz */
  OSCCON = (0x0d << 3) | 0x03 ;
  /* I/O value */
  LATA = 0x00 ;
  /* I/O directions */
  TRISA = 0x38 ; /* 0011 1000 */
  /* pull-up */
  WPUA = 0x30 ;
  /* all pin are digital */
  ANSELA = 0 ;
  /* disable A/D converter */
  ADCON0.ADON = OFF ;
  ADCON2      = 0 ;
  /* disable D/A converter */
  DACCON0.DACEN = OFF ;
  /* disable compare module */
  CM1CON0.C1ON = OFF ;
  CM1CON0.C1OE = OFF ;
  /* initialize Timer 0 */
  {
    /*
       2MHz/4 = 500kHz -> 500kHz/4 = 125kHz prescaler = 1:4
    */
    OPTION_REG = 0x01 ;
    /* 256 - 6 = 250 (2ms) */
    TMR0 = CNTBEGIN ;
    /* enable timer0 overflow interrupt */
    INTCON.TMR0IE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* initialize Timer 1 
    2MHz / 4 = 500kHz -> 500kHz / 8 = 62.5kHz
    50000 / 62.5 = 800 ms
  */
  {
    T1CON  = 0x30 ;
    T1GCON = 0 ;
  }
  /* clear flag */
  eflag = OFF ;
  tflag = OFF ;
  /* clear variables */
  state = 0 ;
  psw_sft = 0 ;
  wsw_sft = 0 ;
}

 すべてのI/Oピンを、デジタルで扱い
 A/D変換、D/A変換、比較処理を
 使わない仕様でまとめておきます。

 内蔵タイマーは、タイマー0とタイマー1を使い
 タイマー1は、出力の'H'パルスの持続時間を扱う
 ことにして、タイマー0はスイッチのチャタリング
 除去に利用。

 1個のスイッチのチャタリング除去は、次の回路と
 等価にしてあります。



 プログラムでみれば、以下。

void get_sw(void)
{
  /* skip */
  if ( tflag == OFF ) return ;
  /* clear interrupt flag */
  tflag = OFF ;
  /* shift */
  psw_sft <= 1 ;
  wsw_sft <= 1 ;
  /* mask */
  psw_sft &= MASK0F ;
  wsw_sft &= MASK0F ;
  /* judge logical level */
  ptmp = PORTA ;
  if ( ptmp.F4 == 0 ) { psw_sft |= ON ; }
  if ( ptmp.F5 == 0 ) { wsw_sft |= ON ; }
  /* judge */
  eflag = OFF ;
  if ( psw_sft == MASK07 ) { eflag = ON ; }
  if ( wsw_sft == MASK07 ) { eflag = ON ; }

 時間経過は、割込みを利用して通知。
 割込み処理は、次の関数で実現。

void interrupt(void)
{
  /* generate 1Hz */
  if ( INTCON.T0IF == ON ) {
    /* clear flag */
    INTCON.T0IF = OFF ;
    /* initialize */
    TMR0 = CNTBEGIN ;
    /* set flag */
    tflag = ON ;
  }
}

 パルス出力は、フラグで通知されるので
 ステートマシンで実現します。

 ステートマシンは、以下のよう組んで見ました。



 プログラムコードに落とすと、以下。

void perform(void)
{
  switch( state ) {
    /* wait trigger */
    case 0 : state = 0 ;
             if ( eflag == ON ) {
               eflag = OFF ;
               state = 1 ; 
             }
             break ;
    /* clear counter */
    case 1 : state = 2 ;
             TMR1H = 0 ;
             TMR1L = 0 ;
             break ;
    /* enable timer */
    case 2 : state = 3 ;
             T1CON.TMR1ON = ON ;
             LATA = ON ;
             break ;
    /* delay */
    case 3 : state = 3 ;
             if ( (TMR1H == VDH) && (TMR1L >= VDL) ) {
               state = 4 ;
             }
             break ;
    /* disable timer */
    case 4 : state = 5 ;
             T1CON.TMR1ON = OFF ;
             LATA = OFF ;
             break ;
    /* return first state */
    case 5 : state = 0 ;
             break ;
    /* others */
    default : state = 0 ;
              break ;
  }
}

 スイッチの状態でイベント通知する関数(get_sw)と
 パルスを出力する関数(perform)を並べていけばよい
 ので、ラッパー関数を用意して、考えやすくします。

void loop(void)
{
  get_sw();
  perform(void);
}

 関数loopは、Arduinoの関数に似せて命名してます。

 ここまでをまとめて、次のようにできます。

/*
      internal 2MHz system clock

      GP0(7 pin) pulse output
      GP1(6 pin) output
      GP2(5 pin) output
      GP3(4 pin) reset
      GP4(3 pin) push switch (negative edge)
      GP5(2 pin) wireless switch (negative edge)
*/
typedef unsigned char UBYTE ;
typedef unsigned short UWORD ;
/*
#define POUT PORTA.F0
#define PSW  PORTA.F4
#define WSW  PORTA.F5
*/
#define OFF 0
#define ON  OFF+1

#define MASK0F 0x0F
#define MASK07 0x07

#define VDH 195 // 50000 / 256
#define VDL  80 // 50000 % 256

#define CNTBEGIN 6

volatile UBYTE state ;
volatile UBYTE eflag ;
volatile UBYTE tflag ;
volatile UBYTE psw_sft ;
volatile UBYTE wsw_sft ;
volatile UBYTE ptmp ;
  
/* interrupt handler */
void interrupt(void)
{
  /* generate 1Hz */
  if ( INTCON.T0IF == ON ) {
    /* clear flag */
    INTCON.T0IF = OFF ;
    /* initialize */
    TMR0 = CNTBEGIN ;
    /* set flag */
    tflag = ON ;
  }
}

/* function prototype */
void setup(void);
void loop(void);
void get_sw(void);
void perform(void);

void main(void)
{
  /* initialize */
  setup();
  /* endless loop */
  while (ON) {
    loop();
  }
}

/* define function body */
void setup(void)
{
  /* select 2MHz */
  OSCCON = (0x0d << 3) | 0x03 ;
  /* I/O value */
  LATA = 0x00 ;
  /* I/O directions */
  TRISA = 0x38 ; /* 0011 1000 */
  /* pull-up */
  WPUA = 0x30 ;
  /* all pin are digital */
  ANSELA = 0 ;
  /* disable A/D converter */
  ADCON0.ADON = OFF ;
  ADCON2      = 0 ;
  /* disable D/A converter */
  DACCON0.DACEN = OFF ;
  /* disable compare module */
  CM1CON0.C1ON = OFF ;
  CM1CON0.C1OE = OFF ;
  /* initialize Timer 0 */
  {
    /*
       2MHz/4 = 500kHz -> 500kHz/4 = 125kHz prescaler = 1:4
    */
    OPTION_REG = 0x01 ;
    /* 256 - 6 = 250 (2ms) */
    TMR0 = CNTBEGIN ;
    /* enable timer0 overflow interrupt */
    INTCON.TMR0IE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* initialize Timer 1 
    2MHz / 4 = 500kHz -> 500kHz / 8 = 62.5kHz
    50000 / 62.5 = 800 ms
  */
  {
    T1CON  = 0x30 ;
    T1GCON = 0 ;
  }
  /* clear flag */
  eflag = OFF ;
  tflag = OFF ;
  /* clear variables */
  state = 0 ;
  psw_sft = 0 ;
  wsw_sft = 0 ;
}

void loop(void)
{
  get_sw();
  perform();
}

void get_sw(void)
{
  /* skip */
  if ( tflag == OFF ) return ;
  /* clear interrupt flag */
  tflag = OFF ;
  /* shift */
  psw_sft <= 1 ;
  wsw_sft <= 1 ;
  /* mask */
  psw_sft &= MASK0F ;
  wsw_sft &= MASK0F ;
  /* judge logical level */
  ptmp = PORTA ;
  if ( ptmp.F4 == 0 ) { psw_sft |= ON ; }
  if ( ptmp.F5 == 0 ) { wsw_sft |= ON ; }
  /* judge */
  eflag = OFF ;
  if ( psw_sft == MASK07 ) { eflag = ON ; }
  if ( wsw_sft == MASK07 ) { eflag = ON ; }
}

void perform(void)
{
  switch( state ) {
    /* wait trigger */
    case 0 : state = 0 ;
             if ( eflag == ON ) {
               eflag = OFF ;
               state = 1 ; 
             }
             break ;
    /* clear counter */
    case 1 : state = 2 ;
             TMR1H = 0 ;
             TMR1L = 0 ;
             break ;
    /* enable timer */
    case 2 : state = 3 ;
             T1CON.TMR1ON = ON ;
             LATA = ON ;
             break ;
    /* delay */
    case 3 : state = 3 ;
             if ( (TMR1H == VDH) && (TMR1L >= VDL) ) {
               state = 4 ;
             }
             break ;
    /* disable timer */
    case 4 : state = 5 ;
             T1CON.TMR1ON = OFF ;
             LATA = OFF ;
             break ;
    /* return first state */
    case 5 : state = 0 ;
             break ;
    /* others */
    default : state = 0 ;
              break ;
  }
}

 「mikroC PRO for PIC」の評価版を使い
 コンパイル、リンクして動作を確認して
 あります。

 半田付けした基板は、以下。




目次

inserted by FC2 system