4行以上の表示機能が欲しかったのでこれを選ばせていただきました。
■第一印象
封を開けたら液晶と基板が外れました。
「半田付けしてないやん!٩(๑`^´๑)۶」と思いましたが、
試しにArduino Unoに接続すると動きました!
Arduino向けのサンプルプログラムを見ていると、キー読み出しはタイマ(Timer2)割り込みを使っています。そのままではGalileoには移植できそうにないです。
■ジョイスティック
とりあえず、キーだけは読みだせるようになりました。
ジョイスティックはアナログ・ピン0(A0)に割り当てられています。
AD変換後の値は128で割るとちょうど良いように抵抗が付いているようです。
商とキーの関係は以下です。
-----
0:左
1:中央
2:下
3:右
4:上
5:割り当てなし
6:開放
-----
サンプルソースでは4msごとに10回一致を取っていますが、
100msで2回読みで試したところ特に読み間違えは無いようです。
私の方法はレスポンスが悪いのでもう少し詰める必要があありそうです。
□LCD
グラフィック液晶なのでフォントを自前で作成して、
文字列 → 文字 → 内部文字コード → フォントパターン
と変換して送信することになります。
必要なのは数字とコロン(:)と数文字なのでやってみようと思います。(時間が、、、)
■サンプルソース
Arduino Uno では動きました。
【写真3】がその様子です。
https://s3-ap-northeast-1.amazonaws.com/sain-amzn/20/20-0...
Galileoでも表示ができました。ラスターデータをシリアル通信で送っているので、非常に遅いです。
ライブラリにある C:\Galileo\arduino-1.5.3\libraries\LCD4884\LCD4884.cpp を改造します。GalileoではAVRのヘッダファイルがないので無効にします。
pgm_read_byte() はマクロ定義で最終的にAVRのアセンブリ言語がインラインで定義されたいましたので、シンプルに関数にしました。
--------------------------------------------------
#define GALILEO
#ifndef GALILEO
extern "C"
{
#include <avr/pgmspace.h>
#include <avr/io.h>
}
#endif
#ifdef GALILEO
unsigned char pgm_read_byte(unsigned char *pFont)
{
return(*pFont);
}
#endif
--------------------------------------------------
サンプルプログラムのソースですが、キー読みをAVRの割り込みからGalileoの割り込みの書き方に変更しました。init_MENU()でも呼ばれる lcd.LCD_clear() は時間がかかるので呼ばないようにします。
--------------------------------------------------
/*
Modified by jacky
version 0.3
Any suggestions are welcome.
E-mail: jacky@gmail.com
Editor : Lauren from SainSmart
Date : 06.01.2012
* Update the library and sketch to compatible with IDE V1.0 and earlier
*/
#define GALILEO
#include "LCD4884.h"
#include "DFrobot_bmp.h"
#include "DFrobot_chinese.h"
#ifdef GALILEO
#include <TimerOne.h>
#endif
//keypad debounce parameter
#define DEBOUNCE_MAX 15
#define DEBOUNCE_ON 10
#define DEBOUNCE_OFF 3
#define NUM_KEYS 5
#define NUM_MENU_ITEM 4
// joystick number
#define LEFT_KEY 0
#define CENTER_KEY 1
#define DOWN_KEY 2
#define RIGHT_KEY 3
#define UP_KEY 4
// menu starting points
#define MENU_X 10 // 0-83
#define MENU_Y 1 // 0-5
int adc_key_val[5] ={
50, 200, 400, 600, 800 };
// debounce counters
byte button_count[NUM_KEYS];
// button status - pressed/released
byte button_status[NUM_KEYS];
// button on flags for user program
byte button_flag[NUM_KEYS];
// menu definition
char menu_items[NUM_MENU_ITEM][12]={
"TEMPERATURE",
"CHAR MAP",
"BITMAP",
"ABOUT"
};
void (*menu_funcs[NUM_MENU_ITEM])(void) = {
temperature,
charmap,
bitmap,
about
};
char current_menu_item;
void setup()
{
#ifdef GALILEO
Timer1.initialize(10000);
Timer1.attachInterrupt(update_adc_key, 10000);
// Serial.begin(9600);
#else
// setup interrupt-driven keypad arrays
// reset button arrays
for(byte i=0; i<NUM_KEYS; i++){
button_count[i]=0;
button_status[i]=0;
button_flag[i]=0;
}
// Setup timer2 -- Prescaler/256
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
TCCR2B = (1<<CS22)|(1<<CS21);
ASSR |=(0<<AS2);
// Use normal mode
TCCR2A =0;
//Timer2 Overflow Interrupt Enable
TIMSK2 |= (0<<OCIE2A);
TCNT2=0x6; // counting starts from 6;
TIMSK2 = (1<<TOIE2);
SREG|=1<<SREG_I;
#endif
lcd.LCD_init();
#ifndef GALILEO
//init_MENU でも呼んでいるので遅いGalileoには不要
lcd.LCD_clear();
#endif
//menu initialization
init_MENU();
current_menu_item = 0;
lcd.backlight(ON);//Turn on the backlight
//lcd.backlight(OFF); // Turn off the backlight
}
/* loop */
void loop()
{
byte i;
delay(100);
for(i=0; i<NUM_KEYS; i++){
if(button_flag[i] !=0){
button_flag[i]=0; // reset button flag
switch(i){
case UP_KEY:
// current item to normal display
lcd.LCD_write_string(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_NORMAL );
current_menu_item -=1;
if(current_menu_item <0) current_menu_item = NUM_MENU_ITEM -1;
// next item to highlight display
lcd.LCD_write_string(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_HIGHLIGHT );
break;
case DOWN_KEY:
// current item to normal display
lcd.LCD_write_string(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_NORMAL );
current_menu_item +=1;
if(current_menu_item >(NUM_MENU_ITEM-1)) current_menu_item = 0;
// next item to highlight display
lcd.LCD_write_string(MENU_X, MENU_Y + current_menu_item, menu_items[current_menu_item], MENU_HIGHLIGHT );
break;
case LEFT_KEY:
init_MENU();
current_menu_item = 0;
break;
case CENTER_KEY:
lcd.LCD_clear();
(*menu_funcs[current_menu_item])();
lcd.LCD_clear();
init_MENU();
current_menu_item = 0;
break;
}
}
}
}
/* menu functions */
void init_MENU(void){
byte i;
lcd.LCD_clear();
lcd.LCD_write_string(MENU_X, MENU_Y, menu_items[0], MENU_HIGHLIGHT );
for (i=1; i<NUM_MENU_ITEM; i++){
lcd.LCD_write_string(MENU_X, MENU_Y+i, menu_items[i], MENU_NORMAL);
}
}
// waiting for center key press
void waitfor_OKkey(){
byte i;
byte key = 0xFF;
while (key!= CENTER_KEY){
for(i=0; i<NUM_KEYS; i++){
if(button_flag[i] !=0){
button_flag[i]=0; // reset button flag
if(i== CENTER_KEY) key=CENTER_KEY;
}
}
}
}
void temperature()
{
lcd.LCD_write_string_big(10, 1, "+12.30", MENU_NORMAL);
lcd.LCD_write_string(78, 2, "C", MENU_NORMAL);
lcd.LCD_write_string(38, 5, "OK", MENU_HIGHLIGHT );
waitfor_OKkey();
}
void charmap(){
char i,j;
for(i=0; i<5; i++){
for(j=0; j<14; j++){
lcd.LCD_set_XY(j*6,i);
lcd.LCD_write_char(i*14+j+32, MENU_NORMAL);
}
}
lcd.LCD_write_string(38, 5, "OK", MENU_HIGHLIGHT );
waitfor_OKkey();
}
void bitmap(){
lcd.LCD_draw_bmp_pixel(0,0, DFrobot_bmp, 84,24);
lcd.LCD_write_chinese(6,3, DFrobot_chinese,12,6,0,0);
lcd.LCD_write_string(38, 5, "OK", MENU_HIGHLIGHT );
waitfor_OKkey();
}
void about(){
lcd.LCD_write_string( 0, 1, "LCD4884 Shield", MENU_NORMAL);
lcd.LCD_write_string( 0, 3, "www.sainsmart.com", MENU_NORMAL);
lcd.LCD_write_string(38, 5, "OK", MENU_HIGHLIGHT );
waitfor_OKkey();
}
// The followinging are interrupt-driven keypad reading functions
// which includes DEBOUNCE ON/OFF mechanism, and continuous pressing detection
// Convert ADC value to key number
char get_key(unsigned int input)
{
char k;
for (k = 0; k < NUM_KEYS; k++)
{
if (input < adc_key_val[k])
{
return k;
}
}
if (k >= NUM_KEYS)
k = -1; // No valid key pressed
return k;
}
void update_adc_key(){
int adc_key_in;
char key_in;
byte i;
adc_key_in = analogRead(0);
key_in = get_key(adc_key_in);
for(i=0; i<NUM_KEYS; i++)
{
if(key_in==i) //one key is pressed
{
if(button_count[i]<DEBOUNCE_MAX)
{
button_count[i]++;
if(button_count[i]>DEBOUNCE_ON)
{
if(button_status[i] == 0)
{
button_flag[i] = 1;
button_status[i] = 1; //button debounced to 'pressed' status
}
}
}
}
else // no button pressed
{
if (button_count[i] >0)
{
button_flag[i] = 0;
button_count[i]--;
if(button_count[i]<DEBOUNCE_OFF){
button_status[i]=0; //button debounced to 'released' status
}
}
}
}
}
#ifndef GALILEO
// Timer2 interrupt routine -
// 1/(160000000/256/(256-6)) = 4ms interval
ISR(TIMER2_OVF_vect) {
TCNT2 = 6;
update_adc_key();
}
#endif
--------------------------------------------------
■自作プログラム
--------------------------------------------------
//
//LCD4884シールド用アナログキー読み取り
//
#define THRESH_UNIT 128
#define K_CHATTARING 2
#define K_REPEAT1 4 //キーリピート開始まで
#define K_REPEAT2 3 //キーリピート中
#define K_LEFT 0
#define K_CENT 1
#define K_DOWN 2
#define K_RIGH 3
#define K_UP 4
#define K_OPEN 6
#define REP_OFF 0
#define REP_ON 1
#define E_OFF 100
#define E_K_LEFT K_LEFT
#define E_K_CENT K_CENT
#define E_K_DOWN K_DOWN
#define E_K_RIGH K_RIGH
#define E_K_UP K_UP
#define E_K_OPEN K_OPEN
#define E_K_REP K_OPEN+1
#define E_K_LEFT_R E_K_LEFT+E_K_REP
#define E_K_CENT_R E_K_CENT+E_K_REP
#define E_K_DOWN_R E_K_DOWN+E_K_REP
#define E_K_RIGH_R E_K_RIGH+E_K_REP
#define E_K_UP___R E_K_UP+E_K_REP
#define E_K_OPEN_R E_K_OPEN+E_K_REP
//char *key[]={"left","center","down","right","up","","open"};
//----------
//アナログピン
//----------
class aInPin
{
private:
int p_Number;
int Value;
public:
void assign(int port);
int Read();
};
void aInPin::assign(int port)
{
p_Number = port;
}
int aInPin::Read()
{
Value = analogRead(p_Number);
return(Value);
}
//----------
//キー
//----------
class aKey : public aInPin
{
private:
int count = 0;
int code = K_OPEN;
int new_code = K_OPEN;
int old_code = K_OPEN;
public:
int Read();
int GetCode();
};
int aKey::Read()
{
old_code = new_code;
new_code = aInPin::Read() / THRESH_UNIT;
new_code = new_code > K_OPEN ? K_OPEN : new_code;
if(new_code == old_code)
{
count--;
if(count <= 0)
{
code = new_code;
}
}else{
count = K_CHATTARING;
}
return(code);
}
int aKey::GetCode()
{
return(code);
}
//----------
//キーイベント
//----------
class KeyEvent : public aKey
{
private:
int count = K_REPEAT1;
int code = E_OFF;
int new_code = E_OFF;
int old_code = E_OFF;
public:
int Read();
int oread(); //確認用
int nread(); //確認用
};
int KeyEvent::Read()
{
old_code = new_code;
new_code = aKey::Read();
if(new_code != old_code)
{
code = new_code + E_K_LEFT;
count = K_REPEAT1;
}else{
count--;
if(count <= 0)
{
code = new_code + E_K_REP;
count = K_REPEAT2;
}else{
code = E_OFF;
}
}
return(code);
}
int KeyEvent::oread()
{
return(old_code);
}
int KeyEvent::nread()
{
return(count);
}
KeyEvent joykey;
int key_code,old_code,new_code,event;
void setup() {
Serial.begin(9600);
joykey.assign(A0);
}
void loop() {
event = joykey.Read();
if(event != E_OFF)
{
key_code = joykey.GetCode();
old_code = joykey.oread();
new_code = joykey.nread();
Serial.print("old_code = " );
Serial.print(old_code);
Serial.print(" new_code = " );
Serial.print(new_code);
Serial.print(" event = ");
Serial.println(event);
}
delay(100);
}
--------------------------------------------------
■改善
サンプルにあるLCD4884.cppをチューニングしました。
LCD_init で行っている2ピン3ピンの出力設定をOUTPUT_FASTにします。LCD_init と LCD_write_byte で呼び出している delayMicroseconds を使わないようにすると劇的に速くなりました。
-
購入金額
0円
-
購入日
2014年02月28日
-
購入場所
ZIGSOWにログインするとコメントやこのアイテムを持っているユーザー全員に質問できます。