I2C / 静電容量式近接 & タッチセンサーAdafruit MPR121 / ベースライン値を見てみる

pp.614ff.

今、チャンネル3にタッチする、リリースする、を繰り返している。 タッチかリリースかは、電極データとベースライン値との比較によって判定される。電極データのほうが小さければタッチであり、電極データのほうが大きければリリースである。ベースライン値は、STOPモードのときであれば手動での書き換えができる。

f:id:ti-nspire:20200827192847p:plain:h250f:id:ti-nspire:20200828081907p:plain:h250

#define F_CPU 8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include "USARTClass.h"

#include "MPR121Class.h"
MPR121Class pad(0x5A); // (I2Cスレーブアドレス)で実体化する。


ISR(INT1_vect){
    usart.printString("touch status (bit[3:0]): ");
    usart.printBinaryNibble(pad.get_touch_status() & 0xF);
    usart.printString("\n");
    
    usart.printString("filtered data: ");
    for(int i=0; i<4; i++){
        usart.printNibble(i);
        usart.printString("ch:");
        usart.printByte(pad.get_filtered_data(i));
        usart.printString(", ");
    }
    usart.printString("\n");

    usart.printString("baseline val : ");
    for(int i=0; i<4; i++){
        usart.printNibble(i);
        usart.printString("ch:");
        usart.printByte(pad.get_baseline_val(i));
        usart.printString(", ");
    }
    usart.printString("\n\n");
}
    
int main(){
    usart.init();

    EIMSK |= (1 << INT1);  // INT1 (外部割り込み要求1)を有効化する。
    EICRA |= (1 << ISC11); // falling edgeで割り込む。
    sei();

    pad.soft_reset();    // ソフトリセットをかける。
    pad.enable_touch(4); // (n)本の電極をタッチセンサーにする。

    while(1);
    return 0;
}
#ifndef MPR121CLASS_H_
#define MPR121CLASS_H_

#include <avr/io.h>
#include "I2CClass.h"

// register addresses and others
const uint8_t ECR            = 0x5E;
const uint8_t SOFT_RESET     = 0x80; const uint8_t SOFT_RESET_VAl = 0x63;
const uint8_t FILTERED_DATA  = 0x04;
const uint8_t BASELINE_VALUE = 0x1E;

class MPR121Class{
private:
    uint8_t _SLA;       // スレーブアドレス。
    uint8_t  get_ECR(); // ECRを読み出す。
    
public:
    void     soft_reset();                  // ソフトリセットをかける。
    uint16_t get_touch_status();            // 12本ぶん(12ビット)のタッチ状態を取得する。
    void     enable_touch(uint8_t ele_n);   // (n)本の電極をタッチセンサーにする。0~12本。
    
    uint16_t get_filtered_data(uint8_t ch); // (チャンネル)ごとのフィルター処理後データ(10ビット)を取得する。
    uint16_t get_baseline_val(uint8_t ch);  // (チャンネル)ごとのベースライン値(10ビット、下2ビットは無効)を取得する。


    // コンストラクタ
    MPR121Class(uint8_t slave_addr);
};

#endif
#include "MPR121Class.h"

void MPR121Class::soft_reset(){
    i2c.write(_SLA, SOFT_RESET, SOFT_RESET_VAl); // (どのスレーブの, どのレジスタに, 1バイトを)書き込む。
}
uint16_t MPR121Class::get_touch_status(){
    uint8_t buff[2];
    i2c.read(_SLA, 0x00, 2, buff); // (どのスレーブの, どのレジスタから, nバイトを, どのバッファに)読み出す。
    return ((uint16_t)(buff[1] & 0x0F) << 8) | buff[0]; // 上位4ビット + 下位8ビットに並べ換えて返す。
}
uint8_t MPR121Class::get_ECR(){
    return i2c.read(_SLA, ECR); // (どのスレーブの, どのレジスタから) 1バイトを読み出す。
}
void MPR121Class::enable_touch(uint8_t ele_n){
    uint8_t sute = (get_ECR() & 0xF0) | ele_n; // ECRを読み出して下4ビットを消してそこだけ書き換える。
    i2c.write(_SLA, ECR, sute); // (どのスレーブの, どのレジスタに, 1バイトを)書き込む。
}
uint16_t MPR121Class::get_filtered_data(uint8_t ch){
    uint8_t buff[2];
    i2c.read(_SLA, FILTERED_DATA + 2 * ch, 2, buff);
    return ((uint16_t)(buff[1] & 0b11) << 8) | buff[0]; // 上位2ビット + 下位8ビットに並べ換えて返す。
}
uint16_t MPR121Class::get_baseline_val(uint8_t ch){
    return (uint16_t)i2c.read(_SLA, BASELINE_VALUE + ch) << 2; // 電極データと比較しやすいよう10ビットにして返す。
}


MPR121Class::MPR121Class(uint8_t slave_addr){
    _SLA = slave_addr;
    i2c.init();
}