tiny2313実験回路 ayame2313 2011.05.10  

 AVR mcu を使う電子工作で時々気になることを実験機を通じて考えてみようと思ったことをメモするページです。自分自身の備忘録的メモですからお読みいただくには内容が稚拙になるだろうと思います。中には?マークつきのものも含まれる可能性があります。


  1 回路 
  2 基板製作 
  3 最初のプログラム 
  4 avr-gcc 定数と変数の考察 
  5  
  6  















  1 回路
 Tiny2313に最小限のIOとして1バイトのLED表示器と入出力機能のためにUART通信(USB-シリアル変換のTDとRDに接続)機能を付けただけのものです。
2313を選んだのはSRAMが少なくその領域が不足したときの影響がわかりやすいと考えたからです。


振動子にセラミック9.22MHzを選んだのは特に理由はありません。手持ちを使っただけです。UARTの安定性から内蔵RC発振は避けました。
電源コネクタは最近はこのようなものを使っています。小型です。廃品利用です。手間はかかります。


  2 基板製作
 基板製作も実験の内です。マジックインクで銅箔にパターンを描くのは昔によくしたものでしたが(これも黒に限ります。赤は被膜が弱くて保護できません。)、今回はこれに加えてボールペン(パイロット マルチボール)を使ってみました。何にでも書けること、時間が経つと水拭きで消えないことがある、と言うのがテストのきっかけです。前回に一本の線だけテストしていました。
中字を使いましたが細字ならさらに細く書けたと思います。被膜の接着力が弱いので乾燥後の修正はかなり困難です。

銅箔面がかなり荒れて見えますが実物は写真で見るよりよい状態です。このように手書きで済ませられる回路では実用になると思います。


  3 最初のプログラム
最初は基本機能のテストです。リセットボタンでUART通信が働いてプログラムのメニューをPCに表示します。メニュー番号を送るとそれを実行します。ハードに入力条件のスイッチを付ける変わりにPCのキーを使う方法です。
とりあえずメニューでLEDを点灯してLEDのテストも兼ねています。動作試験以外にはとくに何もありません。(Tiny2313のUARTソフトのメモになります。今後使うときに参考にします。)
/*************************************************************************************************
kiso_j.c  Tiny2313基礎実験機用プログラム  2011.05.10 im
  mcu=tiny2313 5V 9.22MHzセラミック fuse設定=-fL11001111 -fH11011111 -fx00000001
  UART 19200bps  FT232RLまたはcp2102変換のTDとRDを使用
  LED portB0:7
  
***************************************************************************************************/
#define F_CPU 9220000UL  //  
#include <avr/io.h>
#include <string.h>                  //  strcpy()用
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>

 /* プロトタイプ宣言 */
void string_out (char *msg_string);               // UART送信

 /* グローバル変数定義 */
  volatile  uint8_t rflg;            //uart受信フラグ
  volatile  uint8_t rdat;            //受信データ
  volatile  char recbuf[30];         //
  volatile  uint8_t rec_i;         // rec_index
  
/* 受信割込ルーチン   */
ISR(USART_RX_vect){                                       /* データを読み出すとクリアされる rdat:char変数 */
  recbuf[rec_i]=UDR;
  if((recbuf[rec_i]=='\0')||(recbuf[rec_i]==0x0d)||(recbuf[rec_i]==0x0a)){
    recbuf[rec_i]='\0';
    rflg=1;
    rec_i=0;
    cli();
  } else{                
    rec_i++;
  }
}

/* //////////////////  メインルーチン ////////////////////////////////////////////////////////////////////// */
int main (void)
{
  uint8_t menu_n=0;  // プログラムメニュー用
  uint8_t i;
  char s[20];
  char msg[30];

  DDRB=0xff; PORTB=0x00;                  // LEDポート

  /* USART設定 */
  UBRRH=0;
  UBRRL=29;                                 /* 19200bps  */
//  UCSRA=(1<<U2X);                         /* 有効にすると U2X=1  */
  UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);                /* 送受信許可、受信割込許可*/
  UCSRC=(3<<UCSZ0);                         /* 8ビット  1ストップビット  ノンパリティ*/

  sei();

  strcpy_P(msg,PSTR("-- menu --")); string_out(msg);
  strcpy_P(msg,PSTR("1 プログラム1")); string_out(msg);
  strcpy_P(msg,PSTR("2 プログラム2 ")); string_out(msg);
  
  while(rflg==0){
    if(rflg==1){break;}
  }
  rflg=0;
  strcpy(s,recbuf);
  menu_n=s[0]-0x30;

  string_out("");
  string_out(s);

  while(1){ // 全体ループ処理開始 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    if(menu_n==1){  // menu 1  111111111111111111111111111111111111111111111111 
      while(1){                               
        PORTB=0x55; _delay_ms(1000);
        PORTB=0xaa; _delay_ms(1000);
     }
    }  // menu 1 終わり 111111111111111111111111111111111111111111111111 
  
    if(menu_n==2){  // menu 2  2222222222222222222222222222222222222222222222 
      while(1){                               
        PORTB=0xff; _delay_ms(1000);
        PORTB=0x00; _delay_ms(1000);
     }
    }  // menu 2 終わり 2222222222222222222222222222222222222222222222  
    
  } // 全体ループ処理終わり +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
} /* //////////////////  メインルーチンの終わり ///////////////////////////////////// */

/* ************************ 文字列送信ルーチン ***************************************************** */
void string_out (char *msg_string){   /* "*"で受けると、呼び出し側の配列の番地を受け取る */ 
  uint8_t i;                   
  i=0;
  while (msg_string[i]  !='\0'){
    while ( !(UCSRA & _BV(UDRE)) );   //送信バッファの空きを待って
    UDR = msg_string[i];               //送信データをセットします
    i++;
    _delay_ms(6);
  }
  while(!(UCSRA & _BV(UDRE))); UDR = 0x0d; _delay_ms(6);    /* 送信バッファの空きを待ってデータをセット CRLF送信*/
  while(!(UCSRA & _BV(UDRE))); UDR = 0x0a; _delay_ms(6);    /* 送信バッファの空きを待ってデータをセット */
}
------------------------------------------------------------------------------
PCからの受信機能ではメニューの数値だけでなく複数文字の文を受け付けられるようにしています。


  4 avr-gcc 定数と変数の考察
実機に関係が無いものもありますが、定数と変数のSRAMに関係する事柄を調べてみます。
@ グローバル定数について
上記のプログラムをコンパイルしたときのメモリ使用量は
 Program: 638 bytes (31.2% Full) (.text + .data + .bootloader)
 Data: 25 bytes (19.5% Full) (.data + .bss + .noinit)
でした。ここに
 const uint8_t teisuu =20; を書き加えると Data: 25 bytesと変化はありません。理由不明です。
さらに volatile const uint8_t teisuu1=20; を加えると Data: 27 bytesと2バイト増えます。
その上に volatile const uint8_t teisuu2=20; を加えると Data: 27 bytesと変化はありません。
そして volatile const uint8_t teisuu3=20; を加えると Data: 29 bytesと2バイト増えます。
続いて volatile const uint16_t teisuu4=20; を加えると Data: 31 bytesと2バイト増えます。
グローバル定数を定義すると2バイト単位でSRAMを消費するようです。
この上に const char shokichi[]={"hajimenoatai"}; と12文字の定数を置くと Data: 43 bytesと12バイト増えます。
この定数を"hajimenoatai0"と変更して13文字とすると14バイト増えました。ここでも2バイト単位(?)が関係しているようです。

 グローバル定数を置くと(2バイト単位で)SRAMを消費します。    

 定数に値を代入するとコンパイルエラーとなります。

 定数は #define (例 #define teisuu 20 )を使う方が良いでしょう。


A 関数(含main)内の定数について
main関数の中に const uint16_t を定義しましたが Data: 25 bytesと変化はありません。コンパイル時点ではSRAMの使用量はわかりません。実行時にSRAMにコピーされるようです。
文字定数"hogehoge"はフラッシュとSRAMの両方に置かれるのかコンパイル時にData領域に表示されます。
SRAM容量に比べて文字定数(数値定数も)が大きいときはフラッシュに置く方法を採らねばなりません。

B 変数について グローバル変数はコンパイル時にData領域に表示されます。これは初期値0に初期化されるのと関係があるのかもしれません。
ローカル変数(mainルーチンを含めて)内のものはコンパイル時には現れません。実行時にSRAMが確保されるのだと思います。
したがって、コンパイル時のData領域の表示でSRAMの使用量を考えるのは極めて危険です。多くの変数を使うとテストのプログラムでUART通信ができなくなりました。Deta領域の数値でなく実使用のSRAM量を見極める必要があります。この意味ではSRAMに余裕のあるデバイスを使うのが得策だと感じました。

ポイント:
  コンパイル時のData領域使用より遥かに多くのSRAMが必要。SRAMの多いデバイスが便利。
  SRAMの必要量は直接的には見えない。
  定数はSRAMに置かない、フラッシュのみに置く方法を活用すること。
























inserted by FC2 system