英文原文地址https://learn.sparkfun.com/tutorials/mpr121-hookup-guide
MPR121QR2 是一款電容式觸摸傳感器控製器,可以非常輕鬆地將電容式觸摸感應集成到您的項目中。它通過I 2 C 進行通信,並通過測量十二個電極點的電容來工作。當物體靠近電極連接器時,測得的電容會發生變化。這向 MPR121 發出信號,表明某物觸及了“按鈕”。該 IC 還能夠驅動電極引腳 4 到 11 上的 LED 或基本 GPIO 功能,為您設置項目提供了很大的自由。傳感器的工作電壓為 1.6V 至 3.3V。該傳感器不是很耗電,每 16 毫秒采樣時僅消耗約 29 µA。
材料
要完成本教程,您將需要 MPR121 傳感器的三個版本之一:
您還需要一個烙鐵、一些連接線和一個能夠進行 I 2 C 通信的微控製器。對於我們的示例,我們將使用 Arduino Uno。您還需要某種材料來充當電容感應表麵(也稱為電極,不要與字符Electrode混淆。通常,鋁箔效果很好。但是,您也可以使用硬幣、導電塗料,或銅帶。
推薦閱讀
MPR121 非常容易上手,尤其是示例代碼。但是,如果您以前沒有使用過 Arduino 或不熟悉 I 2 C 通信,您應該查看下麵的教程。
電容式觸摸傳感器分線板
該SparkFun電容式觸摸傳感器接口板是最通用的三個MPR121產品的選擇。您可以將它連接到您想要的任何類型的電極上,而且由於它是一個簡單的分線板,沒有它喜歡的特定微控製器占用空間。
SparkFun 電容式觸摸傳感器突破 - MPR121
SEN-09695
退休
分線板有 4 個引腳,至少需要連接到您的微控製器才能進行通信:電源線和 I 2 C 線。但是,對於我們的示例,我們還將連接 IRQ 引腳以更輕鬆地檢測其中一個電極的變化。
連接
MPR121 Breakout → Arduino Uno
3.3V → 3.3V
SCL → A5
SDA → A4
GND→GND
IRQ → D2
您還需要將電極/LED 引腳連接到您之前選擇的電極材料。您需要確保材料和電路板之間有良好、牢固的連接,因此請確保徹底焊接連接。
查看下麵的弗裏茨圖,了解您的連接應該是什麼樣子。黃色方塊代表您決定用於電極的任何材料。
與分線板溝通
要與您的分線板通信,您需要在此處以 zip 文件形式提供 Arduino 草圖。或者,您還可以在GitHub上找到用於使用分線板的最新固件。讓我們看一看,看看代碼到底在做什麼。
複製代碼 #include "mpr121.h" #include <Wire.h> int irqpin = 2; // Digital 2 boolean touchStates[12]; //to keep track of the previous touch states
在代碼的第一部分中,初始化了 MPR121 庫和 Wire 庫。Wire 庫使 I 2 C 通信易於在 Arduino 上使用。該草圖還將數字引腳 2 定義為 IRQ 引腳連接,並創建布爾變量 touchStates 的 12 個實例。
對於代碼的第二部分,我們將 定義irqpin
為 INPUT,告訴 Arduino 監視通過該引腳傳入的數字信號。串行通信也以 9600 bps 以及 Wire 和 mpr121 庫開始。
複製代碼 void setup(){ pinMode(irqpin, INPUT); digitalWrite(irqpin, HIGH); //enable pullup resistor Serial.begin(9600); Wire.begin(); mpr121_setup(); }
代碼的主循環非常簡單,因為它隻調用了一個函數。
複製代碼 void loop(){ readTouchInputs(); }
該功能實際上在代碼的下一部分中描述。Arduino 在第一部分向傳感器請求電極狀態,並為傳感器定義了最低有效位和最高有效位。
複製代碼void readTouchInputs(){ if(!checkInterrupt()){ //read the touch state from the MPR121 Wire.requestFrom(0x5A,2); byte LSB = Wire.read(); byte MSB = Wire.read(); uint16_t touched = ((MSB << 8) | LSB); //16bits that make up the touch states for (int i=0; i < 12; i++){ // Check what electrodes were pressed if(touched & (1<<i)){ if(touchStates[i] == 0){ //pin i was just touched Serial.print("pin "); Serial.print(i); Serial.println(" was just touched"); }else if(touchStates[i] == 1){ //pin i is still being touched } touchStates[i] = 1; }else{ if(touchStates[i] == 1){ Serial.print("pin "); Serial.print(i); Serial.println(" is no longer being touched"); //pin i is no longer being touched } touchStates[i] = 0; } } }}
Arduino 掃描每個電極並在電極被觸發時通過串行打印出一條消息。一旦不再接觸電極,Arduino 就會打印出一條消息。
代碼的最後一個主要部分定義了每個電極的閾值。每個電極必須有一個觸摸閾值和一個釋放閾值,以便 Arduino 比較電極的當前狀態。
複製代碼void mpr121_setup(void){ set_register(0x5A, ELE_CFG, 0x00); // Section A - Controls filtering when data is > baseline. set_register(0x5A, MHD_R, 0x01); set_register(0x5A, NHD_R, 0x01); set_register(0x5A, NCL_R, 0x00); set_register(0x5A, FDL_R, 0x00); // Section B - Controls filtering when data is < baseline. set_register(0x5A, MHD_F, 0x01); set_register(0x5A, NHD_F, 0x01); set_register(0x5A, NCL_F, 0xFF); set_register(0x5A, FDL_F, 0x02); // Section C - Sets touch and release thresholds for each electrode set_register(0x5A, ELE0_T, TOU_THRESH); set_register(0x5A, ELE0_R, REL_THRESH); set_register(0x5A, ELE1_T, TOU_THRESH); set_register(0x5A, ELE1_R, REL_THRESH); set_register(0x5A, ELE2_T, TOU_THRESH); set_register(0x5A, ELE2_R, REL_THRESH); set_register(0x5A, ELE3_T, TOU_THRESH); set_register(0x5A, ELE3_R, REL_THRESH); set_register(0x5A, ELE4_T, TOU_THRESH); set_register(0x5A, ELE4_R, REL_THRESH); set_register(0x5A, ELE5_T, TOU_THRESH); set_register(0x5A, ELE5_R, REL_THRESH); set_register(0x5A, ELE6_T, TOU_THRESH); set_register(0x5A, ELE6_R, REL_THRESH); set_register(0x5A, ELE7_T, TOU_THRESH); set_register(0x5A, ELE7_R, REL_THRESH); set_register(0x5A, ELE8_T, TOU_THRESH); set_register(0x5A, ELE8_R, REL_THRESH); set_register(0x5A, ELE9_T, TOU_THRESH); set_register(0x5A, ELE9_R, REL_THRESH); set_register(0x5A, ELE10_T, TOU_THRESH); set_register(0x5A, ELE10_R, REL_THRESH); set_register(0x5A, ELE11_T, TOU_THRESH); set_register(0x5A, ELE11_R, REL_THRESH); // Section D // Set the Filter Configuration // Set ESI2 set_register(0x5A, FIL_CFG, 0x04); // Section E // Electrode Configuration // Set ELE_CFG to 0x00 to return to standby mode set_register(0x5A, ELE_CFG, 0x0C); // Enables all 12 Electrodes // Section F // Enable Auto Config and auto Reconfig /*set_register(0x5A, ATO_CFG0, 0x0B); set_register(0x5A, ATO_CFGU, 0xC9); // USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V set_register(0x5A, ATO_CFGL, 0x82); // LSL = 0.65*USL = 0x82 @3.3V set_register(0x5A, ATO_CFGT, 0xB5);*/ // Target = 0.9*USL = 0xB5 @3.3V set_register(0x5A, ELE_CFG, 0x0C);}
它看起來像很多代碼,但它隻是重複為每個電極引腳設置閾值的過程。
示例草圖中的最後兩個函數隻是檢查 的狀態irqpin
以確定 IC 是否發出電極已被觸摸的信號。最後一個函數set_register
隻是通過 Wire 庫中的標準步驟運行 Arduino,將寄存器寫入 IC。
複製代碼boolean checkInterrupt(void){ return digitalRead(irqpin);}void set_register(int address, unsigned char r, unsigned char v){ Wire.beginTransmission(address); Wire.write(r); Wire.write(v); Wire.endTransmission();}
現在您對代碼有了基本的了解,讓我們開始閱讀數據。從您之前下載的文件中打開草圖,並將其上傳到您的 Arduino。上傳後,在 Arduino IDE 中打開串行監視器。如果您按下任何電極或釋放任何電極,您應該開始看到 Arduino 打印出句子。
其他代碼參考:
#include "mpr121.h"
#include <Wire.h>
#define SENSORS 13
#define TOU_THRESH 0x1F
#define REL_THRESH 0x1A
#define PROX_THRESH 0x3f
#define PREL_THRESH 0x3c
// variables: capacitive sensing
bool touchStates[SENSORS]; // holds the current touch/prox state of all sensors
bool activeSensors[SENSORS] = {1,1,1,1,1,1,1,1,1,1,1,1,1}; // holds which sensors are active (0=inactive, 1=active)
bool newData = false; // flag that is set to true when new data is available from capacitive sensor
int irqpin = 2; // pin that connects to notifies when data is available from capacitive sensor
void setup(){
// attach interrupt to pin - interrupt 1 is on pin 2 of the arduino (confusing I know)
attachInterrupt(0, dataAvailable, FALLING);
// set-up the Serial and I2C/Wire connections
Serial.begin(9600);
Wire.begin();
// set the registers on the capacitive sensing IC
setupCapacitiveRegisters();
}
void loop(){
readCapacitiveSensor();
}
/**
* dataAvailable Callback method that runs whenever new data becomes available on from the capacitive sensor.
* This method was attached to the interrupt on pin 2, and is called whenever that pins goes low.
*/
void dataAvailable() {
newData = true;
}
/**
* readCapacitiveSensor Reads the capacitive sensor values from the MP121 IC. It makes a request to
* the sensor chip via the I2C/Wire connection, and then parses the sensor values which are stored on
* the first 13 bits of the 16-bit response msg.
*/
void readCapacitiveSensor(){
if(newData){
Serial.println("yes");
//read the touch state from the MPR121
Wire.requestFrom(0x5A,2);
byte tLSB = Wire.read();
byte tMSB = Wire.read();
uint16_t touched = ((tMSB << 8) | tLSB); //16bits that make up the touch states
for (int i = 0; i < SENSORS; i++){ // Check what electrodes were pressed
if (activeSensors[i] == 0) continue;
char sensor_id [] = {'\0','\0','\0'};
switch (i) {
case 12:
sensor_id[0] = 'P';
break;
default:
if (i < 10) {
sensor_id[0] = char( i+48 );
}
else if (i < 12) {
sensor_id[0] = char('1');
sensor_id[1] = char( ( i % 10 ) + 48 );
}
}
if (sensor_id != '\0') {
// read the humidity level
// if current sensor was touched (check appropriate bit on touched var)
if(touched & (1<<i)){
// if current pin was not previously touched send a serial message
if(touchStates[i] == 0){
Serial.print(sensor_id);
Serial.print(":");
Serial.println("1");
}
touchStates[i] = 1;
} else {
// if current pin was just touched send serial message
if(touchStates[i] == 1){
Serial.print(sensor_id);
Serial.print(":");
Serial.println("0");
}
touchStates[i] = 0;
}
}
}
newData = false;
}
}
/**
* setupCapacitiveRegisters Updates all of configurations on the MP121 capacitive sensing IC. This includes
* setting levels for all filters, touch and proximity sensing activation and release thresholds, debounce,
* and auto-configurations options. At the end it activates all of the electrodes.
*/
void setupCapacitiveRegisters(){
set_register(0x5A, ELE_CFG, 0x00);
// Section A - filtering when data is > baseline.
// touch sensing
set_register(0x5A, MHD_R, 0x01);
set_register(0x5A, NHD_R, 0x01);
set_register(0x5A, NCL_R, 0x00);
set_register(0x5A, FDL_R, 0x00);
// prox sensing
set_register(0x5A, PROX_MHDR, 0xFF);
set_register(0x5A, PROX_NHDAR, 0xFF);
set_register(0x5A, PROX_NCLR, 0x00);
set_register(0x5A, PROX_FDLR, 0x00);
// Section B - filtering when data is < baseline.
// touch sensing
set_register(0x5A, MHD_F, 0x01);
set_register(0x5A, NHD_F, 0x01);
set_register(0x5A, NCL_F, 0xFF);
set_register(0x5A, FDL_F, 0x02);
// prox sensing
set_register(0x5A, PROX_MHDF, 0x01);
set_register(0x5A, PROX_NHDAF, 0x01);
set_register(0x5A, PROX_NCLF, 0xFF);
set_register(0x5A, PROX_NDLF, 0xFF);
// Section C - Sets touch and release thresholds for each electrode
set_register(0x5A, ELE0_T, TOU_THRESH);
set_register(0x5A, ELE0_R, REL_THRESH);
set_register(0x5A, ELE1_T, TOU_THRESH);
set_register(0x5A, ELE1_R, REL_THRESH);
set_register(0x5A, ELE2_T, TOU_THRESH);
set_register(0x5A, ELE2_R, REL_THRESH);
set_register(0x5A, ELE3_T, TOU_THRESH);
set_register(0x5A, ELE3_R, REL_THRESH);
set_register(0x5A, ELE4_T, TOU_THRESH);
set_register(0x5A, ELE4_R, REL_THRESH);
set_register(0x5A, ELE5_T, TOU_THRESH);
set_register(0x5A, ELE5_R, REL_THRESH);
set_register(0x5A, ELE6_T, TOU_THRESH);
set_register(0x5A, ELE6_R, REL_THRESH);
set_register(0x5A, ELE7_T, TOU_THRESH);
set_register(0x5A, ELE7_R, REL_THRESH);
set_register(0x5A, ELE8_T, TOU_THRESH);
set_register(0x5A, ELE8_R, REL_THRESH);
set_register(0x5A, ELE9_T, TOU_THRESH);
set_register(0x5A, ELE9_R, REL_THRESH);
set_register(0x5A, ELE10_T, TOU_THRESH);
set_register(0x5A, ELE10_R, REL_THRESH);
set_register(0x5A, ELE11_T, TOU_THRESH);
set_register(0x5A, ELE11_R, REL_THRESH);
// Section D - Set the touch filter Configuration
set_register(0x5A, FIL_CFG, 0x04);
// Section E - Set proximity sensing threshold and release
set_register(0x5A, PRO_T, PROX_THRESH); // sets the proximity sensor threshold
set_register(0x5A, PRO_R, PREL_THRESH); // sets the proximity sensor release
// Section F - Set proximity sensor debounce
set_register(0x59, PROX_DEB, 0x50); // PROX debounce
// Section G - Set Auto Config and Auto Reconfig for prox sensing
set_register(0x5A, ATO_CFGU, 0xC9); // USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V
set_register(0x5A, ATO_CFGL, 0x82); // LSL = 0.65*USL = 0x82 @3.3V
set_register(0x5A, ATO_CFGT, 0xB5); // Target = 0.9*USL = 0xB5 @3.3V
set_register(0x5A, ATO_CFG0, 0x0B);
// Section H - Start listening to all electrodes and the proximity sensor
set_register(0x5A, ELE_CFG, 0x3C);
}
/**
* set_register Sets a register on a device connected via I2C. It accepts the device's address,
* register location, and the register value.
* @param address The address of the I2C device
* @param r The register's address on the I2C device
* @param v The new value for the register
*/
void set_register(int address, unsigned char r, unsigned char v){
Wire.beginTransmission(address);
Wire.write(r);
Wire.write(v);
Wire.endTransmission();
}