サンプルプログラム F4xxxx_AQM1602_I2C1 の説明
I2C 接続の LCD AQM1602 の
表示を行うサンプルプログラムです。
AQM1602 は秋月電子通商で販売しています。
F4xxxx は、
F405RG, F405VG, F446RE のいずれかです。
それぞれの種類に応じて、F4xxxx の部分を読み代えてください。
プログラムの内容は共通です。
サンプルプログラムの動作を確認するために
えがおのでんし製の評価用基板 Base-F4xxxx と
STMicroelectronics社のfreeの開発ツール、
STM32CubeIDE を使用しています。
目次
LCD AQM1602 の表示の様子
えがおのでんし製の評価用基板 Base-F4xxxx の説明
1. Base-F405RG基板 の説明
2. Base-F405VG基板 の説明
3. Base-F446RE基板 の説明
えがおのでんし製の評価用IF基板 IF-F4xxxx-I2C の説明
サンプルプログラム F4xxxx_AQM1602_I2C1 のプロジェクト
1. サンプルプログラム F405RG_AQM1602_I2C1 のプロジェクト
2. サンプルプログラム F405VG_AQM1602_I2C1 のプロジェクト
3. サンプルプログラム F446RE_AQM1602_I2C1 のプロジェクト
既存のプロジェクトを開く
サンプルプログラム F4xxxx_AQM1602_I2C1 の説明
F4xxxx_AQM1602_I2C1 の構成
F4xxxx_AQM1602_I2C1 の動作パラメータの定義
ユーザープログラムの実行開始位置
F4xxxx_AQM1602_I2C1 の main() の説明
1) LED点滅 と AQM1602 の表示処理 の部分
AQM1602 の表示試験 Test_AQM1602 の説明
1) Test_AQM1602 のソース
2) Test_AQM1602 の動作
AQM1602 コマンド書き込み Write_Command_AQM1602 の説明
1) Write_Command_AQM1602 のソース
2) Write_Command_AQM1602 の動作
AQM1602 データ書き込み Write_DataAQM1602 の説明
1) Write_Data_AQM1602 のソース
2) Write_Data_AQM1602 の動作
LCD AQM1602 の表示の様子
AQM1602 を IF-N446RE-I2C 基板に接続して、表示を行っている様子を、
以下に示します。

えがおのでんし製の評価用基板 Base-F4xxxx の説明
このサンプルプログラムは、
えがおのでんし製の評価用基板 Base-F4xxxx を使用して動作を確認しています。
1. Base-F405RG基板 の説明

Base-F405RG基板については、
Base-F405RG基板 の説明 をご覧ください。
2. Base-F405VG基板 の説明

Base-F405VG基板については、
Base-F405VG基板 の説明 をご覧ください。
3. Base-F446RE基板 の説明

Base-F446RE基板については、
Base-F446RE基板 の説明 をご覧ください。
えがおのでんし製の評価用IF基板 IF-F4xxxx-I2C の説明
このサンプルプログラムは、
えがおのでんし製の評価用基板 IF-F4xxxx-I2C を使用して動作を確認しています。

IF-F4xxxx-I2C基板については、
IF_F4xxxx_I2C基板 の説明 をご覧ください。
サンプルプログラム F4xxxx_AQM1602_I2C1 のプロジェクト
STM32CubeIDE 1.17.0 を使用して作成しました。
1. サンプルプログラム F405RG_AQM1602_I2C1 のプロジェクト
ここからサンプルプログラム L_F405RG_AQM1602_I2C1.zip をダウンロードしてください。
プロジェクト L_F405RG_AQM1602_I2C1 は、
フォルダ C:\Project_CubeIDE\Launch_F405RG\L_F405RG_AQM1602_I2C1 のように配置して作成しました。
フォルダ C:\Project_CubeIDE\Launch_F405RG を作成して、
そのフォルダに L_F405RG_AQM1602_I2C1.zip を貼り付けて解凍し、
プロジェクト作成時と同一に C:\Project_CubeIDE\Launch_F405RG\L_F405RG_AQM1602_I2C1 と
配置した場合は、普通にプロジェクトを開くことができます。
2. サンプルプログラム F405VG_AQM1602_I2C1 のプロジェクト
ここからサンプルプログラム L_F405VG_AQM1602_I2C1.zip をダウンロードしてください。
プロジェクト L_F405VG_AQM1602_I2C1 は、
フォルダ C:\Project_CubeIDE\Launch_F405VG\L_F405VG_AQM1602_I2C1 のように配置して作成しました。
フォルダ C:\Project_CubeIDE\Launch_F405VG を作成して、
そのフォルダに L_F405VG_AQM1602_I2C1.zip を貼り付けて解凍し、
プロジェクト作成時と同一に C:\Project_CubeIDE\Launch_F405VG\L_F405VG_AQM1602_I2C1 と
配置した場合は、普通にプロジェクトを開くことができます。
3. サンプルプログラム F446RE_AQM1602_I2C1 のプロジェクト
ここからサンプルプログラム L_F446RE_AQM1602_I2C1.zip をダウンロードしてください。
プロジェクト L_F446RE_AQM1602_I2C1 は、
フォルダ C:\Project_CubeIDE\Launch_F446RE\L_F446RE_AQM1602_I2C1 のように配置して作成しました。
フォルダ C:\Project_CubeIDE\Launch_F446RE を作成して、
そのフォルダに L_F446RE_AQM1602_I2C1.zip を貼り付けて解凍し、
プロジェクト作成時と同一に C:\Project_CubeIDE\Launch_F446RE\L_F446RE_AQM1602_I2C1 と
配置した場合は、普通にプロジェクトを開くことができます。
既存のプロジェクトを開く
サンプルプログラムのプロジェクトを任意のフォルダに配置した場合に、
STM32CubeIDEにより、そのプロジェクトを開く方法については
既存のプロジェクトを開く方法 をご覧ください。
サンプルプログラム F4xxxx_AQM1602_I2C1 の説明
I2C接続のLCD AQM1602 の表示を行うサンプルプログラムです。
プロジェクトを最初に開いた画面は以下のようになります。

以下、サンプルプログラム F4xxxx_AQM1602_I2C1 について説明していきます。
サンプルプログラムの構成
STM32CubeIDEの画面左側、Project Explorerの
F4xxxx_AQM1602_I2C1を展開した画面は以下のようになります。

サンプルプログラム F4xxxx_AQM1602_I2C1 の構成を以下に示します。
F4xxxx_AQM1602_I2C1
|
|- Includes
|
|- AQM1602_I2C1_Ope : AQM1602 の操作
| |- Control_AQM1602 : AQM1602 の制御
| | |- Control_AQM1602.c
| | |- Control_AQM1602.h
| |
| |- F405RG_AQM1602_I2C1_Config : 動作パラメータの定義
| | |- Dev_Conf.h
| |
| |- Test_AQM1602 : AQM1602 の試験
| |- Test_AQM1602.c
| |- Test_AQM1602.h
|
|- Core
| |- Inc
| | |- main.h
| | |- stm32f4xx_hal_conf.h
| | |- stm32f4xx_it.h : 割り込み処理モジュールのヘッダ
| |
| |- Src
| | |- main.c
| | |- stm32f4xx_hal_msp.c
| | |- stm32f4xx_it.c : 割り込み処理モジュールの記述
| | |- syscalls.c
| | |- system.c
| | |- system_stm32f4xx.c
| |
| |- Startup
|
|- Drivers
| |- CMSIS
| |- STM32F4xx_HAL_Driver
|
|- Periph_Lib : 周辺インターフェースのハンドラ
| |- H_Common_STM32F4 : 共通ハンドラ
| | |- H_Common_STM32F4_I2C : I2Cの共通ハンドラ
| | |- H_Common_STM32F4_I2C.c
| | |- H_Common_STM32F4_I2C.h
| |
| |- H_STM32F4_I2C_1 : I2C1のハンドラ
| |- H_STM32F4_I2C_1.c
| |- H_STM32F4_I2C_1.h
|
|- Shared_Lib : 共有ライブラリ
| |- Handle_UI_Lib : ユーザーインターフェースのライブラリ
| | |- Blink_LED_ST : ST LED点滅処理
| | | |-Blink_LED_ST.c
| | | |-Blink_LED_ST.h
| |
| |- Time_Interval : 時間待ち処理
| |- Time_Interval.c
| |- Time_Interval.h
|
|- F4xxxx_AQM1602_I2C1.launch
|- STM32F4xxxxTX_FLASH.ld
|- STM32F4xxxxTX_RAM.ld
F4xxxx_AQM1602_I2C1 の動作パラメータの定義
サンプルプログラム F4xxxx_AQM1602_I2C1 の動作パラメータの定義を
AQM1602_I2C1_Ope/F4xxxx_AQM1602_I2C1_Config/Dev_Conf.h に記述しています。
使用する CPU の定義、ヘッダ名の定義、GPIO のポートとピンの定義、動作パラメータの定義、
などを記述しています。
ユーザープログラムの実行開始位置
プログラムは、int main(void) から実行開始します。
int main(void) は、フォルダ Core/Src/main.c にあります。

STM32CubeIDEでビルドされたプログラムは、自動的にCPUの初期化を
行った後、int main(void) を呼び出します。
ユーザーコード(記述したプログラム)は、
int main(void) の先頭から実行されます。
F4xxxx_AQM1602_I2C1 の main() の説明
サンプルプログラム F4xxxx_AQM1602_I2C1 の main() の記述は、
以下のとおりです。
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
//------------------------------------------------------------
// main関数内では、以下の処理番号の変数、
// STC_uint8_JobNum_LED と
// STC_uint8_JobNum_LCD は
// while(1){
// }
// の永久ループ内で使用しているので、
// static宣言をする必要はない。
// しかし、main関数以外の全ての関数内では
// static宣言をする必要があるので、
// 合わせるために、ここでも static宣言をしている。
//------------------------------------------------------------
static uint8_t STC_uint8_JobNum_LED; // LED点滅処理番号
static uint8_t STC_uint8_JobNum_LCD; // LCD処理番号
//------------------------------------------------------------
// 呼び出す関数を case 0: から実行させるために
// 処理番号に 0 をセットします。
//------------------------------------------------------------
STC_uint8_JobNum_LED = 0; // LED点滅処理番号初期化
STC_uint8_JobNum_LCD = 0; // LCD処理番号初期化
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//------------------------------------------------------
// ST LED点滅
//------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ
// struct sParam_Blink_LED_ST *pstructParam_Blink_LED_ST :
// ST LED点滅用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG
//------------------------------------------------------
Blink_LED_ST(&STC_uint8_JobNum_LED,
&GLB_structParam_Blink_LED_ST);
//----------------------------------------------------------
// LCD AQM1602 の表示試験
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx :
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK
// 1 : NG
//----------------------------------------------------------
Test_AQM1602(&STC_uint8_JobNum_LCD,
&GLB_structParam_Handle_I2C1);
}
/* USER CODE END 3 */
}
1) 初期化の部分
a) CPUとPeripheral初期化
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
により、CPUとPeripheralなどの基本的な初期化を行います。
PeripheralとはCPUの周辺インターフェースなどのことを言います。
HAL_Init はプロジェクト構築時に自動的に組み込まれる、
HAL Drivers(フォルダ Drivers/STM32F4xx_HAL_Drivers) 内に記述されています。
b) CPU動作クロックの設定
/* Configure the system clock */
SystemClock_Config();
CPUの動作クロックとPeripheralの動作クロックを設定します。
SystemClock_Config(); の設定内容は、
int main(void)
{
.
.
.
}
の、すぐ下に記述されています。
2) LED点滅 と AQM1602 の表示処理 の部分
永久ループ部分の記述を以下に示します。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//------------------------------------------------------
// ST LED点滅
//------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ
// struct sParam_Blink_LED_ST *pstructParam_Blink_LED_ST :
// ST LED点滅用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG
//------------------------------------------------------
Blink_LED_ST(&STC_uint8_JobNum_LED,
&GLB_structParam_Blink_LED_ST);
//----------------------------------------------------------
// LCD AQM1602 の表示試験
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx :
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK
// 1 : NG
//----------------------------------------------------------
Test_AQM1602(&STC_uint8_JobNum_LCD,
&GLB_structParam_Handle_I2C1);
}
/* USER CODE END 3 */
Status LED点滅処理 Blk_LED_Stat と
AQM1602 の表示試験 Test_AQM1602 を呼び出しています。
Blink_LED_ST と Test_AQM1602 は並列に実行されます。
AQM1602 の表示試験 Test_AQM1602 の説明
1) Test_AQM1602 のソース
モジュール Test_AQM1602 は
AQM1602_I2C1_Ope/Test_AQM1602/Test_AQM1602.c 内に記述されています。
モジュール Test_AQM1602 のソースを以下に示します。
//----------------------------------------------------------
// LCD AQM1602 の表示試験
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx :
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK
// 1 : NG
//----------------------------------------------------------
int16_t Test_AQM1602(uint8_t *puint8_JobNum,
struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx)
{
//----------------------------------------------------
// 呼び出す関数の引数に使用する処理番号は、
// 必ず static の変数宣言をしてください。
//----------------------------------------------------
static uint8_t STC_uint8_JobNum_Time; // Time_Interval処理番号
//--------------------------------------------------------
// Time_Interval用パラメータの構造体の宣言は、
// 使用する関数内で、必ず static で宣言してください。
//--------------------------------------------------------
// Time_Interval用パラメータの構造体の宣言
//--------------------------------------------------------
static struct sParam_Time_Interval STC_structParam_Time_Interval;
static uint8_t STC_uint8_JobNum_LCD; // LCD処理番号
static uint8_t STC_uint8_Address; // 設定レジスタAddress
static uint8_t STC_uint8_Number_TX; // 送信データ数
static uint8_t STC_uint8_aData_TX[16]; // 送信データを格納する配列
int16_t int16_Return;
switch(*puint8_JobNum)
{
case 0:
//----------------------------------------------------------
// Handle I2C用パラメータの構造体を初期化
//----------------------------------------------------------
// 引数:
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// なし
//----------------------------------------------------------
Initialize_Parameter_I2Cx(pstructParam_Handle_I2Cx);
// 送信Bufferのポインタをセット
pstructParam_Handle_I2Cx->puint8_aI2C_TxBuffer
= GLB_uint8_aI2C1_TxBuffer;
// 受信Bufferのポインタをセット
pstructParam_Handle_I2Cx->puint8_aI2C_RxBuffer
= GLB_uint8_aI2C1_RxBuffer;
//----------------------------------------------------------
// Addressing Mode指定
//----------------------------------------------------------
// AQM1602 の Addressing Mode
// Specifies if 7-bit or 10-bit addressing mode is selected.
// 7bit : I2C_ADDRESSINGMODE_7BIT
// 10bit : I2C_ADDRESSINGMODE_10BIT
pstructParam_Handle_I2Cx->uint32_AddressingMode
= (uint32_t)I2C_ADDRESSINGMODE_7BIT;
//----------------------------------------------------------
//----------------------------------------------------------
// Slave Address指定
//----------------------------------------------------------
// AQM1602 の Slave Address
pstructParam_Handle_I2Cx->uint16_vI2C_SlaveAddress
= (uint16_t)def_SlaveAddress_AQM1602;
//----------------------------------------------------------
//----------------------------------------------------------
// Clock Speed指定
//----------------------------------------------------------
// AQM1602 の Clock Speed
pstructParam_Handle_I2Cx->uint32_vI2C_Clock_Speed
= (uint32_t)def_I2C_CLOCK_SPEED_100k;
//----------------------------------------------------------
//----------------------------------------------------------
// I2C初期化 : AQM1602
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Initialize_I2C_AQM1602(&STC_uint8_JobNum_LCD,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
HAL_I2C_DeInit(&Handle_I2C1);
pstructParam_Handle_I2Cx->int16_vI2C_Initialize_Done = 0;
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_JobNum_LCD = 0; // LCD表示処理番号初期化
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 1:
//----------------------------------------------------------
// AQM1602 の初期設定を行う。
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx :
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Initial_Setting_AQM1602(&STC_uint8_JobNum_LCD,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
HAL_I2C_DeInit(&Handle_I2C1);
pstructParam_Handle_I2Cx->int16_vI2C_Initialize_Done = 0;
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_Address = 0x80; // レジスタアドレスをセット
// LCD表示データをセット
STC_uint8_Number_TX = 16;
memcpy(STC_uint8_aData_TX, "0123456789ABCDEF", 16);
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 2:
//----------------------------------------------------------
// AQM1602 データ書き込み
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Address : データ書き込みアドレス
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Write_Data_AQM1602(&STC_uint8_JobNum_LCD,
STC_uint8_Address,
STC_uint8_Number_TX,
STC_uint8_aData_TX,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
HAL_I2C_DeInit(&Handle_I2C1);
pstructParam_Handle_I2Cx->int16_vI2C_Initialize_Done = 0;
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_JobNum_Time = 0; // Time_Interval処理番号初期化
STC_structParam_Time_Interval.uint32_Interval = (uint32_t)1000;
// 待ち時間セット : 1000mSec
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 3:
//----------------------------------------------------------
// 時間待ち : 単位 mSec
//----------------------------------------------------------
// 戻り値が -1 以外になるまで、繰り返し呼び出してください。
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ
// struct sParam_Time_Interval *pstructParam_Time_Interval :
// Time_Interval用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中 : 時間が経過していない。
// 0 : OK終了 : 時間が経過した。
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Time_Interval(&STC_uint8_JobNum_Time,
&STC_structParam_Time_Interval);
if(int16_Return == -1){
// 処理中 : 時間未経過
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
STC_uint8_Address = 0xC0;
STC_uint8_Number_TX = 16;
memcpy(STC_uint8_aData_TX, "GHIJKLMNOPQRSTUV", 16);
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 4:
//-------------------------------------------------------
// AQM1602 データ書き込み
//-------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Address : データ書き込みアドレス
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//-------------------------------------------------------
int16_Return = Write_Data_AQM1602(&STC_uint8_JobNum_LCD,
STC_uint8_Address,
STC_uint8_Number_TX,
STC_uint8_aData_TX,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
HAL_I2C_DeInit(&Handle_I2C1);
pstructParam_Handle_I2Cx->int16_vI2C_Initialize_Done = 0;
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_JobNum_Time = 0; // Time_Interval処理番号初期化
STC_structParam_Time_Interval.uint32_Interval = (uint32_t)1000;
// 待ち時間セット : 1000mSec
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 5:
//----------------------------------------------------------
// 時間待ち : 単位 mSec
//----------------------------------------------------------
// 戻り値が -1 以外になるまで、繰り返し呼び出してください。
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ
// struct sParam_Time_Interval *pstructParam_Time_Interval :
// Time_Interval用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中 : 時間が経過していない。
// 0 : OK終了 : 時間が経過した。
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Time_Interval(&STC_uint8_JobNum_Time,
&STC_structParam_Time_Interval);
if(int16_Return == -1){
// 処理中 : 時間未経過
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
STC_uint8_Number_TX = 1; // 送信データ数セット
// コマンドセット
STC_uint8_aData_TX[0] = 0x01; // CLEAR DISPLAY
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 6:
//----------------------------------------------------------
// AQM1602 コマンド書き込み
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// uint32_t uint32_Interval : 待ち時間 (mSec)
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Write_Command_AQM1602(&STC_uint8_JobNum_LCD,
STC_uint8_Number_TX,
STC_uint8_aData_TX,
(uint32_t)3,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
HAL_I2C_DeInit(&Handle_I2C1);
pstructParam_Handle_I2Cx->int16_vI2C_Initialize_Done = 0;
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_Address = 0x80;
STC_uint8_Number_TX = 16;
memcpy(STC_uint8_aData_TX, "Nice to meet you", 16);
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 7:
//----------------------------------------------------------
// AQM1602 データ書き込み
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Address : データ書き込みアドレス
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Write_Data_AQM1602(&STC_uint8_JobNum_LCD,
STC_uint8_Address,
STC_uint8_Number_TX,
STC_uint8_aData_TX,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
HAL_I2C_DeInit(&Handle_I2C1);
pstructParam_Handle_I2Cx->int16_vI2C_Initialize_Done = 0;
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_JobNum_Time = 0; // Time_Interval処理番号初期化
STC_structParam_Time_Interval.uint32_Interval = (uint32_t)1000;
// 待ち時間セット : 1000mSec
(*puint8_JobNum)++; // 次の処理番号に移行する。 : case 8:
int16_Return = -1; // 処理継続
break;
case 8:
//----------------------------------------------------------
// 時間待ち : 単位 mSec
//----------------------------------------------------------
// 戻り値が -1 以外になるまで、繰り返し呼び出してください。
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ
// struct sParam_Time_Interval *pstructParam_Time_Interval :
// Time_Interval用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中 : 時間が経過していない。
// 0 : OK終了 : 時間が経過した。
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Time_Interval(&STC_uint8_JobNum_Time,
&STC_structParam_Time_Interval);
if(int16_Return == -1){
// 処理中 : 時間未経過
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
STC_uint8_Address = 0xC0;
STC_uint8_Number_TX = 16;
memcpy(STC_uint8_aData_TX, "Take it easy! ", 16);
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 9:
//----------------------------------------------------------
// AQM1602 データ書き込み
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Address : データ書き込みアドレス
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Write_Data_AQM1602(&STC_uint8_JobNum_LCD,
STC_uint8_Address,
STC_uint8_Number_TX,
STC_uint8_aData_TX,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
HAL_I2C_DeInit(&Handle_I2C1);
pstructParam_Handle_I2Cx->int16_vI2C_Initialize_Done = 0;
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_JobNum_Time = 0; // Time_Interval処理番号初期化
STC_structParam_Time_Interval.uint32_Interval = (uint32_t)1000;
// 待ち時間セット : 1000mSec
(*puint8_JobNum)++; // 次の処理番号に移行する。 : case 10:
int16_Return = -1; // 処理継続
break;
case 10:
//----------------------------------------------------------
// 時間待ち : 単位 mSec
//----------------------------------------------------------
// 戻り値が -1 以外になるまで、繰り返し呼び出してください。
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ
// struct sParam_Time_Interval *pstructParam_Time_Interval :
// Time_Interval用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中 : 時間が経過していない。
// 0 : OK終了 : 時間が経過した。
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Time_Interval(&STC_uint8_JobNum_Time,
&STC_structParam_Time_Interval);
if(int16_Return == -1){
// 処理中 : 時間未経過
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
STC_uint8_Number_TX = 1; // 送信データ数セット
// コマンドセット
STC_uint8_aData_TX[0] = 0x01; // CLEAR DISPLAY
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 11:
//----------------------------------------------------------
// AQM1602 コマンド書き込み
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// uint32_t uint32_Interval : 待ち時間 (mSec)
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Write_Command_AQM1602(&STC_uint8_JobNum_LCD,
STC_uint8_Number_TX,
STC_uint8_aData_TX,
(uint32_t)3,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
HAL_I2C_DeInit(&Handle_I2C1);
pstructParam_Handle_I2Cx->int16_vI2C_Initialize_Done = 0;
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_Address = 0x80;
STC_uint8_Number_TX = 16;
memcpy(STC_uint8_aData_TX, "0123456789ABCDEF", 16);
*puint8_JobNum = 2; // 処理番号 2 に移行する。: case 2:
// case 2: ~ case 11: をループする。
int16_Return = -1; // 処理継続
break;
default:
*puint8_JobNum = 0;
int16_Return = 1;
break; // NG
}
return(int16_Return);
}
2) Test_AQM1602 の動作
a) case 0:
AQM1602表示に使用する I2C1 を初期化します。
b) case 1:
AQM1602 の初期設定を行います。
b) case 2:
表示データ "0123456789ABCDEF" を AQM1602 の 1行目に書き込みます。
表示結果は以下のようになります。

c) case 3:
1000mSec 待ちます。
d) case 4:
表示データ "GHIJKLMNOPQRSTUV" を AQM1602 の 2行目に書き込みます。
表示結果は以下のようになります。

e) case 5:
1000mSec 待ちます。
f) case 6:
AQM1602 の表示をクリアします。
g) case 7:
表示データ "Nice to meet you" を AQM1602 の 1行目に書き込みます。
表示結果は以下のようになります。

h) case 8:
1000mSec 待ちます。
i) case 9:
表示データ "Take it easy! " を AQM1602 の 2行目に書き込みます。
表示結果は以下のようになります。

j) case 10:
1000mSec 待ちます。
k) case 11:
AQM1602 の表示をクリアします。
クリア動作終了後、表示データバッファ STC_uint8_aData_TX に
"0123456789ABCDEF" をセットして、処理番号に 2 をセットします。
Test_AQM1602 の処理は、再び case 2: から実行されます。
こうして、Test_AQM1602 の処理は、case 2: - case 11: をループします。
AQM1602 コマンド書き込み Write_Command_AQM1602 の説明
1) Write_Command_AQM1602 のソース
モジュール Write_Command_AQM1602 は
AQM1602_I2C1_Ope/Control_AQM1602/Control_AQM1602.c 内に記述されています。
モジュール Write_Command_AQM1602 のソースを以下に示します。
//----------------------------------------------------------
// AQM1602 コマンド書き込み
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// uint32_t uint32_Interval : 待ち時間 (mSec)
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_t Write_Command_AQM1602(uint8_t *puint8_JobNum,
uint8_t uint8_Number_TX,
uint8_t *puint8_aData_TX,
uint32_t uint32_Interval,
struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx)
{
//----------------------------------------------------
// 呼び出す関数の引数に使用する処理番号は、
// 必ず static の変数宣言をしてください。
//----------------------------------------------------
static uint8_t STC_uint8_JobNum_Time; // Time_Interval処理番号
//--------------------------------------------------------
// Time_Interval用パラメータの構造体の宣言は、
// 使用する関数内で、必ず static で宣言してください。
//--------------------------------------------------------
// Time_Interval用パラメータの構造体の宣言
//--------------------------------------------------------
static struct sParam_Time_Interval STC_structParam_Time_Interval;
static uint8_t STC_uint8_JobNum_I2C; // I2C処理番号
static uint8_t STC_uint8_Count_TX; // 送信回数カウンタ
int16_t int16_Return;
switch(*puint8_JobNum)
{
case 0:
STC_uint8_JobNum_I2C = 0; // I2C処理番号初期化
STC_uint8_Count_TX = 0; // 送信回数カウンタ初期化
// I2C送信データセット
pstructParam_Handle_I2Cx->puint8_aI2C_TxBuffer[0] = 0x00;
// control bytee
pstructParam_Handle_I2Cx->puint8_aI2C_TxBuffer[1]
= puint8_aData_TX[STC_uint8_Count_TX];
// data byte : Instruction
pstructParam_Handle_I2Cx->uint16_vI2C_TxNumber
= (volatile uint16_t)2;
(*puint8_JobNum)++; // 次の処理番号に移行する。 : case 1:
int16_Return = -1; // 処理継続
break;
case 1:
//----------------------------------------------------------
// I2Cx Master送信 :
// Register指定 1byte + 設定データ 1byteを送信
//----------------------------------------------------------
//引数 :
// uint8_t *puint8_JobNum : 処理番号
// I2C_HandleTypeDef *pHandle_I2Cx : I2C handler declaration
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
//戻り値 :
// -1 : 処理中
// 0 : OK
// 1 : NG
//----------------------------------------------------------
int16_Return = I2Cx_Master_TxByte(&STC_uint8_JobNum_I2C,
&Handle_I2C1,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break;
}
STC_uint8_JobNum_Time = 0; // Time_Interval処理番号初期化
STC_structParam_Time_Interval.uint32_Interval = uint32_Interval;
// 待ち時間セット
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 2:
//----------------------------------------------------------
// 時間待ち : 単位 mSec
//----------------------------------------------------------
// 戻り値が -1 以外になるまで、繰り返し呼び出してください。
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ
// struct sParam_Time_Interval *pstructParam_Time_Interval :
// Time_Interval用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中 : 時間が経過していない。
// 0 : OK終了 : 時間が経過した。
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Time_Interval(&STC_uint8_JobNum_Time,
&STC_structParam_Time_Interval);
if(int16_Return == -1){
// 処理中 : 時間未経過
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
STC_uint8_Count_TX++; // 送信回数カウンタ インクリメント
// 送信回数判定
if(STC_uint8_Count_TX < uint8_Number_TX){
// 指定された送信回数に達していない。
// I2C送信データセット
pstructParam_Handle_I2Cx->puint8_aI2C_TxBuffer[1]
= puint8_aData_TX[STC_uint8_Count_TX];
// data byte : Instructio
*puint8_JobNum = 1; // 処理番号 1 に戻る。: case 1:
// case 1: ~ case 2: をループする。
int16_Return = -1; // 処理継続
break;
}
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break; // 処理終了
default:
*puint8_JobNum = 0; // 処理番号初期化
int16_Return = 1; // NG
break; // NG
}
return(int16_Return);
}
2) Write_Command_AQM1602 の動作
a) case 0:
I2C処理番号初期化 と 送信回数カウンタ初期化 を行い、
送信データバッファ STC_uint8_aData_TX に
control byte と Instruction をセットします。
b) case 1:
AQM1602 に control byte と Instruction を送信します。
c) case 2:
指定された時間を待ちます。
時間待ち終了後、送信回数を判定します。
送信回数に達していない場合
STC_uint8_aI2C_TX[1] に次の Instruction をセットして、
処理番号を 1 にします。
送信回数に達するまで case 1: と case 2: をループします。
送信回数に達した場合
処理番号を 0 にして、処理を終了します。
AQM1602 データ書き込み Write_Data_AQM1602 の説明
1) Write_Data_AQM1602 のソース
モジュール Write_Data_AQM1602 は
AQM1602_I2C1_Ope/Control_AQM1602/Control_AQM1602.c 内に記述されています。
モジュール Write_Data_AQM1602 のソースを以下に示します。
//----------------------------------------------------------
// AQM1602 データ書き込み
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Address : データ書き込みアドレス
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_t Write_Data_AQM1602(uint8_t *puint8_JobNum,
uint8_t uint8_Address,
uint8_t uint8_Number_TX,
uint8_t *puint8_aData_TX,
struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx)
{
static uint8_t STC_uint8_JobNum_I2C; // I2C処理番号
static uint8_t STC_uint8_Count_TX; // 送信回数カウンタ
static uint8_t STC_uint8_aData_TX[4]; // 送信データを格納する配列
int16_t int16_Return;
switch(*puint8_JobNum)
{
case 0:
STC_uint8_JobNum_I2C = 0; // I2C処理番号初期化
STC_uint8_Count_TX = 0; // 送信回数カウンタ初期化
// 送信データセット
STC_uint8_aData_TX[0] = uint8_Address; // 表示アドレス
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 1:
//-------------------------------------
// 表示アドレスセット
//-------------------------------------
//----------------------------------------------------------
// AQM1602 コマンド書き込み
//----------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// uint8_t uint8_Number_TX : 送信データ数
// uint8_t *puint8_aData_TX : 送信データを格納するバッファのポインタ
// uint32_t uint32_Interval : 待ち時間 (mSec)
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK終了
// 1 : NG終了
//----------------------------------------------------------
int16_Return = Write_Command_AQM1602(&STC_uint8_JobNum_I2C,
(uint8_t)1,
STC_uint8_aData_TX,
(uint32_t)2,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break; // 処理終了
}
// 送信データセット
pstructParam_Handle_I2Cx->puint8_aI2C_TxBuffer[0] = 0x40;
// control byte
pstructParam_Handle_I2Cx->puint8_aI2C_TxBuffer[1]
= puint8_aData_TX[STC_uint8_Count_TX];
// data byte ; 表示データ
pstructParam_Handle_I2Cx->uint16_vI2C_TxNumber
= (volatile uint16_t)2;
(*puint8_JobNum)++; // 次の処理番号に移行する。
int16_Return = -1; // 処理継続
break;
case 2:
//------------------------------------
// 表示データ書き込み
//------------------------------------
//----------------------------------------------------------
// I2Cx Master送信
//----------------------------------------------------------
//引数:
// uint8_t *puint8_JobNum : 処理番号
// I2C_HandleTypeDef *pHandle_I2Cx : I2C handler declaration
// struct sParam_Handle_I2Cx *pstructParam_Handle_I2Cx
// Handle I2C用パラメータの構造体のポインタ
//戻り値 :
// -1 : 処理中
// 0 : OK
// 1 : NG
//----------------------------------------------------------
int16_Return = I2Cx_Master_TxByte(&STC_uint8_JobNum_I2C,
&Handle_I2C1,
pstructParam_Handle_I2Cx);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : 現在の処理番号をループ
}
if(int16_Return != 0){
// NG終了
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break; // 処理終了
}
(*puint8_JobNum)++; // 次の処理番号に移行する。 : case 3:
int16_Return = -1; // 処理継続
break;
case 3:
//---------------------------------------------------
// LCD AQM1602 のビジーチェック
//---------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ
// 戻り値:
// -1 : 処理中
// 0 : OK
// 1 : NG
//---------------------------------------------------
int16_Return = Check_Busy_AQM1602(&STC_uint8_JobNum_I2C);
if(int16_Return == -1){
// 処理中
break; // 処理番号維持 : 処理継続 : case 3: をループ
}
if(int16_Return != 0){
// NG終了
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break; // 処理終了
}
STC_uint8_Count_TX++; // 送信回数カウンタ インクリメント
// 送信回数判定
if(STC_uint8_Count_TX < uint8_Number_TX){
// 指定された送信回数に達していない。
// 送信データセット
pstructParam_Handle_I2Cx->puint8_aI2C_TxBuffer[1]
= puint8_aData_TX[STC_uint8_Count_TX];
// data byte ; 表示データ
*puint8_JobNum = 2; // 処理番号 2 に移行する。: case 2:
int16_Return = -1; // 処理継続
break;
}
*puint8_JobNum = 0; // 処理番号初期化
// int16_Return : 結果
break; // 処理終了
default:
*puint8_JobNum = 0;
int16_Return = 1;
break; // NG
}
return(int16_Return);
}
2) Write_Data_AQM1602 の動作
a) case 0:
I2C処理番号初期化 と 送信回数カウンタ初期化 を行い、
送信データバッファ STC_uint8_aData_TX[0] に
指定された表示アドレスをセットします。
b) case 1:
モジュール Write_Command_AQM1602 により
AQM1602 に 表示アドレスをセットします。
Write_Command_AQM1602 の処理終了後、
送信データバッファ STC_uint8_aData_TX に
control byte と 表示データ および データ数 をセットします。
c) case 2:
I2C通信により送信データバッファのデータを送信します。
d) case 3:
モジュール Check_Busy_AQM1602 により、ビジーをチェックします。
AQM1602 はI2Cインターフェースを使用する場合、ビジーフラグ BF を
読み込むことができないため、時間待ちで対応しています。
ビジーチェック終了後、送信回数を判定します。
送信回数に達していない場合
STC_uint8_aI2C_TX[1] に次の 表示データ をセットして、
処理番号を 2 にします。
送信回数に達するまで case 2: と case 3: をループします。
送信回数に達した場合
処理番号を 0 にして、処理を終了します。
A+-2C (ええ加減にC) のページに戻る
メールアドレス: apm2c.sumi@gmail.com
なんでも、気軽に ご相談ください。
担当:おの
えがおのでんし 案内