LCD文字表示(RTOS)

MAPLE board

頑張ってハンダ付けしましょうw
そんなに大変な作業ではないです。
まぁ、私はフリー拡張スロットのコネクタのハンダ付け、一部失敗して斜めについてますけどね……。

LCDモジュール

MAPLE boardについてきたのは、TC1602E-25Aという型番のLCDでした。
このLCDは、4または8ビットモード(HD44780互換)ということですから、HD44780のデータシートを探してくることにします。

というわけで、alldatasheetから拾って来ました。

基本的には、AVRの時にやったLCDサンプルと変わりません。

構成

MAPLE board附属の回路図を見れば分かる通り、DB0〜DB3は接続されていませんので、4ビットモードでの動作となります。
また、R/WがGNDに接続されていますので、Writeモード固定ということになります。
Writeモード固定なので、Busyフラグチェックは出来ませんから、コマンド実行後は実行時間分待つ必要があります。

LPC1769は、LPC1768と同じなので、MAPLE boardの取扱説明書「8.3 LPCXPresso LPC1768 使用時」というところのピン配置を見ると、どのピンが何に割当たっているのかわかります。
以下のようになっているみたいですね。

ポート番号ピン番号LCD
P015D5
P016D6
P017D4
P21RS
P22E
P23D7

プロジェクト

まずは、ledtest02と同じように、FreeRTOSの新規プロジェクトを作って、ひと通り設定をしておきます。
プロジェクト名は、「lcdtest」としました。

元々のLEDと今回のLCD、それに全体的な管理をするアプリケーションとしてのタスクを作って動かすようにしてみましょう。
それぞれをモジュールとして管理し、モジュールを管理するためのデータをハンドル的に扱えるようにします。
データをハンドル化し、ロジックと切り離すことによって、LEDが2つとか、LCDが2つとかになった場合でも、それぞれを独立して動かせるようになるはずです。

ソースコード

共通定義等

LEDのソースにもありましたが、ピンをGPIOとして使うのでも、ペリフェラルの機能を使うのでも、ポート番号とピン番号の指定が必要になります。
なので、セットで扱えるような構造体を用意しておきます。
共通で使うので、src直下に置いておきましょう。
ファイル名はapldevice.hとしました。

#ifndef APLDEVICE_H_
#define APLDEVICE_H_

// ポートピンセット
typedef struct _tagPORTPIN_SET{
	uint8_t	port_num;	// ポート番号
	uint8_t pin_num;	// ピン番号
} PORTPIN_SET, *LPPORTPIN_SET;

#endif /* APLDEVICE_H_ */

次に、各タスクのプライオリティ定義を用意しておきましょう。
タスク間の関係は、アプリケーション全体で相互に意識しなければならないので、これもsrc直下に置いて共通で使います。
ファイル名はapltask.hとし、これをincludeすればFreeRTOSのタスク機能が使えるように、FreeRTOS.hとtask.hを参照します。

#ifndef APLTASK_H_
#define APLTASK_H_

#include "FreeRTOS.h"
#include "task.h"

#define APL_TASK_PRIORITY		( tskIDLE_PRIORITY + 1 )
#define LED_TASK_PRIORITY		( tskIDLE_PRIORITY + 2 )
#define LCD_TASK_PRIORITY		( tskIDLE_PRIORITY + 2 )

#define APL_STACK_SIZE	64
#define LED_STACK_SIZE	64
#define LCD_STACK_SIZE	64

void TaskDelay( portTickType time );

#endif /* APLTASK_H_ */

タスクプライオリティの関係は、アプリケーションとしての動作をアイドルの一つ上に、表示系をその一つ上としました。
スタックサイズも、全体のリソース管理という意味から、一箇所にまとまっていた方がいいと思うので、一緒に記載しています。

また、LEDサンプルの時に使ったvTaskDelayのラッパーとして、TaskDelayという関数を定義しておきます。
TaskDelayの実体は、apltask.cファイルをsrc直下に作って、以下のように作っておきます。

#include "apltask.h"

void TaskDelay( portTickType time )
{
	vTaskDelay( time / portTICK_RATE_MS );
}

vTaskDelayは、引数がtick数であり、msではありません。
前回書きましたが、FreeRTOSConfig.h内のconfigTICK_RATE_HZで、毎秒1000tickという指定をしているので、たまたま1tickが1msと同義になっているだけにすぎません。
configTICK_RATE_HZの値を書き換えてしまうと、ms単位の動作を期待しているのに、実際にsleepする時間が変化してしまいます。
このため、msを指定できるラッパー関数を用意して、それに対応します。

参考までに、portTICK_RATE_MSは、FreeRTOS内で以下のように定義されています。

#define portTICK_RATE_MS			( ( portTickType ) 1000 / configTICK_RATE_HZ )		

タスクの次は、イベントキューを使うための定義を用意します。
イベントキューは、LCDに表示するためのデータをLCDタスクに送信するために使います。
ファイル名はaplqueue.hとし、これをincludeすればFreeRTOSのキュー機能が使えるように、FreeRTOS.hとqueue.hを参照します。
こちらも、キュー全体のリソース管理という意味から、src直下に置いて共通で使います。

#ifndef APLQUEUE_H_
#define APLQUEUE_H_

#include "FreeRTOS.h"
#include "queue.h"

// イベントキューデータ
typedef struct _tagQUE_DATA{
	uint8_t	evcode;	// イベント番号
	int32_t	param;	// パラメータ
	void	*data;	// イベントデータ
} QUE_DATA, *LPQUE_DATA;

#define LCD_QUE_LENGTH	32

#endif /* APLQUEUE_H_ */

キューのデータは汎用的にQUE_DATAとして定義し、これを送受信します。
タスクで受け取って動作を切り分けるためのイベントコード、そのパラメータ、パラメータでは足りないデータを送りたい時に、それをぶら下げるためのポインタを定義しておきます。

そして、LCDのキューとしては、QUE_DATAを32個分までためられるものとします。
LCDの表示領域は、16文字*2行の最大32文字なので、一つのQUE_DATAに1文字をぶら下げたら最大サイズを食うことになりますが、まとめて書きたい時は文字列として一つのQUE_DATAで送ればいいですし、LCDタスクが処理しきる前にこのキューを食いつぶすような送り方をすることは、よほどないでしょう。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS