目次
前
次
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マトリクス基板。
目次
前
次