がじぇるねでユーザースイッチを使う

2012年11月3日

つい3日ほど前にRSコンポーネンツで注文したGR-SAKURAボードが届いたのでちょっとだけいじってみました。

Web上のビルド環境もあってはじめの動作はとてもお手軽。とはいえ、複雑なことをしようとするとよく分からない部分も多々あったのであまり変なことはできませんでした。。。

rxduinoや春ライブラリではあまり自由度はなさそう?なので、いずれはRxマイコン(Rx63N)を直にいじることになるかなと思ってます。

さて、はじめの動作確認でLEDを点滅させたはいいもののせっかく載っているスイッチが使えずどうしたものかと考えたのと、タイマー割り込みが使えないと実用性ないだろうと思ったので合わせて使ってみました、というのが本日のお題。

春ライブラリではタイマ割り込みが1msに固定されていてアレですが、とりあえず妥協して入力を読み取る関数を呼んでやるように指定。スイッチにはチャタリングがあるのでちゃんと読めるようにクラス化して全部まとめてみました。

Switchクラスの中でやっていることは単純で、読み取った値をupdateすると中でその値を保存し、前3つの値から適当な値(HIGH or LOW)を返すようになっています。updateしたあとにpositive_edgeとかnegative_edgeを呼ぶことで立ち上がりと立ち下がりが分かるようにもしてみました。

がじぇるねユーザー会でスイッチのサンプルがなかなか見つからなかったので役に立てばいいかなと思います。

#include "switch.h"

Switch sw; /* スイッチ入力 */

void timer_interrupt()
{
 /* スイッチの入力を更新 */
 sw.update(digitalRead(PIN_SW));

 if(sw.positive_edge()) { /* 立ち上がり */
  digitalWrite(PIN_LED0, 0);
 }
 else if(sw.negative_edge()) { /* 立ち下がり */
  digitalWrite(PIN_LED0, 1);
 }
}

void setup()
{
 /* ピン設定 */
 pinMode(PIN_LED0,OUTPUT);
 pinMode(PIN_SW,INPUT);

 /* タイマ設定 */
 timer_init();
 timer_regist_userfunc(timer_interrupt);
 delay(100);
}
void loop() {}
/*
* switch.h
*
* Created on: 2012/10/21
* Author: tanitanin
*/

#ifndef SWITCH_H_
#define SWITCH_H_

/*
* スイッチのチャタリングを回避するためのクラス
* update関数に読み取った値を入れていく
* updateの返り値が現在の値
* positive_edge,negative_edgeで立ち上がり、立ち下がりを見る
*/
class Switch {
private:
 unsigned int sw_seq; /* スイッチ入力の読み取り系列 */
 int sw_prev; /* スイッチ入力の前回読み取り時の値 */
 int sw_cur; /* スイッチ入力の現在の値 */

public:
 Switch() : sw_seq(0xFF), sw_prev(1) ,sw_cur(1){} /* デフォルトコンストラクタ */
 ~Switch(){} /* デフォルトデストラクタ */

 enum Mode {
  MODE_3BIT,
  MODE_5BIT,
  MODE_7BIT,
 };

private:
 int get_3bit_majority();/* 直近3回分で多い方(0,1)を返す */
 int get_5bit_majority();/* 直近5回分で多い方(0,1)を返す */
 int get_7bit_majority();/* 直近7回分で多い方(0,1)を返す */

public:
 int update(int val); /* 最新の値を入力系列に反映する */
 int update(int val,Mode mode); /* 最新の値を入力系列に反映する */

 bool positive_edge(); /* 立ち上がりかどうか */
 bool negative_edge(); /* 立ち下がりかどうか */
};

#endif /* SWITCH_H_ */
/*
* switch.cpp
*
* Created on: 2012/10/21
* Author: tanitanin
*/

#include "switch.h"

/* 値を更新する関数:入力系列のLSBに最新の値(0,1)を入れる */
int Switch::update(int val) {
sw_seq = (sw_seq << 1) | val;
sw_cur = get_3bit_majority();
return sw_cur;
}

int Switch::update(int val, Mode mode) {
  sw_seq = (sw_seq << 1) | val; 
  if(mode==MODE_3BIT) sw_cur = get_3bit_majority();
  else if(mode==MODE_5BIT) sw_cur = get_5bit_majority();
  else if(mode==MODE_7BIT) sw_cur = get_7bit_majority();
  return sw_cur; 
} 

/* 立ち上がり・立ち下がりを検出する */ 
bool Switch::positive_edge() {
  return sw_prev == LOW and sw_cur == HIGH; 
}
bool Switch::negative_edge() {
 return sw_prev == HIGH and sw_cur == LOW; 
} 

/* 値を返す関数:入力系列の最新のものから多い方を選択 */
int Switch::get_3bit_majority() {
  unsigned char cur;
  cur = sw_seq & 0x07; 
  cur = (cur & 0x05) + (cur >> 1 & 0x05);
  cur = (cur & 0x03) + (cur >> 2 & 0x03);
  return (cur>1 ? HIGH : LOW);
}

int Switch::get_5bit_majority() {
  unsigned char cur;
  cur = sw_seq & 0x1F;
  cur = (cur & 0x55) + (cur >> 1 & 0x55);
  cur = (cur & 0x33) + (cur >> 2 & 0x33);
  cur = (cur & 0x0F) + (cur >> 4 & 0x0F);
  return (cur>2 ? HIGH : LOW);
}

int Switch::get_7bit_majority() {
  unsigned char cur;
  cur = sw_seq & 0x7F;
  cur = (cur & 0x55) + (cur >> 1 & 0x55);
  cur = (cur & 0x33) + (cur >> 2 & 0x33);
  cur = (cur & 0x0F) + (cur >> 4 & 0x0F);
  return (cur>3? ? HIGH : LOW);
}