Skip to content

Instantly share code, notes, and snippets.

@kyontan
Last active October 31, 2015 02:40
Show Gist options
  • Save kyontan/3109e93583121cef62f4 to your computer and use it in GitHub Desktop.
Save kyontan/3109e93583121cef62f4 to your computer and use it in GitHub Desktop.
Arduino で ADXL345 (加速度センサー) と OSL641501 (8x8 ドットマトリックスLED) を使った教材用のラッパーライブラリ
#include <Wire.h> // I2C用
#include <ADXL345.h> // 加速度センサ用
#include <TimerOne.h> //timer1 //timer0はdelay、timer2はtoneで使われてる(´・ω・`)
// #include "dtmtdatas.h"
#include "Helper.h"
// val の値を min と max の値に収まるようにする
// val < min :=> min
// min <= val <= max :=> val
// max < val :=> max
int clamp(int val, int min, int max) {
if (val < min) { return min; }
if (max < val) { return max; }
return val;
}
/****************
* 基板の向きと,ドトマトの向きと,センサの向きがバラバラなので
* うまく整合させていきたい
*/
// ドットマトリクス
//完成版基板用
#define COL1A 14
#define COL2A 2
#define COL3A 3
#define COL4A 9
#define COL5A 5
#define COL6A 10
#define COL7A 16
#define COL8A 17
#define ROW1K 8
#define ROW2K 15
#define ROW3K 7
#define ROW4K 11
#define ROW5K 1
#define ROW6K 6
#define ROW7K 0
#define ROW8K 4
#define BUZZER 12
// ドットマトリクスの配線
const int rowpin[8] = { ROW1K, ROW2K, ROW3K, ROW4K, ROW5K, ROW6K, ROW7K, ROW8K };
const int colpin[8] = { COL1A, COL2A, COL3A, COL4A, COL5A, COL6A, COL7A, COL8A };
// I2C
#define ADXL345_ID 0x1D
#define APDS9960_ID 0x39
// 加速度センサ
ADXL345 adxl;
void initialize() {
// printf("init\n");
// 加速度センサ初期化
sendi2c(ADXL345_ID, 0x2C, B00001100);//3200Hz書き出し
sendi2c(ADXL345_ID, 0x31, B00001000);//fullresmode
initializeAccelerometer();
// ピンの出力設定
for(int i=0; i<18; i++) {//digital 0-13,analog 0-3
pinMode(i, OUTPUT);
}
// 出力の初期値すべて消灯
for(int i=0; i<8; i++) {
digitalWrite(rowpin[i], LOW);
digitalWrite(colpin[i], LOW);
}
// タイマー1
//割り込み周期[usec]//887@16MH動作//8Mhz動作なら単純に考えて倍
Timer1.initialize(6000);
// showdtmt の処理にかかる時間以上(約890us)を設定しよう
// すごいおそい
Timer1.attachInterrupt(interrupt); //割り込みする関数
// debug用
// Serial.begin(9600);
// Serial.println("started");
delay(1000);//初期状態確認用
}
void updateData() {
int count = 20, sumx = 0, sumy = 0, sumz = 0;
int rawx = 0, rawy = 0, rawz = 0;
// 水準器
for(int i=0; i<count; i++){
adxl.readAccel(&rawx, &rawy, &rawz);
sumx += rawx;
sumy += rawy;
sumz += rawz;
}
// sum(x, y, z) は -10240 - 10240 をとる?
// 1G で x, y: 4900, z: 4500 ぐらいの値をとる => (x, y は 610, z は 560 で割って clamp して) -8 - 8 に縮める
// by kyontan
// NOTE: 割る値 は適宜調整してください
int8_t x = clamp(sumx / 610, -8, 8);
int8_t y = clamp(sumy / 610, -8, 8);
int8_t z = clamp(sumz / 560, -8, 8);
Accel &a = Accel::getInstance();
// a.x = x;
// a.y = y;
// a.z = z;
a.updateAccel(&x, &y, &z);
};
// timer1割り込みで走る関数
void interrupt() {
DotMatrix::show();
};
// I2C通信
void sendi2c(byte id, byte reg, byte data) {
Wire.beginTransmission(id); // Adxl345 のアドレス: 0x1D
Wire.write(reg);
Wire.write(data);
Wire.endTransmission();
};
// Accel
Accel &Accel::getInstance() {
static Accel instance;
return instance;
};
int8_t Accel::x() {
Accel &a = Accel::getInstance();
return a._x;
};
int8_t Accel::y() {
Accel &a = Accel::getInstance();
return a._y;
};
int8_t Accel::z() {
Accel &a = Accel::getInstance();
return a._z;
};
void Accel::updateAccel(int8_t *x, int8_t *y, int8_t *z) {
Accel &a = Accel::getInstance();
a._x = *x;
a._y = *y;
a._z = *z;
};
// DotMatrix
DotMatrix &DotMatrix::getInstance() {
static DotMatrix instance;
return instance;
};
void DotMatrix::show() {
DotMatrix &dt = DotMatrix::getInstance();
for(int r=0; r<8; r++) {
digitalWrite(rowpin[r], LOW);
for(int c=0; c<8; c++) {
digitalWrite(colpin[c], DotMatrix::getDot(r, c) ? HIGH : LOW);
}
for(int c=0; c<8; c++) {
digitalWrite(colpin[c], LOW);
}
digitalWrite(rowpin[r], HIGH);
}
};
void DotMatrix::reset() {
DotMatrix &dt = DotMatrix::getInstance();
Timer1.stop();
for(int r=0; r<8; r++) {
dt.data[r] = 0;
}
dt.show();
Timer1.resume();
};
bool DotMatrix::getDot(byte x, byte y) {
DotMatrix &dt = DotMatrix::getInstance();
return dt.data[x] & (1 << y);
};
void DotMatrix::setDot(byte x, byte y, byte dot) { // dot: 0 or 1
DotMatrix &dt = DotMatrix::getInstance();
if (dot == 1) {
dt.data[x] |= 1 << y;
} else { // 0
dt.data[x] &= ~(1 << y);
}
};
void DotMatrix::setRow(byte row, byte data) {
DotMatrix &dt = DotMatrix::getInstance();
dt.data[row] = data;
};
// Dot
void Dot::move(byte x, byte y) {
this->x = x;
this->y = y;
};
void Dot::moveLeft() {
if (1 < this->x) {
this->x--;
}
};
void Dot::moveRight() {
if (this->x < 8) {
this->x++;
}
};
void Dot::moveUp() {
if (this->y < 8) {
this->y++;
}
};
void Dot::moveDown() {
if (1 < this->y) {
this->y--;
}
};
void Dot::show() {
if (this->isFirst) {
this->isFirst = false;
} else {
// 前回の show した時のドットを消す
// もしかしたら他の描画と衝突するかもしれないです
DotMatrix::setDot(this->old_y, this->old_x, 0);
}
DotMatrix::setDot(7 - (this->y - 1), 7 - (this->x - 1), 1);
DotMatrix::show();
this->old_x = 7 - (x - 1);
this->old_y = 7 - (y - 1);
};
// void Dot::debug_show() {
// printf("(%d, %d)\n", this->x, this->y);
// };
// Image
void Image::rotateLeft() {
byte new_row[8][8];
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
new_row[i][j] = this->getDot(j, 7-i);
}
}
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
this->setDot(i, j, new_row[i][j]);
}
}
};
void Image::rotateRight() {
byte new_row[8][8];
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
new_row[i][j] = this->getDot(7-j, i);
}
}
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
this->setDot(i, j, new_row[i][j]);
}
}
};
void Image::mirrorHorizontal() {
byte new_row[8][8];
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
new_row[i][j] = this->getDot(i, 7-j);
}
}
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
this->setDot(i, j, new_row[i][j]);
}
}
};
void Image::mirrorVertical() {
byte new_row[8][8];
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
new_row[i][j] = this->getDot(7-i, j);
}
}
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
this->setDot(i, j, new_row[i][j]);
}
}
};
void Image::show() {
for (int i=0; i<8; i++) {
for (int j=0; j<8; j++) {
DotMatrix::setRow(i, this->row[i]);
}
}
DotMatrix::show();
};
bool Image::getDot(byte x, byte y) {
return this->row[x] & (1 << y);
};
void Image::setDot(byte x, byte y, byte dot) { // dot: 0 or 1
if (dot == 1) {
this->row[x] |= 1 << y;
} else { // 0
this->row[x] &= ~(1 << y);
}
};
// void Image::debug_show() {
// for (int i=0; i<8; i++) {
// for (int j=0; j<8; j++) {
// printf("%d", this->getDot(i, j));
// }
// printf("\n");
// }
// };
// Buzzer
Buzzer &Buzzer::getInstance() {
static Buzzer instance;
return instance;
};
void Buzzer::tone(unsigned int frequency) {
::tone(BUZZER, frequency);
};
void Buzzer::tone(unsigned int frequency, unsigned long duration) {
::tone(BUZZER, frequency, duration);
};
void Buzzer::stop() {
::noTone(BUZZER);
};
//
void initializeAccelerometer() {
adxl.powerOn();
adxl.setRangeSetting(2); //測定範囲
// 動作した or してないの閾値を設定 (0-255)
adxl.setActivityThreshold(75); //値:*62.5[mg]
adxl.setInactivityThreshold(75); //値:*62.5[mg]
adxl.setTimeInactivity(10); //非動作の判定までに要する時間//値:*5[ms]
// 動作したかを監視する軸の設定 (1 == on; 0 == off)
//各軸の判定の論理和
adxl.setActivityX(1);
adxl.setActivityY(1);
adxl.setActivityZ(1);
// 動作してないを監視する軸の設定 (1 == on; 0 == off)
//各軸の判定の論理積
adxl.setInactivityX(1);
adxl.setInactivityY(1);
adxl.setInactivityZ(1);
// タップされたことを検視する軸の設定 (1 == on; 0 == off)
adxl.setTapDetectionOnX(0);
adxl.setTapDetectionOnY(0);
adxl.setTapDetectionOnZ(0);
// タップ,ダブルタップに関数る閾値の設定 (0-255)
adxl.setTapThreshold(80); //値:*62.5[mg]
adxl.setTapDuration(15); //値:*625[μs]
adxl.setDoubleTapLatency(80); //値:*1.25[ms]
adxl.setDoubleTapWindow(200); //値:*1.25[ms]
// 自由落下に関する閾値の設定 (0-255)
//閾値と時間の論理積
adxl.setFreeFallThreshold(0x09); //閾値//(0x05 - 0x09) 推薦 - 値:*62.5[mg]
adxl.setFreeFallDuration(0x0A); //時間//(0x14 - 0.46) 推薦 - 値:*5[ms]
//setting all interupts to take place on int pin 1
//I had issues with int pin 2, was unable to reset it
adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT, ADXL345_INT1_PIN );
adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT, ADXL345_INT1_PIN );
adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT, ADXL345_INT1_PIN );
adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT, ADXL345_INT1_PIN );
adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT, ADXL345_INT1_PIN );
//register interupt actions - 1 == on; 0 == off
adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT, 1);
adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT, 1);
adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);
}
#pragma once
#include <stdbool.h>
// #include <stdint.h>
// typedef int8_t byte;
void initialize();
void initializeAccelerometer();
void updateData();
void interrupt();
void sendi2c(byte id, byte reg, byte data);
class Accel {
public:
static int8_t x();
static int8_t y();
static int8_t z();
static void updateAccel(int8_t *x, int8_t *y, int8_t *z);
static Accel &getInstance();
private:
int8_t _x, _y, _z;
Accel() {};
Accel(const Accel &other) {};
};
class DotMatrix {
public:
byte data[8];
static DotMatrix &getInstance();
static void show(); // 表示に反映させる
static void reset(); // 全消し
static bool getDot(byte x, byte y);
static void setDot(byte x, byte y, byte dot); // dot: 0 or 1
static void setRow(byte row, byte data);
private:
DotMatrix() {};
DotMatrix(const DotMatrix &other) {};
};
class Dot {
public:
byte x, y;
Dot() { this->isFirst = true; };
Dot(byte x, byte y) {
this->x = x;
this->y = y;
this->isFirst = true;
};
void move(byte x, byte y);
void moveLeft();
void moveRight();
void moveUp();
void moveDown();
void show();
// void debug_show();
Dot(const Dot &other) {};
private:
bool isFirst;
byte old_x, old_y;
};
class Image {
public:
byte row[8];
Image() {};
Image(byte r1, byte r2, byte r3, byte r4,
byte r5, byte r6, byte r7, byte r8) {
this->row[0] = r1;
this->row[1] = r2;
this->row[2] = r3;
this->row[3] = r4;
this->row[4] = r5;
this->row[5] = r6;
this->row[6] = r7;
this->row[7] = r8;
};
Image(const Image &other) {};
void rotateLeft();
void rotateRight();
void mirrorHorizontal();
void mirrorVertical();
void show();
// void debug_show();
private:
bool getDot(byte x, byte y);
void setDot(byte x, byte y, byte dot); // dot: 0 or 1
};
class Buzzer {
public:
static Buzzer &getInstance();
static void tone(unsigned int frequency);
static void tone(unsigned int frequency, unsigned long duration);
static void stop();
private:
Buzzer() {};
Buzzer(const Buzzer &other) {};
};
#include <Wire.h>
#include <ADXL345.h> // 加速度センサ用
#include <TimerOne.h> //timer1 //timer0はdelay、timer2はtoneで使われてる(´・ω・`)
#include <Helper.h>
Image i0;
Dot d0, d1, d2;
// Accel a;
void setup() {
initialize();
d0 = Dot(4, 4);
i0 = Image(0b00010000,
0b00001000,
0b00111100,
0b01011010,
0b11111111,
0b11010011,
0b01100110,
0b00111100);
}
void loop() {
updateData();
// i0.mirrorHorizontal();
delay(1000);
if (0 < Accel::x()) {
d0.moveRight();
} else if (Accel::x() < 0) {
d0.moveLeft();
}
if (0 < Accel::y()) {
d0.moveUp();
} else if (Accel::y() < 0) {
d0.moveDown();
}
d0.show();
// i0.show();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment