LEDの点灯と消灯
これまでに,モニタプログラムを使ってLEDの点灯と消灯を行った.
これからは,C言語のプログラムにより各種デバイスを制御することを目標にして学習を進める.本ページでは,まずモニタプログラムを使って行ったLEDの点灯と消灯をC言語のプログラムによって行うことを目標にする.
MEMEs 上のLED5 とLED6 の点灯と消灯を行う.まず,ハードウェアと扱うレジスタの復習から始める.
図1:LED周辺の回路図
LED5 と LED6 は,図1のような回路構成になっており,LEDのアノード側が抵抗を介して電源と接続され,カソード側がSH7085 の PE9 および PE11 に接続されている.
このような回路構成の場合,PE9 およびPE11 から Highレベル(この場合3.3V)を出力すれば電位差がなくなり,LEDは消灯状態となる.逆に,Lowレベル(この場合0V)を出力すればアノードとカソード間に電位差が生じてLED が点灯する仕組みになっている.
最低限この程度の情報を図1から読み取れなければLED の点灯や消灯のプログラムすら記述することはできない.
次にLEDが接続された端子の入出力の方向や出力データについて考えなければならない.これもモニタプログラムでLEDの点灯と消灯を行ったときに操作したレジスタである.図2のように,端子の入出力方向を決めるのは,PEIORLレジスタを操作する.
出力端子として設定された場合は,PEDRLレジスタの当該ビットに0または1を格納することで,HighまたLowレベルを出力できる.入力端子として設定された場合,当該ビットをプログラムで読みだすことで端子の状態を確認することができる.
図2:端子の入出力設定とデータの関係
モニタプログラムでLEDを制御したとき,上記の2つのレジスタのアドレス(番地)に対してい直接値を書き込みLED の点灯と消灯を行った.
図3:PEIORLレジスタへの書き込み
図3のように,レジスタの番地に直接,値を書き込んで端子を出力ポートにし,図4のようにPEDRLレジスタの番地に直接,値を書き込んでLEDの点灯と消灯を行った.
図4:PEDRLレジスタへの書き込み
ここまでは復習である.
SH7085 のハードウェアマニュアルによると,PEIORLレジスタは,PFCと呼ばれる機能の中のレジスタである.またPEDRLレジスタは,I/Oポートと呼ばれる機能の中のレジスタである.それぞれのアドレスは,ハードウェアマニュアルを参照すればわかるが,下記のようなアドレスとなっている.
- PEIORL:0xFFFFD306 から16ビット分がPEのビット0 から ビット15までの入出力を決めるレジスタとなっている.
- PEDRL:0xFFFFD302から16ビット分がPEのビット0 からビット15までのデータの入出力を決めるレジスタとなっている.
さて,アドレスを意識してプログラムを構築することは大変なことである.7080S.H というアドレスとレジスタの名称を対応づけたファイルを,環境作成の際にダウンロードした.
C プログラムでは,このファイルをインクルードすることにより,アドレスを意識せずにプログラム作成することができる.
PEIORLおよびPEDRL は 7080S.H の中で下記のように定義されている.
下記は 7080S.H の PEIORL 部分の抜粋である.
struct st_pfc { /* struct PFC */ ~ 中略 ~ union { /* PEIORL */ unsigned short WORD; /* Word Access */ struct { /* Byte Access */ unsigned char H; /* High */ unsigned char L; /* Low */ } BYTE; /* */ struct { /* Bit Access */ unsigned char B15:1; /* Bit 15 */ unsigned char B14:1; /* Bit 14 */ unsigned char B13:1; /* Bit 13 */ unsigned char B12:1; /* Bit 12 */ unsigned char B11:1; /* Bit 11 */ unsigned char B10:1; /* Bit 10 */ unsigned char B9 :1; /* Bit 9 */ unsigned char B8 :1; /* Bit 8 */ unsigned char B7 :1; /* Bit 7 */ unsigned char B6 :1; /* Bit 6 */ unsigned char B5 :1; /* Bit 5 */ unsigned char B4 :1; /* Bit 4 */ unsigned char B3 :1; /* Bit 3 */ unsigned char B2 :1; /* Bit 2 */ unsigned char B1 :1; /* Bit 1 */ unsigned char B0 :1; /* Bit 0 */ } BIT; /* */ } PEIORL; /* */
#define PFC (*(volatile struct st_pfc *)0xFFFFD104)/* PFC Address*/
ここでのポイントは,PEIORLというレジスタに対して,3種類のアクセス方法があることである.WORD,BYTE,BIT アクセスの3つである.
WORD のイメージを下記に示す.
WORDは16ビット,BYTEは8ビット,BITは1ビットのアクセスである.
たとえば,PE9のみを1にする(PE9を出力にする)場合,書き方としては少なくとも下記の3種類が存在する.
PFC.PEIORL.WORD |= 0x0200; /* WORD アクセスの場合 */ PFC.PEIORL.BYTE.H |= 0x02; /* BYTE アクセスの場合 */ PFC.PEIORL.BIT.B9 = 1; /* BIT アクセスの場合 */
下記は,PEDR 部分の抜粋である.
struct st_pe { /* struct PE */ union { /* PEDR */ unsigned int LONG; /* Long Access */ struct { /* Word Access */ unsigned short H; /* High */ unsigned short L; /* Low */ } WORD; /* */ struct { /* Byte Access */ char wk; /* */ unsigned char HL; /* High,Low */ unsigned char LH; /* Low ,High */ unsigned char LL; /* Low ,Low */ } BYTE; /* */ struct { /* Bit Access */ unsigned char :8; /* */ unsigned char :2; /* */ unsigned char B21:1; /* Bit 21 */ unsigned char B20:1; /* Bit 20 */ unsigned char B19:1; /* Bit 19 */ unsigned char B18:1; /* Bit 18 */ unsigned char B17:1; /* Bit 17 */ unsigned char B16:1; /* Bit 16 */ unsigned char B15:1; /* Bit 15 */ unsigned char B14:1; /* Bit 14 */ unsigned char B13:1; /* Bit 13 */ unsigned char B12:1; /* Bit 12 */ unsigned char B11:1; /* Bit 11 */ unsigned char B10:1; /* Bit 10 */ unsigned char B9 :1; /* Bit 9 */ unsigned char B8 :1; /* Bit 8 */ unsigned char B7 :1; /* Bit 7 */ unsigned char B6 :1; /* Bit 6 */ unsigned char B5 :1; /* Bit 5 */ unsigned char B4 :1; /* Bit 4 */ unsigned char B3 :1; /* Bit 3 */ unsigned char B2 :1; /* Bit 2 */ unsigned char B1 :1; /* Bit 1 */ unsigned char B0 :1; /* Bit 0 */ } BIT; /* */ } DR; /* */
#define PE (*(volatile struct st_pe *)0xFFFFD300)/* PE Address */
ここでのポイントも上記と同じように,レジスタに対するアクセスの方法が複数あるということである.PE(ポートE)は,22ビットで構成されているため,LONG という32ビットアクセスの方法が存在するのである.
LONG のイメージを下記に示す.
たとえば,出力設定されたPE9 からLow を出力するための方法は次の4通りが考えられる.(SH7075では,B21~B16は実装されていない)
PE.DR.LONG &= 0x0000FDFF; /* LONG アクセスの場合 */ PE.DR.WORD.L &= 0xFDFF; /* WORD アクセスの場合 */ (SH7085では WORD.H は未実装なので,実際には使用しない) PE.DR.BYTE.LH &= 0xFD; /* BYTE アクセスの場合 */ PE.DR.BIT.B9 = 0; /* BIT アクセスの場合 */
LONG は,32 ビットで構成されているレジスタに適応されており,WORD は,16ビットで構成されているレジスタに適応されている.8 ビットで構成されるレジスタも存在しており,この場合は,BYTE か BIT のどちらかでしかアクセスできない.BYTE のイメージを下記に示す.
下記のワークスペースを Windows から見た Linux ファイルシステムである
¥¥Linux¥Ubuntu¥home¥[User]¥micon にダウンロードする.
WSL2 を起動し Linux 環境上で
$ cd micon $ tar xvf LED.tar
とし,ファイルを抽出する.
ls コマンドでファイル群を確認できる.
LED.c をエディタで開くと下記のようなソースプログラムがすでに入力されている.
/*******************************/ /* LED5, LED6 の点灯と消灯 */ /*******************************/ #include <7080S.H> void main(void) { PFC.PEIORL.WORD |= 0x0200; PE.DR.WORD.L &= 0xFDFF; while(1) ; }
プログラムリスト1:LED5のみの点灯プログラム
ここでは,ソースファイルの変更はせずにメイク(make LED)する.
TeraTerm を起動させて,MEMEsと接続する.
メイクして出来上がったファイル(LED.mot)ファイルをMEMEsへダウンロード(L コマンド)し,実行(G コマンド)すると,図5のようにLED5のみが点灯する.
図5:LED5のみ点灯
演習問題
- 演習1:2進数 8桁で,10010101 を16進数で表現せよ.
- 演習2:16進数 2桁で,0x3C を 2進数 8桁で表せ.
- 演習3:上記のプログラムリスト1をBYTEまたはBITでアクセスするように書き換えて,LED5のみ点灯するプログラムを作成せよ.
- 演習4:上記のプログラムリスト1を書き換えて,図6のようにLED6のみが点灯するプログラムを作成せよ.
- 演習5:上記のプログラムリスト1を書き換えて,図7のようにLED5とLED6が同時に点灯するプログラムを作成せよ.
-
- 演習6:上記のプログラムリスト1を書き換えて,動画1のように一定時間ごとにLED5とLED6が同時に点滅するプログラムを作成せよ.
一定時間は,下記のように作成する.
#include "typedef.h" /* typedef.hをインクルードする */ 中略 void main(void) { _UINT i; /* unsigned int で i を宣言する. */ /* _UINT はtypedef.h で定義済み */ 中略 for ( i = 0 ; i < 65000 ; i++){} 中略 }
動画1:一定時間ごとに点灯と消灯を繰り返す
実践問題に挑戦
【問題】下記の動画2のように徐々にLED が明るくなったり,暗くなったりするプログラムを作成せよ.
ヒントは,PWM である.この技術は,モータなどの回転に対してスロースタートやスローストップさせる技術である.
動画では見づらいかもしれないが,交互に点灯と消灯をホタルのように繰り返している.
動画2:ホタルのように点灯と消灯を繰り返す
Linux(WSL2)の便利機能
・↑(上矢印)キーで,コマンド履歴を呼び出すことができる
・コマンドやファイル名を途中まで入力し[TAB]キーを押すと,残りの部分を補完できる
・Linux 環境において ~ は,ユーザーのホームディレクトリを示す
・[TAB]キーを押したときのサウンドを消すには,~/.inputrc に
set bell-style none
と書いておく
$ cd <-- ホームディレクトリに移動 $ touch .inputrc <-- 空のファイルを作成
のように Linux 環境でファイルを作成しておき,Windows 環境のエディタで編集する