自作赤外線リモコンコントロールアンプのシステム設定インターフェースを実装した
最低限必要な機能
- ボリューム初期値の登録
システム電源OFFはAVRのスリープモードなのでSRAM内に記憶されているのですが,電源断後の初期ボリュームはEEPROMに保存しておいたものを使います。
このメニューではその値を登録します。 - 電源リモコンコードの登録
受信したコードをEEPROMに保存します。 - 音量リモコンコードの登録
受信したコードをEEPROMに保存します。 - ディスプレイOFFリモコンコードの登録
受信したコードをEEPROMに保存します。
メニューとメニューアイテム
//
//セットアップメニューアイテム
//
typedef struct {
//メニューの見出し
const char * PROGMEM caption;
//フック関数に渡す情報
void *detail;
//onFocusイベントフック関数
void (*onFocus_hook)( display_buffer_t display_buf, uint8_t target_linenum, void* detail );
//keyUpイベントフック関数
bool (*onKeyUp_hook)( display_buffer_t display_buf, uint8_t target_linenum, void* detail );
} setup_menu_item_t;
//
//セットアップメニュー
//
typedef struct _setup_menu_t {
void (*constructor)(void *initializer); //コンストラクタ関数
setup_menu_item_t menu_items[]; //メニューアイテムの配列
} setup_menu_t;
onFocusイベントとkeyUpイベントの発生時にそれぞれのフック関数が呼ばれます。
トップメニュー
カーソルに選択されている時に対応するonFocusフック関数が呼ばれます. スイッチが押された時に対応するonKeyUpフック関数が呼ばれます.
const setup_menu_t top_setup_menu = {
top_setup_menu_constructor, //コンストラクタ,
{
{ WhiteSpaceFilledLine, NULL, nop_onFocus_hook, nop_and_continue_onKeyUp_hook }, //ガード
// 1234567890123456
{ "ABOUT", &workspace_for_about_menu_hook, messages_menu_onFocus_hook, messages_menu_onKeyUp_hook },
{ "license", &workspace_for_license_menu_hook, messages_menu_onFocus_hook, messages_menu_onKeyUp_hook },
{ "PWR fail", NULL, bor_count_menu_onFocus_hook, nop_and_continue_onKeyUp_hook },
{ "system down", NULL, wdt_count_menu_onFocus_hook, nop_and_continue_onKeyUp_hook },
{ "Init vol", NULL, init_vol_menu_onFocus_hook, init_vol_menu_onKeyUp_hook },
{ "check IR", workspace_for_IR_hook, learn_IR_sub_menu_onFocus_hook, check_IR_menu_onKeyUp_hook },
{ "ON/OFF", &Saved_EEPROM_data.ircodes[IRCODE_onoff], learn_IR_menu_onFocus_hook, learn_IR_menu_onKeyUp_hook },
{ "SwSrc", &Saved_EEPROM_data.ircodes[IRCODE_switch_source], learn_IR_menu_onFocus_hook, learn_IR_menu_onKeyUp_hook },
{ "Vol +", &Saved_EEPROM_data.ircodes[IRCODE_volume_up], learn_IR_menu_onFocus_hook, learn_IR_menu_onKeyUp_hook },
{ "Vol -", &Saved_EEPROM_data.ircodes[IRCODE_volume_down], learn_IR_menu_onFocus_hook, learn_IR_menu_onKeyUp_hook },
{ "MUTE", &Saved_EEPROM_data.ircodes[IRCODE_mute], learn_IR_menu_onFocus_hook, learn_IR_menu_onKeyUp_hook },
{ "OmitDisp", &Saved_EEPROM_data.ircodes[IRCODE_omit_display], learn_IR_menu_onFocus_hook, learn_IR_menu_onKeyUp_hook },
{ "Revert", NULL, revert_menu_onFocus_hook, nop_and_break_reset_onKeyUp_hook },
{ "Save&Exit", NULL, save_and_exit_menu_onFocus_hook, save_and_exit_menu_onKeyUp_hook },
// 1234567890123456
{ WhiteSpaceFilledLine, NULL, nop_onFocus_hook, nop_and_continue_onKeyUp_hook }, //ガード
},
};
ABOUTメニューでは
//
//ABOUTメニューのメッセージ
//プログラムメモリへ配置する
//
static const char about_menu_message[] PROGMEM = {
// 1234567890123456
"firmware Ver1.00 for IR remote control headphone amplifier main board"
" "
"Rev:A2.0 or above."
// 1234567890123456
" "
};
//
//ABOUT,licenseメニューonFocusフック関数
//
static void messages_menu_onFocus_hook( display_buffer_t display_buf, uint8_t target_linenum, void* detail )
{
struct workspace_for_messages_menu_hook_t *workspace = (struct workspace_for_messages_menu_hook_t *)detail;
int16_t delta;
if (workspace == NULL) {
return;
}
//1文字目
delta = workspace->counter - DISPLAY_WIDTH;
if (delta < 0) { //最初は表示行幅一杯になるまで表示する delta = 0; } //スクロール表示 strncpy_P( display_buf[target_linenum].line, &workspace->message[delta], DISPLAY_WIDTH );
if (pgm_read_byte (&workspace->message[workspace->counter]) == '�') {
//始めに戻る
workspace->counter = 0;
workspace->remain = MESSAGE_SCROLL_WAIT;
}
///
if (--workspace->remain < 0) { workspace->counter++;
workspace->remain = MESSAGE_SCROLL_WAIT;
}
}
//
//ABOUT,licenseメニューonKeyUpフック関数
//
static bool messages_menu_onKeyUp_hook( display_buffer_t display_buf, uint8_t target_linenum, void* detail )
{
struct workspace_for_messages_menu_hook_t *workspace = (struct workspace_for_messages_menu_hook_t *)detail;
if (workspace != NULL) {
workspace->counter = 0;
workspace->remain = MESSAGE_SCROLL_WAIT;
}
return true; //現在の状態を継続する
}
カーソルに選択されている時に対応するonFocusフック関数が呼ばれます。 ここではスクロールしてメッセージを表示します。
スイッチが押された時に対応するonKeyUpフック関数が呼ばれます。 ここではカウンタをクリアしてメッセージの最初から表示します。
ボリューム選択メニュー
onKeyUpイベントが発生する=スイッチが押された時に選択中のボリュームが選択されます。
static const setup_menu_t volume_setup_menu = {
volume_setup_menu_constructor, //コンストラクタ
{
{ WhiteSpaceFilledLine, NULL, nop_onFocus_hook, nop_and_continue_onKeyUp_hook }, //ガード
// 1234567890123456
{ "0", "x00", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "1", "x01", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "2", "x02", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "3", "x03", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "4", "x04", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "5", "x05", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "6", "x06", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "7", "x07", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "8", "x08", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "9", "x09", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "10", "x0a", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "11", "x0b", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "12", "x0c", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "13", "x0d", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "14", "x0e", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "15", "x0f", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "16", "x10", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "17", "x11", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "18", "x12", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "19", "x13", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "20", "x14", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "21", "x15", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "22", "x16", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "23", "x17", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "24", "x18", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "25", "x19", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "26", "x1a", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "27", "x1b", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "28", "x1c", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "29", "x1d", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "30", "x1e", nop_onFocus_hook, volume_set_onKeyUp_hook },
{ "31", "x1f", nop_onFocus_hook, volume_set_onKeyUp_hook },
// 1234567890123456
{ WhiteSpaceFilledLine, NULL, nop_onFocus_hook, nop_and_continue_onKeyUp_hook }, //ガード
}
};
赤外線信号登録メニュー
static const setup_menu_t learn_IR_sub_menu = {
learn_IR_sub_menu_constructor, //コンストラクタ関数
{
{ WhiteSpaceFilledLine, NULL, nop_onFocus_hook, nop_and_continue_onKeyUp_hook }, //ガード
// 1234567890123456
{ "Cancel", workspace_for_IR_hook, learn_IR_sub_menu_onFocus_hook, nop_and_break_reset_onKeyUp_hook },
{ "OK", workspace_for_IR_hook, learn_IR_sub_menu_onFocus_hook, learn_IR_sub_menu_OK_onKeyUp_hook },
// 1234567890123456
{ WhiteSpaceFilledLine, NULL, nop_onFocus_hook, nop_and_continue_onKeyUp_hook }, //ガード
}
};
再帰構造だから素直な再帰呼び出しで処理。
メニューの中にメニューがある構造なので,トップメニューより再帰的に下のメニューに降りていきます。
//
//init volメニューonKeyUpフック関数
//
static bool init_vol_menu_onKeyUp_hook( display_buffer_t display_buf, uint8_t target_linenum, void* detail )
{
//再帰的に呼びだす
system_setup( display_buf, target_linenum, &volume_setup_menu, detail, get_volume_menu_cursor_pos(Saved_EEPROM_data.init_volume) );
return true; //現在の状態を継続する
}
SRAMに入りきらないので出来るだけプログラムメモリーへ
SRAM 2kBが貴重なので出来るだけ32kBあるプログラムメモリーに押し込みます。
プログラムメモリーへの配置方法
#include <avr/pgmspace.h>
static const char about_menu_message[] PROGMEM = {
avr/pgmspace.h をincludeしてから PROGMEMを配列につけることでプログラムメモリーに配置されます。
EEPROMアクセス
初期ボリュームとリモコンコードをEEPROMに保存/読み出す時の構造体定義
typedef enum {
IRCODE_onoff = 0, //電源ONOFFリモコンコード
IRCODE_switch_source = 1, //入力切替リモコンコード
IRCODE_volume_up = 2, //音量+リモコンコード
IRCODE_volume_down = 3, //音量ーリモコンコード
IRCODE_mute = 4, //ミュートリモコンコード
IRCODE_omit_display = 5, //表示省略リモコンコード
//
IRCODE_total_num = 6, //全リモコンコード数
//
IRCODE_not_found = -1, //見つからないリモコンコード
} IRCODE_t;
//
//EEPROMに保存するデーター
//
typedef struct __attribute__((__packed__)) {
elevol_t init_volume; //電子ボリュームの初期値
union irr_necformat_or_uint32_t ircodes[IRCODE_total_num]; //リモコンコード
} saved_eeprom_data_t;
システム設定ソースコード
AudioAmpApplication.c
setup_menu.h
setup_menu.c
store_EEPROM.h
store_EEPROM.c
2 thoughts on “自作赤外線リモコンコントロールアンプのシステム設定インターフェースを実装した”
I would like this!!!
Much thanks again. Want more.