チーム1211

課題名

CoSP: Calculator on Single PSoC

研究者名

2-15-43 菱沼 和弘
2-15-44 平野 圭祐

概要

PSoC 上に再帰下降構文解析を用いた数式計算プログラムを実装した。
また,その応用例としてテルミン風楽器を制作した。

解説

再帰下降構文解析

今回実装した数式計算プログラムに対する入力文法を以下に示す。
<if_statement> ::= <expression> ( "?" <expression> ":" <expression> )?
  <expression> ::= <factor> ( ( "+" | "-" ) <factor> )*
      <factor> ::= <term> ( ( "*" | "/" ) <term> )*
                 | <term> "(" <if_statement ")"
                 | ( "+" | "-" ) <term>
                 | <number>
      <number> ::= <digit>+ | "X"
       <digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
なお,ここで丸括弧は文法定義のグループ化を表し,後置する? は0 回または1 回の登場を,後置する* は0 回以上の登場をそれぞれ表す。

上述文法を再帰下降構文解析によってC言語で実装し,PSoC 内MPUに書き込んだ。
数式の入力は,コンピュータからシリアルポート通信によって行い,結果は基板上LCDとコンピュータの画面上に出力される。(下の図を参照のこと)
IMG_0485_convert_20120514203735.jpgIMG_0482_convert_20120514203711.jpg

また,この装置のモジュール配置ブロック図を次に示す。
kcalc.gif

テルミン風楽器

今回制作したテルミン風楽器のモジュール配置図を次に示す。
Untitled.gif


これは,PSoCに接続されている距離センサーに物体を近づけたり遠ざけたりすると,スピーカから出力される音声の周波数が変化するものである。
コンピュータ上からシリアル通信によって数式を送信することにより,その周波数の特性を任意に動的に変更できる。

下に動作例を示す。
DSC00005_convert_20120515153808.jpgDSC00004_convert_20120515153748.jpg

考察

ハードウエアを容易に制御することができるPSoC に,構文解析器というソフトウエアを容易に制御することができる機構を搭載することで,PSoC の動作をハードウェア的にもソフトウェア的にもより柔軟に制御することができるということが分かった。
今回のようにあとからPSoC の動作を変えたい,またはその時その時によってさまざまな動作をPSoC にさせたいというときに,この手法は有用であると提言したい。
ただし,構文解析で用いた比較的深い再帰や乗除算という処理は本来PSoC が苦手とするものであり,その用途によっては実用に耐えられないボトルネックを生じる可能性があることを付記する。

Appendix

ソースコード(再帰下降構文解析)

#include <stdlib.h>
#include <ctype.h>
#include <m8c.h>
#include "PSoCAPI.h"

#define N 128

static int failed;
static char * e;
static char s[ N ];

static int if_statement ( void );

static int
term (
  void
  )
{
  int res;
  
  switch ( *e )
  {
    case '(':
      ++e;
      res = if_statement ( );
      if ( *e == ')' ) ++e;
      else failed = 1;
      break ;
    case '+':
      ++e;
      res = term ( );
      break ;
    case '-':
      ++e;
      res = -term ( );
      break ;
    default:
      if ( isdigit ( *e ) )
      {
        for ( res = 0; isdigit ( *e ); ++e )
        {
          res = res * 10 + ( *e - '0' );
        }
      }
      else failed = 1;
  }

  return ( res );
}

static int
factor (
  void
  )
{
  int res, rt;
  
  res = term ( );
  if ( failed ) return ( res );

  for ( ; ; )
  {
    switch ( *e )
    {
      case '*':
        ++e;
        rt = term ( );
        if ( failed ) return ( res );
        res *= rt;
        break ;
      case '/':
        ++e;
        rt = term ( );
        if ( failed ) return ( res );
        res /= rt;
        break ;
      default:
        return ( res );
    }
  }
}

static int
expression (
  void
  )
{
  int res, rt;
  
  res = factor ( );
  if ( failed ) return ( res );

  for ( ; ; )
  {
    switch ( *e )
    {
      case '+':
        ++e;
        rt = factor ( );
        if ( failed ) return ( res );
        res += rt;
        break ;
      case '-':
        ++e;
        rt = factor ( );
        if ( failed ) return ( res );
        res -= rt;
        break ;
      default:
        return ( res );
    }
  }
}

static int
if_statement (
  void
  )
{
  int res, lt, rt;

  res = expression ( );
  if ( failed ) return ( res );

  switch ( *e )
  {
    case '\0': break ;
    case '?':
      ++e;
      lt = expression ( );
      if ( failed | | *e != ':' )
      {
        failed = 1;
        return ( res );
      }
      ++e;
      rt = expression ( );
      if ( failed ) return ( res );
      res = res ? lt : rt;
      break ;
  }
  
  return ( res );
}

static void
getLine ( void )
{
  char * p = s;
  
  for ( ; ; )
  {
    char ch;

    ch = UART_cGetChar ( );
    if ( ch == '\r' ) break ;
    switch ( ch )
    {
      case '\b':
        if ( p != s )
        {
          --p;
          UART_CPutString ( "\b \b" );
        }
        break ;
      case ' ':
      case '\t':
        break ;
      default:
        *( p++ ) = ch;
        UART_PutChar ( ch );
        break ;
    }
  }
  UART_CPutString ( "\r\n" );
  *p = '\0';
  
  return ;
}

static void
printInt (
  void
  )
{
}

/** Application main entry point. */
void
main (
  void
  )
{
  int res;

  Counter8_1_Start ( );
  UART_Start ( UART_PARITY_NONE );
  LCD_Start ( );

  UART_CPutString ( "==============================\r\n" );
  UART_CPutString ( "  Kazh's Calculator on PSoC\r\n" );
  UART_CPutString ( "    Version: 0.01\r\n" );
  UART_CPutString ( "==============================\r\n\r\n" );
  
  for ( ; ; )
  {
    UART_CPutString ( "wait: " );
    getLine ( );
    LCD_Position ( 0, 0 ); LCD_PrCString ( "                " );
    LCD_Position ( 1, 0 ); LCD_PrCString ( "                " );
    LCD_Position ( 0, 0 ); LCD_PrString ( s );
    LCD_Position ( 1, 0 ); LCD_PrCString ( "  = " );
    e = s; failed = 0;
    res = if_statement ( );
    if ( failed | | *e != '\0' )
    {
      LCD_PrCString ( "Error!" );
      UART_CPutString ( "Error!\r\n" );
    }
    else
    {
      char a[ 17 ];
      
      itoa ( a, res, 10 );
      LCD_PrString ( a );
      UART_PutString ( a );
      UART_CPutString ( "\r\n" );
    }
  }

  return ;
}

ソースコード(テルミン風楽器)

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <m8c.h>
#include "PSoCAPI.h"

#define N 64

static int failed;
static int shifted = 0;
static char * e;
static char s[ N ] = "0";
static char t[ N ] = "", *p = t;
static unsigned int adc_data;

static int if_statement ( void );

static int
term (
  void
  )
{
  int res;
  
  switch ( *e )
  {
    case '(':
      ++e;
      res = if_statement ( );
      if ( *e == ')' ) ++e;
      else failed = 1;
      break ;
    case '+':
      ++e;
      res = term ( );
      break ;
    case '-':
      ++e;
      res = -term ( );
      break ;
    case 'X':
      ++e;
      res = adc_data;
      break ;
    default:
      if ( isdigit ( *e ) )
      {
        for ( res = 0; isdigit ( *e ); ++e )
        {
          res = res * 10 + ( *e - '0' );
        }
      }
      else failed = 1;
  }

  return ( res );
}

static int
factor (
  void
  )
{
  int res, rt;
  
  res = term ( );
  if ( failed ) return ( res );

  for ( ; ; )
  {
    switch ( *e )
    {
      case '*':
        ++e;
        rt = term ( );
        if ( failed ) return ( res );
        res *= rt;
        break ;
      case '/':
        ++e;
        rt = term ( );
        if ( failed ) return ( res );
        res /= rt;
        break ;
      default:
        return ( res );
    }
  }
}

static int
expression (
  void
  )
{
  int res, rt;
  
  res = factor ( );
  if ( failed ) return ( res );

  for ( ; ; )
  {
    switch ( *e )
    {
      case '+':
        ++e;
        rt = factor ( );
        if ( failed ) return ( res );
        res += rt;
        break ;
      case '-':
        ++e;
        rt = factor ( );
        if ( failed ) return ( res );
        res -= rt;
        break ;
      default:
        return ( res );
    }
  }
}

static int
if_statement (
  void
  )
{
  int res, lt, rt;

  res = expression ( );
  if ( failed ) return ( res );

  switch ( *e )
  {
    case '\0': break ;
    case '?':
      ++e;
      lt = expression ( );
      if ( failed | | *e != ':' )
      {
        failed = 1;
        return ( res );
      }
      ++e;
      rt = expression ( );
      if ( failed ) return ( res );
      res = res ? lt : rt;
      break ;
  }
  
  return ( res );
}

static void
getLine (
  void
  )
{
  int ch = UART_iReadChar ( );
  
  if ( ch & 0xFF00 ) return ;

  if ( ch == '\r' )
  {
    *p = '\0';
    
    strcpy ( s, t );
    p = t;

    UART_CPutString ( "\r\n" );
    UART_CPutString ( "wait: " );

    return ;
  }
    
  switch ( ch )
  {
    case '\b':
      if ( p != t )
      {
        --p;
        UART_CPutString ( "\b \b" );
      }
      break ;
    case ' ':
    case '\t':
      break ;
    default:
      if ( p != t + N - 1 )
      {
        ch = toupper ( ch );
        *( p++ ) = ch;
        UART_PutChar ( ch );
      }
      break ;
  }
  
  return ;
}

static void
calcLine (
  void
  )
{
  int res;
  
  if ( !( shifted ) ) return;
  
  if ( !( ADCINC_fIsDataAvailable ( ) ) ) return ;

  adc_data = ADCINC_wClearFlagGetData ( );
  adc_data /= 100;

  LCD_Position ( 0, 0 ); LCD_PrCString ( "                " );
  LCD_Position ( 1, 0 ); LCD_PrCString ( "                " );
  LCD_Position ( 0, 0 ); LCD_PrString ( s );
  LCD_Position ( 1, 0 ); LCD_PrCString ( "  = " );
  e = s; failed = 0;
  res = if_statement ( );
  if ( failed | | *e != '\0' )
  {
    LCD_PrCString ( "Error!" );
  }
  else
  {
    char a[ 17 ];
    
    itoa ( a, res, 10 );
    LCD_PrString ( a );
  
    if ( res < 0 ) res = 0;
    PWM_WritePeriod ( res );
    PWM_WritePulseWidth ( res >> 1 );
  }
  
  shifted = 0;
  
  return ;
}

#pragma interrupt_handler shifter
void
shifter (
  void
  )
{
  shifted = 1;
}

/** Application main entry point. */
void
main (
  void
  )
{
  PGA_Start ( PGA_HIGHPOWER );
  ADCINC_Start ( ADCINC_HIGHPOWER );
  ADCINC_GetSamples ( 0 );
  PWM_Start ( );
  
  Counter8_1_Start ( );
  UART_Start ( UART_PARITY_NONE );
  LCD_Start ( );

  Interrupter_EnableInt ( );
  Interrupter_Start ( );
  M8C_EnableGInt;

  UART_CPutString ( "==============================\r\n"
                    "  Kazh's Calculator on PSoC\r\n"
                    "    Version: 0.11\r\n"
                    "==============================\r\n\r\n"
                    "wait: " );
  
  for ( ; ; )
  {
    getLine ( );
    calcLine ( );
  }

  return ;
}

  • 最終更新:2012-05-15 16:03:38

このWIKIを編集するにはパスワード入力が必要です

認証パスワード