2 ライントレースカーのソフトウェアー

2.1 メイクファイル

プログラムの実行ファイルは複数のソースファイルから作られることが多い.このような とき,コンパイル作業はかなり面倒である.この面倒な作業を自動的に行わせるために, makeがある.ここで使うプログラムも,C言語,アセンブラ言語,各種ヘッダーファ イル,スタートアップルーチンのファイルから構成される.そのため,makeを使い, 自動的にコンパイルできるようにしている.リスト2のMakefileは, コンパイルのこのコンパイルの方法を記述している.

また,H8マイコンへのバイナリーデータ転送の面倒な処理もmakeでできる.このよ うにすることにより,諸君の作業は格段に楽になる.

この実験で使うMakefileには,次の機能がある.

表 5: Makefileの機能
コマンド 実行内容
make ソースファイルをコンパイルリンクして,転送用のmotファイルを作成す る.
make clean オブジェクトファイルとexe,motファイルを削除する.
make write motファイルをH8マイコンへ転送する.


   1 TARGET		=	h8exp.mot
   2 
   3 CFLAGS		=	-O -mh -g -mrelax -mint32 -DH8_3664
   4 TOOL_PREFIX	=	h8300-hms-
   5 CC		=	$(TOOL_PREFIX)gcc
   6 
   7 LDSCRIPT	=	h8_link.x
   8 CRT0		=	h8_start.s
   9 SRCS		=	experiment.c
  10 FUNC		=	h8c.c
  11 
  12 all : $(TARGET)
  13 
  14 $(TARGET): $(TARGET:.mot=.exe)
  15 	$(TOOL_PREFIX)objcopy -O srec $(TARGET:.mot=.exe) $@
  16 
  17 $(TARGET:.mot=.exe): Makefile $(LDSCRIPT) $(SRCS:.c=.o) $(FUNC:.c=.o) \
  18 $(CRT0) $(LIBS)
  19 	$(CC) $(CFLAGS) -T $(LDSCRIPT) -nostdlib $(CRT0) \
  20 $(SRCS:.c=.o) $(FUNC:.c=.o) -o $@ $(LIBS) -lc -lgcc
  21 
  22 write:
  23 	h8write -3664 $(TARGET) /dev/ttyS0
  24 
  25 clean :
  26 	rm -f $(TARGET)
  27 	rm -f $(TARGET:.mot=.exe)
  28 	rm -f $(SRCS:.c=.o)
  29 	rm -f $(FUNC:.c=.o)

2.2 ライントレースカー用の関数

ライントレースカーの制御の変更は,p.[*]に示したリスト 1を変えることによりできる.しかし,ライントレーサーを制御 を司るH8マイコンのプログラムは,リスト1のみでできているわ けではない.これから示すさまざまなプログラムからできあがっている.

2.2.1 ヘッダーファイル

ここのライントレースカーを制御するために6個の専用の関数をリスト4 で作成している.リスト3のヘッダーファイルでは,その関数のプロトタ イプ宣言やグローバル変数を定義している.
   1 #ifndef H8C_H
   2 #define H8C_H
   3 
   4 #define _nop() asm volatile ("nop");
   5 
   6 void init_led(void);
   7 void init_pwm(void);
   8 void start_pwm(void);
   9 void duty_pwm(unsigned int b, unsigned int d);
  10 void ADC_init(void);
  11 void ADC(void);
  12 
  13 typedef union{
  14   unsigned char BYTE;
  15   struct{
  16     unsigned char ADF:1;
  17     unsigned char ADIE:1;
  18     unsigned char ADST:1;
  19     unsigned char SCAN:1;
  20     unsigned char CKS:1;
  21     unsigned char CH2:1;
  22     unsigned char CH1:1;
  23     unsigned char CH0:1;
  24   }BIT;
  25 }set_ADC;
  26 
  27 int ch1, ch2, ch3, ch4;
  28 
  29 #endif


2.2.2 制御用の関数

リスト3のヘッダーファイルでプロトタイプ宣言した関数の実装をリスト 4のプログラムで行っている.マイコンを実行させるためには多くのビッ ト操作が必要なので,このように別ファイルの別関数にするとその操作を隠すことができ る.ユーザーにはその関数の実行方法のみを示すことにより,容易にプログラムができる ようになる.
   1 #include "h8_3664.h"
   2 #include "h8c.h"
   3 
   4 
   5 //============================================================
   6 // LED点灯のための初期化関数
   7 //    Port5を使うときに最初,1回だけに呼び出す
   8 //    PDR5のビットの設定で,点灯するLEDを決める
   9 //============================================================
  10 void init_led(void){
  11   PMR5 &= 0xc0;        // Port Mode Register 5 の設定 
  12 		       //    0:汎用入出力 1:マニュアルを見よ
  13   PCR5 |= 0x3f;	       // Port Control Register 5の設定 
  14                        //    0:入力 1:出力 */
  15   PDR5 &= 0xc0;	       // Port Data Register
  16 }
  17 
  18 
  19 //============================================================
  20 // PWMを使うための初期化関数
  21 //    PWMを使うときに,最初1回呼び出す
  22 //============================================================
  23 void init_pwm(void){
  24   TMRW |= 0x05;       /* FTIOBとFTIOD端子をPWM出力に */
  25 
  26   TCRW |= 0x80;       /* コンペアマッチAによりカウンタクリアー */
  27   TCRW |= 0x30;       /* クロックセレクト 内部クロック phi/8 (=2MHz)*/
  28   TCRW |= 0x0a;       /* タイマ出力セットレベル コンペアマッチまで1 */
  29 
  30   TCNT = 0x0000;      /* カウンタ16ビットの初期値 */
  31 
  32   GRA = 0xffff;
  33 
  34 }
  35 
  36 
  37 //============================================================
  38 // PWMのDutyを決める
  39 //   第一引数:FTIOB  第二引数:FTIOD
  40 //============================================================
  41 void duty_pwm(unsigned int b, unsigned int d){   // pwm デューティ [%]
  42 
  43   GRB = (unsigned int)655*b;
  44   GRD = (unsigned int)655*d;
  45 
  46 }
  47 
  48 
  49 //============================================================
  50 // PWMのスタート時に呼び出す
  51 //============================================================
  52 void start_pwm(void){
  53   TMRW |= 0x80;       /* カウンタースタート */
  54 }
  55 
  56 
  57 //============================================================
  58 // AD変換器の初期化関数
  59 //============================================================
  60 void init_ADC(void)
  61 {
  62 
  63   set_ADC *set;
  64 
  65   set=(set_ADC *)&ADCSR;
  66 
  67   set->BIT.ADF=0;
  68   set->BIT.ADIE=0;
  69   set->BIT.ADST=0;
  70   set->BIT.SCAN=1;
  71   set->BIT.CKS=0;
  72   set->BIT.CH2=0;
  73   set->BIT.CH1=1;
  74   set->BIT.CH0=1;
  75   
  76 }
  77 
  78 //============================================================
  79 // AD変換器を行い結果を設定
  80 //      ch1:AN0の結果  0:白 1:黒
  81 //      ch2:AN1の結果  0:白 1:黒
  82 //      ch3:AN2の結果  0:白 1:黒
  83 //      ch4:AN3の結果  0:白 1:黒
  84 //============================================================
  85 void ADC(void)
  86 {
  87 
  88   ADCSR &=0x7f;            // ADF=0   AD完了フラグをゼロに
  89   ADCSR |= 0x20;           // ADST=1  ADCスタート
  90 
  91   while(!(ADCSR & 0x80));   // AD変換完了まで待つ
  92   ADCSR &= 0xdf;           // ADST=0  ADC stop
  93 
  94   ch1=(unsigned int)(ADDRA >> 6)<200 ? 1:0;
  95   ch2=(unsigned int)(ADDRB >> 6)<200 ? 1:0;
  96   ch3=(unsigned int)(ADDRC >> 6)<200 ? 1:0;
  97   ch4=(unsigned int)(ADDRD >> 6)<200 ? 1:0;
  98 
  99 }

2.3 H8マイコン3664のヘッダーファイル

リスト5のヘッダーファイル(3664.h)は,一部のアセンブラ言 語で書かれた関数とレジスターのアドレスを定義している.

3-5行目がアセンブラで命令を記述している.マクロ名を指定することにで,アセンブラ の命令が実行される.簡単なアセンブラの命令を実行するときに便利である.

14-96行目でレジスターのアドレスを定義している.レジスター名--ここではマクロ名 になるが--とそれに対応するアドレスは,H8のマニュアルに書いてある.このようにす ると,無味乾燥な16進数のアドレスが意味のある名前に置き換えることができる.プログ ラムが書きやすくなる.コンパイル時にgccのプリプロセッサーがこのマクロ名を対応す る16進数に変換する.

レジスターとアドレスの関係は,ルネサステクノロジー社の「H8/3664グループハードウェ アーマニュアル」 [3]に詳しく書かれている.

   1 #ifndef H8_3664_H
   2 #define H8_3664_H
   3 #define STI()	asm volatile ("andc.b #0x7f,ccr")
   4 #define CLI()	asm volatile ("orc.b #0x80,ccr")
   5 #define	SLEEP()	asm volatile ("sleep")
   6 
   7 #define	VOLATILE_BYTE(addr)   (*(volatile unsigned char*)(addr))
   8 #define	VOLATILE_WORD(addr)   (*(volatile unsigned short*)(addr))
   9 
  10 //======================================================================
  11 //	Definitions of H8/3664 Internal Registers
  12 //	DO NOT EDIT!
  13 //======================================================================
  14 #define	TMRW	VOLATILE_BYTE(0xff80)
  15 #define	TCRW	VOLATILE_BYTE(0xff81)
  16 #define	TIERW	VOLATILE_BYTE(0xff82)
  17 #define	TSRW	VOLATILE_BYTE(0xff83)
  18 #define	TIOR0	VOLATILE_BYTE(0xff84)
  19 #define	TIOR1	VOLATILE_BYTE(0xff85)
  20 
  21 #define	TCNT	VOLATILE_WORD(0xff86)
  22 #define	GRA	VOLATILE_WORD(0xff88)
  23 #define	GRB	VOLATILE_WORD(0xff8a)
  24 #define	GRC	VOLATILE_WORD(0xff8c)
  25 #define	GRD	VOLATILE_WORD(0xff8e)
  26 
  27 #define	FLMCR1	VOLATILE_BYTE(0xff90)
  28 #define	FLMCR2	VOLATILE_BYTE(0xff91)
  29 #define	FLPWCR	VOLATILE_BYTE(0xff92)
  30 #define	EBR1	VOLATILE_BYTE(0xff93)
  31 #define	FENR	VOLATILE_BYTE(0xff9b)
  32 #define	TCRV0	VOLATILE_BYTE(0xffa0)
  33 #define	TCSRV	VOLATILE_BYTE(0xffa1)
  34 #define	TCORA	VOLATILE_BYTE(0xffa2)
  35 #define	TCORB	VOLATILE_BYTE(0xffa3)
  36 #define	TCNTV	VOLATILE_BYTE(0xffa4)
  37 #define	TCRV1	VOLATILE_BYTE(0xffa5)
  38 #define	TMA	VOLATILE_BYTE(0xffa6)
  39 #define	TCA	VOLATILE_BYTE(0xffa7)
  40 #define	SMR	VOLATILE_BYTE(0xffa8)
  41 #define	BRR	VOLATILE_BYTE(0xffa9)
  42 #define	SCR3	VOLATILE_BYTE(0xffaa)
  43 #define	TDR	VOLATILE_BYTE(0xffab)
  44 
  45 #define	SSR	VOLATILE_BYTE(0xffac)
  46 #define	RDR	VOLATILE_BYTE(0xffad)
  47 
  48 #define	ADDRA	VOLATILE_WORD(0xffb0)
  49 #define	ADDRB	VOLATILE_WORD(0xffb2)
  50 #define	ADDRC	VOLATILE_WORD(0xffb4)
  51 #define	ADDRD	VOLATILE_WORD(0xffb6)
  52 #define	ADCSR	VOLATILE_BYTE(0xffb8)
  53 #define	ADCR	VOLATILE_BYTE(0xffb9)
  54 
  55 #define	TCSRWD	VOLATILE_BYTE(0xffc0)
  56 #define	TCWD	VOLATILE_BYTE(0xffc1)
  57 #define	TMWD	VOLATILE_BYTE(0xffc2)
  58 #define	ICCR	VOLATILE_BYTE(0xffc4)
  59 #define	ICSR	VOLATILE_BYTE(0xffc5)
  60 #define	ICDR	VOLATILE_BYTE(0xffc6)
  61 #define	SARX	VOLATILE_BYTE(0xffc6)
  62 #define	ICMR	VOLATILE_BYTE(0xffc7)
  63 #define	SAR	VOLATILE_BYTE(0xffc7)
  64 #define	ABRKCR	VOLATILE_BYTE(0xffc8)
  65 #define	ABRKSR	VOLATILE_BYTE(0xffc9)
  66 #define	BARH	VOLATILE_BYTE(0xffca)
  67 #define	BARL	VOLATILE_BYTE(0xffcb)
  68 #define	BDRH	VOLATILE_BYTE(0xffcc)
  69 #define	BDRL	VOLATILE_BYTE(0xffcd)
  70 #define	PUCR1	VOLATILE_BYTE(0xffd0)
  71 #define	PUCR5	VOLATILE_BYTE(0xffd1)
  72 #define	PDR1	VOLATILE_BYTE(0xffd4)
  73 #define	PDR2	VOLATILE_BYTE(0xffd5)
  74 #define	PDR5	VOLATILE_BYTE(0xffd8)
  75 #define	PDR7	VOLATILE_BYTE(0xffda)
  76 #define	PDR8	VOLATILE_BYTE(0xffdb)
  77 #define	PDRB	VOLATILE_BYTE(0xffdd)
  78 
  79 #define	PMR1	VOLATILE_BYTE(0xffe0)
  80 #define	PMR5	VOLATILE_BYTE(0xffe1)
  81 #define	PCR1	VOLATILE_BYTE(0xffe4)
  82 #define	PCR2	VOLATILE_BYTE(0xffe5)
  83 #define	PCR5	VOLATILE_BYTE(0xffe8)
  84 #define	PCR7	VOLATILE_BYTE(0xffea)
  85 #define	PCR8	VOLATILE_BYTE(0xffeb)
  86 #define	SYSCR1	VOLATILE_BYTE(0xfff0)
  87 #define	SYSCR2	VOLATILE_BYTE(0xfff1)
  88 #define	IEGR1	VOLATILE_BYTE(0xfff2)
  89 #define	IEGR2	VOLATILE_BYTE(0xfff3)
  90 #define	IENR1	VOLATILE_BYTE(0xfff4)
  91 #define	IRR1	VOLATILE_BYTE(0xfff6)
  92 #define	IWPR	VOLATILE_BYTE(0xfff8)
  93 #define	MSTCR1	VOLATILE_BYTE(0xfff9)
  94 #define	TSCR	VOLATILE_BYTE(0xfffc)
  95 
  96 #define	EKR	VOLATILE_BYTE(0xff10)
  97 
  98 #endif

2.4 スタートアップルーチン

H8マイコンに電源を入れたときやリセットスイッチを押したとき,実行されるプログラム をスタートアップルーチンと言う.リスト6が,ここで使っている スタートアップルーチンである.

このスタートアップルーチンでは,まずはスタックポインターを設定している.リンカー スクリプトで設定されたスタック領域の先頭アドレス(_stack)をスタックポインター (sp)に設定している.次にROM 領域のデータをRAM領域に転送している.このように することにより,初期値がある変数に対応している.その後,リスト 1main関数に実行を移している.実際にはこのメイン関数 は機械語に翻訳され,ラベルは_mainとなる.ここでは,jsrでジャンプして いる.この_mainから戻るようなことがあると,無限ループに入るようにしている.


   1         ;; H8/3664 Startup routine
   2 
   3         .h8300h
   4         .section .text
   5         .global _start
   6 _start:
   7         mov.l #_stack,sp ;; スタックポインターの設定
   8 
   9         ;; ROM領域のデータをRAMへ転送
  10 
  11         mov.l #___dtors_end,er0 ;; .dtorsの終わりのアドレス
  12         mov.l #___data,er1 ;; .dataの開始アドレス
  13         mov.l #_edata,er2 ;; .dataの終わりのアドレス
  14 ram_data:
  15         mov.w @er0,r3
  16         mov.w r3,@er1
  17         adds #2,er0
  18         adds #2,er1
  19         cmp.l er2,er1
  20         blo ram_data
  21 
  22         ;; main関数の実行
  23 
  24         jsr @_main
  25 sleep:
  26         sleep
  27         bra sleep
  28 
  29         .end

2.5 リンカースクリプト

リンカースクリプトは,プログラムのメモリーの配置の仕方を決めるものである.このあ たりの詳細を知りたければ,私の「リンカースクリプトの書き 方」を見よ.
   1 OUTPUT_FORMAT("coff-h8300")
   2 OUTPUT_ARCH(h8300h)
   3 ENTRY("_start")
   4 MEMORY
   5 {
   6 	vectors : o = 0x0000, l = 0x0034
   7 	rom     : o = 0x0034, l = 0x7fcc
   8 	ram     : o = 0xf780, l = 0x0400
   9 	stack   : o = 0xff80, l = 0x0000
  10 }
  11 
  12 SECTIONS 				
  13 { 					
  14 .vectors : {
  15 	SHORT(ABSOLUTE(_start))
  16 	SHORT(ABSOLUTE(_start))
  17 	SHORT(ABSOLUTE(_start))
  18 	SHORT(ABSOLUTE(_start))
  19 	SHORT(ABSOLUTE(_start))
  20 	SHORT(ABSOLUTE(_start))
  21 	SHORT(ABSOLUTE(_start))
  22 	SHORT(DEFINED(_int_nmi)?ABSOLUTE(_int_nmi):ABSOLUTE(_start))
  23 	SHORT(DEFINED(_int_trap0)?ABSOLUTE(_int_trap0):ABSOLUTE(_start))
  24 	SHORT(DEFINED(_int_trap1)?ABSOLUTE(_int_trap1):ABSOLUTE(_start))
  25 	SHORT(DEFINED(_int_trap2)?ABSOLUTE(_int_trap2):ABSOLUTE(_start))
  26 	SHORT(DEFINED(_int_trap3)?ABSOLUTE(_int_trap3):ABSOLUTE(_start))
  27 	SHORT(DEFINED(_int_break)?ABSOLUTE(_int_break):ABSOLUTE(_start))
  28 	SHORT(DEFINED(_int_sleep)?ABSOLUTE(_int_sleep):ABSOLUTE(_start))
  29 	SHORT(DEFINED(_int_irq0)?ABSOLUTE(_int_irq0):ABSOLUTE(_start))
  30 	SHORT(DEFINED(_int_irq1)?ABSOLUTE(_int_irq1):ABSOLUTE(_start))
  31 	SHORT(DEFINED(_int_irq2)?ABSOLUTE(_int_irq2):ABSOLUTE(_start))
  32 	SHORT(DEFINED(_int_irq3)?ABSOLUTE(_int_irq3):ABSOLUTE(_start))
  33 	SHORT(DEFINED(_int_wkp)?ABSOLUTE(_int_wkp):ABSOLUTE(_start))
  34 	SHORT(DEFINED(_int_timera)?ABSOLUTE(_int_timera):ABSOLUTE(_start))
  35 	SHORT(ABSOLUTE(_start))
  36 	SHORT(DEFINED(_int_timerw)?ABSOLUTE(_int_timerw):ABSOLUTE(_start))
  37 	SHORT(DEFINED(_int_timerv)?ABSOLUTE(_int_timerv):ABSOLUTE(_start))
  38 	SHORT(DEFINED(_int_sci3)?ABSOLUTE(_int_sci3):ABSOLUTE(_start))
  39 	SHORT(DEFINED(_int_iic)?ABSOLUTE(_int_iic):ABSOLUTE(_start))
  40 	SHORT(DEFINED(_int_adi)?ABSOLUTE(_int_adi):ABSOLUTE(_start))
  41         }  > vectors
  42 
  43 .text 0x0034 : {
  44 	*(.text) 				
  45 	*(.strings)
  46 	*(.rodata) 				
  47    	 _etext = . ; 
  48 	} > rom
  49 
  50 .tors : {
  51 	___ctors = . ;
  52 	*(.ctors)
  53 	___ctors_end = . ;
  54 	___dtors = . ;
  55 	*(.dtors)
  56 	___dtors_end = . ;
  57 	}  > rom
  58 
  59 .data : AT ( ADDR(.tors) + SIZEOF(.tors) ){
  60 	___data = . ;
  61 	*(.data)
  62 	*(.tiny)
  63 	 _edata = .;
  64 	} > rom
  65 
  66 .bss : AT ( LOADADDR(.data) + SIZEOF(.data) ) {
  67 	 _bss_start = . ;
  68 	*(.bss)
  69 	*(COMMON)
  70 	 _end = . ;  
  71 	}  >ram
  72 
  73 .stack : {
  74 	 _stack = . ; 
  75 	*(.stack)
  76 	}  > stack
  77 
  78 .stab 0 (NOLOAD) : {
  79 	[ .stab ]
  80 	}
  81 
  82 .stabstr 0 (NOLOAD) : {
  83 	[ .stabstr ]
  84 	}
  85 }

ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成19年12月27日


no counter