LCD文字表示(RTOS)
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
#analog
#norelated
#contents
* LCD文字表示(RTOS) [#bb712a69]
** MAPLE board [#ba36d854]
頑張ってハンダ付けしましょうw~
そんなに大変な作業ではないです。~
まぁ、私はフリー拡張スロットのコネクタのハンダ付け、一部...
** LCDモジュール [#k233bed7]
MAPLE boardについてきたのは、[[TC1602E-25A:http://www.lin...
このLCDは、4または8ビットモード(HD44780互換)ということで...
というわけで、[[alldatasheet:http://www.alldatasheet.jp/d...
基本的には、AVRの時にやった[[LCDサンプル]]と変わりません。~
** 構成 [#y147a72c]
MAPLE board附属の回路図を見れば分かる通り、DB0〜DB3は接続...
また、R/WがGNDに接続されていますので、Writeモード固定とい...
Writeモード固定なので、Busyフラグチェックは出来ませんから...
LPC1769は、LPC1768と同じなので、MAPLE boardの取扱説明書「...
以下のようになっているみたいですね。~
|ポート番号|ピン番号|LCD|h
|P0|15|D5|
|P0|16|D6|
|P0|17|D4|
|P2|1|RS|
|P2|2|E|
|P2|3|D7|
** プロジェクト [#o8640e7e]
まずは、ledtest02と同じように、FreeRTOSの新規プロジェクト...
プロジェクト名は、「lcdtest」としました。~
元々のLEDと今回のLCD、それに全体的な管理をするアプリケー...
それぞれをモジュールとして管理し、モジュールを管理するた...
データをハンドル化し、ロジックと切り離すことによって、LED...
今回の最終的なsrcフォルダ以下の構成は、以下のようになりま...
アプリケーションモジュール、LCDモジュール、LEDモジュール...
#ref(folder.png,left,nowrap,プロジェクトフォルダ構成)
** ソースコード [#r84ebfbc]
*** 共通定義等 [#k9e1191b]
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_ */
----
次に、各タスクのプライオリティ定義を用意しておきましょう。~
タスク間の関係は、アプリケーション全体で相互に意識しなけ...
ファイル名はapltask.hとし、これをincludeすればFreeRTOSの...
#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の実体は、apltask.cファイルをsrc直下に作って、以...
#include "apltask.h"
void TaskDelay( portTickType time )
{
vTaskDelay( time / portTICK_RATE_MS );
}
vTaskDelayは、引数がtick数であり、msではありません。~
前回書きましたが、FreeRTOSConfig.h内のconfigTICK_RATE_HZ...
configTICK_RATE_HZの値を書き換えてしまうと、ms単位の動作...
このため、msを指定できるラッパー関数を用意して、それに対...
参考までに、portTICK_RATE_MSは、FreeRTOS内で以下のように...
#define portTICK_RATE_MS ( ( portTickType ) 1000 / con...
----
タスクの次は、イベントキューを使うための定義を用意します。~
イベントキューは、LCDに表示するためのデータをLCDタスクに...
ファイル名はaplqueue.hとし、これをincludeすればFreeRTOSの...
こちらも、キュー全体のリソース管理という意味から、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_...
----
*** メイン [#cdae8a84]
まず先に、main.cの中身を書いてしまいます。~
#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif
#include <cr_section_macros.h>
#include <NXP/crp.h>
// Variable to store CRP value in. Will be placed automa...
// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
__CRP const unsigned int CRP_WORD = CRP_NO_CRP;
// TODO: insert other include files here
#include "led/led.h"
#include "lcd/lcd.h"
#include "apl/apl.h"
static LED_DATA led_data;
static LCD_DATA lcd_data;
static APL_DATA apl_data;
int main(void) {
// TODO: insert code here
PORTPIN_SET portpinset;
// 管理データ初期化
LED_InitHandle( &led_data );
LCD_InitHandle( &lcd_data );
APL_InitHandle( &apl_data );
// LEDポートピン設定
portpinset.port_num = PINSEL_PORT_0;
portpinset.pin_num = PINSEL_PIN_22;
LED_Setting( &led_data, &portpinset );
// LCDポートピン設定
portpinset.port_num = PINSEL_PORT_0;
portpinset.pin_num = PINSEL_PIN_17;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_DATA4, &portpi...
portpinset.pin_num = PINSEL_PIN_15;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_DATA5, &portpi...
portpinset.pin_num = PINSEL_PIN_16;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_DATA6, &portpi...
portpinset.port_num = PINSEL_PORT_2;
portpinset.pin_num = PINSEL_PIN_1;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_RS, &portpinse...
portpinset.pin_num = PINSEL_PIN_2;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_E, &portpinset...
portpinset.pin_num = PINSEL_PIN_3;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_DATA7, &portpi...
// モジュール初期化
LED_Init( &led_data, LED_ONOFF_ON );
LCD_Init( &lcd_data );
APL_Init( &apl_data );
// ハンドル設定
APL_SetLCDHandle( &apl_data, &lcd_data );
// タスク生成
LED_Start( &led_data, ( int8_t* )"LED" );
LCD_Start( &lcd_data, ( int8_t* )"LCD" );
APL_Start( &apl_data, ( int8_t* )"APL" );
// スケジューラ実行
vTaskStartScheduler();
return 0;
}
----
*** LEDモジュール [#ve9bd177]
次に、LEDモジュールです。~
まずは、外部ヘッダのled.h。~
#ifndef LED_H_
#define LED_H_
// include定義
#include "lpc17xx_pinsel.h"
#include "apldevice.h"
#include "apltask.h"
// LEDモジュールデータ
typedef struct _tagLED_DATA{
xTaskHandle htask; // タスクハンドル
PORTPIN_SET portpin; // ポートピンセット
} LED_DATA, *LPLED_DATA;
typedef enum _tagLED_ONOFF_MODE{
LED_ONOFF_OFF,
LED_ONOFF_ON
} LED_ONOFF_MODE;
// LEDハンドル初期化
int LED_InitHandle( LPLED_DATA handle );
// LEDハード設定
int LED_Setting( LPLED_DATA handle, LPPORTPIN_SET lpport...
// LEDモジュール初期化
int LED_Init( LPLED_DATA handle, LED_ONOFF_MODE onoff );
// LEDタスクスタート
int LED_Start( LPLED_DATA handle, const int8_t* const na...
#endif /* LED_H_ */
次に、内部用ヘッダのledin.h。~
#ifndef LEDIN_H_
#define LEDIN_H_
// LEDタスク
void led_task( void *param );
#endif /* LEDIN_H_ */
最後に、LEDモジュール本体の、led.cです。~
// include定義
#include "lpc17xx_pinsel.h"
#include "lpc17xx_gpio.h"
#include "led.h"
#include "ledin.h"
// LEDハンドル初期化
int LED_InitHandle( LPLED_DATA handle )
{
if( NULL == handle ){
return -1;
}
handle->portpin.port_num = PINSEL_PORT_0;
handle->portpin.pin_num = PINSEL_PIN_0;
handle->htask = NULL;
return 0;
}
// LEDハード設定
int LED_Setting( LPLED_DATA handle, LPPORTPIN_SET lpport...
{
if( NULL == handle || NULL == lpportpin ){
return -1;
}
handle->portpin = *lpportpin;
return 0;
}
// LEDモジュール初期化
int LED_Init( LPLED_DATA handle, LED_ONOFF_MODE onoff )
{
PINSEL_CFG_Type pincfg; // ピン設定構造体
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
// LED初期化
pincfg.Funcnum = PINSEL_FUNC_0;
pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
pincfg.Pinmode = PINSEL_PINMODE_PULLUP;
pincfg.Portnum = handle->portpin.port_num;
pincfg.Pinnum = handle->portpin.pin_num;
PINSEL_ConfigPin( &pincfg );
GPIO_SetDir( handle->portpin.port_num, ( 1 << handle->p...
if( LED_ONOFF_OFF == onoff ){ // OFFで初期化
GPIO_ClearValue( handle->portpin.port_num, ( 1 << hand...
} else { // ONで初期化
GPIO_SetValue( handle->portpin.port_num, ( 1 << handle...
}
return 0;
}
// LEDタスクスタート
int LED_Start( LPLED_DATA handle, const int8_t* const na...
{
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
// タスク生成
if( pdTRUE != xTaskCreate( led_task, name, LED_STACK_SI...
return -1;
}
return 0;
}
// LEDタスク
void led_task( void *param ){
LPLED_DATA handle = ( LPLED_DATA )param;
uint32_t state = 0;
// unsigned portBASE_TYPE freesize = 0;
while (1) {
vTaskDelay(500);
state = GPIO_ReadValue( handle->portpin.port_num );
GPIO_ClearValue( handle->portpin.port_num, state & (1 ...
GPIO_SetValue( handle->portpin.port_num, ~state & (1 <...
// freesize = uxTaskGetStackHighWaterMark(NULL);
}
}
----
*** LCDモジュール [#tfde4bc2]
次に、LCDモジュールです。~
まずは、外部ヘッダのlcd.h。~
#ifndef LCD_H_
#define LCD_H_
// include定義
#include "lpc17xx_pinsel.h"
#include "apldevice.h"
#include "apltask.h"
#include "aplqueue.h"
typedef enum _tagLCD_PORTPIN_TYPE{
LCD_PORTPIN_TYPE_RS,
LCD_PORTPIN_TYPE_E,
LCD_PORTPIN_TYPE_DATA4,
LCD_PORTPIN_TYPE_DATA5,
LCD_PORTPIN_TYPE_DATA6,
LCD_PORTPIN_TYPE_DATA7,
LCD_PORTPIN_TYPE_MAX
} LCD_PORTPIN_TYPE;
// LCDモジュールデータ
typedef struct _tagLCD_DATA{
xTaskHandle htask; // タスクハンドル
xQueueHandle hque; // キューハンドル
PORTPIN_SET portpin[LCD_PORTPIN_TYPE_MAX]; // ポートピ...
uint8_t ready; // 準備状態
} LCD_DATA, *LPLCD_DATA;
// LCDハンドル初期化
int LCD_InitHandle( LPLCD_DATA handle );
// LCDハード設定
int LCD_Setting( LPLCD_DATA handle, LCD_PORTPIN_TYPE typ...
// LCDモジュール初期化
int LCD_Init( LPLCD_DATA handle );
// LCDタスクスタート
int LCD_Start( LPLCD_DATA handle, const int8_t* const na...
// LCD準備状態取得
int LCD_GetReady( LPLCD_DATA handle );
// LCD文字送信
int LCD_SendChar( LPLCD_DATA handle, char ch );
// LCD文字列送信
int LCD_SendString( LPLCD_DATA handle, char *str );
// LCD数字送信
int LCD_SendNumber( LPLCD_DATA handle, int32_t num );
// LCD消去
int LCD_Clear( LPLCD_DATA handle );
// LCD位置設定
int LCD_SetPos( LPLCD_DATA handle, uint8_t x, uint8_t y );
#endif /* LCD_H_ */
次に、内部用ヘッダのlcdin.h。~
#ifndef LCDIN_H_
#define LCDIN_H_
// 送信モード
typedef enum _tagLCDIN_SENDMODE{
LCDIN_SENDMODE_COMMAND,
LCDIN_SENDMODE_DATA
} LCDIN_SENDMODE;
// イベントコード
typedef enum _tagLCDIN_EVENTCODE{
LCDIN_EVENTCODE_SENDCHAR, // 文字表示
LCDIN_EVENTCODE_SENDSTR, // 文字列表示
LCDIN_EVENTCODE_SENDNUMBER, // 数字表示
LCDIN_EVENTCODE_SENDCOMMAND // コマンド送信
} LCDIN_EVENTCODE;
// LCDタスク
void lcdin_task( void *param );
// LCDデバイス初期化
void lcdin_devinit( LPLCD_DATA handle );
// LCDデバイス4bit送信
void lcdin_snd4bit( LPLCD_DATA handle, LCDIN_SENDMODE mo...
// LCDデバイスコマンド送信
void lcdin_sendcmd( LPLCD_DATA handle, uint32_t cmd );
// LCDデバイス文字送信
void lcdin_sendchar( LPLCD_DATA handle, char data );
// LCDデバイス数字送信
void lcdin_sendnumber( LPLCD_DATA handle, int32_t data );
// LCDイベント送信
int lcdin_sendevent( LPLCD_DATA handle, LPQUE_DATA lpque...
#endif /* LCDIN_H_ */
最後に、LCDモジュール本体の、lcd.cです。~
// include定義
#include "lpc17xx_pinsel.h"
#include "lpc17xx_gpio.h"
#include "lcd.h"
#include "lcdin.h"
// LCDコマンド
typedef enum _tagLCDIN_CMD_MODE{
LCDIN_CMD_CLEAR, // クリア
LCDIN_CMD_SETPOS, // 位置設定
} LCDIN_CMD_MODE;
static const uint8_t LCDCmd[] = {
0x01, // クリア
0x80, // 位置設定
};
static const uint8_t LCDCmdWait[] = {
0x01, // クリア
0x00, // 位置設定
};
// LCDハンドル初期化
int LCD_InitHandle( LPLCD_DATA handle )
{
int i = 0; // ループ変数
if( NULL == handle ){
return -1;
}
for( i = 0; i < LCD_PORTPIN_TYPE_MAX; i++ ){
handle->portpin[i].port_num = PINSEL_PORT_0;
handle->portpin[i].pin_num = PINSEL_PIN_0;
}
handle->htask = NULL;
handle->hque = NULL;
handle->ready = 0;
return 0;
}
// LCDハード設定
int LCD_Setting( LPLCD_DATA handle, LCD_PORTPIN_TYPE typ...
{
if( NULL == handle || 0 > type || LCD_PORTPIN_TYPE_MAX ...
return -1;
}
handle->portpin[type] = *lpportpin;
return 0;
}
// LCDモジュール初期化
int LCD_Init( LPLCD_DATA handle )
{
PINSEL_CFG_Type pincfg; // ピン設定構造体
int i = 0; // ループ変数
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
// LCD初期化
pincfg.Funcnum = PINSEL_FUNC_0;
pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
pincfg.Pinmode = PINSEL_PINMODE_PULLUP;
for( i = 0; i < LCD_PORTPIN_TYPE_MAX; i++ ){
pincfg.Portnum = handle->portpin[i].port_num;
pincfg.Pinnum = handle->portpin[i].pin_num;
PINSEL_ConfigPin( &pincfg );
GPIO_SetDir( handle->portpin[i].port_num, ( 1 << handl...
GPIO_ClearValue( handle->portpin[i].port_num, ( 1 << h...
}
return 0;
}
// LCDタスクスタート
int LCD_Start( LPLCD_DATA handle, const int8_t* const na...
{
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask || NULL != handle->hque ){
return -1;
}
// キュー生成
handle->hque = xQueueCreate( LCD_QUE_LENGTH, sizeof( QU...
if( NULL == handle->hque ){
return -1;
}
// タスク生成
if( pdTRUE != xTaskCreate( lcdin_task, name, LCD_STACK_...
vQueueDelete( handle->hque );
handle->hque = NULL;
return -1;
}
return 0;
}
// LCD準備状態取得
int LCD_GetReady( LPLCD_DATA handle )
{
if( NULL == handle ){
return -1;
}
return handle->ready;
}
// LCDタスク
void lcdin_task( void *param ){
LPLCD_DATA handle = ( LPLCD_DATA )param;
char *str = NULL; // 文字列表示用
QUE_DATA que_data; // イベントキューデータ
unsigned portBASE_TYPE freesize = 0;
lcdin_devinit( handle );
while (1) {
if( pdTRUE != xQueueReceive( handle->hque, &que_data, ...
continue;
}
switch( que_data.evcode ){
case LCDIN_EVENTCODE_SENDCHAR : // 文字表示
lcdin_sendchar( handle, ( char )que_data.param );
break;
case LCDIN_EVENTCODE_SENDSTR : // 文字列表示
str = que_data.data;
if( NULL != str ){
while( *str ){
lcdin_sendchar( handle, *str );
str++;
}
vPortFree( que_data.data );
}
break;
case LCDIN_EVENTCODE_SENDNUMBER : // 数字表示
lcdin_sendnumber( handle, que_data.param );
break;
case LCDIN_EVENTCODE_SENDCOMMAND : // コマンド送信
lcdin_sendcmd( handle, ( uint32_t )que_data.param );
break;
default :
break;
}
freesize = uxTaskGetStackHighWaterMark(NULL);
}
}
// LCDデバイス初期化
void lcdin_devinit( LPLCD_DATA handle )
{
// 初期化コマンド送信
TaskDelay( 50 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0011 );
TaskDelay( 5 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0011 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0011 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0010 );
// Function Set
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0010 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b1000 );
// Display on/off
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0000 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b1111 );
// Clear Display
lcdin_sendcmd( handle, ( LCDCmdWait[LCDIN_CMD_CLEAR] <<...
// Entry Mode
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0000 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0110 );
handle->ready = 1;
}
// LCDデバイス4bit送信
void lcdin_snd4bit( LPLCD_DATA handle, LCDIN_SENDMODE mo...
{
uint8_t i = 0; // ループ変数
if( LCDIN_SENDMODE_COMMAND == mode ){
GPIO_ClearValue( handle->portpin[LCD_PORTPIN_TYPE_RS]....
} else {
GPIO_SetValue( handle->portpin[LCD_PORTPIN_TYPE_RS].po...
}
for( i = LCD_PORTPIN_TYPE_DATA4; i < LCD_PORTPIN_TYPE_M...
GPIO_ClearValue( handle->portpin[i].port_num, ( 1 << (...
GPIO_SetValue( handle->portpin[i].port_num, ((( cmd >>...
}
GPIO_SetValue( handle->portpin[LCD_PORTPIN_TYPE_E].port...
TaskDelay( 1 );
GPIO_ClearValue( handle->portpin[LCD_PORTPIN_TYPE_E].po...
TaskDelay( 1 );
}
// LCDデバイスコマンド送信
void lcdin_sendcmd( LPLCD_DATA handle, uint32_t cmd )
{
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, ( cmd >>...
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, cmd & 0x...
if(( cmd >> 8 ) & 0xff ){
TaskDelay(( cmd >> 8 ) & 0xff );
}
}
// LCDデバイス文字送信
void lcdin_sendchar( LPLCD_DATA handle, char data )
{
lcdin_snd4bit( handle, LCDIN_SENDMODE_DATA, data >> 4 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_DATA, data );
}
// LCDデバイス数字送信
void lcdin_sendnumber( LPLCD_DATA handle, int32_t data )
{
int32_t tmpnum = data; // 数字変換用
int8_t keta = 0; // 数字変換用
int8_t i= 0, j = 0; // ループ変数
if( 0 > data ){
lcdin_sendchar( handle, '-' );
data = -data;
}
if( 0 == data ){
tmpnum++; // 0の桁を1とするため
}
while( 0 != tmpnum ){
tmpnum /= 10;
keta++;
}
for( i = keta - 1; i >= 0; i-- ){
tmpnum = 1;
for( j = 0; j < i; j++ ){
tmpnum *= 10;
}
lcdin_sendchar( handle, 48 + data / tmpnum );
data %= tmpnum;
}
}
// LCDイベント送信
int lcdin_sendevent( LPLCD_DATA handle, LPQUE_DATA lpque )
{
if( NULL == handle->hque ){
return -1;
}
if( pdTRUE != xQueueSend( handle->hque, lpque, 0 )){
return -1;
}
return 0;
}
// LCD文字送信
int LCD_SendChar( LPLCD_DATA handle, char ch )
{
QUE_DATA que_data;
if( NULL == handle ){
return -1;
}
que_data.evcode = LCDIN_EVENTCODE_SENDCHAR;
que_data.param = ( int32_t )ch;
que_data.data = NULL;
return lcdin_sendevent( handle, &que_data );
}
// LCD文字列送信
int LCD_SendString( LPLCD_DATA handle, char *str )
{
QUE_DATA que_data;
size_t size = 0; // 確保サイズ
int ret = -1; // 結果格納用
char *ptr = NULL; // コピー用
if( NULL == handle || NULL == str ){
return -1;
}
ptr = str;
while( *ptr ){
size++;
ptr++;
}
if( 0 == size ){
return -1;
}
que_data.evcode = LCDIN_EVENTCODE_SENDSTR;
que_data.param = 0;
que_data.data = pvPortMalloc( size );
if( NULL == que_data.data ){
return -1;
}
ptr = ( char* )que_data.data;
while( *str ){
*ptr = *str;
str++;
ptr++;
}
ret = lcdin_sendevent( handle, &que_data );
if( 0 > ret ){
vPortFree( que_data.data );
}
return ret;
}
// LCD数字送信
int LCD_SendNumber( LPLCD_DATA handle, int32_t num )
{
QUE_DATA que_data;
if( NULL == handle ){
return -1;
}
que_data.evcode = LCDIN_EVENTCODE_SENDNUMBER;
que_data.param = num;
que_data.data = NULL;
return lcdin_sendevent( handle, &que_data );
}
// LCD消去
int LCD_Clear( LPLCD_DATA handle )
{
QUE_DATA que_data;
uint32_t cmd = ( LCDCmdWait[LCDIN_CMD_CLEAR] << 8 ) | L...
if( NULL == handle ){
return -1;
}
que_data.evcode = LCDIN_EVENTCODE_SENDCOMMAND;
que_data.param = ( int32_t )cmd;
que_data.data = NULL;
return lcdin_sendevent( handle, &que_data );
}
// LCD位置設定
int LCD_SetPos( LPLCD_DATA handle, uint8_t x, uint8_t y )
{
QUE_DATA que_data;
uint32_t cmd = ( LCDCmdWait[LCDIN_CMD_SETPOS] << 8 ) | ...
if( NULL == handle ){
return -1;
}
if( 0 != y ){
cmd += 0x40;
}
cmd += x;
que_data.evcode = LCDIN_EVENTCODE_SENDCOMMAND;
que_data.param = ( int32_t )cmd;
que_data.data = NULL;
return lcdin_sendevent( handle, &que_data );
}
----
*** APLモジュール [#bce77d3d]
最後に、APLモジュールです。~
まずは、外部ヘッダのapl.h。~
#ifndef APL_H_
#define APL_H_
// include定義
#include "apldevice.h"
#include "apltask.h"
#include "lcd/lcd.h"
// APLモジュールデータ
typedef struct _tagAPL_DATA{
xTaskHandle htask; // タスクハンドル
LPLCD_DATA hlcd; // LCDハンドル
} APL_DATA, *LPAPL_DATA;
// APLハンドル初期化
int APL_InitHandle( LPAPL_DATA handle );
// LCDハンドル設定
int APL_SetLCDHandle( LPAPL_DATA hapl, LPLCD_DATA hlcd );
// APLモジュール初期化
int APL_Init( LPAPL_DATA handle );
// APLタスクスタート
int APL_Start( LPAPL_DATA handle, const int8_t* const na...
#endif /* APL_H_ */
次に、内部用ヘッダのaplin.h。~
#ifndef APLIN_H_
#define APLIN_H_
// APLタスク
void apl_task( void *param );
#endif /* APLIN_H_ */
最後に、APLモジュール本体の、apl.cです。~
// include定義
#include "apl.h"
#include "aplin.h"
// APLハンドル初期化
int APL_InitHandle( LPAPL_DATA handle )
{
if( NULL == handle ){
return -1;
}
handle->htask = NULL;
handle->hlcd = NULL;
return 0;
}
// LCDハンドル設定
int APL_SetLCDHandle( LPAPL_DATA hapl, LPLCD_DATA hlcd )
{
if( NULL == hapl || NULL == hlcd ){
return -1;
}
hapl->hlcd = hlcd;
return 0;
}
// APLモジュール初期化
int APL_Init( LPAPL_DATA handle )
{
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
return 0;
}
// APLタスクスタート
int APL_Start( LPAPL_DATA handle, const int8_t* const na...
{
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
// タスク生成
if( pdTRUE != xTaskCreate( apl_task, name, APL_STACK_SI...
return -1;
}
return 0;
}
void apl_task( void *param ){
LPAPL_DATA handle = ( LPAPL_DATA )param;
unsigned portBASE_TYPE freesize = 0;
// LCD準備待機
while( 1 != LCD_GetReady( handle->hlcd )){
TaskDelay(100);
}
while (1) {
LCD_SendChar( handle->hlcd, 'A' );
LCD_SendNumber( handle->hlcd, 0 );
LCD_SendChar( handle->hlcd, 'B' );
LCD_SendNumber( handle->hlcd, 1234567890 );
LCD_SetPos( handle->hlcd, 0, 1 );
LCD_SendChar( handle->hlcd, 'C' );
LCD_SendNumber( handle->hlcd, 2 );
LCD_SendChar( handle->hlcd, 'D' );
LCD_SendNumber( handle->hlcd, -987654321 );
TaskDelay(5000);
LCD_Clear( handle->hlcd );
LCD_SendString( handle->hlcd, "LCD\xc3\xbd\xc4\xc1\xad...
TaskDelay(5000);
LCD_Clear( handle->hlcd );
freesize = uxTaskGetStackHighWaterMark(NULL);
}
}
** ソースコード解説 [#t6a7ed0f]
共通定義のところはある程度書いたので、メインから。~
*** メイン [#sd61156e]
先頭はお決まりのincludeとCRPです。~
まずは、LED、LCD、APLと、各モジュールのヘッダをincludeし...
main関数の先頭で、それらの領域を初期化します。~
次に、LEDとLCDで使うポートとピンの設定をしています。~
LEDは一つのみですが、LCDは6本使うので、enum型で指定するよ...
次に、各モジュールを使えるように初期化します。~
こちらは領域の初期化ではなく、GPIOの設定等をしています。~
APLモジュールは、実際にはやることがないので、呼ぶだけで何...
そして、APLモジュールでLCDを操作するために、LCDのハンドル...
最後に、各モジュールのタスクやキューを生成して、スケジュ...
同じモジュールのインスタンスを複数作れることを考えて、タ...
ハンドル的な考え方以外は、そんなに大したことしてないです...
----
*** LEDモジュール [#f1865ffc]
次に、LEDモジュールです。~
外部ヘッダのled.hには、まずモジュールデータとして、自分自...
LED_ONOFF_MODEのenumは、ONで初期化、OFFで初期化を選べるよ...
内部用ヘッダのledin.hは、外部には公開しないタスク関数のみ...
LEDモジュール本体の、led.cについては、基本的には[[LEDチカ...
今は周期的な点滅を繰り返しているだけですが、そのうち外部...
----
*** LCDモジュール [#y8d62d65]
次に、今回のメイン、LCDモジュールです。~
外部ヘッダのlcd.hには、まず、ポートピンのenumを定義してい...
モジュールデータとして、自分自身のタスクハンドルとコマン...
そしてもう一つ、LCDは初期化に多少の時間を必要とするため、...
このため、LCDを使用する他タスクは、LCDの初期化が終わって...
この、初期化が終わっているかどうかを保存しておくフラグも...
あとは、各種機能のプロトタイプですね。~
内部用ヘッダのlcdin.hは、LCDの送信モード、キューで受け取...
最後に、LCDモジュール本体の、lcd.cですが、基本的な流れと...
LCD_Startでは、タスクハンドルと共に、このためのキューハン...
lcdin_taskでは、まずlcdin_devinitを呼んでLCDの初期化を行...
他のモジュールは、LCD_GetReadyを呼んでこの準備フラグを参...
本来、複数のタスクから同時に参照・変更するような変数は、...
lcdin_devinitでの初期化は、HD44780のデータシート通りです。~
「Figure 24 4-Bit Interface」のところですね。~
1ms以上の待ちが必要なものは、TaskDelayで待ちを入れていま...
1ms未満のものであれば、lcdin_snd4bitでのenableパルス送信...
コマンドは2つくらいテーブルに持っていますが、他に使うもの...
LCD_SendCharやLCD_SendNumber、コマンド系については、LCDタ...
----
*** APLモジュール [#sc6d1fe0]
最後のAPLモジュールは、タスク起動時にLCDが使用できるまで...
AVRの時みたいに、ソースコードがShift-JISだとそのまま書け...
----
** 実行・デバッグ [#u6ecacd5]
#u2b(-lMBHMhbqmg,w=640,h=360)
終了行:
#analog
#norelated
#contents
* LCD文字表示(RTOS) [#bb712a69]
** MAPLE board [#ba36d854]
頑張ってハンダ付けしましょうw~
そんなに大変な作業ではないです。~
まぁ、私はフリー拡張スロットのコネクタのハンダ付け、一部...
** LCDモジュール [#k233bed7]
MAPLE boardについてきたのは、[[TC1602E-25A:http://www.lin...
このLCDは、4または8ビットモード(HD44780互換)ということで...
というわけで、[[alldatasheet:http://www.alldatasheet.jp/d...
基本的には、AVRの時にやった[[LCDサンプル]]と変わりません。~
** 構成 [#y147a72c]
MAPLE board附属の回路図を見れば分かる通り、DB0〜DB3は接続...
また、R/WがGNDに接続されていますので、Writeモード固定とい...
Writeモード固定なので、Busyフラグチェックは出来ませんから...
LPC1769は、LPC1768と同じなので、MAPLE boardの取扱説明書「...
以下のようになっているみたいですね。~
|ポート番号|ピン番号|LCD|h
|P0|15|D5|
|P0|16|D6|
|P0|17|D4|
|P2|1|RS|
|P2|2|E|
|P2|3|D7|
** プロジェクト [#o8640e7e]
まずは、ledtest02と同じように、FreeRTOSの新規プロジェクト...
プロジェクト名は、「lcdtest」としました。~
元々のLEDと今回のLCD、それに全体的な管理をするアプリケー...
それぞれをモジュールとして管理し、モジュールを管理するた...
データをハンドル化し、ロジックと切り離すことによって、LED...
今回の最終的なsrcフォルダ以下の構成は、以下のようになりま...
アプリケーションモジュール、LCDモジュール、LEDモジュール...
#ref(folder.png,left,nowrap,プロジェクトフォルダ構成)
** ソースコード [#r84ebfbc]
*** 共通定義等 [#k9e1191b]
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_ */
----
次に、各タスクのプライオリティ定義を用意しておきましょう。~
タスク間の関係は、アプリケーション全体で相互に意識しなけ...
ファイル名はapltask.hとし、これをincludeすればFreeRTOSの...
#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の実体は、apltask.cファイルをsrc直下に作って、以...
#include "apltask.h"
void TaskDelay( portTickType time )
{
vTaskDelay( time / portTICK_RATE_MS );
}
vTaskDelayは、引数がtick数であり、msではありません。~
前回書きましたが、FreeRTOSConfig.h内のconfigTICK_RATE_HZ...
configTICK_RATE_HZの値を書き換えてしまうと、ms単位の動作...
このため、msを指定できるラッパー関数を用意して、それに対...
参考までに、portTICK_RATE_MSは、FreeRTOS内で以下のように...
#define portTICK_RATE_MS ( ( portTickType ) 1000 / con...
----
タスクの次は、イベントキューを使うための定義を用意します。~
イベントキューは、LCDに表示するためのデータをLCDタスクに...
ファイル名はaplqueue.hとし、これをincludeすればFreeRTOSの...
こちらも、キュー全体のリソース管理という意味から、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_...
----
*** メイン [#cdae8a84]
まず先に、main.cの中身を書いてしまいます。~
#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif
#include <cr_section_macros.h>
#include <NXP/crp.h>
// Variable to store CRP value in. Will be placed automa...
// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
__CRP const unsigned int CRP_WORD = CRP_NO_CRP;
// TODO: insert other include files here
#include "led/led.h"
#include "lcd/lcd.h"
#include "apl/apl.h"
static LED_DATA led_data;
static LCD_DATA lcd_data;
static APL_DATA apl_data;
int main(void) {
// TODO: insert code here
PORTPIN_SET portpinset;
// 管理データ初期化
LED_InitHandle( &led_data );
LCD_InitHandle( &lcd_data );
APL_InitHandle( &apl_data );
// LEDポートピン設定
portpinset.port_num = PINSEL_PORT_0;
portpinset.pin_num = PINSEL_PIN_22;
LED_Setting( &led_data, &portpinset );
// LCDポートピン設定
portpinset.port_num = PINSEL_PORT_0;
portpinset.pin_num = PINSEL_PIN_17;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_DATA4, &portpi...
portpinset.pin_num = PINSEL_PIN_15;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_DATA5, &portpi...
portpinset.pin_num = PINSEL_PIN_16;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_DATA6, &portpi...
portpinset.port_num = PINSEL_PORT_2;
portpinset.pin_num = PINSEL_PIN_1;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_RS, &portpinse...
portpinset.pin_num = PINSEL_PIN_2;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_E, &portpinset...
portpinset.pin_num = PINSEL_PIN_3;
LCD_Setting( &lcd_data, LCD_PORTPIN_TYPE_DATA7, &portpi...
// モジュール初期化
LED_Init( &led_data, LED_ONOFF_ON );
LCD_Init( &lcd_data );
APL_Init( &apl_data );
// ハンドル設定
APL_SetLCDHandle( &apl_data, &lcd_data );
// タスク生成
LED_Start( &led_data, ( int8_t* )"LED" );
LCD_Start( &lcd_data, ( int8_t* )"LCD" );
APL_Start( &apl_data, ( int8_t* )"APL" );
// スケジューラ実行
vTaskStartScheduler();
return 0;
}
----
*** LEDモジュール [#ve9bd177]
次に、LEDモジュールです。~
まずは、外部ヘッダのled.h。~
#ifndef LED_H_
#define LED_H_
// include定義
#include "lpc17xx_pinsel.h"
#include "apldevice.h"
#include "apltask.h"
// LEDモジュールデータ
typedef struct _tagLED_DATA{
xTaskHandle htask; // タスクハンドル
PORTPIN_SET portpin; // ポートピンセット
} LED_DATA, *LPLED_DATA;
typedef enum _tagLED_ONOFF_MODE{
LED_ONOFF_OFF,
LED_ONOFF_ON
} LED_ONOFF_MODE;
// LEDハンドル初期化
int LED_InitHandle( LPLED_DATA handle );
// LEDハード設定
int LED_Setting( LPLED_DATA handle, LPPORTPIN_SET lpport...
// LEDモジュール初期化
int LED_Init( LPLED_DATA handle, LED_ONOFF_MODE onoff );
// LEDタスクスタート
int LED_Start( LPLED_DATA handle, const int8_t* const na...
#endif /* LED_H_ */
次に、内部用ヘッダのledin.h。~
#ifndef LEDIN_H_
#define LEDIN_H_
// LEDタスク
void led_task( void *param );
#endif /* LEDIN_H_ */
最後に、LEDモジュール本体の、led.cです。~
// include定義
#include "lpc17xx_pinsel.h"
#include "lpc17xx_gpio.h"
#include "led.h"
#include "ledin.h"
// LEDハンドル初期化
int LED_InitHandle( LPLED_DATA handle )
{
if( NULL == handle ){
return -1;
}
handle->portpin.port_num = PINSEL_PORT_0;
handle->portpin.pin_num = PINSEL_PIN_0;
handle->htask = NULL;
return 0;
}
// LEDハード設定
int LED_Setting( LPLED_DATA handle, LPPORTPIN_SET lpport...
{
if( NULL == handle || NULL == lpportpin ){
return -1;
}
handle->portpin = *lpportpin;
return 0;
}
// LEDモジュール初期化
int LED_Init( LPLED_DATA handle, LED_ONOFF_MODE onoff )
{
PINSEL_CFG_Type pincfg; // ピン設定構造体
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
// LED初期化
pincfg.Funcnum = PINSEL_FUNC_0;
pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
pincfg.Pinmode = PINSEL_PINMODE_PULLUP;
pincfg.Portnum = handle->portpin.port_num;
pincfg.Pinnum = handle->portpin.pin_num;
PINSEL_ConfigPin( &pincfg );
GPIO_SetDir( handle->portpin.port_num, ( 1 << handle->p...
if( LED_ONOFF_OFF == onoff ){ // OFFで初期化
GPIO_ClearValue( handle->portpin.port_num, ( 1 << hand...
} else { // ONで初期化
GPIO_SetValue( handle->portpin.port_num, ( 1 << handle...
}
return 0;
}
// LEDタスクスタート
int LED_Start( LPLED_DATA handle, const int8_t* const na...
{
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
// タスク生成
if( pdTRUE != xTaskCreate( led_task, name, LED_STACK_SI...
return -1;
}
return 0;
}
// LEDタスク
void led_task( void *param ){
LPLED_DATA handle = ( LPLED_DATA )param;
uint32_t state = 0;
// unsigned portBASE_TYPE freesize = 0;
while (1) {
vTaskDelay(500);
state = GPIO_ReadValue( handle->portpin.port_num );
GPIO_ClearValue( handle->portpin.port_num, state & (1 ...
GPIO_SetValue( handle->portpin.port_num, ~state & (1 <...
// freesize = uxTaskGetStackHighWaterMark(NULL);
}
}
----
*** LCDモジュール [#tfde4bc2]
次に、LCDモジュールです。~
まずは、外部ヘッダのlcd.h。~
#ifndef LCD_H_
#define LCD_H_
// include定義
#include "lpc17xx_pinsel.h"
#include "apldevice.h"
#include "apltask.h"
#include "aplqueue.h"
typedef enum _tagLCD_PORTPIN_TYPE{
LCD_PORTPIN_TYPE_RS,
LCD_PORTPIN_TYPE_E,
LCD_PORTPIN_TYPE_DATA4,
LCD_PORTPIN_TYPE_DATA5,
LCD_PORTPIN_TYPE_DATA6,
LCD_PORTPIN_TYPE_DATA7,
LCD_PORTPIN_TYPE_MAX
} LCD_PORTPIN_TYPE;
// LCDモジュールデータ
typedef struct _tagLCD_DATA{
xTaskHandle htask; // タスクハンドル
xQueueHandle hque; // キューハンドル
PORTPIN_SET portpin[LCD_PORTPIN_TYPE_MAX]; // ポートピ...
uint8_t ready; // 準備状態
} LCD_DATA, *LPLCD_DATA;
// LCDハンドル初期化
int LCD_InitHandle( LPLCD_DATA handle );
// LCDハード設定
int LCD_Setting( LPLCD_DATA handle, LCD_PORTPIN_TYPE typ...
// LCDモジュール初期化
int LCD_Init( LPLCD_DATA handle );
// LCDタスクスタート
int LCD_Start( LPLCD_DATA handle, const int8_t* const na...
// LCD準備状態取得
int LCD_GetReady( LPLCD_DATA handle );
// LCD文字送信
int LCD_SendChar( LPLCD_DATA handle, char ch );
// LCD文字列送信
int LCD_SendString( LPLCD_DATA handle, char *str );
// LCD数字送信
int LCD_SendNumber( LPLCD_DATA handle, int32_t num );
// LCD消去
int LCD_Clear( LPLCD_DATA handle );
// LCD位置設定
int LCD_SetPos( LPLCD_DATA handle, uint8_t x, uint8_t y );
#endif /* LCD_H_ */
次に、内部用ヘッダのlcdin.h。~
#ifndef LCDIN_H_
#define LCDIN_H_
// 送信モード
typedef enum _tagLCDIN_SENDMODE{
LCDIN_SENDMODE_COMMAND,
LCDIN_SENDMODE_DATA
} LCDIN_SENDMODE;
// イベントコード
typedef enum _tagLCDIN_EVENTCODE{
LCDIN_EVENTCODE_SENDCHAR, // 文字表示
LCDIN_EVENTCODE_SENDSTR, // 文字列表示
LCDIN_EVENTCODE_SENDNUMBER, // 数字表示
LCDIN_EVENTCODE_SENDCOMMAND // コマンド送信
} LCDIN_EVENTCODE;
// LCDタスク
void lcdin_task( void *param );
// LCDデバイス初期化
void lcdin_devinit( LPLCD_DATA handle );
// LCDデバイス4bit送信
void lcdin_snd4bit( LPLCD_DATA handle, LCDIN_SENDMODE mo...
// LCDデバイスコマンド送信
void lcdin_sendcmd( LPLCD_DATA handle, uint32_t cmd );
// LCDデバイス文字送信
void lcdin_sendchar( LPLCD_DATA handle, char data );
// LCDデバイス数字送信
void lcdin_sendnumber( LPLCD_DATA handle, int32_t data );
// LCDイベント送信
int lcdin_sendevent( LPLCD_DATA handle, LPQUE_DATA lpque...
#endif /* LCDIN_H_ */
最後に、LCDモジュール本体の、lcd.cです。~
// include定義
#include "lpc17xx_pinsel.h"
#include "lpc17xx_gpio.h"
#include "lcd.h"
#include "lcdin.h"
// LCDコマンド
typedef enum _tagLCDIN_CMD_MODE{
LCDIN_CMD_CLEAR, // クリア
LCDIN_CMD_SETPOS, // 位置設定
} LCDIN_CMD_MODE;
static const uint8_t LCDCmd[] = {
0x01, // クリア
0x80, // 位置設定
};
static const uint8_t LCDCmdWait[] = {
0x01, // クリア
0x00, // 位置設定
};
// LCDハンドル初期化
int LCD_InitHandle( LPLCD_DATA handle )
{
int i = 0; // ループ変数
if( NULL == handle ){
return -1;
}
for( i = 0; i < LCD_PORTPIN_TYPE_MAX; i++ ){
handle->portpin[i].port_num = PINSEL_PORT_0;
handle->portpin[i].pin_num = PINSEL_PIN_0;
}
handle->htask = NULL;
handle->hque = NULL;
handle->ready = 0;
return 0;
}
// LCDハード設定
int LCD_Setting( LPLCD_DATA handle, LCD_PORTPIN_TYPE typ...
{
if( NULL == handle || 0 > type || LCD_PORTPIN_TYPE_MAX ...
return -1;
}
handle->portpin[type] = *lpportpin;
return 0;
}
// LCDモジュール初期化
int LCD_Init( LPLCD_DATA handle )
{
PINSEL_CFG_Type pincfg; // ピン設定構造体
int i = 0; // ループ変数
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
// LCD初期化
pincfg.Funcnum = PINSEL_FUNC_0;
pincfg.OpenDrain = PINSEL_PINMODE_NORMAL;
pincfg.Pinmode = PINSEL_PINMODE_PULLUP;
for( i = 0; i < LCD_PORTPIN_TYPE_MAX; i++ ){
pincfg.Portnum = handle->portpin[i].port_num;
pincfg.Pinnum = handle->portpin[i].pin_num;
PINSEL_ConfigPin( &pincfg );
GPIO_SetDir( handle->portpin[i].port_num, ( 1 << handl...
GPIO_ClearValue( handle->portpin[i].port_num, ( 1 << h...
}
return 0;
}
// LCDタスクスタート
int LCD_Start( LPLCD_DATA handle, const int8_t* const na...
{
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask || NULL != handle->hque ){
return -1;
}
// キュー生成
handle->hque = xQueueCreate( LCD_QUE_LENGTH, sizeof( QU...
if( NULL == handle->hque ){
return -1;
}
// タスク生成
if( pdTRUE != xTaskCreate( lcdin_task, name, LCD_STACK_...
vQueueDelete( handle->hque );
handle->hque = NULL;
return -1;
}
return 0;
}
// LCD準備状態取得
int LCD_GetReady( LPLCD_DATA handle )
{
if( NULL == handle ){
return -1;
}
return handle->ready;
}
// LCDタスク
void lcdin_task( void *param ){
LPLCD_DATA handle = ( LPLCD_DATA )param;
char *str = NULL; // 文字列表示用
QUE_DATA que_data; // イベントキューデータ
unsigned portBASE_TYPE freesize = 0;
lcdin_devinit( handle );
while (1) {
if( pdTRUE != xQueueReceive( handle->hque, &que_data, ...
continue;
}
switch( que_data.evcode ){
case LCDIN_EVENTCODE_SENDCHAR : // 文字表示
lcdin_sendchar( handle, ( char )que_data.param );
break;
case LCDIN_EVENTCODE_SENDSTR : // 文字列表示
str = que_data.data;
if( NULL != str ){
while( *str ){
lcdin_sendchar( handle, *str );
str++;
}
vPortFree( que_data.data );
}
break;
case LCDIN_EVENTCODE_SENDNUMBER : // 数字表示
lcdin_sendnumber( handle, que_data.param );
break;
case LCDIN_EVENTCODE_SENDCOMMAND : // コマンド送信
lcdin_sendcmd( handle, ( uint32_t )que_data.param );
break;
default :
break;
}
freesize = uxTaskGetStackHighWaterMark(NULL);
}
}
// LCDデバイス初期化
void lcdin_devinit( LPLCD_DATA handle )
{
// 初期化コマンド送信
TaskDelay( 50 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0011 );
TaskDelay( 5 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0011 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0011 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0010 );
// Function Set
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0010 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b1000 );
// Display on/off
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0000 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b1111 );
// Clear Display
lcdin_sendcmd( handle, ( LCDCmdWait[LCDIN_CMD_CLEAR] <<...
// Entry Mode
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0000 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, 0b0110 );
handle->ready = 1;
}
// LCDデバイス4bit送信
void lcdin_snd4bit( LPLCD_DATA handle, LCDIN_SENDMODE mo...
{
uint8_t i = 0; // ループ変数
if( LCDIN_SENDMODE_COMMAND == mode ){
GPIO_ClearValue( handle->portpin[LCD_PORTPIN_TYPE_RS]....
} else {
GPIO_SetValue( handle->portpin[LCD_PORTPIN_TYPE_RS].po...
}
for( i = LCD_PORTPIN_TYPE_DATA4; i < LCD_PORTPIN_TYPE_M...
GPIO_ClearValue( handle->portpin[i].port_num, ( 1 << (...
GPIO_SetValue( handle->portpin[i].port_num, ((( cmd >>...
}
GPIO_SetValue( handle->portpin[LCD_PORTPIN_TYPE_E].port...
TaskDelay( 1 );
GPIO_ClearValue( handle->portpin[LCD_PORTPIN_TYPE_E].po...
TaskDelay( 1 );
}
// LCDデバイスコマンド送信
void lcdin_sendcmd( LPLCD_DATA handle, uint32_t cmd )
{
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, ( cmd >>...
lcdin_snd4bit( handle, LCDIN_SENDMODE_COMMAND, cmd & 0x...
if(( cmd >> 8 ) & 0xff ){
TaskDelay(( cmd >> 8 ) & 0xff );
}
}
// LCDデバイス文字送信
void lcdin_sendchar( LPLCD_DATA handle, char data )
{
lcdin_snd4bit( handle, LCDIN_SENDMODE_DATA, data >> 4 );
lcdin_snd4bit( handle, LCDIN_SENDMODE_DATA, data );
}
// LCDデバイス数字送信
void lcdin_sendnumber( LPLCD_DATA handle, int32_t data )
{
int32_t tmpnum = data; // 数字変換用
int8_t keta = 0; // 数字変換用
int8_t i= 0, j = 0; // ループ変数
if( 0 > data ){
lcdin_sendchar( handle, '-' );
data = -data;
}
if( 0 == data ){
tmpnum++; // 0の桁を1とするため
}
while( 0 != tmpnum ){
tmpnum /= 10;
keta++;
}
for( i = keta - 1; i >= 0; i-- ){
tmpnum = 1;
for( j = 0; j < i; j++ ){
tmpnum *= 10;
}
lcdin_sendchar( handle, 48 + data / tmpnum );
data %= tmpnum;
}
}
// LCDイベント送信
int lcdin_sendevent( LPLCD_DATA handle, LPQUE_DATA lpque )
{
if( NULL == handle->hque ){
return -1;
}
if( pdTRUE != xQueueSend( handle->hque, lpque, 0 )){
return -1;
}
return 0;
}
// LCD文字送信
int LCD_SendChar( LPLCD_DATA handle, char ch )
{
QUE_DATA que_data;
if( NULL == handle ){
return -1;
}
que_data.evcode = LCDIN_EVENTCODE_SENDCHAR;
que_data.param = ( int32_t )ch;
que_data.data = NULL;
return lcdin_sendevent( handle, &que_data );
}
// LCD文字列送信
int LCD_SendString( LPLCD_DATA handle, char *str )
{
QUE_DATA que_data;
size_t size = 0; // 確保サイズ
int ret = -1; // 結果格納用
char *ptr = NULL; // コピー用
if( NULL == handle || NULL == str ){
return -1;
}
ptr = str;
while( *ptr ){
size++;
ptr++;
}
if( 0 == size ){
return -1;
}
que_data.evcode = LCDIN_EVENTCODE_SENDSTR;
que_data.param = 0;
que_data.data = pvPortMalloc( size );
if( NULL == que_data.data ){
return -1;
}
ptr = ( char* )que_data.data;
while( *str ){
*ptr = *str;
str++;
ptr++;
}
ret = lcdin_sendevent( handle, &que_data );
if( 0 > ret ){
vPortFree( que_data.data );
}
return ret;
}
// LCD数字送信
int LCD_SendNumber( LPLCD_DATA handle, int32_t num )
{
QUE_DATA que_data;
if( NULL == handle ){
return -1;
}
que_data.evcode = LCDIN_EVENTCODE_SENDNUMBER;
que_data.param = num;
que_data.data = NULL;
return lcdin_sendevent( handle, &que_data );
}
// LCD消去
int LCD_Clear( LPLCD_DATA handle )
{
QUE_DATA que_data;
uint32_t cmd = ( LCDCmdWait[LCDIN_CMD_CLEAR] << 8 ) | L...
if( NULL == handle ){
return -1;
}
que_data.evcode = LCDIN_EVENTCODE_SENDCOMMAND;
que_data.param = ( int32_t )cmd;
que_data.data = NULL;
return lcdin_sendevent( handle, &que_data );
}
// LCD位置設定
int LCD_SetPos( LPLCD_DATA handle, uint8_t x, uint8_t y )
{
QUE_DATA que_data;
uint32_t cmd = ( LCDCmdWait[LCDIN_CMD_SETPOS] << 8 ) | ...
if( NULL == handle ){
return -1;
}
if( 0 != y ){
cmd += 0x40;
}
cmd += x;
que_data.evcode = LCDIN_EVENTCODE_SENDCOMMAND;
que_data.param = ( int32_t )cmd;
que_data.data = NULL;
return lcdin_sendevent( handle, &que_data );
}
----
*** APLモジュール [#bce77d3d]
最後に、APLモジュールです。~
まずは、外部ヘッダのapl.h。~
#ifndef APL_H_
#define APL_H_
// include定義
#include "apldevice.h"
#include "apltask.h"
#include "lcd/lcd.h"
// APLモジュールデータ
typedef struct _tagAPL_DATA{
xTaskHandle htask; // タスクハンドル
LPLCD_DATA hlcd; // LCDハンドル
} APL_DATA, *LPAPL_DATA;
// APLハンドル初期化
int APL_InitHandle( LPAPL_DATA handle );
// LCDハンドル設定
int APL_SetLCDHandle( LPAPL_DATA hapl, LPLCD_DATA hlcd );
// APLモジュール初期化
int APL_Init( LPAPL_DATA handle );
// APLタスクスタート
int APL_Start( LPAPL_DATA handle, const int8_t* const na...
#endif /* APL_H_ */
次に、内部用ヘッダのaplin.h。~
#ifndef APLIN_H_
#define APLIN_H_
// APLタスク
void apl_task( void *param );
#endif /* APLIN_H_ */
最後に、APLモジュール本体の、apl.cです。~
// include定義
#include "apl.h"
#include "aplin.h"
// APLハンドル初期化
int APL_InitHandle( LPAPL_DATA handle )
{
if( NULL == handle ){
return -1;
}
handle->htask = NULL;
handle->hlcd = NULL;
return 0;
}
// LCDハンドル設定
int APL_SetLCDHandle( LPAPL_DATA hapl, LPLCD_DATA hlcd )
{
if( NULL == hapl || NULL == hlcd ){
return -1;
}
hapl->hlcd = hlcd;
return 0;
}
// APLモジュール初期化
int APL_Init( LPAPL_DATA handle )
{
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
return 0;
}
// APLタスクスタート
int APL_Start( LPAPL_DATA handle, const int8_t* const na...
{
if( NULL == handle ){
return -1;
}
if( NULL != handle->htask ){
return -1;
}
// タスク生成
if( pdTRUE != xTaskCreate( apl_task, name, APL_STACK_SI...
return -1;
}
return 0;
}
void apl_task( void *param ){
LPAPL_DATA handle = ( LPAPL_DATA )param;
unsigned portBASE_TYPE freesize = 0;
// LCD準備待機
while( 1 != LCD_GetReady( handle->hlcd )){
TaskDelay(100);
}
while (1) {
LCD_SendChar( handle->hlcd, 'A' );
LCD_SendNumber( handle->hlcd, 0 );
LCD_SendChar( handle->hlcd, 'B' );
LCD_SendNumber( handle->hlcd, 1234567890 );
LCD_SetPos( handle->hlcd, 0, 1 );
LCD_SendChar( handle->hlcd, 'C' );
LCD_SendNumber( handle->hlcd, 2 );
LCD_SendChar( handle->hlcd, 'D' );
LCD_SendNumber( handle->hlcd, -987654321 );
TaskDelay(5000);
LCD_Clear( handle->hlcd );
LCD_SendString( handle->hlcd, "LCD\xc3\xbd\xc4\xc1\xad...
TaskDelay(5000);
LCD_Clear( handle->hlcd );
freesize = uxTaskGetStackHighWaterMark(NULL);
}
}
** ソースコード解説 [#t6a7ed0f]
共通定義のところはある程度書いたので、メインから。~
*** メイン [#sd61156e]
先頭はお決まりのincludeとCRPです。~
まずは、LED、LCD、APLと、各モジュールのヘッダをincludeし...
main関数の先頭で、それらの領域を初期化します。~
次に、LEDとLCDで使うポートとピンの設定をしています。~
LEDは一つのみですが、LCDは6本使うので、enum型で指定するよ...
次に、各モジュールを使えるように初期化します。~
こちらは領域の初期化ではなく、GPIOの設定等をしています。~
APLモジュールは、実際にはやることがないので、呼ぶだけで何...
そして、APLモジュールでLCDを操作するために、LCDのハンドル...
最後に、各モジュールのタスクやキューを生成して、スケジュ...
同じモジュールのインスタンスを複数作れることを考えて、タ...
ハンドル的な考え方以外は、そんなに大したことしてないです...
----
*** LEDモジュール [#f1865ffc]
次に、LEDモジュールです。~
外部ヘッダのled.hには、まずモジュールデータとして、自分自...
LED_ONOFF_MODEのenumは、ONで初期化、OFFで初期化を選べるよ...
内部用ヘッダのledin.hは、外部には公開しないタスク関数のみ...
LEDモジュール本体の、led.cについては、基本的には[[LEDチカ...
今は周期的な点滅を繰り返しているだけですが、そのうち外部...
----
*** LCDモジュール [#y8d62d65]
次に、今回のメイン、LCDモジュールです。~
外部ヘッダのlcd.hには、まず、ポートピンのenumを定義してい...
モジュールデータとして、自分自身のタスクハンドルとコマン...
そしてもう一つ、LCDは初期化に多少の時間を必要とするため、...
このため、LCDを使用する他タスクは、LCDの初期化が終わって...
この、初期化が終わっているかどうかを保存しておくフラグも...
あとは、各種機能のプロトタイプですね。~
内部用ヘッダのlcdin.hは、LCDの送信モード、キューで受け取...
最後に、LCDモジュール本体の、lcd.cですが、基本的な流れと...
LCD_Startでは、タスクハンドルと共に、このためのキューハン...
lcdin_taskでは、まずlcdin_devinitを呼んでLCDの初期化を行...
他のモジュールは、LCD_GetReadyを呼んでこの準備フラグを参...
本来、複数のタスクから同時に参照・変更するような変数は、...
lcdin_devinitでの初期化は、HD44780のデータシート通りです。~
「Figure 24 4-Bit Interface」のところですね。~
1ms以上の待ちが必要なものは、TaskDelayで待ちを入れていま...
1ms未満のものであれば、lcdin_snd4bitでのenableパルス送信...
コマンドは2つくらいテーブルに持っていますが、他に使うもの...
LCD_SendCharやLCD_SendNumber、コマンド系については、LCDタ...
----
*** APLモジュール [#sc6d1fe0]
最後のAPLモジュールは、タスク起動時にLCDが使用できるまで...
AVRの時みたいに、ソースコードがShift-JISだとそのまま書け...
----
** 実行・デバッグ [#u6ecacd5]
#u2b(-lMBHMhbqmg,w=640,h=360)
ページ名: