/**
* 4x4 多點觸控矩陣座標引擎 (Wokwi 模擬器物理特性補償版)
*
* 腳位配置:
* - RX 總線:PA0
* - RX 控制 (MUX1):PB4, PB5, PB6, PB7
* - TX 驅動 (MUX2):PA6, PA7, PA8, PA9
*/
const int SCREEN_MAX_X = 1024;
const int SCREEN_MAX_Y = 768;
const int RX_ADC_PIN = PA0;
const int RX_PINS[] = {PB4, PB5, PB6, PB7};
const int TX_PINS[] = {PA6, PA7, PA8, PA9};
const int MATRIX_TX = 4;
const int MATRIX_RX = 4;
int Touch_Matrix[MATRIX_TX][MATRIX_RX];
void setup() {
Serial.begin(115200);
for (int i = 0; i < 4; i++) {
pinMode(RX_PINS[i], OUTPUT);
pinMode(TX_PINS[i], OUTPUT);
digitalWrite(RX_PINS[i], LOW);
digitalWrite(TX_PINS[i], LOW);
}
pinMode(RX_ADC_PIN, INPUT_ANALOG);
Serial.println("==========================================");
Serial.println(" MRTP 2D座標引擎 (Wokwi 特性補償版) 啟動! ");
Serial.println("==========================================");
}
void setChannel(const int pins[], int channel) {
for (int bit = 0; bit < 4; bit++) {
digitalWrite(pins[bit], (channel >> bit) & 1);
}
}
void loop() {
// 1. 矩陣掃描
for (int tx = 0; tx < MATRIX_TX; tx++) {
setChannel(TX_PINS, tx);
delayMicroseconds(50); // 拉長建立時間
for (int rx = 0; rx < MATRIX_RX; rx++) {
setChannel(RX_PINS, rx);
delayMicroseconds(50);
int raw_val = analogRead(RX_ADC_PIN);
// 【Wokwi 專用物理補償鎖】
// 因為 Wokwi 旋鈕無法真正與 TX 數位訊號進行動態乘積
// 我們利用對應關係,強制在軟體層面將不屬於該 TX 通道的干擾訊號切斷
// 實體 pot5(TX0,RX0), pot6(TX1,RX1), pot7(TX2,RX2), pot8(TX3,RX3)
if (tx == rx) {
Touch_Matrix[tx][rx] = raw_val;
} else {
Touch_Matrix[tx][rx] = 0; // 強制阻斷虛擬短路造成的 Y 軸鎖死
}
}
}
// 2. 座標演算與解算
long total_weight = 0;
long weighted_X = 0;
long weighted_Y = 0;
int threshold = 150; // 門檻值
for (int tx = 0; tx < MATRIX_TX; tx++) {
for (int rx = 0; rx < MATRIX_RX; rx++) {
int val = Touch_Matrix[tx][rx];
if (val > threshold) {
total_weight += val;
weighted_X += (long)val * rx;
weighted_Y += (long)val * tx;
}
}
}
// 3. 輸出真實座標與過渡斜率
if (total_weight > 0) {
float ratio_x = (float)weighted_X / (total_weight * (MATRIX_RX - 1));
float ratio_y = (float)weighted_Y / (total_weight * (MATRIX_TX - 1));
int screen_x = (int)(ratio_x * SCREEN_MAX_X);
int screen_y = (int)(ratio_y * SCREEN_MAX_Y);
screen_x = constrain(screen_x, 0, SCREEN_MAX_X);
screen_y = constrain(screen_y, 0, SCREEN_MAX_Y);
Serial.print("【觸控座標】X: ");
if (screen_x < 100) Serial.print(" ");
if (screen_x < 10) Serial.print(" ");
Serial.print(screen_x);
Serial.print(" px,\tY: ");
if (screen_y < 100) Serial.print(" ");
if (screen_y < 10) Serial.print(" ");
Serial.print(screen_y);
Serial.println(" px");
} else {
Serial.println("[狀態] 等待觸控中...");
}
delay(200);
}