目次

ESP32シリアルインタフェース処理

 ESP32の動作クロックは、80MHzというので、シリアル
 インタフェースがどうなっているのかを調べてみます。

 最初に書いたスケッチは、以下。

#define LED_PINA 2
#define LED_PINB 4

#define OFF 0
#define ON  OFF+1

/* initialize timer */
hw_timer_t* xtimer = NULL ;

void init_tim0();

boolean uflag ;

byte xcnt ;

byte left   ;
byte leftx  ;

byte right  ;
byte rightx ;

char sbuf[16] ;
byte sindex ;
char cmd ;

/* interrupt service routine */
void IRAM_ATTR MY_TIM0_INT()
{
  if ( xcnt < leftx )
  {
    digitalWrite(LED_PINA,HIGH);
  } else {
    digitalWrite(LED_PINA,LOW);
  }
  if ( xcnt < rightx )
  {
    digitalWrite(LED_PINB,HIGH);
  } else {
    digitalWrite(LED_PINB,LOW);
  }
  /* update */
  xcnt++ ;
  /* judge */
  if ( xcnt == 100 ) {
    xcnt = 0 ;
    leftx  = left ;
    rightx = right ;
  }
}

void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_help();
byte getHex(char x);
char getAsc(byte x);
void show_value(byte x);

void setup()
{
  pinMode(3,INPUT_PULLUP);
  /* serial */
  Serial.begin(9600,SERIAL_8N1,3,1);
  rs_puts("Hello !");
  crlf();
  show_help();
  /* initialize PIN value and direction */
  digitalWrite(LED_PINA,LOW);
  digitalWrite(LED_PINB,LOW);
  pinMode(LED_PINA,OUTPUT);
  pinMode(LED_PINB,OUTPUT);
  /* clear flag */
  uflag = OFF ;
  /* clear counters */
  xcnt = 0 ;
  left   = 50 ;
  leftx  = 50 ;
  right  = 50 ;
  rightx = 50 ;
  /* initialize timers */
  init_tim0();
}

void loop()
{
  /* command interpreter */
  if ( uflag == ON ) {
    /* clear event flag */
    uflag = OFF ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* ? */
    if ( cmd == '?' ) { show_help() ; }
    /* left duty */
    if ( cmd == 'L' ) {
      /* clear */
      left = 0 ;
      /* update */
      left |= getHex( *(sbuf+1) ) ;
      left *= 10 ;
      left |= getHex( *(sbuf+2) ) ;
    }
    /* right duty */
    if ( cmd == 'R' ) {
      /* clear */
      right = 0 ;
      /* update */
      right |= getHex( *(sbuf+1) ) ;
      right *= 10 ;
      right |= getHex( *(sbuf+2) ) ;
    }
    /* show duty ratio */
    if ( cmd == 'D' ) {
      rs_puts("LEFT  "); show_value( left )  ; crlf();
      rs_puts("RIGHT "); show_value( right ) ; crlf();
    }
    /* new line */
    crlf();
  }
}

void init_tim0()
{
  /* 80MHz / 80 = 1MHz (1us) */
  xtimer = timerBegin(0, 80, true); 
  /* attach ISR */
  timerAttachInterrupt(xtimer,&MY_TIM0_INT,true);
  /* set period 100us */
  timerAlarmWrite(xtimer,100,true);
  /* enable timer interrupt */
  timerAlarmEnable(xtimer);
}

void rs_putchar(char x)
{
  Serial.write(x);
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

void crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void show_help()
{
  rs_puts("? list command")        ; crlf();
  rs_puts("L set left duty ratio") ; crlf();
  rs_puts("R set right duty ratio"); crlf();
  rs_puts("D show both duty ratio"); crlf();
}

byte getHex(char x)
{
  byte result ;
  /* default */
  result = 0 ;
  /* judge */
  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 ;
}

char getAsc(byte x)
{
  char result ;
  /* default */
  result = '0' ;
  /* judge */
  if ( x < 10 ) { result = x + '0' ; }
  else          { result = x - 10 + 'A' ; }

  return result ;
}

void show_value(byte x)
{
  byte tmp ;
  char msg[4] ;
  /* copy */
  tmp = x ;
  /* delimiter */
  *(msg+3) = '\0' ;
  /* separate */
  *(msg+2) = getAsc(tmp % 10) ; tmp /= 10 ;
  *(msg+1) = getAsc(tmp % 10) ; tmp /= 10 ;
  *(msg+0) = getAsc(tmp % 10) ;
  /* zero surpress */
  if ( *(msg+0) == '0' ) {
    *(msg+0) = ' ' ;
    if ( *(msg+1) == '0' ) {
      *(msg+1) = ' ' ;
    }
  }
  /* show */
  rs_puts( msg );
}

void serialEvent()
{
  byte ch;
  byte ii ;
  byte caps ;
  /* get context size */
  caps = Serial.available();
  /* */
  if ( caps > 0 ) {
    /* transfer */
    for ( ii = 0 ; ii < caps ; ii++ ) {
      /* get 1 character */
      ch = Serial.read();
      /* store */
      *(sbuf+sindex) = ch ;
      /* increment */
      sindex++ ;
      /* judge */
      if ( ch == '\r' ) {
        sindex = 0 ; 
        uflag  = ON ;
      }
    }
  }
}

 2つのLEDを使い、PWM波形をLEDに送信する処理を
 タイマー割込みで実現しています。

 PWM波形は、DUTY比を変えると、LEDの輝度が変化するので
 DUTY比を変えて、確認しようとしました。

 TeraTermでコマンドを与えても、レスポンスがありません。



 この現象が何を意味するのか不明でした。

 レスポンスがないのは、コマンドインタプリタが動いて
 いないということ。インタプリタはイベント通知フラグ
 で駆動されるので、受信割込みが発生していないのだ。

 こう考えれば、ATmega168を利用した場合とESP32では
 受信割込みの扱いが違うことを理解しました。

 一晩寝て、次のカラクリを思いつきました。

 loop()の中でハードウエアのもつバッファを見て、データが
 あれば、自前の受信バッファに転送してやれば、いけるはず。

 この考え方で、スケッチを書き直し。

#define LED_PINA 2
#define LED_PINB 4

#define OFF 0
#define ON  OFF+1

/* initialize timer */
hw_timer_t* xtimer = NULL ;

void init_tim0();

boolean uflag ;

byte xcnt ;

byte left   ;
byte leftx  ;

byte right  ;
byte rightx ;

char sbuf[16] ;
byte sindex ;
char cmd ;

/* interrupt service routine */
void IRAM_ATTR MY_TIM0_INT()
{
  if ( xcnt < leftx )
  {
    digitalWrite(LED_PINA,HIGH);
  } else {
    digitalWrite(LED_PINA,LOW);
  }
  if ( xcnt < rightx )
  {
    digitalWrite(LED_PINB,HIGH);
  } else {
    digitalWrite(LED_PINB,LOW);
  }
  /* update */
  xcnt++ ;
  /* judge */
  if ( xcnt == 100 ) {
    xcnt = 0 ;
    leftx  = left ;
    rightx = right ;
  }
}

void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_help();
byte getHex(char x);
char getAsc(byte x);
void show_value(byte x);
void serialHandling();

void setup()
{
  pinMode(3,INPUT_PULLUP);
  /* serial */
  Serial.begin(9600,SERIAL_8N1,3,1);
  rs_puts("Hello !");
  crlf();
  show_help();
  /* initialize PIN value and direction */
  digitalWrite(LED_PINA,LOW);
  digitalWrite(LED_PINB,LOW);
  pinMode(LED_PINA,OUTPUT);
  pinMode(LED_PINB,OUTPUT);
  /* clear flag */
  uflag = OFF ;
  /* clear counters */
  xcnt = 0 ;
  left   = 50 ;
  leftx  = 50 ;
  right  = 50 ;
  rightx = 50 ;
  /* initialize timers */
  init_tim0();
}

void loop()
{
  /* command interpreter */
  if ( uflag == ON ) {
    /* clear event flag */
    uflag = OFF ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* ? */
    if ( cmd == '?' ) { show_help() ; }
    /* left duty */
    if ( cmd == 'L' ) {
      /* clear */
      left = 0 ;
      /* update */
      left |= getHex( *(sbuf+1) ) ;
      left *= 10 ;
      left |= getHex( *(sbuf+2) ) ;
    }
    /* right duty */
    if ( cmd == 'R' ) {
      /* clear */
      right = 0 ;
      /* update */
      right |= getHex( *(sbuf+1) ) ;
      right *= 10 ;
      right |= getHex( *(sbuf+2) ) ;
    }
    /* show duty ratio */
    if ( cmd == 'D' ) {
      rs_puts("LEFT  "); show_value( left )  ; crlf();
      rs_puts("RIGHT "); show_value( right ) ; crlf();
    }
    /* new line */
    crlf();
  }
  /* serial buffer watch */
  serialHandling();
}

void init_tim0()
{
  /* 80MHz / 80 = 1MHz (1us) */
  xtimer = timerBegin(0, 80, true); 
  /* attach ISR */
  timerAttachInterrupt(xtimer,&MY_TIM0_INT,true);
  /* set period 100us */
  timerAlarmWrite(xtimer,100,true);
  /* enable timer interrupt */
  timerAlarmEnable(xtimer);
}

void rs_putchar(char x)
{
  Serial.write(x);
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

void crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void show_help()
{
  rs_puts("? list command")        ; crlf();
  rs_puts("L set left duty ratio") ; crlf();
  rs_puts("R set right duty ratio"); crlf();
  rs_puts("D show both duty ratio"); crlf();
}

byte getHex(char x)
{
  byte result ;
  /* default */
  result = 0 ;
  /* judge */
  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 ;
}

char getAsc(byte x)
{
  char result ;
  /* default */
  result = '0' ;
  /* judge */
  if ( x < 10 ) { result = x + '0' ; }
  else          { result = x - 10 + 'A' ; }

  return result ;
}

void show_value(byte x)
{
  byte tmp ;
  char msg[4] ;
  /* copy */
  tmp = x ;
  /* delimiter */
  *(msg+3) = '\0' ;
  /* separate */
  *(msg+2) = getAsc(tmp % 10) ; tmp /= 10 ;
  *(msg+1) = getAsc(tmp % 10) ; tmp /= 10 ;
  *(msg+0) = getAsc(tmp % 10) ;
  /* zero surpress */
  if ( *(msg+0) == '0' ) {
    *(msg+0) = ' ' ;
    if ( *(msg+1) == '0' ) {
      *(msg+1) = ' ' ;
    }
  }
  /* show */
  rs_puts( msg );
}

void serialHandling()
{
  byte ch;
  byte ii ;
  byte caps ;
  /* get context size */
  caps = Serial.available();
  /* */
  if ( caps > 0 ) {
    /* transfer */
    for ( ii = 0 ; ii < caps ; ii++ ) {
      /* get 1 character */
      ch = Serial.read();
      /* store */
      *(sbuf+sindex) = ch ;
      /* increment */
      sindex++ ;
      /* judge */
      if ( ch == '\r' ) {
        sindex = 0 ; 
        uflag  = ON ;
      }
    }
  }
}

 このスケッチで、動作試験すると次のように
 なりました。



 コマンドを受け付けるようになり、与えた機能を
 全うするようになっています。

 この動作を確認したのは、5x5のLEDマトリクス基板。




目次

inserted by FC2 system