以前ジャンク袋で手に入れたkeypadをi2cで使えるようにしてみました。
電話機などで使われている12キーのもので3x4のマトリックスになっています。
i2c keypadをネットで調べるとマイコンを使ったものと、i2c gpio変換を使ったものがあります。後者はホスト側でスキャンするようです。
ホスト側の処理を簡単にするためにマイコンを使い、8ピンでは処理できないので、ピンの多いMSP430を使います。
P1はI2CやISPで使うので、P2で処理する事にしてP2.0,P2.1,P2.2が出力でP2.3,P2.4,P2.5,P2.6を入力にします。
ネットの記事を参考に出力には適当なダイオードを入れました。
keypadの端子をP2.1,P2.3,P2.0,P2.6,P2.2,P2.5,P2.4の並びで接続します。
mainのループで繰り返しキースキャンを行い、i2cのリクエストで返すようにします。
以前試したコードをベースにPlatformIOで開発します。
/*
* This file is part of the MSP430 USCI I2C slave example.
*
* Copyright (C) 2012 Stefan Wendler <sw@kaltpost.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* This firmware acts as an I2C slave on address 0x90(W)/0x91(R).
* It receives a command / parameter pair from the I2C master and
* sends out a response on a masters read request.
*
* The firmware knows two commands:
*
* CMD_SETLED: sets the build in LED (P1.0) of the launchpad depending
* on the given parameter to HIGH (0x01) or LOW (0x00).
*
* CMD_GETBTN: copies the state of the build in push-button (P1.3) to
* the response buffer and transmits it to the master on the next read
* request.
*
* As a I2C master, the bus pirate could be used. To set the BP into
* I2C mode use:
*
* m4 3
*
* Bus-Piret I2C commands to
*
* - set LED HIGH (P1.0)
* [0x90 0x00 0x01
*
* - set LED LOW (P1.0)
* [0x90 0x00 0x00
*
* - get BUTTON state (P1.3)
* [0x90 0x01 [0x91 r
*
* For a quick start to setup the I2C slave, the TI USCI I2C slave
* code from slaa383 was used and slightly modified to work on
* the MSP430G2553 and the MSP-GCC. For detail on leagal issues
* regarding the TI_USCI_I2C_slave code see "ti-usci-i2c-slave-legal.txt".
*
* NOTE: 100k extrnal pull-ups are needed on SDA/SDC.
*/
#include <msp430.h>
#include <legacymsp430.h>
#include "TI_USCI_I2C_slave.h"
/* callback for start condition */
void start_cb();
/* callback for bytes received */
void receive_cb(unsigned char receive);
/* callback to transmit bytes */
void transmit_cb(unsigned char volatile *receive);
/* Commands */
#define CMD_SETLED 0x00
#define CMD_GETBTN 0x01
#define CMD_GETKEY 0x02
#define CMD_UNKNOWN 0xFF
/* Parameters */
#define PAR_LEDOFF 0x00
#define PAR_LEDON 0x01
#define PAR_UNKNOWN 0xFF
/* Responses */
#define RES_ERROR 0xFF
/* last command */
unsigned char cmd = CMD_UNKNOWN;
/* last parameter */
unsigned char par = PAR_UNKNOWN;
/* response to send out on read req. */
unsigned char res = RES_ERROR;
unsigned char key = 0;
void process_cmd(unsigned char cmd, unsigned char par)
{
res = RES_ERROR;
switch(cmd) {
case CMD_SETLED:
if(par == PAR_LEDON) {
P1OUT |= BIT0;
} else if(par == PAR_LEDOFF) {
P1OUT &= ~BIT0;
}
break;
case CMD_GETBTN:
if((P1IN & BIT3)) {
res = 0x01;
} else {
res = 0x00;
}
break;
case CMD_GETKEY:
res = key;
break;
}
}
void start_cb()
{
cmd = CMD_UNKNOWN;
par = PAR_UNKNOWN;
}
void receive_cb(unsigned char receive)
{
if(cmd == CMD_UNKNOWN) {
cmd = receive;
if(cmd == CMD_GETBTN || cmd == CMD_GETKEY) {
process_cmd(cmd, PAR_UNKNOWN);
}
} else {
par = receive;
process_cmd(cmd, par);
}
}
void transmit_cb(unsigned char volatile *byte)
{
*byte = res;
}
char keymap_char[12] = {'1', '4', '7', '*',
'2', '5', '8', '0',
'3', '6', '9', '#'};
scan()
{
unsigned int o_pins[3] = {BIT0, BIT1, BIT2};
unsigned int i_pins[4] = {BIT3, BIT4, BIT5, BIT6};
int row, col;
unsigned char tmp = 0;
int i;
for(row = 0; row < 3; ++row)
{
P2OUT = o_pins[row];
for (i = 0; i < 100; ++i)
P2IN;
for(col = 0; col < 4; ++col)
{
if(P2IN & i_pins[col])
tmp = keymap_char[row*4+col];
}
P2OUT = 0;
}
key = tmp;
}
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P1DIR |= BIT0; // Set P1.0 to output direction
P1DIR &= ~BIT3; // Set P1.3 to input direction
P1REN |= BIT3; // Enable internal pullup on P1.3
P1OUT &= ~BIT0;
TI_USCI_I2C_slaveinit(start_cb, transmit_cb, receive_cb, 0x48);
BCSCTL1 = CALBC1_16MHZ;
DCOCTL = CALDCO_16MHZ;
__bis_SR_register(GIE);
P2SEL = 0;
P2REN = (BIT3 | BIT4 | BIT5 | BIT6);
P2DIR = (BIT0 | BIT1 | BIT2);
while(1) scan();
return 0;
}
何故かポートの最初の読み込みが安定しないので、ダミーリードを入れてあります。こうするととりあえず正常に拾えます。keypadの問題かもしれません。
ArduinoにはKeypadのライブラリがありますが、C++ではないので使えません。
mruby-bsdiicで拾ってみます。
#!/usr/local/bin/mruby
MSPADDR = 0x48
t = BsdIic.new(0)
last = 0
loop do
cur = t.read(MSPADDR, 1, 2)
if cur != 0 && cur != last
p cur.chr + ","
end
last = cur
usleep 100_000
end