Featured image of post 自作赤外線リモコンコントロールアンプのシステム設定インターフェースを実装した

自作赤外線リモコンコントロールアンプのシステム設定インターフェースを実装した

最低限必要な機能

  • ボリューム初期値の登録
    システム電源OFFはAVRのスリープモードなのでSRAM内に記憶されているのですが,電源断後の初期ボリュームはEEPROMに保存しておいたものを使います。
    このメニューではその値を登録します。
  • 電源リモコンコードの登録
    受信したコードをEEPROMに保存します。
  • 音量リモコンコードの登録
    受信したコードをEEPROMに保存します。
  • ディスプレイOFFリモコンコードの登録
    受信したコードをEEPROMに保存します。

メニューとメニューアイテム

設定メニューの計画

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
//
//セットアップメニューアイテム
//
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フック関数が呼ばれます.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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メニューでは

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//
//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イベントが発生する=スイッチが押された時に選択中のボリュームが選択されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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 },               //ガード
    }
};

赤外線信号登録メニュー

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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 },                //ガード
    }
};

再帰構造だから素直な再帰呼び出しで処理。 設定メニューの再帰的構造

メニューの中にメニューがある構造なので,トップメニューより再帰的に下のメニューに降りていきます。

1
2
3
4
5
6
7
8
9
//
//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あるプログラムメモリーに押し込みます。

プログラムメモリーへの配置方法

1
2
#include <avr/pgmspace.h>
static const char about_menu_message[] PROGMEM = {

avr/pgmspace.h をincludeしてから PROGMEMを配列につけることでプログラムメモリーに配置されます。

EEPROMアクセス

初期ボリュームとリモコンコードをEEPROMに保存/読み出す時の構造体定義

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
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 “自作赤外線リモコンコントロールアンプのシステム設定インターフェースを実装した”

  • camiseta del sevilla fc より:
  • 2017年4月1日 11:18 AM

    I would like this!!!

  • bayern munich より:
  • 2017年4月17日 2:45 AM

    Much thanks again. Want more.

    comments powered by Disqus

    This website uses cookies to improve your experience.
    このサイトは「Googleアナリティクス」を使用しています。
    Googleアナリティクスはデータの収集のためにCookieを使用しています。


    Built with Hugo
    テーマ StackJimmy によって設計されています。