├── 43iNCHMai2Touch202211111446Fixed └── Mai2Touch202211111446Fixed.ino ├── Arduino-Aime-Reader ├── Arduino-Aime-Reader.ino ├── README.md ├── arduino_nano适用,需要强制禁止ch340重启mcu.txt ├── cmd.h ├── doc │ ├── Example.txt │ ├── aime示例.mct │ └── nfc.txt └── tools │ ├── DTR-RTS.c │ ├── DTR-RTS.exe │ ├── ReaderTest │ └── ReaderTest.ino │ ├── chunihook.dll │ └── sg-cmd.c ├── Mai2TouchOK ├── Mai2TouchOK.ino └── 高敏度低延迟可能串音版本.txt ├── Pictures ├── anjiandeng001.png ├── caiqie001.png ├── caiqie002.png ├── caiqie003.png ├── chuping001.png ├── dukaqifan001.png ├── dukaqizheng001.png ├── dydzz001.png ├── huaichu001.png ├── jiexian001.png ├── lldx_001.jpg ├── lldx_002.jpg ├── tongku001.png ├── xianshi001.png ├── yinxian001.png ├── zhantieduiying001.png ├── zonglan001.png └── zouxian001.png ├── README.md ├── newmap-llvermtn202212271340 ├── newmap-llvermtn202212271340.ino ├── 接线设计来自学习制作者春暖花开 └── 此版本可以单独调整每一个区块的连线和阈值!newmap-llvermtn202212271340.txt ├── onlytest_single2.zip └── tn ├── 2.md ├── che1.md ├── che2.md ├── orig1.md ├── pics2 ├── 1688990326190.jpg ├── 20230710200504.jpg ├── 3dpicplacetip.png ├── 64487299ec4fd8f8f76f5ab4a3d3574613060190.png ├── IMG_20230619_224416.jpg ├── IMG_20230710_201123.jpg ├── IMG_20230710_201250.jpg ├── IMG_20230711_100851.jpg ├── _-132907346__e724d59b98bfc1cbadeffaf42d3683f8_-599726569_IMG_20230629_114720_0_wifi_0.jpg ├── _9c71d0aeb05dcb9d64f227d082b27e66_-1674909351_IMG_20230629_113243.jpg ├── arduinoidea.png ├── arduinoided.png ├── arduinolibrary1.png ├── arduinolibrary2.png ├── caiqie003.png ├── cheapito.png ├── itolineA.png ├── lineconnectall.png ├── mgxywzt_lineway.png ├── mprAddsel.jpg ├── qbx.png ├── samd211.png ├── samd212.png ├── samd213.png ├── touchall.jpg └── zizhishike1.jpg └── pr.md /43iNCHMai2Touch202211111446Fixed/Mai2Touch202211111446Fixed.ino: -------------------------------------------------------------------------------- 1 | //Fixed 202211111446(1550) 2 | 3 | 4 | 5 | //#define SerialDevice SerialUSB //32u4,samd21 6 | #define SerialDevice Serial //esp8266 7 | 8 | // bitWrite 不支持 uint64_t,以下定义来自 https://forum.arduino.cc/t/bitset-only-sets-bits-from-0-to-31-previously-to-15/193385/5 9 | #define bitSet64(value, bit) ((value) |= (bit<32?1UL:1ULL) <<(bit)) 10 | #define bitClear64(value, bit) ((value) &= ~(bit<32?1UL:1ULL) <<(bit)) 11 | #define bitWrite64(value, bit, bitvalue) (bitvalue ? bitSet64(value, bit) : bitClear64(value, bit)) 12 | #define Threshold 40 //触摸触发阈值 13 | 14 | #include "Adafruit_MPR121.h"//mpr121定义 15 | Adafruit_MPR121 mprA, mprB, mprC; 16 | #define CLAMP(val) (val < 0 ? 0 : (val > 255 ? 255 : val)) 17 | uint8_t packet[6]; 18 | uint8_t len = 0;//当前接收的包长度 19 | #define sA1(x) bitWrite(TPD, 0, x)//设置 sensor 20 | #define sB1(x) bitWrite(TPD, 8, x) 21 | #define sC1(x) bitWrite(TPD, 16, x) 22 | #define sD1(x) bitWrite(TPD, 18, x) 23 | #define sE1(x) bitWrite(TPD, 26, x) 24 | enum { 25 | commandRSET = 0x45,//E 26 | commandHALT = 0x4C,//L 27 | commandSTAT = 0x41,//A 28 | commandRatio = 0x72,//r 29 | commandSens = 0x6B,//k 30 | }; 31 | 32 | bool Conditioning = 1; 33 | void setup() { 34 | SerialDevice.begin(9600); 35 | SerialDevice.setTimeout(0); 36 | uint8_t TOUCH = 1;//按下敏感度 37 | uint8_t RELEASE = 1;//松开敏感度 38 | mprA.begin(0x5A, &Wire); 39 | mprB.begin(0x5C, &Wire); 40 | mprC.begin(0x5B, &Wire); 41 | Wire.setClock(800000); 42 | 43 | } 44 | 45 | void loop() { 46 | Recv(); 47 | Conditioning ? void() : TouchSend();//只有不处于设定模式时才发送触摸数据 48 | } 49 | void MprSetup(Adafruit_MPR121 cap) {//mpr121自定义初始化 25 50 | cap.writeRegister(MPR121_SOFTRESET, 0x63);//MprReset 51 | delay(1); 52 | cap.writeRegister(MPR121_ECR, 0x0);//MprStop 53 | cap.writeRegister(MPR121_MHDR, 1);// 上升最大变化值 54 | cap.writeRegister(MPR121_NHDR, 16);//上升幅度 55 | cap.writeRegister(MPR121_NCLR, 4);//上升修正样本个数 56 | cap.writeRegister(MPR121_FDLR, 0);//修正前等待样本个数 57 | cap.writeRegister(MPR121_MHDF, 4);//下降最大变化值 58 | cap.writeRegister(MPR121_NHDF, 1);//下降幅度 59 | cap.writeRegister(MPR121_NCLF, 16);//下降修正样本个数 60 | cap.writeRegister(MPR121_FDLF, 4);//修正前等待样本个数 61 | cap.writeRegister(MPR121_NHDT, 0); 62 | cap.writeRegister(MPR121_NCLT, 0); 63 | cap.writeRegister(MPR121_FDLT, 0); 64 | cap.setThresholds(Threshold, Threshold); //设置触发阈值和充放电流时间 65 | cap.writeRegister(MPR121_DEBOUNCE, (4 << 4) | 2); //去抖动 释放等待4,按下等待2 66 | cap.writeRegister(MPR121_CONFIG1, 16);//0x10 67 | cap.writeRegister(MPR121_CONFIG2, 1 << 5); 68 | cap.writeRegister(MPR121_AUTOCONFIG0, 0x01); 69 | cap.writeRegister(MPR121_AUTOCONFIG1, (1 << 7)); 70 | cap.writeRegister(MPR121_UPLIMIT, 202);//上限,((Vdd - 0.7)/Vdd) * 256 71 | cap.writeRegister(MPR121_TARGETLIMIT, 182);//目标,UPLIMIT * 0.9 72 | cap.writeRegister(MPR121_LOWLIMIT, 131);//下限,UPLIMIT * 0.65 73 | cap.writeRegister(MPR121_ECR, B10000000 + 12);//MprRun 74 | } 75 | void cmd_RSET() {//Reset 76 | MprSetup(mprA); 77 | MprSetup(mprB); 78 | MprSetup(mprC); 79 | 80 | 81 | 82 | } 83 | void cmd_HALT() {//Start Conditioning Mode 84 | mprA.writeRegister(MPR121_ECR, 0x0);//MprStop 85 | mprB.writeRegister(MPR121_ECR, 0x0); 86 | mprC.writeRegister(MPR121_ECR, 0x0); 87 | Conditioning = true; 88 | } 89 | 90 | void cmd_Ratio() {//Set Touch Panel Ratio 91 | SerialDevice.write((byte)'('); 92 | SerialDevice.write((byte)packet[1]);//L,R 93 | SerialDevice.write((byte)packet[2]);//sensor 94 | SerialDevice.write((byte)'r'); 95 | SerialDevice.write((byte)packet[4]);//Ratio 96 | SerialDevice.write((byte)')'); 97 | } 98 | 99 | void cmd_Sens() {//Set Touch Panel Sensitivity 100 | SerialDevice.write((byte)'('); 101 | SerialDevice.write((byte)packet[1]);//L,R 102 | SerialDevice.write((byte)packet[2]);//sensor 103 | SerialDevice.write((byte)'k'); 104 | SerialDevice.write((byte)packet[4]);//Sensitivity 105 | SerialDevice.write((byte)')'); 106 | } 107 | 108 | void cmd_STAT() { //End Conditioning Mode 109 | Conditioning = false; 110 | mprA.writeRegister(MPR121_ECR, B10000000 + 12);//MprRun 111 | mprB.writeRegister(MPR121_ECR, B10000000 + 12); 112 | mprC.writeRegister(MPR121_ECR, B10000000 + 12); 113 | } 114 | 115 | void Recv() { 116 | while (SerialDevice.available()) { 117 | uint8_t r = SerialDevice.read(); 118 | if (r == '{') { 119 | len = 0; 120 | } 121 | if (r == '}') { 122 | break; 123 | } 124 | packet[len++] = r; 125 | } 126 | if (len == 5) { 127 | switch (packet[3]) { 128 | case commandRSET: 129 | cmd_RSET(); 130 | break; 131 | case commandHALT: 132 | cmd_HALT(); 133 | break; 134 | case commandRatio: 135 | cmd_Ratio(); 136 | break; 137 | case commandSens: 138 | cmd_Sens(); 139 | break; 140 | case commandSTAT: 141 | cmd_STAT(); 142 | break; 143 | } 144 | len = 0; 145 | memset(packet, 0, 6); 146 | } 147 | } 148 | 149 | void TouchSend() { 150 | 151 | uint64_t TouchData = 0; //触摸数据包 152 | 153 | for (int i = 9; i >= 0; i--) { // E8 ~ D7 154 | TouchData = (TouchData | (int)(mprC.baselineData(i) - mprC.filteredData(i) + 20) > Threshold) << 1; 155 | } 156 | for (int i = 11; i >= 0; i--) { // D6 ~ B5 157 | TouchData = (TouchData | (int)(mprB.baselineData(i) - mprB.filteredData(i) + 20) > Threshold) << 1; 158 | } 159 | for (int i = 11; i >= 0; i--) { // B4 ~ A1 160 | TouchData = (TouchData | (int)(mprA.baselineData(i) - mprA.filteredData(i) + 20) > Threshold) << 1; 161 | } 162 | TouchData >>= 1; 163 | 164 | SerialDevice.write((byte)'('); 165 | for (uint8_t r = 0; r < 7; r++) { 166 | SerialDevice.write((byte)TouchData & B11111); 167 | TouchData >>= 5; 168 | } 169 | SerialDevice.write((byte)')'); 170 | } 171 | -------------------------------------------------------------------------------- /Arduino-Aime-Reader/Arduino-Aime-Reader.ino: -------------------------------------------------------------------------------- 1 | #include "cmd.h" 2 | bool high_baudrate = true;//high_baudrate=true 3 | 4 | void setup() { 5 | FastLED.addLeds(leds, NUM_LEDS); 6 | FastLED.setBrightness(255); 7 | FastLED.showColor(0); 8 | nfc.begin(); 9 | while (!nfc.getFirmwareVersion()) { 10 | FastLED.showColor(0xFF0000); 11 | delay(500); 12 | FastLED.showColor(0); 13 | delay(500); 14 | } 15 | nfc.setPassiveActivationRetries(0x10);//设定等待次数 16 | nfc.SAMConfig(); 17 | memset(&req, 0, sizeof(req.bytes)); 18 | memset(&res, 0, sizeof(res.bytes)); 19 | 20 | SerialDevice.begin(high_baudrate ? 115200 : 38400); 21 | FastLED.showColor(high_baudrate ? 0x0000FF : 0x00FF00); 22 | } 23 | 24 | void loop() { 25 | SerialCheck(); 26 | packet_write(); 27 | } 28 | 29 | static uint8_t len, r, checksum; 30 | static bool escape = false; 31 | 32 | static uint8_t packet_read() { 33 | 34 | while (SerialDevice.available()) { 35 | r = SerialDevice.read(); 36 | if (r == 0xE0) { 37 | req.frame_len = 0xFF; 38 | continue; 39 | } 40 | if (req.frame_len == 0xFF) { 41 | req.frame_len = r; 42 | len = 0; 43 | checksum = r; 44 | continue; 45 | } 46 | if (r == 0xD0) { 47 | escape = true; 48 | continue; 49 | } 50 | if (escape) { 51 | r++; 52 | escape = false; 53 | } 54 | req.bytes[++len] = r; 55 | if (len == req.frame_len && checksum == r) { 56 | return req.cmd; 57 | } 58 | checksum += r; 59 | } 60 | return 0; 61 | } 62 | 63 | static void packet_write() { 64 | uint8_t checksum = 0, len = 0; 65 | if (res.cmd == 0) { 66 | return; 67 | } 68 | SerialDevice.write(0xE0); 69 | while (len <= res.frame_len) { 70 | uint8_t w; 71 | if (len == res.frame_len) { 72 | w = checksum; 73 | } else { 74 | w = res.bytes[len]; 75 | checksum += w; 76 | } 77 | if (w == 0xE0 || w == 0xD0) { 78 | SerialDevice.write(0xD0); 79 | SerialDevice.write(--w); 80 | } else { 81 | SerialDevice.write(w); 82 | } 83 | len++; 84 | } 85 | res.cmd = 0; 86 | } 87 | 88 | void SerialCheck() { 89 | switch (packet_read()) { 90 | case SG_NFC_CMD_RESET: 91 | sg_nfc_cmd_reset(); 92 | break; 93 | case SG_NFC_CMD_GET_FW_VERSION: 94 | sg_nfc_cmd_get_fw_version(); 95 | break; 96 | case SG_NFC_CMD_GET_HW_VERSION: 97 | sg_nfc_cmd_get_hw_version(); 98 | break; 99 | case SG_NFC_CMD_POLL: 100 | sg_nfc_cmd_poll(); 101 | break; 102 | case SG_NFC_CMD_MIFARE_READ_BLOCK: 103 | sg_nfc_cmd_mifare_read_block(); 104 | break; 105 | case SG_NFC_CMD_FELICA_ENCAP: 106 | sg_nfc_cmd_felica_encap(); 107 | break; 108 | case SG_NFC_CMD_AIME_AUTHENTICATE: 109 | sg_nfc_cmd_aime_authenticate(); 110 | break; 111 | case SG_NFC_CMD_BANA_AUTHENTICATE: 112 | sg_nfc_cmd_bana_authenticate(); 113 | break; 114 | case SG_NFC_CMD_MIFARE_SELECT_TAG: 115 | sg_nfc_cmd_mifare_select_tag(); 116 | break; 117 | case SG_NFC_CMD_MIFARE_SET_KEY_AIME: 118 | sg_nfc_cmd_mifare_set_key_aime(); 119 | break; 120 | case SG_NFC_CMD_MIFARE_SET_KEY_BANA: 121 | sg_nfc_cmd_mifare_set_key_bana(); 122 | break; 123 | case SG_NFC_CMD_RADIO_ON: 124 | sg_nfc_cmd_radio_on(); 125 | break; 126 | case SG_NFC_CMD_RADIO_OFF: 127 | sg_nfc_cmd_radio_off(); 128 | break; 129 | case SG_RGB_CMD_RESET: 130 | sg_led_cmd_reset(); 131 | break; 132 | case SG_RGB_CMD_GET_INFO: 133 | sg_led_cmd_get_info(); 134 | break; 135 | case SG_RGB_CMD_SET_COLOR: 136 | sg_led_cmd_set_color(); 137 | break; 138 | case 0: 139 | break; 140 | default: 141 | sg_res_init(); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Arduino-Aime-Reader/README.md: -------------------------------------------------------------------------------- 1 | # Arduino-Aime-Reader 2 | 使用 Arduino + PN532 + WS2812B 制作的 Aime 兼容读卡器。 3 | **目前所有主要功能已经实现,如果没有 bug 应该不会再更新。** 4 | English: [lawliuwuu/Arduino-Aime-Reader](https://github.com/lawliuwuu/Arduino-Aime-Reader) 5 | 6 | 支持卡片类型: [FeliCa](https://zh.wikipedia.org/wiki/FeliCa)(Amusement IC、Suica、八达通等)和 [MIFARE](https://zh.wikipedia.org/wiki/MIFARE)(Aime,Banapassport)。 7 | 实现逻辑为官方读卡器串口数据对比 + 脑补,不保证正确实现。 8 | 通信数据格式参考了 [Segatools]() 和官方读卡器抓包数据,可在 [Example.txt](doc/Example.txt) 和 [nfc.txt](doc/nfc.txt) 查看。 9 | 一个使用例:[ESP32-CardReader](https://github.com/Sucareto/ESP32-CardReader) 10 | 11 | ### 使用方法: 12 | 1. 按照 [PN532](https://github.com/elechouse/PN532) 的提示安装库 13 | 2. 按照使用方式,在 Arduino 和 PN532 接好连接线(I2C或SPI),并调整 PN532 上的拨码开关 14 | 3. 接上 WS2812B 灯条(可选) 15 | 4. 上传 [ReaderTest](tools/ReaderTest/ReaderTest.ino) 测试硬件是否工作正常 16 | 5. 若读卡正常,可按照支持列表打开设备管理器设置 COM 端口号 17 | 6. 按照游戏的波特率设置代码的`high_baudrate`选项,`115200`是`true`,`38400`是`false` 18 | 7. 上传程序打开游戏测试 19 | 8. 安装 [MifareClassicTool](https://github.com/ikarus23/MifareClassicTool),修改 [Aime 卡示例](doc/aime示例.mct) 后写入空白 MIFARE UID/CUID 卡 20 | 21 | 某些 Arduino 可能需要在游戏主程序连接前给串口以正确的波特率发送 DTR/RTS,需要先打开一次 Arduino 串口监视器再启动主程序。 22 | 如果是 SDBT,可以在启动前运行一次 [DTR-RTS.exe](tools/DTR-RTS.exe) 以向 COM1 和 COM12 发送DTR/RTS。 23 | 如果需要向其他端口和特定的波特率发送,可以修改 [DTR-RTS.c](tools/DTR-RTS.c) 然后编译。 24 | 25 | 26 | ### 支持列表: 27 | | 游戏代号 | COM端口号 | 支持的卡 | 默认波特率 | 28 | | - | - | - | - | 29 | | SDDT/SDEZ | COM1 | FeliCa,MIFARE | 115200 | 30 | | SDEY | COM2 | MIFARE | 38400 | 31 | | SDHD | COM4 | FeliCa,MIFARE | cvt=38400,sp=115200 | 32 | | SBZV/SDDF | COM10 | FeliCa,MIFARE | 38400 | 33 | | SDBT | COM12 | FeliCa,MIFARE | 38400 | 34 | 35 | - 如果读卡器没有正常工作,可以切换波特率试下 36 | - 有使用 amdaemon 的,可以参考 config_common.json 内 aime > unit > port 确认端口号 37 | - 如果 `"high_baudrate" : true` 则波特率是`115200`,否则就是`38400` 38 | 39 | 40 | ### 已测试开发板: 41 | - SparkFun Pro Micro(ATmega32U4),需要发送 DTR/RTS 42 | - SparkFun SAMD21 Dev Breakout(ATSAMD21G18) 43 | - NodeMCU 1.0(ESP-12E + CP2102 & CH340),SDA=D2,SCL=D1 44 | - NodeMCU-32S(ESP32-S + CH340) 45 | 46 | 47 | ### 已知问题: 48 | - 在 NDA_08 命令的写入 Felica 操作没有实现,因为未确认是否会影响卡片后续使用 49 | - 未确定`res.status`的意义,因此`res.status = 1;`可能是错误的 50 | - 未实现`mifare_select_tag`,未支持多卡选择,只会读到最先识别的卡片 51 | 52 | 53 | ### 引用库: 54 | - 驱动 WS2812B:[FastLED](https://github.com/FastLED/FastLED) 55 | - 驱动 PN532:[PN532](https://github.com/elechouse/PN532) 56 | - 读取 FeliCa 参考:[PN532を使ってArduinoでFeliCa学生証を読む方法](https://qiita.com/gpioblink/items/91597a5275862f7ffb3c) 57 | - 读取 FeliCa 数据的程序:[NFC TagInfo](https://play.google.com/store/apps/details?id=at.mroland.android.apps.nfctaginfo),[NFC TagInfo by NXP](https://play.google.com/store/apps/details?id=com.nxp.taginfolite) 58 | -------------------------------------------------------------------------------- /Arduino-Aime-Reader/arduino_nano适用,需要强制禁止ch340重启mcu.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Arduino-Aime-Reader/arduino_nano适用,需要强制禁止ch340重启mcu.txt -------------------------------------------------------------------------------- /Arduino-Aime-Reader/cmd.h: -------------------------------------------------------------------------------- 1 | #include "FastLED.h" 2 | #define NUM_LEDS 1 3 | CRGB leds[NUM_LEDS]; 4 | 5 | #define SerialDevice Serial 6 | #define LED_PIN 5 7 | 8 | 9 | #if defined(PN532_SPI_SS) 10 | #pragma message "使用 SPI 连接 PN532" 11 | #include 12 | #include 13 | PN532_SPI pn532(SPI, PN532_SPI_SS); 14 | #else 15 | #include 16 | #include 17 | PN532_I2C pn532(Wire); 18 | #endif 19 | 20 | #include "PN532.h" 21 | PN532 nfc(pn532); 22 | 23 | uint8_t AimeKey[6], BanaKey[6]; 24 | 25 | enum { 26 | SG_NFC_CMD_GET_FW_VERSION = 0x30, 27 | SG_NFC_CMD_GET_HW_VERSION = 0x32, 28 | SG_NFC_CMD_RADIO_ON = 0x40, 29 | SG_NFC_CMD_RADIO_OFF = 0x41, 30 | SG_NFC_CMD_POLL = 0x42, 31 | SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, 32 | SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50, 33 | SG_NFC_CMD_BANA_AUTHENTICATE = 0x51, 34 | SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, 35 | SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, 36 | SG_NFC_CMD_AIME_AUTHENTICATE = 0x55, 37 | SG_NFC_CMD_TO_UPDATER_MODE = 0x60, 38 | SG_NFC_CMD_SEND_HEX_DATA = 0x61, 39 | SG_NFC_CMD_RESET = 0x62, 40 | SG_NFC_CMD_FELICA_ENCAP = 0x71, 41 | SG_RGB_CMD_SET_COLOR = 0x81, 42 | SG_RGB_CMD_GET_INFO = 0xF0, 43 | SG_RGB_CMD_RESET = 0xF5, 44 | 45 | //FELICA_ENCAP 46 | FELICA_CMD_POLL = 0x00, 47 | FELICA_CMD_NDA_06 = 0x06, 48 | FELICA_CMD_NDA_08 = 0x08, 49 | FELICA_CMD_GET_SYSTEM_CODE = 0x0C, 50 | FELICA_CMD_NDA_A4 = 0xA4, 51 | }; 52 | 53 | typedef union packet_req { 54 | uint8_t bytes[128]; 55 | struct { 56 | uint8_t frame_len; 57 | uint8_t addr; 58 | uint8_t seq_no; 59 | uint8_t cmd; 60 | uint8_t payload_len; 61 | union { 62 | uint8_t key[6]; //sg_nfc_req_mifare_set_key(bana or aime) 63 | uint8_t color_payload[3];//sg_led_req_set_color 64 | struct { //sg_nfc_cmd_mifare_select_tag,sg_nfc_cmd_mifare_authenticate,sg_nfc_cmd_mifare_read_block 65 | uint8_t uid[4]; 66 | uint8_t block_no; 67 | }; 68 | struct { //sg_nfc_req_felica_encap 69 | uint8_t encap_IDm[8]; 70 | uint8_t encap_len; 71 | uint8_t encap_code; 72 | union { 73 | struct { //FELICA_CMD_POLL,猜测 74 | uint8_t poll_systemCode[2]; 75 | uint8_t poll_requestCode; 76 | uint8_t poll_timeout; 77 | }; 78 | struct { //NDA_06,NDA_08,NDA_A4 79 | uint8_t RW_IDm[8]; 80 | uint8_t numService;//and NDA_A4 unknown byte 81 | uint8_t serviceCodeList[2]; 82 | uint8_t numBlock; 83 | uint8_t blockList[1][2];//长度可变 84 | uint8_t blockData[16];//WriteWithoutEncryption,ignore 85 | }; 86 | uint8_t felica_payload[1]; 87 | }; 88 | }; 89 | }; 90 | }; 91 | } packet_req_t; 92 | 93 | typedef union packet_res { 94 | uint8_t bytes[128]; 95 | struct { 96 | uint8_t frame_len; 97 | uint8_t addr; 98 | uint8_t seq_no; 99 | uint8_t cmd; 100 | uint8_t status; 101 | uint8_t payload_len; 102 | union { 103 | char version[23]; //sg_nfc_res_get_fw_version,sg_nfc_res_get_hw_version 104 | uint8_t info_payload[9]; //sg_led_res_get_info 105 | uint8_t block[16]; //sg_nfc_res_mifare_read_block 106 | struct { //sg_nfc_res_poll 107 | uint8_t count; 108 | uint8_t type; 109 | uint8_t id_len; 110 | union { 111 | uint8_t mifare_uid[4]; 112 | struct { 113 | uint8_t IDm[8]; 114 | uint8_t PMm[8]; 115 | }; 116 | }; 117 | }; 118 | struct { //sg_nfc_res_felica_encap 119 | uint8_t encap_len; 120 | uint8_t encap_code; 121 | uint8_t encap_IDm[8]; 122 | union { 123 | struct {//FELICA_CMD_POLL 124 | uint8_t poll_PMm[8]; 125 | uint8_t poll_systemCode[2]; 126 | }; 127 | struct { 128 | uint8_t RW_status[2];//猜测,NDA_06,NDA_08 129 | uint8_t numBlock;//NDA_06 130 | uint8_t blockData[1][1][16];//NDA_06 131 | }; 132 | uint8_t felica_payload[1]; 133 | }; 134 | }; 135 | }; 136 | }; 137 | } packet_res_t; 138 | 139 | static packet_req_t req; 140 | static packet_res_t res; 141 | 142 | static void sg_res_init(uint8_t payload_len = 0) { //初始化模板 143 | res.frame_len = 6 + payload_len; 144 | res.addr = req.addr; 145 | res.seq_no = req.seq_no; 146 | res.cmd = req.cmd; 147 | res.status = 0; 148 | res.payload_len = payload_len; 149 | } 150 | 151 | static void sg_nfc_cmd_reset() { //重置读卡器 152 | nfc.begin(); 153 | nfc.setPassiveActivationRetries(0x01); //设定等待次数,0xFF永远等待 154 | nfc.SAMConfig(); 155 | if (nfc.getFirmwareVersion()) { 156 | nfc.SAMConfig(); 157 | sg_res_init(); 158 | res.status = 3; 159 | return; 160 | } 161 | FastLED.showColor(0xFF0000); 162 | } 163 | 164 | static void sg_nfc_cmd_get_fw_version() { 165 | sg_res_init(23); 166 | memcpy(res.version, "TN32MSEC003S F/W Ver1.2", 23); 167 | } 168 | 169 | static void sg_nfc_cmd_get_hw_version() { 170 | sg_res_init(23); 171 | memcpy(res.version, "TN32MSEC003S H/W Ver3.0", 23); 172 | } 173 | 174 | static void sg_nfc_cmd_mifare_set_key_aime() { 175 | sg_res_init(); 176 | memcpy(AimeKey, req.key, 6); 177 | } 178 | 179 | static void sg_nfc_cmd_mifare_set_key_bana() { 180 | sg_res_init(); 181 | memcpy(BanaKey, req.key, 6); 182 | } 183 | 184 | static void sg_led_cmd_reset() { 185 | sg_res_init(); 186 | } 187 | 188 | static void sg_led_cmd_get_info() { 189 | sg_res_init(9); 190 | static uint8_t info[9] = {'1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12}; 191 | memcpy(res.info_payload, info, 9); 192 | } 193 | 194 | static void sg_led_cmd_set_color() { 195 | FastLED.showColor(CRGB(req.color_payload[0], req.color_payload[1], req.color_payload[2])); 196 | } 197 | 198 | static void sg_nfc_cmd_radio_on() { 199 | sg_res_init(); 200 | nfc.setRFField(0x00, 0x01); 201 | } 202 | 203 | static void sg_nfc_cmd_radio_off() { 204 | sg_res_init(); 205 | nfc.setRFField(0x00, 0x00); 206 | } 207 | 208 | static void sg_nfc_cmd_poll() { //卡号发送 209 | uint16_t SystemCode; 210 | if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, res.mifare_uid, &res.id_len)) { 211 | sg_res_init(0x07); 212 | res.count = 1; 213 | res.type = 0x10; 214 | return; 215 | } 216 | else if (nfc.felica_Polling(0xFFFF, 0x00, res.IDm, res.PMm, &SystemCode, 200) == 1) {//< 0: error 217 | sg_res_init(0x13); 218 | res.count = 1; 219 | res.type = 0x20; 220 | res.id_len = 0x10; 221 | return; 222 | } else { 223 | sg_res_init(1); 224 | res.count = 0; 225 | return; 226 | } 227 | } 228 | 229 | static void sg_nfc_cmd_mifare_select_tag() { 230 | sg_res_init(); 231 | } 232 | 233 | static void sg_nfc_cmd_aime_authenticate() { 234 | sg_res_init(); 235 | //AuthenticateBlock(uid,uidLen,block,keyType(A=0,B=1),keyData) 236 | if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 1, AimeKey)) { 237 | return; 238 | } else { 239 | res.status = 1; 240 | } 241 | } 242 | 243 | static void sg_nfc_cmd_bana_authenticate() { 244 | sg_res_init(); 245 | //AuthenticateBlock(uid,uidLen,block,keyType(A=0,B=1),keyData) 246 | if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, 0, BanaKey)) { 247 | return; 248 | } else { 249 | res.status = 1; 250 | } 251 | } 252 | 253 | static void sg_nfc_cmd_mifare_read_block() {//读取卡扇区数据 254 | if (nfc.mifareclassic_ReadDataBlock(req.block_no, res.block)) { 255 | sg_res_init(0x10); 256 | return; 257 | } 258 | sg_res_init(); 259 | res.status = 1; 260 | } 261 | 262 | static void sg_nfc_cmd_felica_encap() { 263 | uint16_t SystemCode; 264 | if (nfc.felica_Polling(0xFFFF, 0x01, res.encap_IDm, res.poll_PMm, &SystemCode, 200) == 1) { 265 | SystemCode = SystemCode >> 8 | SystemCode << 8;//SystemCode,大小端反转注意 266 | } 267 | else { 268 | sg_res_init(); 269 | res.status = 1; 270 | return; 271 | } 272 | uint8_t code = req.encap_code; 273 | res.encap_code = code + 1; 274 | switch (code) { 275 | case FELICA_CMD_POLL: 276 | { 277 | sg_res_init(0x14); 278 | res.poll_systemCode[0] = SystemCode; 279 | res.poll_systemCode[1] = SystemCode >> 8; 280 | } 281 | break; 282 | case FELICA_CMD_GET_SYSTEM_CODE: 283 | { 284 | sg_res_init(0x0D); 285 | res.felica_payload[0] = 0x01;//未知 286 | res.felica_payload[1] = SystemCode;//SystemCode 287 | res.felica_payload[2] = SystemCode >> 8; 288 | } 289 | break; 290 | case FELICA_CMD_NDA_A4: 291 | { 292 | sg_res_init(0x0B); 293 | res.felica_payload[0] = 0x00; 294 | } 295 | break; 296 | case FELICA_CMD_NDA_06: 297 | { 298 | uint16_t serviceCodeList[1] = {(uint16_t)(req.serviceCodeList[1] << 8 | req.serviceCodeList[0])};//大小端反转注意 299 | for (uint8_t i = 0; i < req.numBlock; i++) { 300 | uint16_t blockList[1] = {(uint16_t)(req.blockList[i][0] << 8 | req.blockList[i][1])}; 301 | if (nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 1, blockList, res.blockData[i]) != 1) { 302 | memset(res.blockData[i], 0, 16);//dummy data 303 | } 304 | } 305 | res.RW_status[0] = 0; 306 | res.RW_status[1] = 0; 307 | res.numBlock = req.numBlock; 308 | sg_res_init(0x0D + req.numBlock * 16); 309 | } 310 | break; 311 | case FELICA_CMD_NDA_08: 312 | { 313 | sg_res_init(0x0C);//此处应有写入卡,但是不打算实现 314 | res.RW_status[0] = 0; 315 | res.RW_status[1] = 0; 316 | } 317 | break; 318 | default: 319 | sg_res_init(); 320 | res.status = 1; 321 | } 322 | res.encap_len = res.payload_len; 323 | } 324 | -------------------------------------------------------------------------------- /Arduino-Aime-Reader/doc/Example.txt: -------------------------------------------------------------------------------- 1 | //SG_NFC_CMD_GET_FW_VERSION 2 | E0 [05] 00 09 (30) 00 [ ] 3 | E0 [1D] 00 [ ] (30) 00 17 [54 4E 33 32 4D 53 45 43 30 30 33 53 20 46 2F 57 20 56 65 72 31 2E 32] [ ] 4 | 5 | //SG_NFC_CMD_GET_HW_VERSION 6 | E0 [05] 00 [ ] (32) 00 [ ] 7 | E0 [1D] 00 [ ] (32) 00 17 [54 4E 33 32 4D 53 45 43 30 30 33 53 20 48 2F 57 20 56 65 72 33 2E 30] [ ] 8 | 9 | //SG_RGB_CMD_GET_INFO 10 | E0 [05] 08 [ ] (F0) 00 [ ] 11 | E0 [0F] 08 [ ] (F0) 00 [09 31 35 30 38 34 FF 10 00 12] [ ] 12 | 13 | //SG_NFC_CMD_POLL,FELICA 14 | E0 [05] 00 [ ] (42) 00 [ ] 15 | E0 [19] 00 [ ] (42) 00 13 01 20 10 [ 8 byte IDm ] [ 8 byte PMm ] [ ] 16 | 17 | //SG_NFC_CMD_FELICA_ENCAP,Skip reply 18 | E0 [13] 00 [ ] (71) [ ] [ 8 byte IDm ] [ payload_len ] ( ) [ any data ] [ ] 19 | E0 [06] 00 [ ] (71) [01] 00 [ ] 20 | 21 | //SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_POLL 22 | E0 [13] 00 [ ] (71) 0E [ 8 byte IDm ] 06 (00) [FF FF 01 0F] [ ] 23 | E0 [1A] 00 [ ] (71) 00 [14 14] (01) [ 8 byte IDm ] [ 8 byte PMm ] [ 2 byte system_code ] [ ] 24 | 25 | //SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_GET_SYSTEM_CODE 26 | E0 [17] 00 [ ] (71) 12 [ 8 byte IDm ] 0A (0C) [ 8 byte IDm ] [ ] 27 | E0 [13] 00 [ ] (71) 00 [0D 0D] (0D) [ 8 byte IDm ] 01 00 00 [ ] 28 | 29 | //SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_NDA_A4 30 | E0 [18] 00 [ ] (71) 13 [ 8 byte IDm ] 0B (A4) [ 8 byte IDm ] 00 [ ] 31 | E0 [11] 00 [ ] (71) 00 [0B 0B] (A5) [ 8 byte IDm ] 00 [ ] 32 | 33 | //SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_NDA_06,read block 34 | E0 [1D] 00 [ ] (71) 18 [ 8 byte IDm ] 10 (06) [ 8 byte IDm ] [ Service len ] [ Service Code(little-endian) ] [ Block len ] [ Block Code(big-endian) ] [ ] 35 | E0 [23] 00 [ ] (71) 00 [1D 1D] (07) [ 8 byte IDm ] [00 00] [ Block len ] [ 16 byte Block Data ] [ ] 36 | 37 | //SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_NDA_06, read multiple blocks,Service Code=0x000B(read-only),Block Code={0x8082,0x8086,0x8090,0x8091} 38 | E0 [23] 00 [ ] (71) 1E [ 8 byte IDm ] 16 (06) [ 8 byte IDm ] [01] [0B 00] [04] [80 82] [80 86] [80 90] [80 91] [ ] 39 | E0 [53] 00 [ ] (71) 00 [4D 4D] (07) [ 8 byte IDm ] [00 00] [04] [ 8 byte IDm ] [ 16*len byte Block Data ] [ ] 40 | 41 | //SG_NFC_CMD_FELICA_ENCAP,FELICA_CMD_NDA_08,write block,Service Code=0x0009(read/write),Block Code=0x8080 42 | E0 [2D] 00 [ ] (71) 28 [ 8 byte IDm ] 20 (08) [ 8 byte IDm ] [01] [09 00] [01] [80 80] [ 16 byte Block Data ] [ ] 43 | E0 [12] 00 [ ] (71) 00 [0C 0C] (09) [ 8 byte IDm ] [00 00] [ ] 44 | 45 | //SG_NFC_CMD_POLL,MIFARE 46 | E0 [05] 00 [ ] (42) 00 [ ] 47 | E0 [0D] 00 [ ] (42) 00 07 01 10 04 [ 4 byte UID ] [ ] 48 | 49 | //SG_NFC_CMD_MIFARE_READ_BLOCK 50 | E0 [0A] 00 [ ] (52) 05 [ 4 byte UID ] [ block_no ] 84 51 | E0 [16] 00 [ ] (52) 00 10 [ 16 byte block data ] [ ] 52 | -------------------------------------------------------------------------------- /Arduino-Aime-Reader/doc/aime示例.mct: -------------------------------------------------------------------------------- 1 | +Sector: 0 2 | 1DB40F0DAB880400C832002000000016 3 | 00000000000000000000000000000000 4 | 00000000000010114514191981023333 5 | 57434346763208778F11574343467632 6 | +Sector: 1 7 | 00000000000000000000000000000000 8 | 00000000000000000000000000000000 9 | 00000000000000000000000000000000 10 | 57434346763208778F11574343467632 11 | +Sector: 2 12 | 00000000000000000000000000000000 13 | 00000000000000000000000000000000 14 | 00000000000000000000000000000000 15 | 57434346763208778F11574343467632 16 | +Sector: 3 17 | 00000000000000000000000000000000 18 | 00000000000000000000000000000000 19 | 00000000000000000000000000000000 20 | 57434346763208778F11574343467632 21 | +Sector: 4 22 | 00000000000000000000000000000000 23 | 00000000000000000000000000000000 24 | 00000000000000000000000000000000 25 | 57434346763208778F11574343467632 26 | +Sector: 5 27 | 00000000000000000000000000000000 28 | 00000000000000000000000000000000 29 | 00000000000000000000000000000000 30 | 57434346763208778F11574343467632 31 | +Sector: 6 32 | 00000000000000000000000000000000 33 | 00000000000000000000000000000000 34 | 00000000000000000000000000000000 35 | 57434346763208778F11574343467632 36 | +Sector: 7 37 | 00000000000000000000000000000000 38 | 00000000000000000000000000000000 39 | 00000000000000000000000000000000 40 | 57434346763208778F11574343467632 41 | +Sector: 8 42 | 00000000000000000000000000000000 43 | 00000000000000000000000000000000 44 | 00000000000000000000000000000000 45 | 57434346763208778F11574343467632 46 | +Sector: 9 47 | 00000000000000000000000000000000 48 | 00000000000000000000000000000000 49 | 00000000000000000000000000000000 50 | 57434346763208778F11574343467632 51 | +Sector: 10 52 | 00000000000000000000000000000000 53 | 00000000000000000000000000000000 54 | 00000000000000000000000000000000 55 | 57434346763208778F11574343467632 56 | +Sector: 11 57 | 00000000000000000000000000000000 58 | 00000000000000000000000000000000 59 | 00000000000000000000000000000000 60 | 57434346763208778F11574343467632 61 | +Sector: 12 62 | 00000000000000000000000000000000 63 | 00000000000000000000000000000000 64 | 00000000000000000000000000000000 65 | 57434346763208778F11574343467632 66 | +Sector: 13 67 | 00000000000000000000000000000000 68 | 00000000000000000000000000000000 69 | 00000000000000000000000000000000 70 | 57434346763208778F11574343467632 71 | +Sector: 14 72 | 00000000000000000000000000000000 73 | 00000000000000000000000000000000 74 | 00000000000000000000000000000000 75 | 57434346763208778F11574343467632 76 | +Sector: 15 77 | 00000000000000000000000000000000 78 | 00000000000000000000000000000000 79 | 00000000000000000000000000000000 80 | 57434346763208778F11574343467632 -------------------------------------------------------------------------------- /Arduino-Aime-Reader/doc/nfc.txt: -------------------------------------------------------------------------------- 1 | N.B. Quoted strings are NOT NUL-terminated unless otherwise noted. 2 | Useful reading: https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf 3 | 4 | (AiMe branded cards are Mifare Classic cards. Other technologies exist though) 5 | 6 | Summary 7 | ------- 8 | 9 | Hardware: 10 | Assembly connector: 11 | 5V Host in 12 | Tx;Rx;GND Host RS232 in 13 | Tx;Rx;GND Daisy-chain out 14 | Main board (probably LED controller): 15 | Silk "837-15084" 16 | CN1: Host 5V power in, ?V NFC-sub power out 17 | CN2: Host RS232 Tx;Rx;GND in, NFC-sub Tx;Rx out 18 | CN3: LED-Sub power and data(?) out 19 | DIPSW1: Set to hex nibble 8. 20 | Contains ADM3222 RS232 transceiver IC 21 | Contains ATMega32 MCU 22 | NFC subboard: 23 | Sticker: Model "TN32MSEC003S" 24 | CN1: ?V power and Tx;Rx;GND in, Tx;Rx;GND ass'y CN daisy out. 25 | DIPSW1: Set to hex nibble 0. 26 | Contains ATmega168 MCU 27 | Contains ADM3202A RS232 transceiver IC 28 | Contains shielded RF circuit 29 | Entire non-ground-plane PCB area is visible through the chassis 30 | torx screws lol 31 | LED subboard: 32 | Silk: "837-15120" 33 | CN1: ?V power and Tx;Rx;GND in. 34 | Five RGB LEDs and a bunch of resistors 35 | No visible logic ICs..? 36 | No DIPSW. 37 | 38 | JVS framing: 39 | E0 sync 40 | D0 escape (+1 to unescape) 41 | Checksum is sum of bytes after unescaping 42 | 43 | Frame header: 44 | Frame length (including length byte itself) 45 | Address 46 | Sequence no, hopefully loops before hitting esc byte... 47 | Command byte 48 | 49 | Bus addressing: 50 | Low nibble set using DIPSWs 51 | High nibble ??? 52 | Daisy chaining mechanism unknown (RS232 wires probably multi-tap) 53 | 54 | Startup 55 | ------- 56 | 57 | Addr 00 Command 62: 58 | Req: 59 | 00 Payload length 60 | Resp: 61 | 00 Status byte 62 | 00 Payload length 63 | Description: 64 | Unknown. Reset? 65 | 66 | Addr 00 Command 30: 67 | Req: 68 | 00 Payload length 69 | Resp: 70 | 00 Status byte 71 | 17 Payload length 72 | .. "TN32MSEC003S F/W Ver1.2E" 73 | Description: 74 | Get firmware version 75 | 76 | Addr 00 Command 32: 77 | Req: 78 | 00 Payload length 79 | Resp: 80 | 00 Status byte 81 | 17 Payload length 82 | .. "TN32MSEC003S H/W Ver3.0J" 83 | Description: 84 | Get hardware version 85 | 86 | Addr 08 Command f5: 87 | Req: 88 | 00 Payload length 89 | Resp: 90 | 00 Status byte 91 | 00 Payload length 92 | Description: 93 | LED sub-board reset. 94 | Won't accept LED commands until you do this. 95 | 96 | Addr 08 Command f0: 97 | Req: 98 | 00 Payload length 99 | Resp: 100 | 00 Status byte 101 | 09 Payload length 102 | .. "15084" (part nr for LED board) 103 | FF ?? 104 | 11 ?? 105 | 00 ?? 106 | 12 ?? 107 | Description: 108 | Get board "info" 109 | 110 | Addr 00 Command 54: 111 | Req: 112 | 06 Payload length 113 | 57 'W' 114 | 43 'C' 115 | 43 'C' 116 | 46 'F' 117 | 76 'v' 118 | 32 '2' 119 | Resp: 120 | 00 Status byte? 121 | 00 ?? 122 | Description: 123 | Set Mifare KeyA. 124 | "WCCF" might refer this this SEGA arcade game: 125 | https://en.wikipedia.org/wiki/World_Club_Champion_Football 126 | It's quite old and has AiMe readers, maybe where they first appeared? 127 | 128 | Addr 00 Command 50: 129 | Req: 130 | 06 Payload length 131 | 60 ?? 132 | 90 ?? 133 | D0 ?? (This is escaped of course) 134 | 06 ?? 135 | 32 ?? 136 | F5 ?? 137 | Resp: 138 | 00 Status byte 139 | 00 Payload length 140 | Description: 141 | Possibly Mifare KeyB. 142 | 143 | Polling 144 | ------- 145 | 146 | Addr 00 Command 40: 147 | Req: 148 | 01 Payload length 149 | 03 ?? 150 | Resp: 151 | 00 Status byte 152 | 00 Payload length 153 | Description: 154 | Poll some other NFC technology? 155 | 156 | Addr 00 Command 42: 157 | Req: 158 | 00 Payload length 159 | Resp if no MiFare card: 160 | 00 Status byte 161 | 01 Payload length 162 | 00 (represents nothing i guess) 163 | Resp if MiFare card: 164 | 00 Status byte? 165 | 07 Payload length 166 | 01 Chunk length? 167 | 10 ?? Block size maybe? 168 | 04 Chunk length? 169 | .. Mifare UID, four bytes. 170 | Description: 171 | Check for Mifare card presence? 172 | 173 | Addr 00 Command 41: 174 | Req: 175 | 00 Payload length 176 | Resp: 177 | 00 Status byte 178 | 00 Payload length 179 | Description: 180 | Unknown. Poll some other NFC technology? 181 | 182 | Card read 183 | --------- 184 | 185 | Addr 00 Command 43: 186 | Req: 187 | 04 Payload length 188 | .. Mifare UID, four bytes. 189 | Resp: 190 | 00 Status byte 191 | 00 Payload length 192 | Description: 193 | Select MiFare by UID? 194 | 195 | Addr 00 Command 55: 196 | Req: 197 | 05 Payload length 198 | .. Mifare UID, four bytes. 199 | 03 ?? 200 | Resp: 201 | 00 Status byte 202 | 00 Payload length 203 | Description: 204 | Unknown. 205 | Block 3 on a Mifare sector contains keys and an access control list. 206 | It is generally not accessed directly (unless being provisioned?) 207 | 208 | Addr 00 Command 52: 209 | Req: 210 | 05 Payload length 211 | .. Mifare UID, four bytes. 212 | .. Block number, 1 or 2. 213 | Resp for Block 1: 214 | 00 Status byte 215 | 10 Payload length (1 block) 216 | .. "SBSD" 217 | 00 00 00 00 218 | 00 00 00 00 219 | 00 4E C6 22 220 | Resp for Block 2: 221 | 00 Status byte 222 | 10 Payload length (1 block) 223 | .. 00 00 00 00 00 00 xx xx 224 | xx xx xx xx xx xx xx xx 225 | Description: 226 | Probably reads blocks 1 and 2 from Mifare sector 0. 227 | Block 0 contains the "vendor information" and UID. 228 | Block 1 contents are unknown, probably AiMe DB info. 229 | Block 2 last 10 bytes hex are printed on the card ("local unique id"). 230 | (Block 3 contains encryption keys so is not allowed to be read) 231 | 232 | LED 233 | --- 234 | 235 | Addr 08 Command 81: 236 | Req: 237 | 03 Payload length 238 | ff Red intensity 239 | ff Green intensity 240 | ff Blue intensity 241 | Resp: 242 | None! Command is not acknowledged 243 | Description: 244 | Set LED color 245 | -------------------------------------------------------------------------------- /Arduino-Aime-Reader/tools/DTR-RTS.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | HANDLE com; 5 | com = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 6 | FILE_ATTRIBUTE_NORMAL, 0); 7 | DCB dcbSerialParams = {0}; 8 | COMMTIMEOUTS timeouts = {0}; 9 | dcbSerialParams.DCBlength = sizeof(dcbSerialParams); 10 | GetCommState(com, &dcbSerialParams); 11 | dcbSerialParams.BaudRate = 115200; 12 | dcbSerialParams.ByteSize = 8; 13 | dcbSerialParams.StopBits = ONESTOPBIT; 14 | dcbSerialParams.Parity = NOPARITY; 15 | SetCommState(com, &dcbSerialParams); 16 | timeouts.ReadIntervalTimeout = 1; 17 | timeouts.ReadTotalTimeoutConstant = 1; 18 | timeouts.ReadTotalTimeoutMultiplier = 1; 19 | timeouts.WriteTotalTimeoutConstant = 1; 20 | timeouts.WriteTotalTimeoutMultiplier = 1; 21 | SetCommTimeouts(com, &timeouts); 22 | EscapeCommFunction(com, SETDTR); 23 | EscapeCommFunction(com, SETRTS); 24 | 25 | com = CreateFile("\\\\.\\COM12", GENERIC_READ | GENERIC_WRITE, 0, 0, 26 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 27 | dcbSerialParams.DCBlength = sizeof(dcbSerialParams); 28 | GetCommState(com, &dcbSerialParams); 29 | dcbSerialParams.BaudRate = 38400; 30 | dcbSerialParams.ByteSize = 8; 31 | dcbSerialParams.StopBits = ONESTOPBIT; 32 | dcbSerialParams.Parity = NOPARITY; 33 | SetCommState(com, &dcbSerialParams); 34 | timeouts.ReadIntervalTimeout = 1; 35 | timeouts.ReadTotalTimeoutConstant = 1; 36 | timeouts.ReadTotalTimeoutMultiplier = 1; 37 | timeouts.WriteTotalTimeoutConstant = 1; 38 | timeouts.WriteTotalTimeoutMultiplier = 1; 39 | SetCommTimeouts(com, &timeouts); 40 | EscapeCommFunction(com, SETDTR); 41 | EscapeCommFunction(com, SETRTS); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /Arduino-Aime-Reader/tools/DTR-RTS.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Arduino-Aime-Reader/tools/DTR-RTS.exe -------------------------------------------------------------------------------- /Arduino-Aime-Reader/tools/ReaderTest/ReaderTest.ino: -------------------------------------------------------------------------------- 1 | #if defined(__AVR_ATmega32U4__) || defined(ARDUINO_SAMD_ZERO) 2 | #pragma message "当前的开发板是 ATmega32U4 或 SAMD_ZERO" 3 | #define SerialDevice SerialUSB 4 | #define PN532_SPI_SS 10 //32U4 不使用 SPI 时,执行 ReadWithoutEncryption 会失败 5 | 6 | #elif defined(__AVR_ATmega328P__) 7 | #pragma message "当前的开发板是 UNO/NANO/Micro" 8 | #define SerialDevice Serial 9 | 10 | #elif defined(ARDUINO_NodeMCU_32S) 11 | #pragma message "当前的开发板是 NodeMCU_32S" 12 | #define SerialDevice Serial 13 | #define PN532_SPI_SS 5 14 | 15 | #else 16 | #error "未经测试的开发板,请检查串口和阵脚定义" 17 | #endif 18 | 19 | #if defined(PN532_SPI_SS) 20 | #pragma message "使用 SPI 连接 PN532" 21 | #include 22 | #include 23 | PN532_SPI pn532(SPI, PN532_SPI_SS); 24 | #else 25 | #include 26 | #include 27 | PN532_I2C pn532(Wire); 28 | #endif 29 | 30 | #include "PN532.h" 31 | PN532 nfc(pn532); 32 | 33 | typedef union { 34 | uint8_t block[18]; 35 | struct { 36 | uint8_t IDm[8]; 37 | uint8_t PMm[8]; 38 | union { 39 | uint16_t SystemCode; 40 | uint8_t System_Code[2]; 41 | }; 42 | }; 43 | } Card; 44 | Card card; 45 | 46 | uint8_t AimeKey[6] = {0x57, 0x43, 0x43, 0x46, 0x76, 0x32}; 47 | uint8_t BanaKey[6] = {0x60, 0x90, 0xD0, 0x06, 0x32, 0xF5}; 48 | uint8_t MifareKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 49 | #define M2F_B 1 50 | uint16_t blockList[4] = {0x8080, 0x8081, 0x8082, 0x8083}; 51 | uint16_t serviceCodeList[1] = {0x000B}; 52 | uint8_t blockData[1][16]; 53 | 54 | void setup() { 55 | SerialDevice.begin(115200); 56 | // Wire.setClock(800000); 57 | while (!SerialDevice); 58 | nfc.begin(); 59 | while (!nfc.getFirmwareVersion()) { 60 | SerialDevice.println("Didn't find PN53x board"); 61 | delay(500); 62 | } 63 | SerialDevice.println("START!"); 64 | nfc.setPassiveActivationRetries(0x10); 65 | nfc.SAMConfig(); 66 | } 67 | 68 | void loop() { 69 | uint8_t uid[4], uL; 70 | 71 | if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, 1, 1, AimeKey)) { 72 | SerialDevice.println("Aime card!"); 73 | SerialDevice.print("UID Value:"); 74 | nfc.PrintHex(uid, uL); 75 | SerialDevice.print("Block 2 Data:"); 76 | if (nfc.mifareclassic_ReadDataBlock(2, card.block)) { 77 | nfc.PrintHex(card.block, 16); 78 | } 79 | delay(2000); 80 | return; 81 | } 82 | if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, 1, 0, BanaKey)) { 83 | SerialDevice.println("Banapassport card!"); 84 | SerialDevice.print("UID Value:"); 85 | nfc.PrintHex(uid, uL); 86 | SerialDevice.print("Block 2 Data:"); 87 | if (nfc.mifareclassic_ReadDataBlock(2, card.block)) { 88 | nfc.PrintHex(card.block, 16); 89 | } 90 | delay(2000); 91 | return; 92 | } 93 | if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL) && nfc.mifareclassic_AuthenticateBlock(uid, uL, M2F_B, 0, MifareKey)) { 94 | SerialDevice.println("Default Key Mifare!"); 95 | if (nfc.mifareclassic_ReadDataBlock(2, card.block)) { 96 | SerialDevice.print("Fake IDm:"); 97 | nfc.PrintHex(card.IDm, 8); 98 | SerialDevice.print("Fake PMm:"); 99 | nfc.PrintHex(card.PMm, 8); 100 | } 101 | delay(2000); 102 | return; 103 | } 104 | if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uL)) { 105 | SerialDevice.println("Unknown key Mifare."); 106 | SerialDevice.print("UID Value:"); 107 | nfc.PrintHex(uid, uL); 108 | delay(2000); 109 | return; 110 | } 111 | 112 | if (nfc.felica_Polling(0xFFFF, 0x01, card.IDm, card.PMm, &card.SystemCode, 200)) { 113 | SerialDevice.println("FeliCa card!"); 114 | SerialDevice.print("IDm:"); 115 | nfc.PrintHex(card.IDm, 8); 116 | SerialDevice.print("PMm:"); 117 | nfc.PrintHex(card.PMm, 8); 118 | SerialDevice.print("SystemCode:"); 119 | card.SystemCode = card.SystemCode >> 8 | card.SystemCode << 8; 120 | nfc.PrintHex(card.System_Code, 2); 121 | 122 | 123 | Serial.println("FeliCa Block:"); 124 | for (uint8_t i = 0; i < 4; i++) { 125 | if (nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 1, &blockList[i], blockData) == 1) { 126 | Serial.println(blockList[i], HEX); 127 | nfc.PrintHex(blockData[0], 16); 128 | } else { 129 | Serial.println("error"); 130 | } 131 | } 132 | delay(2000); 133 | return; 134 | } 135 | SerialDevice.println("Didn't find card"); 136 | delay(500); 137 | } 138 | -------------------------------------------------------------------------------- /Arduino-Aime-Reader/tools/chunihook.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Arduino-Aime-Reader/tools/chunihook.dll -------------------------------------------------------------------------------- /Arduino-Aime-Reader/tools/sg-cmd.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "board/sg-cmd.h" 4 | #include "board/sg-frame.h" 5 | 6 | #include "hook/iobuf.h" 7 | 8 | #include "util/dprintf.h" 9 | 10 | union sg_req_any { 11 | struct sg_req_header req; 12 | uint8_t bytes[256]; 13 | }; 14 | 15 | union sg_res_any { 16 | struct sg_res_header res; 17 | uint8_t bytes[256]; 18 | }; 19 | 20 | static HRESULT sg_req_validate(const void *ptr, size_t nbytes); 21 | 22 | static void sg_res_error( 23 | struct sg_res_header *res, 24 | const struct sg_req_header *req); 25 | 26 | static HRESULT sg_req_validate(const void *ptr, size_t nbytes) 27 | { 28 | const struct sg_req_header *req; 29 | size_t payload_len; 30 | 31 | assert(ptr != NULL); 32 | 33 | if (nbytes < sizeof(*req)) { 34 | dprintf("SG Cmd: Request header truncated\n"); 35 | 36 | return E_FAIL; 37 | } 38 | 39 | req = ptr; 40 | 41 | if (req->hdr.frame_len != nbytes) { 42 | dprintf("SG Cmd: Frame length mismatch: got %i exp %i\n", 43 | req->hdr.frame_len, 44 | (int) nbytes); 45 | 46 | return E_FAIL; 47 | } 48 | 49 | payload_len = req->hdr.frame_len - sizeof(*req); 50 | 51 | if (req->payload_len != payload_len) { 52 | dprintf("SG Cmd: Payload length mismatch: got %i exp %i\n", 53 | req->payload_len, 54 | (int) payload_len); 55 | 56 | return E_FAIL; 57 | } 58 | 59 | return S_OK; 60 | } 61 | 62 | void sg_req_transact( 63 | struct iobuf *res_frame, 64 | const uint8_t *req_bytes, 65 | size_t req_nbytes, 66 | sg_dispatch_fn_t dispatch, 67 | void *ctx) 68 | { 69 | struct iobuf req_span; 70 | union sg_req_any req; 71 | union sg_res_any res; 72 | HRESULT hr; 73 | 74 | assert(res_frame != NULL); 75 | assert(req_bytes != NULL); 76 | assert(dispatch != NULL); 77 | 78 | req_span.bytes = req.bytes; 79 | req_span.nbytes = sizeof(req.bytes); 80 | req_span.pos = 0; 81 | 82 | hr = sg_frame_decode(&req_span, req_bytes, req_nbytes); 83 | 84 | if (FAILED(hr)) { 85 | return; 86 | } 87 | 88 | hr = sg_req_validate(req.bytes, req_span.pos); 89 | 90 | if (FAILED(hr)) { 91 | return; 92 | } 93 | 94 | hr = dispatch(ctx, &req, &res); 95 | 96 | if (hr != S_FALSE) { 97 | if (FAILED(hr)) { 98 | sg_res_error(&res.res, &req.req); 99 | } 100 | 101 | sg_frame_encode(res_frame, res.bytes, res.res.hdr.frame_len); 102 | printf("req: "); 103 | for (uint8_t i = 0; i < req_nbytes; i++) 104 | printf("%02X ", req_bytes[i]); 105 | printf("\n"); 106 | printf("res: "); 107 | for (uint8_t i = 0; i < res_frame->pos; i++) 108 | printf("%02X ", res_frame->bytes[i]); 109 | printf("\n"); 110 | } 111 | } 112 | 113 | void sg_res_init( 114 | struct sg_res_header *res, 115 | const struct sg_req_header *req, 116 | size_t payload_len) 117 | { 118 | assert(res != NULL); 119 | assert(req != NULL); 120 | 121 | res->hdr.frame_len = sizeof(*res) + payload_len; 122 | res->hdr.addr = req->hdr.addr; 123 | res->hdr.seq_no = req->hdr.seq_no; 124 | res->hdr.cmd = req->hdr.cmd; 125 | res->status = 0; 126 | res->payload_len = payload_len; 127 | } 128 | 129 | static void sg_res_error( 130 | struct sg_res_header *res, 131 | const struct sg_req_header *req) 132 | { 133 | assert(res != NULL); 134 | assert(req != NULL); 135 | 136 | res->hdr.frame_len = sizeof(*res); 137 | res->hdr.addr = req->hdr.addr; 138 | res->hdr.seq_no = req->hdr.seq_no; 139 | res->hdr.cmd = req->hdr.cmd; 140 | res->status = 1; 141 | res->payload_len = 0; 142 | } 143 | -------------------------------------------------------------------------------- /Mai2TouchOK/Mai2TouchOK.ino: -------------------------------------------------------------------------------- 1 | //高敏度低延迟可能串音版本 2 | 3 | 4 | 5 | //#define SerialDevice SerialUSB //32u4,samd21 6 | #define SerialDevice Serial //esp8266 7 | 8 | // bitWrite 不支持 uint64_t,以下定义来自 https://forum.arduino.cc/t/bitset-only-sets-bits-from-0-to-31-previously-to-15/193385/5 9 | #define bitSet64(value, bit) ((value) |= (bit<32?1UL:1ULL) <<(bit)) 10 | #define bitClear64(value, bit) ((value) &= ~(bit<32?1UL:1ULL) <<(bit)) 11 | #define bitWrite64(value, bit, bitvalue) (bitvalue ? bitSet64(value, bit) : bitClear64(value, bit)) 12 | #define Threshold 10 //触摸触发阈值 13 | 14 | #include "Adafruit_MPR121.h"//mpr121定义 15 | Adafruit_MPR121 mprA, mprB, mprC; 16 | #define CLAMP(val) (val < 0 ? 0 : (val > 255 ? 255 : val)) 17 | uint8_t packet[6]; 18 | uint8_t len = 0;//当前接收的包长度 19 | #define sA1(x) bitWrite(TPD, 0, x)//设置 sensor 20 | #define sB1(x) bitWrite(TPD, 8, x) 21 | #define sC1(x) bitWrite(TPD, 16, x) 22 | #define sD1(x) bitWrite(TPD, 18, x) 23 | #define sE1(x) bitWrite(TPD, 26, x) 24 | enum { 25 | commandRSET = 0x45,//E 26 | commandHALT = 0x4C,//L 27 | commandSTAT = 0x41,//A 28 | commandRatio = 0x72,//r 29 | commandSens = 0x6B,//k 30 | }; 31 | 32 | bool Conditioning = 1; 33 | void setup() { 34 | SerialDevice.begin(9600); 35 | SerialDevice.setTimeout(0); 36 | uint8_t TOUCH = 1;//按下敏感度 37 | uint8_t RELEASE = 1;//松开敏感度 38 | mprA.begin(0x5A, &Wire); 39 | mprB.begin(0x5C, &Wire); 40 | mprC.begin(0x5B, &Wire); 41 | Wire.setClock(800000); 42 | // delay(100); 43 | // MprSetup(mprA); 44 | // MprSetup(mprB); 45 | // MprSetup(mprC); 46 | // delay(100); 47 | } 48 | 49 | void loop() { 50 | Recv(); 51 | Conditioning ? void() : TouchSend();//只有不处于设定模式时才发送触摸数据 52 | } 53 | void MprSetup(Adafruit_MPR121 cap) {//mpr121自定义初始化 54 | cap.writeRegister(MPR121_SOFTRESET, 0x63);//MprReset 55 | delay(1); 56 | cap.writeRegister(MPR121_ECR, 0x0);//MprStop 57 | cap.writeRegister(MPR121_MHDR, 1);// 上升最大变化值 58 | cap.writeRegister(MPR121_NHDR, 4);//上升幅度 59 | cap.writeRegister(MPR121_NCLR, 8);//上升修正样本个数 60 | cap.writeRegister(MPR121_FDLR, 0);//修正前等待样本个数 61 | cap.writeRegister(MPR121_MHDF, 1);//下降最大变化值 62 | cap.writeRegister(MPR121_NHDF, 1);//下降幅度 63 | cap.writeRegister(MPR121_NCLF, 4);//下降修正样本个数 64 | cap.writeRegister(MPR121_FDLF, 4);//修正前等待样本个数 65 | cap.writeRegister(MPR121_NHDT, 0); 66 | cap.writeRegister(MPR121_NCLT, 0); 67 | cap.writeRegister(MPR121_FDLT, 0); 68 | // cap.writeRegister(MPR121_ESI,MPR121_ESI_1MS);/ 69 | cap.setThresholds(Threshold, Threshold); //设置触发阈值和充放电流时间 70 | cap.writeRegister(MPR121_DEBOUNCE, (4 << 4) | 2); //设置采样数,0 71 | cap.writeRegister(MPR121_CONFIG1, 16);//0x10 72 | cap.writeRegister(MPR121_CONFIG2, 1<<5); 73 | cap.writeRegister(MPR121_AUTOCONFIG0, 0x0B); 74 | cap.writeRegister(MPR121_AUTOCONFIG1, (1 << 7)); 75 | cap.writeRegister(MPR121_UPLIMIT, 202);//上限,((Vdd - 0.7)/Vdd) * 256 76 | cap.writeRegister(MPR121_TARGETLIMIT, 182);//目标,UPLIMIT * 0.9 77 | cap.writeRegister(MPR121_LOWLIMIT, 131);//下限,UPLIMIT * 0.65 78 | cap.writeRegister(MPR121_ECR, B01000000 + 12);//MprRun 79 | } 80 | void cmd_RSET() {//Reset 81 | MprSetup(mprA); 82 | MprSetup(mprB); 83 | MprSetup(mprC); 84 | 85 | 86 | 87 | } 88 | void cmd_HALT() {//Start Conditioning Mode 89 | mprA.writeRegister(MPR121_ECR, 0x0);//MprStop 90 | mprB.writeRegister(MPR121_ECR, 0x0); 91 | mprC.writeRegister(MPR121_ECR, 0x0); 92 | Conditioning = true; 93 | } 94 | 95 | void cmd_Ratio() {//Set Touch Panel Ratio 96 | SerialDevice.write((byte)'('); 97 | SerialDevice.write((byte)packet[1]);//L,R 98 | SerialDevice.write((byte)packet[2]);//sensor 99 | SerialDevice.write((byte)'r'); 100 | SerialDevice.write((byte)packet[4]);//Ratio 101 | SerialDevice.write((byte)')'); 102 | } 103 | 104 | void cmd_Sens() {//Set Touch Panel Sensitivity 105 | SerialDevice.write((byte)'('); 106 | SerialDevice.write((byte)packet[1]);//L,R 107 | SerialDevice.write((byte)packet[2]);//sensor 108 | SerialDevice.write((byte)'k'); 109 | SerialDevice.write((byte)packet[4]);//Sensitivity 110 | SerialDevice.write((byte)')'); 111 | } 112 | 113 | void cmd_STAT() { //End Conditioning Mode 114 | Conditioning = false; 115 | mprA.writeRegister(MPR121_ECR, B10000000 + 12);//MprRun 116 | mprB.writeRegister(MPR121_ECR, B10000000 + 12); 117 | mprC.writeRegister(MPR121_ECR, B10000000 + 12); 118 | } 119 | 120 | void Recv() { 121 | while (SerialDevice.available()) { 122 | uint8_t r = SerialDevice.read(); 123 | if (r == '{') { 124 | len = 0; 125 | } 126 | if (r == '}') { 127 | break; 128 | } 129 | packet[len++] = r; 130 | } 131 | if (len == 5) { 132 | switch (packet[3]) { 133 | case commandRSET: 134 | cmd_RSET(); 135 | break; 136 | case commandHALT: 137 | cmd_HALT(); 138 | break; 139 | case commandRatio: 140 | cmd_Ratio(); 141 | break; 142 | case commandSens: 143 | cmd_Sens(); 144 | break; 145 | case commandSTAT: 146 | cmd_STAT(); 147 | break; 148 | } 149 | len = 0; 150 | memset(packet, 0, 6); 151 | } 152 | } 153 | 154 | void TouchSend() { 155 | uint64_t TouchData = 0; //触摸数据包 156 | // 简单方法,从 mpr.touched() 一次读取 12个触摸点的按下状态,需要正确配置 mpr121 的各种参数值才能获取准确的状态 157 | TouchData = (TouchData | mprC.touched()) << 12; 158 | TouchData = (TouchData | mprB.touched()) << 12; 159 | TouchData = (TouchData | mprA.touched()); 160 | 161 | // 高级方法,读取每个触摸点的 baselineData 和 filteredData,可以单独设置敏感度过滤 162 | // for (uint8_t i = 0; i < 12; i++) { 163 | // bitWrite64(TouchData, i, CLAMP(mprA.baselineData(i) - mprA.filteredData(i)+20) > 27);//另外一种检测方法 164 | // Serial.print(CLAMP(mprA.baselineData(i) - mprA.filteredData(i)+20)); 165 | // Serial.print(" "); 166 | // } 167 | // for (uint8_t i = 0; i < 12; i++) { 168 | // bitWrite64(TouchData, i+12, CLAMP(mprB.baselineData(i) - mprB.filteredData(i)+20) > 30);//另外一种检测方法 169 | //// Serial.print(CLAMP(mprA.baselineData(i) - mprA.filteredData(i)+20)); 170 | //// Serial.print(" "); 171 | // } 172 | // for (uint8_t i = 0; i < 12; i++) { 173 | // bitWrite64(TouchData, i+24, CLAMP(mprC.baselineData(i) - mprC.filteredData(i)+20) > 30);//另外一种检测方法 174 | //// Serial.print(CLAMP(mprA.baselineData(i) - mprA.filteredData(i)+20)); 175 | //// Serial.print(" "); 176 | // } 177 | //Serial.println(""); 178 | SerialDevice.write((byte)'('); 179 | for (uint8_t r = 0; r < 7; r++) { 180 | SerialDevice.write((byte)TouchData & B11111); 181 | TouchData >>= 5; 182 | } 183 | SerialDevice.write((byte)')'); 184 | } 185 | -------------------------------------------------------------------------------- /Mai2TouchOK/高敏度低延迟可能串音版本.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Mai2TouchOK/高敏度低延迟可能串音版本.txt -------------------------------------------------------------------------------- /Pictures/anjiandeng001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/anjiandeng001.png -------------------------------------------------------------------------------- /Pictures/caiqie001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/caiqie001.png -------------------------------------------------------------------------------- /Pictures/caiqie002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/caiqie002.png -------------------------------------------------------------------------------- /Pictures/caiqie003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/caiqie003.png -------------------------------------------------------------------------------- /Pictures/chuping001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/chuping001.png -------------------------------------------------------------------------------- /Pictures/dukaqifan001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/dukaqifan001.png -------------------------------------------------------------------------------- /Pictures/dukaqizheng001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/dukaqizheng001.png -------------------------------------------------------------------------------- /Pictures/dydzz001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/dydzz001.png -------------------------------------------------------------------------------- /Pictures/huaichu001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/huaichu001.png -------------------------------------------------------------------------------- /Pictures/jiexian001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/jiexian001.png -------------------------------------------------------------------------------- /Pictures/lldx_001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/lldx_001.jpg -------------------------------------------------------------------------------- /Pictures/lldx_002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/lldx_002.jpg -------------------------------------------------------------------------------- /Pictures/tongku001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/tongku001.png -------------------------------------------------------------------------------- /Pictures/xianshi001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/xianshi001.png -------------------------------------------------------------------------------- /Pictures/yinxian001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/yinxian001.png -------------------------------------------------------------------------------- /Pictures/zhantieduiying001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/zhantieduiying001.png -------------------------------------------------------------------------------- /Pictures/zonglan001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/zonglan001.png -------------------------------------------------------------------------------- /Pictures/zouxian001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/Pictures/zouxian001.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 自制省钱高性价比maimaiDX控制器$全!$解 2 | 3 | ## 在此添置一个公告栏! 4 | # 请先不要参阅旧版教程,它太老了,很多做法现在认为都是相当错误的,至少22寸以上不要参考!!请等和看新版教程 5 | # [跳转到正在编写的新版教程](tn/2.md) 6 | 7 | ## 我现在特别的后悔把蚀刻的方案发出来,蚀刻这个东西是给完全把教程理解的人用来提升使用的,是进阶方案,不是让人人都做蚀刻的,蚀刻的效果可能最好,但是其难度之类的可能也较高,就类似有两个解题方法,A方法能五分钟解出来小学生都会做拿99分,B方法解一个周能解出来还得大学生高等数学方法去做能解100分,除非你确实能力足够,否则虽然我们都知道100>99但是还是去做A解更好。基本上什么人能做蚀刻呢,就是看了蚀刻的那几行简单小步骤就能在脑子里想象出怎么操作细节是什么的人一个词做出来是没问题的。如果你连这个东西的基本原理都没有理解甚至裁切法都没有吃透,甚至最基础的电学里面,电阻越小越好都不知道的话,搞蚀刻等于九九乘法表背过都困难去做大学数学题。蚀刻必然效果会很好很好,而且我这个方法做出来的成本巨低(是定制的十分之一左右),但是并不意味着这个方法他好做,都知道这个方法做出来好但是没有能力的情况下不要涉足这个东西。这个东西好但是你做不出来,就不要硬做,在激光切割之类的方法裁切ITO膜完全成功可用之前,手动裁切单区块并用漆包线引出仍然是目前自制综合各方面最适合从零开始学开始做的最优解,漆包线的导电性能会避免掉ITO走线的导电性问题,其直接用线走的方法也可以避免裁切线的容易切坏,是成功率巨高而且巨简单而且最适合新手而且实际判定效果完全不输其他方案的最优解。 8 | ## 本教程目前用的所有透明导电材质都是带胶ITO膜,主要是教程里面也没提玻璃啊,全程都是用的膜,凡是教程没提就不会是。因为玻璃本身就贵而且效果并不会比膜好上多少,你想那个导电的玻璃他玻璃基材一般性能不及钢化玻璃,不能直接作为手打歌的面板使用,你还要把那层导电玻璃跟一层钢化玻璃固定一起,又是一大块气隙,还不如弄个膜直接贴到钢化玻璃板上容易,而且膜成本还低透光度也不错,为什么非要用玻璃折磨自己? 9 | 10 | ## ISSUE里面如果你的问题觉得非常有意义再提,像是15Ω的ito可不可以什么的,这都是导电性越好越佳,40欧,150欧的可以那15欧的肯定可以,这样基础的问题就不要再问了,作者(我)现在处于一定程度的抑郁当中,暂时没有 太多心思去管理这些项目什么的,讨论群也已经解散,最好不要低质量问题来问,就非常显然的基础问题就不要问了,实在不知道怎么买就按照教程推荐的买不会有错。像是自己用什么导电铜箔引出之类的巴拉巴拉的各种做法凡是教程没写的操作做出来的一律视为脱离教程,其效果不代表教程效果,效果好效果差都不代表教程好教程不好之类的,只认为教程里面写的内容是可行的,换言之,你觉得可能更好的方案可能并不及教程甚至更简单的做法有效,做出来的东西导电性不佳跟教程半毛钱关系没有,指不定用教程的方法性能就上去了。 11 | 12 | 13 | 1. 43寸版本已经有至少3人成功,总成功人数不论尺寸,至少有5人成功,目前没有失败案例,听我话的制作成功率100%!!! 14 | 2. 更新了可以调整每个分区连线,阈值的版本,非常方便。 15 | 3. 测得了刷新率,如果使用mpr.baselineData()-mpr.filteredData()读取34个分区,刷新率大约100hz,如果使用touched()来读取,刷新率至少1000hz!!!! 16 | 3.1.根据原版io协议即官机协议,波特率为9600,每个包包括包头包尾,总共72bit,所以官机理论最大刷新率133.333333333333333333333Hz,上文提到“如果使用touched()来读取,刷新率至少1000hz”,实测是否具体1000hz不明?(可能测试方法有问题),在“使用mpr.baselineData()-mpr.filteredData()读取34个分区,刷新率大约100hz”情况下,将pro micro换成AtSAMD21(seeed XIAO SAMD21),由于支持更快更稳定的i2c,可以达到200hz左右,但是200hz时有神奇的加了灯光之类的串口设备后触摸初始化成功但是不能正常使用问题,故降低i2c速率,约在140-160hz正常工作(因为使用USB-CDC 串口,由于不经过真正串口信号,无需波特率,实际波特率无视,速度最高为usb fs速度12Mbps,所以可以不受波特率9600限制),纸面参数严格超越官方设备。 17 | 3.2 所以,因为目前认为,14,15之类小于20寸大小(暂认为15寸左右都可以,再大未尝试!)设备目前mpr121参数稳定,可以直接使用touched获取,所以无需关心i2c速度,可以选择pro micro来制作,刷新率很高。但是20寸以上建议必买samd21制作(samd21(优信电子售卖seeed牌)价格33CNY左右,promicro 3.3v 16mhz(无名科技开源硬件)约31CNY左右,实际上,价格相差不大,建议不论尺寸无脑选择samd21(samd21同价格性能更高,有利无害(?)具体samd21会不会有特殊问题(类似部分stm32 i2c有坑),目前至少没有遇到)),保证刷新率不会影响游玩。(已买pro micro也不用担心,16Mhz的pro micro运行在近100hz,实际效果也相当足够,毕竟官机理论最大值才133hz!)。**samd21iic速度较快,对于单片机到mpr的连线要求比promicro要高很多很多,失败记录较大,所以先用promicro保证整体没问题再升级samd21更好** 18 | 4. 正在写新版程序,一周内更新,可以选择两种读取方式,三种刷新率模式,可以调整增加延迟以匹配官机面板的高延迟,防止游玩全是fast(early)!!!! 19 | 5.作者突然回归文化课,程序更新失效将失去保证,对不起(。 20 | 21 | ## 第零部分 协议 22 | 23 | ### 对于请勿侵犯SEGA以及WAHLAP权益的声明 24 | 本作仅适用于个人制作游玩,原则上不提倡也不反对制作后发售。若发售或由读者自己的行为造成不当影响和任何纠纷,本教程作者和本教程不负任何责任。请勿侵犯SEGA以及WAHLAP权益。若作者行为或是本教程产生了不良影响,我对我的行为表示抱歉并可修补甚至撤下本教程,希望大家的理解。 25 | 当大家在展示自己手台效果的时候,不要发布不该发布的东西,让我们一起遵守。 26 | 27 | ### 对于协力者,贡献者的感谢 28 | 29 | 我的触摸代码部分几乎完全是mai2touch的项目搬来的,然后更改修复了一些mpr121配置上的问题,配置部分借鉴了Arduino-Chunithm-Controller的代码。读卡器使用的也是同作者的Arduino-Aime-Reader。在此对mai2touch,Arduino-Chunithm-Controller,Arduino-Aime-Reader和它们的作者表示衷心的感谢,如果没有mai2touch和Arduino-Chunithm-Controller以及对它们下了很多心血的作者,我的控制器将失去它最重要的灵魂。 30 | 在此感谢[Sucareto](https://github.com/Sucareto)以及他的项目[Arduino-Aime-Reader](https://github.com/Sucareto/Arduino-Aime-Reader),[Arduino-Chunithm-Controller](https://github.com/Sucareto/Arduino-Chunithm-Controller)和[mai2Touch](https://github.com/Sucareto/Mai2Touch)! 31 | 32 | 此版本可以单独调整每一个区块的连线和阈值!内置接线mpr分区来自**春暖花开**的设计!newmap-llvermtn202212271340 33 | 34 | 里面使用一个数组存储了每个区块具体的接线信息和阈值,这样更加方便大家使用自己对于接线方法的设计!建议自制的同志们每个人都下载看一下,比以前的程序接线自由度好很多! 35 | 数值里面是每个区的信息,对于每个区,第一个是这个区连接在哪个mpr上,1-4分别对应0x5a到0x5c,第二个是接在这个mpr的哪个引脚,从0到11可选,第三个是阈值,越大越难触发,越小越容易触发。 36 | 请记住,你需要将程序里面每个 cap.writeRegister(MPR121_ECR, B10000000 + XXXXXX);中的XXXXXX改为对应mpr的接线脚位号最大值,例如你四片mpr,每片接8,9,8,9个,那么在mprsetup最后一行就是填9,然后还有一连四个的那个地方,就按对应的写8,9,8,9,如果不知道怎么修改,就全部写成12,如果填写的小了,会导致大于设置开启数量的之后的分区无法正常工作。 37 | 38 | 39 | 里面带的分区的接线是**春暖花开**的设计,“这样分可以更简单的做到膜到mpr的每根漆包线都不会交叉,有充足的空间给每一根放置”,使用四片mpr,分别放在四角进行连接,并设计减少了交叉造成的干扰,是非常大方和聪明的设计,这种无私奉献的精神值得我们每个人去学习! 40 | 里面带的是43寸的mpr参数。 41 | **注:春暖花开=洛梨** 42 | 43 | **感谢yywooc提供的mpr放在面板周围分布和重划分区块归属mpr的宝贵思路,可以减少制作难度,降低干扰** 44 | 45 | **感谢tansuotro提出增加从mpr到区块的电阻来组成LC滤波降低干扰降低虚空触发让充放电更稳定的设计,暂未进行测试但是很有道理,在此表示感谢!!** 46 | ~~虽然他说是LC,但是我感觉应该是RC~~ 47 | 传承开源精神,我将自用的程序开源,但是仅仅用于我手里的硬件测试成功,不同的走线,制作方法,使用的mpr配置等也不一样,不建议照搬。 48 | 49 | ### 对于本教程版权的声明 50 | 51 | **HWDK_OPENSOURCE 开源项目** 52 | **本项目为 Helloworld 团队 Dk 提项并研发验证,作为开源项目,上传Github** 53 | **商业性:本作品允许合理商业,但作者不支持也不反对,但商业化造成的任何影响和结果,造成任何纠纷与作者无任何关系,有了我的教程,制作会简单一些,但是也很难,不保证所有人都能制作成功** 54 | **对本作品商业化的额外要求:基于本方案的作品,在您的改动不大的情况下(添加图形文字丝印/在程序等地添加自己的标识不计算为改动,若对功能做出改变,如在本基础上添加其他游戏兼容读卡器代码使新代码有意义部分可见字符长度远远大于原来程序,或更改电路PCB,增加无线(?)功能,不受本要求约束!),严厉禁止售卖产生大于500元/每个43寸等大台,75元/每个15寸及以下的小台的利润,使用本项目制作售卖者,我有权查你的原料账单,如果不符合我的要求,有权挂你不让你卖,看看谁能那么厚脸皮!!!!** 55 | **以上加粗字,‘本作品’指本ITO裁切区块和漆包线引出到mpr等触摸芯片的设计(也就是本Readme.md长篇大论讲述的东西),以及对于原来Mai2Touch项目的我更改的部分,例如随心设置区块等功能!!!其他的不是由我设计的部分,不受我约束!!!** 56 | 57 | **本作品使用mpr121,漆包线,裁切等方案虽然非常‘破烂‘,可能电气环境不是很好,但是依然达到可以正常游玩没有问题,刷新率和延迟非常可观的效果,即使硬件确实存在瓶颈,但是瓶颈足够不明显以至于完全不影响使用的底部,所以可以说,虽然看上去差,使用的材料方案不是那种高大上的,但是完全足够了,已经有多人实测证明,视频为证!!!希望大家擦亮眼睛,不要被表象所迷惑** 58 | 59 | 60 | 本教程是由Helloworld_Dk纯手打写出的,思路也是几乎完全自己想的。 61 | 如果我能给大家的想法产生帮助,我感到非常荣幸,如果您觉得我的方案对您有帮助,希望可以在您的项目发布时,跟上一句"本方案的部分灵感来自Dk"或类似的话,我将不甚感激 62 | 63 | ## 第一部分 总览 64 | 65 | ![总览](Pictures/zonglan001.png) 66 | 67 | 本方案是使用导电膜裁切,漆包线引出的触摸部分为核心的低价maimai控制器制作方案。由于被~~逼到无奈~~很多也像制作maimai手台的玩家支持,而写了这样的一个教程。 68 | 69 | 本作品旨在弄个便宜好用的方案,让大多数人都可以轻松把这个东西做出来,同时不要效果差到没法玩。 70 | 71 | **43寸版本已经有至少三台制作成功** 72 | **根据核算的价格,约三千多元可以实现没有按键的整台43寸控制器,约五千不到可以实现带有按键和灯光的整台43寸控制器** 73 | **根据核算的价格,约两百多元可以实现没有按键的整台15寸以下控制器,约四百不到可以实现带有按键和灯光的整台15寸以下控制器** 74 | 75 | 下图是朋友洛梨制作的43寸!非常的漂亮,他的评价是触摸非常好用! 76 | ![luoli_43](Pictures/lldx_002.jpg) 77 | 78 | 79 | 为想要做一个maimai手台,而又对高昂的价格和空缺的思路望而却步的观众们提供一个全新的高性价比的思路。 80 | 81 | 只要你不嫌麻烦,有耐心,有学习的精神,就可以以非常低的价格做出视频中的样子。甚至,可以使用这个思路做一个超低价的街机尺寸台 82 | 83 | 所以没有想过类似定制玻璃什么的,当然,使用定制的材料一定会让效果更好,甚至还原出街机的水准。 84 | 85 | 被骂哭了,视频删掉了。 86 | 我错了,请不要再骂我或者嘲讽我了。 87 | 以下两个链接无效: 88 | 89 | ``` 90 | ### [方案效果展示](https://www.bilibili.com/video/BV1pe4y1m7pr/) 91 | ### [使用32u4的延迟更新后的展示](https://www.bilibili.com/video/BV1PW4y1E7io/) 92 | ``` 93 |

todo: 另一个项目,顺利的话,大的要来了|来了,是读卡器那个项目,请进入我的主页打开读卡器项目!

94 | 95 | ## 常见问题 96 | 1.本教程内程序似乎无法在43寸设备上正常运行,但不意味着本项目无法做43寸版本。需要调整mpr121参数才可以在43寸设备上使用,具体参数请自行尝试,后续我会公开43寸参数。 现在已在43寸上测试成功可用,程序已发。 97 | ### 本项目有14寸,15寸,43寸已有人制作成功,如果你没有成功,请不要急着喷项目,因为大有可能是你制作上的问题,以下是别的同志在制作过程 ~~自以为是~~ 中遇到的问题,我让其改正后均可解决。问题存在性和致命性均经过事实验证,不保证这样做一定会失败,也不保证不这样做一定会成功,但这样做大概率会失败。同时如果你想要找我指导或者提出issue,请确保你没有犯下述内容中的错误,否则拉黑不予处理。 98 | ``` 99 | 1.自以为是,擅自不按照教程执行,还觉得自己很对,觉得这样不影响。如果您对mpr之类的原理不熟悉,比如不知道他是个电容触摸传感器,没有注意,然后将触摸板或模块置于金属桌子或腿上测试失败者。还有不知道电容类传感器电极相关注意事项而使用自己的错误方法连接模块和电极等。 (解决:不熟悉的按照教程来,完全复刻,不容易出问题,您认为的影响不大,可能影响很大。) 100 | 2.使用杜邦线连接各设备,或者直接将线拧在一起来连接,将线芯跟mpr焊盘绑起来连接,如果杜邦线,连接方式不牢靠,松动,劣质,氧化严重,可能导致触摸板电极或mpr无故停止工作,数据异常。(原因:瞬间的电容值变化容易让mpr的自动适应算法无法处理,会导致mpr内部出错。而mpr数据线松动,可能导致mpr数据传输错误,或断点重启而未初始化。同时,公头杜邦线那根金属针如果直接接触电极,由于杜邦线自带塑料会让其倾斜,实际上连接会非常不稳定,只有一个似断非断的点状导电面接触脆弱的导电涂层,导致电气性能极差等)(解决:作者建议能焊接的线不要怕麻烦,全部进行焊接,实际上掌握了焊接,熟练的时候焊接比插线快。mpr引脚连接电极,mpr端焊接,另一端剥长皮打圈) 101 | 3.电极导线触及屏幕,屏幕内走线等有可能导电,相当于手去触摸,导致电极一直处于按下状态,mpr无法识别到底手按还是没按(解决方法:走线固定好,与电极一同距离屏幕有一段距离) 102 | 4.电极导线长度差距巨大,长的导线可能造成更大的电容值,短的导线电容值小,导致mpr电极间读数呈现一些高一些低,灵敏度设置极其复杂难以实现。(解决方法:尽量规整走线,用多长截多长,并让线间距离相等,不要过远过近,其次以较短的路径连接到mpr,可以让导线间差距缩到比较小) 103 | 5.将mpr所有引进包括电极插到面包板再插杜邦线引出,杜邦线说过不再提,面包板内部是许多条金属片,金属片具有一定面积,会让电极间产生不必要的电容,轻则影响读数,重则无法读数。(解决方法:建议用焊接线的方法,连接所有电路,并将整个电路固定在一张不导电的板上,等效于电路悬空不受干扰。而不使用其他连接方式) 104 | 6.尝试使用5v单片机,mpr电源/IO电压是2.5-3.6v,低则可能无法工作,高则可能直接烧坏mpr。目前大家能买到的mpr模块(上面仅由mpr,几个电容电阻组成)不带电压转换芯片,无法在5v下正常工作。目前没见到使用简易mpr板子配合5v单片机能正常工作的。(解决方法:使用3.3v单片机,或使用adafruit出品的mpr之类,自带电平转换,支持3.3-5v宽电压的版本。实际一片带电平转换的版本跟简易mpr的差价就超过了5v单片机跟3.3v的差价,所以还是买3.3v单片机合适)(下有常见单片机电压) 105 | 7.不会写程序,乱改程序还觉得自己很对,自己反省。(解决方案:小台直接使用sucareto开源的版本或者我开源的版本,大台自己学一学再整或者等我发大台参数) 106 | 8.找我问问题,指导或提issue,而不把自己改了什么东西告诉我,不按照教程做但隐瞒,我让你怎么处理你不按我要求处理,我让刷我测试程序告诉我数据你非要把程序改了再发我数据,让打狗却去逮鸡,还表现的得意洋洋,觉得自己很对,这种人再出现在我面前我直接拉黑。 107 | 9.切割导电膜误差大,两片触控区间缝隙小,可能会造成串区和数据异常。(解决方案:按照教程一步步来,打印对照纸来辅助裁切,切得缝隙间距不要一窄一宽。如果是大台一张a4打印不完,可以分多张打印,总之,尽量裁切准确,贴准确,让缝隙大小均等,避免问题) 108 | ``` 109 | 110 | 111 | | 常见品类 | 单片机常见支持电压 | 说明 | 112 | |---------|------------------|-----------| 113 | | ESP系列 | 3.3v | esp系列一般都是3.3v,一般可以直接连接mpr| 114 | | 328p,168p| 1.8v-5v,常见为3.3v| 代表产品:Arduino UNO/NANO/MINI 一般可以直接连接mpr| 115 | | 32u4 | 具体多少不知道,常见为3.3v和5v| 代表产品:Leonardo,pro micro。其大部分未说明的都是5v,少数有说明是3.3v的,才是3.3v版本,5v不可以连接mpr,3.3v可以。| 116 | 117 | 第二行uno/nano/mini我近期发现还是有很多5v的,一定做好分辨,否则买回来不能用就傻了 118 | 119 | ~~tips:esp,328p,168p大部分需要连接usb串口才能造出usb串口,延迟较大,本人推荐32u4这种自带usb的有低延迟usb串口的芯片。3.3vpromicro一般很贵且只有8Mhz晶振版本。作者在某橙色购物软件上找到一款,typec的有粉色黑色沉金pcb自带复位键还引出iic的版本16Mhz,只要30,具体店铺就不放了,本人试过非常好用,性价比很高,可以搜搜看~~ 120 | 121 | stat: 延迟的问题已经被消除,写一个常见问题解答(重要!!,包含非常普遍和致命(?)或麻烦的错误)已完成 122 | 123 | ## 43寸版本 制作测试成功!!!!!43寸可用代码(参数)已经上传!!! 124 | **43寸版本 73行 cap.writeRegister(MPR121_ECR, B10000000 + 12);//MprRun 改成B01000000 + 12可能有优化的效果!感谢yywooc的优化** 125 | 目前14,15,43寸都已被测试成功可用 126 | 127 | ## 第二部分 目录 128 | - 第零部分 协议 129 | - 对于请勿侵犯SEGA以及WAHLAP权益的声明 130 | - 对于协力者,贡献者的感谢 131 | - 对于本教程版权的声明 132 | - 第一部分 总览 133 | - 介绍 134 | - 方案效果展示 135 | - todo和stat 136 | - 第二部分 目录 137 | - 目录 138 | - 第三部分 触屏制作指导 139 | - 第四部分 读卡器个人思路分享 140 | - 第五部分 已删除 141 | - 第六部分 按键和灯光(未完成) 142 | ## 第三部分 触屏制作指导 143 | **这位更是重量级** 144 | 145 | ![触屏ALL](Pictures/chuping001.png) 146 | 147 | 整个制作是非常的省钱,非常的好用,像是铝箔贴的chuni控制器,纯手作省钱能用就行精神是这样的。 148 | 149 | 被骂哭了,专栏一并删掉了。 150 | 我错了,请不要再骂我或者嘲讽我了。 151 | 以下一个链接无效: 152 | 本教程与之前发布的[专栏](https://www.bilibili.com/read/cv19157015)相互照应,相互补充,建议一起阅读 153 | 154 | ```圣经 155 | 做 手 台 不 试 试 瞎 搞 手 作 便 宜 省 钱 , 就 像 四 大 名 著 不 看 红 楼 梦 , 说 明 这 个 人 文 学 造 诣 和 自 我 修 养 不 足 , 他 理 解 不 了 这 种 内 在 的 阳 春 白 雪 的 高 雅 艺 术 , 他 只 能 看 到 外 表 的 辞 藻 堆 砌 , 参 不 透 其 中 深 奥 的 精 神 内 核 , 他 整 个 人 的 层 次 就 卡 在 这 里 了 , 只 能 度 过 一 个 相 对 失 败 的 人 生。 156 | ``` 157 | 158 | **你需要的材料:** 159 | - 触摸部分 160 | - 尺寸合适的ito导电膜,一定要买带胶,除非你真的想好了胶怎么办。下面会有为什么要这么做的说明。 161 | - 一张较薄的亚克力板或者玻璃板,尺寸至少覆盖圆形屏幕区域。此处感觉玻璃容易碎,亚克力容易划花,大家自行斟酌。本人使用的一张比亚克力优秀的塑料板。 162 | - 较细的漆包线 163 | - 你超棒的手工能力 164 | - 透明胶带 165 | - 屏幕部分 166 | - 一块跟你触摸板相对应的合适大小的屏幕,本教程应该不适用于小于十寸的屏幕。 167 | - 程序和mcu 168 | - 本人使用的mai2touch项目,并对其进行修改,相关链接在教程开头协议部分。 169 | - Arduino或类似的开发板,我建议使用pro micro,不建议使用使用了ch340串口ic的板子。但是我使用pro micro被喷过和嘲讽过.....别人说它性能太差,可是我真的喜欢。 170 | 171 | **mpr最大支持电压是3.6v,使用5v io/vcc 的单片机十有九.八会造成mpr不可用,请使用3.3v io/vcc的单片机。大多Leonardo,promicro都是5v的,少数3.3v才是我们需要的,请不要买错否则白买。** 172 | 173 | 174 | **制作过程详解** 175 | 这部分在专栏讲的很详细,特别是图片详细。 176 | 统共有以下步骤: 177 | ### 1\. 打印对照纸 178 | 说的玄乎,其实就是用一张A4纸或类似的纸,将触摸区块图片打印下来。尺寸要与你目标屏幕显示的大小完全对应。建议打印至少两张。 179 | 180 | ![打印对照纸](Pictures/dydzz001.png) 181 | 182 | ### 2\. 裁切 183 | 把a4纸跟买到的触摸膜贴在一起固定好,然后根据a4纸,裁下每一片触摸区块 184 | 注意一定要固定好哦,不然剪着剪着位移了剪除奇形怪状的区块可就难办了! 185 | ![裁切](Pictures/caiqie001.png) 186 | ![裁切](Pictures/caiqie002.png) 187 | ![裁切](Pictures/caiqie003.png) 188 | ## 3\.粘贴 189 | 190 | 首先你不是打印了两张A4纸吗,一张被剪了,另一张好好的,请规划好位置之后,把A4纸打印面朝向亚克力板或玻璃板粘贴,在另一面应该可以透过亚克力板或者玻璃板,看到另一面清晰的打印的区块。用于之后粘贴位置的对应。 191 | ![粘贴对应](Pictures/zhantieduiying001.png) 192 | 193 | 导电膜是这样的结构: 194 | 不导电面朝上,导电面朝下,依次是: 195 | 196 | 0. 一层保护膜 197 | 1. (如果是带胶的才有)一层透明胶 198 | 2. 聚酯离型膜,自此间隔,上面称为不导电面,下面称为导电面,不导电面有胶,导电面无胶 199 | 3. ito导电涂层 200 | 4. 一层保护膜 201 | 202 | 在**粘贴**这一步,我们需要完成的是 203 | 204 | 0. 亚克力或玻璃板 205 | 1. (如果是带胶的自带,没带胶的会让你痛苦到怀疑人生)一层透明胶 206 | 2. 聚酯离型膜 207 | 3. ito导电涂层 208 | 4. 一层保护膜 209 | 210 | 假设没有买带胶的膜,就自行点胶(透明的,支持粘贴塑料的,不会腐蚀塑料的,固化不回缩的,粘贴可以调整的)固定每片触摸块到屏幕上。 211 | 在写这篇教程的时候,我自己搞的胶腐蚀了我的塑料板,导致A5区域透明性下降...**距今已过去十分钟,警钟敲烂**,所以千万别贪便宜买不带胶的! 212 | 需要撕下不导电面的保护膜。不导电面朝向塑料板粘贴,**请勿将导电面贴到塑料板上**。 213 | 如果是买的带胶的导电膜,不导电面恰好是带胶面,裁好了可以轻松粘在塑料板上。完全不用经历大力对抗胶水的那一步。 214 | ~~唉,这个地方别省钱,要不让你感受人间痛苦,宛如晚清十大酷刑。~~ 215 | 216 | ~~自己搞胶的痛苦,详见专栏图片。~~ 217 | 218 | ![痛苦](Pictures/tongku001.png) 219 | ![坏处](Pictures/huaichu001.png) 220 | ## 4\.引线 221 | 222 | 在**引线**这一步,我们需要完成的是 223 | 224 | 0. 亚克力或玻璃板 225 | 1. 一层透明胶 226 | 2. 聚酯离型膜 227 | 3. ito导电涂层 228 | 4. 漆包线 229 | 5. 单面带胶的透明胶带 230 | 231 | ![引线](Pictures/yinxian001.png) 232 | 233 | 之前我说的是 234 | ``` 235 | 要去漆包线的绝缘漆, 236 | 撕掉导电面保护膜, 237 | 用透明胶带初固定, 238 | 尽力沿着区间缝隙走线, 239 | 240 | 评价是先走中心的c区,然后慢慢向外区块做,这个是中心思想, 241 | 其次是按照从下到上 顺序操作的,先是最底下的区,56那些处理好,慢慢往上处理。 242 | 这样在处理完一些之后,可以横着贴一张长长的透明胶带把已经完成的区固定好避免之后散掉。 243 | ``` 244 | 依然可以参照,在此补充操作绝对步骤,引用我教别人的聊天记录 245 | ``` 246 | 这样 247 | 先把漆包线准备好,头上刮漆打圈 248 | 把带胶不导电面贴好 249 | 然后准备一段透明胶带 250 | 然后把导电面保护膜解开 251 | 放漆包线 252 | 粘胶带 253 | 一气呵成 254 | ``` 255 | 这里有关ito的一个特性,是ito遇水,二氧化碳容易变质,影响导电性能和透明性。 256 | 所以在放上漆包线后,应当尽快用一些方法将导电面全部覆盖隔绝空气。我使用的是透明胶带,虽然不是特别好看但是能用。 257 | 258 | 关于导线具体从区块到触摸板边缘的引出方法,详见b站专栏,非常详细! 259 | 260 | 261 | ``` 262 | 总的说就是先从底下的中间考虑,也就是看下图先处理底下中间红圈再处理绿圈再处理橙圈再贴一张透明胶带上去。再往上一步一步地处理整个触摸面板。 263 | 264 | 运用了贪心的思想,中间的区肯定是最需要往外走的,所以需要先考虑,从哪条缝走过去。而边上的很简单就可以引出去,可以在把难搞的安顿好之后再处理。从下往上一是因为可以做一块贴一整块透明胶带,其次是下面不会像上面一样被屏幕挡住无法从边上轻松走线。先把东西往下安顿可以减少后续上面的工作量。 265 | 266 | 267 | 要点:处理顺序、不要吝啬在圆外面的初固定胶带,周围挡起来游玩看不见,减少线乱飞 268 | ``` 269 | 270 | 更新:由于根据思考,是否绕过区块都可能造成少量干扰,所以直接直线从区块上方走过去,还是从区块边缘绕过去应该效果差不多,根据试验,无论是哪种走线方式都是可行的,请按需走线 271 | 272 | ![走线](Pictures/zouxian001.png) 273 | 274 | ## 4\.接线 275 | 详见b站专栏,讲的足够详细,基本没有要补充的。 276 | 277 | **发现一件逝情,我好像没说mpr跟arduino怎么连线,有人不会连,所以在此补充:** 278 | 首先由于mpr121通过I2C总线与主控连接,所以每个mpr是并联起来的,即 279 | 每片mpr的vcc(3.3v)接在一起,接到主控的VCC上 280 | 每片mpr的gnd接在一起,接到主控的GND上 281 | 每片mpr的SDA接在一起,接到主控的SDA上,如果不知道主控哪个引脚是SDA,请谷歌搜索主控板名字+pinout,或百度搜索主控板名字+引脚定义 282 | 每片mpr的SCL接在一起,接到主控的SCL上,如果不知道主控哪个引脚是SCL,请谷歌搜索主控板名字+pinout,或百度搜索主控板名字+引脚定义 283 | 但是在此注意,I2C总线通过地址辨识设备,mpr每片买回来的时候是同一地址,需要手动切换地址,具体方法是: 284 | 找到您买的mpr的ADD跳线,其大概默认是短接的(默认ADD短接到GND,地址0x5A),请用小刀,螺丝刀等尖锐物将短接走线割断(刻断),请一定刻稳准狠,要确保跳线被完全刻断,并且不要伤到其他电路。然后板子应该引出了ADD的接口,ADD短接GND,VCC,SDA,SCL分别获得地址0x5A,0x5B,0x5C,0x5D。 285 | 286 | 割断/刻断过程请小心,不要伤到自己或板子其他电路 287 | 请勿在不割断的情况下短接ADD到其他引脚特别是VCC!!!,否则造成短路!所以我们要求必须确保完全割断,不能似断非断。 288 | 289 | 290 | ![接线](Pictures/jiexian001.png) 291 | ``` 292 | 1.先把arduino跟mpr121的I2C连好。 293 | 294 | 2.根据程序确定哪个区接在哪个mpr121的哪个io,如果你的程序不知道是哪个io,把程序写到板子里面,用一根螺丝刀按在每个io上,看游戏测试汇报哪个区被按下。通常是连续的,比如A1到A8是一个mpr的0到7之类的,很好确定,这个是一种办法。另一种是根据你从触摸面板上接出的漆包线的位置,在程序里面规划好哪个接哪个合适不用绕,可以走线不像我一样乱糟糟。 295 | 296 | 3.走漆包线。面对从塑料板边缘引出的34根漆包线无从下手是吗?我感觉这样比较好:以横向中轴为开始的地方,从这里向上下处理。 297 | 298 | 因为两边的线很容易可以从边上引到中间的mpr121上,而偏上偏下的难搞要绕。所以从中间处理会方便很多。走线原则:从空闲地方走,尽量隔出空隙,不要横跨一张mpr121板子,上面不能直接 绕,绕最好从左右,下面也可以勉强绕一下。 299 | 300 | 之前留的漆包线建议足一些,不然这步容易踩坑:要绕一些地方焊接,就需要足够长的线。有时候线发现不够长,这时候如果你发现在透明胶带下走的路径对现在要走的地方不合适,觉得拽回来就可以了,不绕路了,够长了。但是小心!!你一拉那个漆包线,很可能把上面在触摸区域走的打好圈的线拽移位,到其他区或者圈没了。这会让你极其难办。你不得不拆下粘的很牢的透明胶带,把线重新拽回原位打圈放在该在的位置上。透明胶带这种东西撕下来粘第二次透明效果就会很差,所以千万不要乱拽漆包线,返工让你怀疑人生 301 | 302 | 但是遇到真的不够长怎么办呢,可以尝试用圆滑的焊接接上一段,做好绝缘应该没什么问题。 303 | 304 | 到这里,你的线接好了。 305 | 306 | 要点:确定好io对应区,写在之前打印过的A4纸上,对照着纸上面的区块位置接会方便很多。不要拽漆包线。 307 | ``` 308 | 309 | ## 5\.程序部分 310 | 311 | 我使用的是github上的开源项目mai2Touch。曾遇到过问题如下 312 | 313 | QA1:对于328p编译失败,不支持的开发板:改改上面的宏定义即可。(不建议使用带ch340的328p板子... ~~感觉是延迟的来源,新买的板子还没到...不确定。~~ 就是延迟的来源,不用洗,我promicro已经到了,非常低延迟,爱来自32u4。这条QA仅限于你要用UNO/NANO/MICRO才可能会用到,但是本人非常不建议使用,因为延迟极大 314 | 315 | QA2:Serial.write 歧义 编译失败:在write传入的参数前面强制类型转换为(byte)。如Serial.write('A');改为Serial.write((byte)'A'); 316 | 317 | QA3:触摸出现问题,莫名触发,串音,灵敏度错:~~我自己重写了mpr121配置部分代码然后就解决了,某论坛有配置详细教程,这就不发了。~~实际上是从Arduino-Chunithm-Controller搬来的寄存器设定代码并加以改动,我摊牌了。 318 | 319 | ## 6\.游戏连接部分 320 | 321 | 你好,不可能发游戏的,这里只提一下连接的一些问题 322 | 323 | QA1:怎么连的:串口直连,按照github上的readme走。 324 | 325 | QA2:怎么按下在闪,不是长按:github(截止到写这个专栏)里面教的写错了。**DummyTouchPanel=1应该是0**,1的话是开启了的mai程序自带的调试触摸,然后导致自己的设备和自带的调试对着干,一个说按了一个说没按,就开始闪。设置为0避免程序调试触摸影响。 326 | 327 | QA3: 怎么感觉我的触摸没问题,但是程序里面好像跟无响应一样:~~神奇问题,你插上电脑之后先用ide传一遍程序进去就会好。用rts|dts小工具试过也不行,就是ide传程序可以,非常神奇。仅发生在我手上的ch340的arduino nano上,其他板子也许没问题。传过程序之后,只要不断电,reset arduino 不会影响。断电需要重传程序解决。~~ 听国际友人说好像是ch340在arduino上锁i2c什么的?我英语很差,初中水平,看不懂.....反正避免使用328p+ch340即可解决问题。非要用的话,每次重新上电需要重刷一遍程序。 328 | 329 | ~~ 其实我当时这么乱的接线我觉得我必定失败,一定串音,结果上测试程序告诉我静默跟没接一样的一点干扰都没有\(7\-11\),按下能上最高100多的数值\(40\-120\),我超,太美丽了,这必成功,我都不敢相信,但是真的可以!!乱搞万岁 ~~ 删除线挂了,给其它符号转义了也没用,不知道为什么。 330 | 331 | ~~至此,已成艺术品~~ 332 | **至此,触摸部分硬件软件完成,撒花 *★,°*:.☆( ̄▽ ̄)/$:*.°★** 333 | 334 | ## 6\.屏幕部分 335 | 336 | ### 触摸面板跟屏幕的摆放 337 | 338 | 对准位置,然后固定就ok了。也可做成跟我一样的可插拔式。 339 | 340 | 注意屏幕跟触摸面板之间一般需要留出3-5mm的空隙避免屏幕干扰 341 | 342 | 比如像我在边框上加了一圈单面带胶EVA垫(也可双面,直接用于固定屏幕,但是就不能做可插拔屏幕了。 343 | 344 | 345 | 346 | ### 屏幕1p设置 347 | 348 | 我的展示中的1p是因为我有俩屏幕,估计诱骗也非常的可行。 349 | 在显示设置里面设置maimai屏幕为主屏,然后摆放在不作为maimai屏幕的那块的右边,上对齐,就可以了。 350 | 需要启动命令全屏0,然后-popupwindow 351 | 不知道我的方法是否适用于您的屏幕 352 | ![显示设置](Pictures/xianshi001.png) 353 | 354 | 355 | 关于怎么开1p+2p,暂时没有需求,就不搞了( 356 | 应该不难 357 | 358 | ## 第四部分 读卡器个人思路分享 359 | 360 | ![读卡器正](Pictures/dukaqizheng001.png) 361 | ![读卡器反](Pictures/dukaqifan001.png) 362 | 363 | 在最新一次发布的b站展示视频中,可以看见我的读卡器。他最亮眼的部分是均匀的光。其原理是使用了一块拆机的 **屏幕背光板** 进行光的一个导,视频中并非完成品,要做的更完善,需要使用大一点的背光板,配合侧照的灯,而不是我这粗制滥造的测试机的操作,不过对于全尺寸的灯加上手动侧照已经能达到如此不错的效果,等到完善之后效果应该不言而喻的非常不错。 364 | 365 | 目前我看到其他大佬们制作的读卡器,没有使用了本方案的,我觉得这个思路对于光的均匀度方面效果不错,于是就发出来供大家参考。 366 | 367 | 关于读卡器的程序 368 | 使用的是Arduino-Aime-Reader项目。但是注意,这个项目并不原生支持328p。由于~~我家328p奇多~~读卡器并不需要极低的延迟,所以我考虑了使用~~我家奇多的~~ arduino nano(328p+ch340)制作,因为成本低。在过程中遇到了一些问题并解决了,如下: 369 | QA1:程序无法通过编译:需要改改宏,这个上面说过了。 370 | QA2:程序编译正常,readertest正常,手动发包疑似正常,就是游戏不可以:发现游戏发送初始化命令,发送dts/rts或相关内容的时候会让arduino重启(reset触发),显然不对劲,因为在重启过程中,游戏发包arduino不会给出回应。尝试短接rst与3v3强制禁止其重启,问题解决。 371 | ``` 372 | 但是usb转串口可以重启arduino不是bug而是一个不错的功能,arduino在下载程序的时候需要重启才可以开始。电脑可以让arduino重启本身是为了方便下载程序而做出的美好设计,但是在此处影响了功能。 373 | 如果直接短接会造成无法正常下载程序。我的解决方法是在rst跟3v3直接加一个开关,下载程序就断开,当读卡器的时候就闭合。 374 | 这样也许会?对复位电路产生略微的短路,但是目前使用效果极佳,就先这样用了。 375 | ``` 376 | 377 | ## 第五部分 已删除 378 | 379 | ## 第六部分 按键和灯光 380 | 381 | ![不存在的按键,和简单的灯光](Pictures/anjiandeng001.png) 382 | 383 | 直接promicro做成键盘就完事,这个人人都会不用教网上一抓一大把。 384 | 据说可以把灯光塞进跟按键同一个promicro,但是我没试过( 385 | 在todo列表中 386 | 待完成 387 | 388 | 由于up主不再想造街机大小的控制器,关于制作街机尺寸的按键应该是等不到了。 389 | 390 | 小台(14寸或类似)按键制作方法,即将完成和发布(约11.5前) 391 | 小台按键教程比触摸还难,作者认为不适合本文风格,很有可能不发了,发也是开另一个项目,感觉意义不大 392 | 393 |
394 | 395 | ------ 396 | END SEL                                                                  DOCUMENT BY HELLOWORLD_DK 397 | -------------------------------------------------------------------------------- /newmap-llvermtn202212271340/newmap-llvermtn202212271340.ino: -------------------------------------------------------------------------------- 1 | //llvermtn202212271340.ino with new!! map 2 | 3 | #define SerialDevice Serial 4 | #define Threshold 60 5 | #include "Adafruit_MPR121.h"//mpr121定义 6 | Adafruit_MPR121 mpr[5]; 7 | 8 | class touchblock { 9 | public: 10 | uint8_t mprid; 11 | uint8_t portid; 12 | uint16_t thres; 13 | }; 14 | 15 | 16 | /* 17 | {mprid,portid,threshold} 18 | 19 | mprid: the id of mpr,1 = 0x5a,2=0x5b,3=0x5c,4=0x5d 20 | portid: mpr pin port,0-11 21 | threshold:threshold) 22 | 23 | remember all cap.writeRegister(MPR121_ECR, B10000000 + XXX);(total 5) ,the XXX must > max{portid}+1. 24 | 25 | */ 26 | touchblock touchmap[34] = { 27 | // Group A 28 | {1, 0, 40}, //1 29 | {1, 6, 40}, //2 30 | {2, 0, 40}, //3 31 | {2, 7, 40}, //4 32 | {4, 0, 40}, //5 33 | {4, 7, 40}, //6 34 | {3, 0, 40}, //7 35 | {3, 6, 40}, //8 36 | //Group B 37 | {1, 1, 40}, //1 38 | {1, 4, 40}, //2 39 | {2, 1, 40}, //3 40 | {2, 5, 40}, //4 41 | {4, 1, 40}, //5 42 | {4, 5, 40}, //6 43 | {3, 1, 40}, //7 44 | {3, 4, 40}, //8 45 | //Group C 46 | {2, 4, 40}, //1 47 | {4, 2, 40}, //2 48 | //Group D 49 | {3, 7, 40}, //1 50 | {1, 2, 40}, //2 51 | {1, 7, 40}, //3 52 | {2, 2, 40}, //4 53 | {2, 8, 40}, //5 54 | {4, 3, 40}, //6 55 | {4, 8, 40}, //7 56 | {3, 3, 40}, //8 57 | //Group E 58 | {3, 5, 40}, //1 59 | {1, 3, 40}, //2 60 | {1, 5, 40}, //3 61 | {2, 3, 40}, //4 62 | {2, 6, 40}, //5 63 | {4, 4, 40}, //6 64 | {4, 6, 40}, //7 65 | {3, 2, 40}, //8 66 | }; 67 | 68 | 69 | 70 | 71 | #define CLAMP(val) (val < 0 ? 0 : (val > 255 ? 255 : val)) 72 | uint8_t packet[6]; 73 | uint8_t len = 0;//当前接收的包长度 74 | 75 | enum { 76 | commandRSET = 0x45,//E 77 | commandHALT = 0x4C,//L 78 | commandSTAT = 0x41,//A 79 | commandRatio = 0x72,//r 80 | commandSens = 0x6B,//k 81 | }; 82 | 83 | bool Conditioning = 1; 84 | void setup() { 85 | SerialDevice.begin(9600); 86 | SerialDevice.setTimeout(0); 87 | mpr[1].begin(0x5A, &Wire); 88 | mpr[2].begin(0x5B, &Wire); 89 | mpr[3].begin(0x5C, &Wire); 90 | mpr[4].begin(0x5D, &Wire); 91 | Wire.setClock(800000); 92 | 93 | } 94 | 95 | void loop() { 96 | Recv(); 97 | Conditioning ? void() : TouchSend(); 98 | } 99 | 100 | void MprSetup(Adafruit_MPR121 cap) { 101 | cap.writeRegister(MPR121_SOFTRESET, 0x63); 102 | delay(1); 103 | cap.writeRegister(MPR121_ECR, 0x0); 104 | cap.writeRegister(MPR121_MHDR, 1); 105 | cap.writeRegister(MPR121_NHDR, 16); 106 | cap.writeRegister(MPR121_NCLR, 4); 107 | cap.writeRegister(MPR121_FDLR, 0); 108 | cap.writeRegister(MPR121_MHDF, 4); 109 | cap.writeRegister(MPR121_NHDF, 1); 110 | cap.writeRegister(MPR121_NCLF, 16); 111 | cap.writeRegister(MPR121_FDLF, 4); 112 | cap.writeRegister(MPR121_NHDT, 0); 113 | cap.writeRegister(MPR121_NCLT, 0); 114 | cap.writeRegister(MPR121_FDLT, 0); 115 | cap.setThresholds(Threshold, Threshold); 116 | cap.writeRegister(MPR121_DEBOUNCE, (4 << 4) | 2); 117 | cap.writeRegister(MPR121_CONFIG1, 16); 118 | cap.writeRegister(MPR121_CONFIG2, 1 << 5); 119 | cap.writeRegister(MPR121_AUTOCONFIG0, 0x01); 120 | cap.writeRegister(MPR121_AUTOCONFIG1, (1 << 7)); 121 | cap.writeRegister(MPR121_UPLIMIT, 202); 122 | cap.writeRegister(MPR121_TARGETLIMIT, 182); 123 | cap.writeRegister(MPR121_LOWLIMIT, 131); 124 | cap.writeRegister(MPR121_ECR, B10000000 + 9 ); 125 | } 126 | void cmd_RSET() {//Reset 127 | MprSetup(mpr[1]); 128 | MprSetup(mpr[2]); 129 | MprSetup(mpr[3]); 130 | MprSetup(mpr[4]); 131 | 132 | 133 | } 134 | void cmd_HALT() {//Start Conditioning Mode 135 | mpr[1].writeRegister(MPR121_ECR, 0x0);//MprStop 136 | mpr[2].writeRegister(MPR121_ECR, 0x0); 137 | mpr[3].writeRegister(MPR121_ECR, 0x0); 138 | mpr[4].writeRegister(MPR121_ECR, 0x0); 139 | Conditioning = true; 140 | } 141 | 142 | void cmd_Ratio() {//Set Touch Panel Ratio 143 | SerialDevice.write((byte)'('); 144 | SerialDevice.write((byte)packet[1]);//L,R 145 | SerialDevice.write((byte)packet[2]);//sensor 146 | SerialDevice.write((byte)'r'); 147 | SerialDevice.write((byte)packet[4]);//Ratio 148 | SerialDevice.write((byte)')'); 149 | } 150 | 151 | void cmd_Sens() {//Set Touch Panel Sensitivity 152 | SerialDevice.write((byte)'('); 153 | SerialDevice.write((byte)packet[1]);//L,R 154 | SerialDevice.write((byte)packet[2]);//sensor 155 | SerialDevice.write((byte)'k'); 156 | SerialDevice.write((byte)packet[4]);//Sensitivity 157 | SerialDevice.write((byte)')'); 158 | } 159 | 160 | void cmd_STAT() { //End Conditioning Mode 161 | Conditioning = false; 162 | mpr[1].writeRegister(MPR121_ECR, B10000000 + 8);//MprRun 163 | mpr[2].writeRegister(MPR121_ECR, B10000000 + 9); 164 | mpr[3].writeRegister(MPR121_ECR, B10000000 + 8); 165 | mpr[4].writeRegister(MPR121_ECR, B10000000 + 9); 166 | } 167 | 168 | void Recv() { 169 | while (SerialDevice.available()) { 170 | uint8_t r = SerialDevice.read(); 171 | if (r == '{') { 172 | len = 0; 173 | } 174 | if (r == '}') { 175 | break; 176 | } 177 | packet[len++] = r; 178 | } 179 | if (len == 5) { 180 | switch (packet[3]) { 181 | case commandRSET: 182 | cmd_RSET(); 183 | break; 184 | case commandHALT: 185 | cmd_HALT(); 186 | break; 187 | case commandRatio: 188 | cmd_Ratio(); 189 | break; 190 | case commandSens: 191 | cmd_Sens(); 192 | break; 193 | case commandSTAT: 194 | cmd_STAT(); 195 | break; 196 | } 197 | len = 0; 198 | memset(packet, 0, 6); 199 | } 200 | } 201 | 202 | void TouchSend() { 203 | 204 | uint64_t TouchData = 0; 205 | for (int i = 33; i >= 0; i--) { 206 | TouchData <<= 1; 207 | TouchData = (TouchData | 208 | (int)(mpr[touchmap[i].mprid].baselineData(touchmap[i].portid) - 209 | mpr[touchmap[i].mprid].filteredData(touchmap[i].portid) + 210 | 20) 211 | > touchmap[i].thres) ; 212 | } 213 | 214 | SerialDevice.write((byte)'('); 215 | for (uint8_t r = 0; r < 7; r++) { 216 | SerialDevice.write((byte)TouchData & B11111); 217 | TouchData >>= 5; 218 | } 219 | SerialDevice.write((byte)')'); 220 | } 221 | -------------------------------------------------------------------------------- /newmap-llvermtn202212271340/接线设计来自学习制作者春暖花开: -------------------------------------------------------------------------------- 1 | 接线设计来自学习制作者 春暖花开 2 | -------------------------------------------------------------------------------- /newmap-llvermtn202212271340/此版本可以单独调整每一个区块的连线和阈值!newmap-llvermtn202212271340.txt: -------------------------------------------------------------------------------- 1 | 接线设计来自学习制作者 春暖花开 2 | -------------------------------------------------------------------------------- /onlytest_single2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/onlytest_single2.zip -------------------------------------------------------------------------------- /tn/2.md: -------------------------------------------------------------------------------- 1 | # Preview版本 不代表最终品质 请静等更新 2 | # 自制省钱高性价比maimaiDX触屏控制器新版教程 3 | ## 与旧版的比较 4 | 1. 采用最新做法编写新教程,采用最新的研究成果,与最前沿的思路 5 | 2. 新版走线方式,干扰更少,性能更高 6 | 3. 简化制作步骤,制作更美观 7 | 4. 将教学群内教学内容和文章结合,配合大家曾经提出的问题加以细致解释,避免困惑 8 | 5. 也许以后标题会改成"自制省钱高性价比maimaiDX全套控制器新版教程" 9 | 6. 添加过程图片和更多的原理解释 10 | 11 | 12 | ~~旧版文档相当落后没有更新,内部做法很多已经弃用,非常丢人,非常乱~~ 13 | 14 | 15 | **本教程着重关注触屏这一部分,对于按键,固定结构等并不关注,也不提供教程,后续可能会加,但是不要期望现在的以下内容会有结构,按键,屏幕之类的内容,更不会提供任何关于游戏软件的任何支持** 16 | **目前着重更新主要内容部分,对于协力者感谢,版权声明和一些公告,一些注意事项,一些会大概率导致失败的制作细节反例,请参阅旧版教程!!!(在上面代码那块里面)** 17 | **本文章硬件部分制作完全原创,若有类似,可能是平行互不干扰的项目** 18 | **程序部分是基于已有开源项目经过调试参数数周修改得到,并非直接搬用,可以自行查阅代码,很多部分不一样** 19 | ## 第一部分 总览 20 | 21 | 本作品旨在弄个便宜好用的方案,让大多数人都可以轻松把这个东西做出来,同时不要效果差到没法玩。 22 | 新教程的思路是引导思考,提出不同做法来比较,让您自行选择自己喜欢的做法去做 23 | 24 | **[成功作品展示]** 25 | 26 | Under Wrinting 27 | Todo:Add pictures 28 | 29 | **以下说法是个人定义,配合解释,可能对很多人不适用,自行判断哦!** 30 | **以下说法仅适用于触屏部分在完全按照要求** 31 | 难度:**一般** 32 | ``` 33 | **不对所有人制作难度做保证,以下内容为对部分人来说制作难度的一种参考** 34 | **每个人的实现都不一样,每个人买到的材料也不一样,每个人成功与否,效果好不好肯定也不一样** 35 | 其实触屏这块制作已经被简化了很多,改进了很多, 36 | 旧版教程很多东西都已经弃用,此新版做法相当好理解, 37 | 我认为对于16岁以上有耐心的大部分人都可以完成, 38 | 其中最要求严格的就是裁切和贴装ito膜,要求严格的精确, 39 | 其他部分,就【触屏这块触摸面板部分】而言, 40 | 已经没有任何难度,不需要特别多的思考。 41 | 几乎不需要有代码能力,代码开箱即用, 42 | 只需要调整少量阈值即可。 43 | 按照教程严格规范制作,目前未见有人失败 44 | 有失败或者教程很差的,可以看看他们的不听话,触摸区块裁的歪歪扭扭, 45 | 贴的一边近一边远,根本不按要求来,不按照教程要求来,这失败本教程不背锅 46 | ``` 47 | 48 | 成本:**按照已有工具情况下计算较低** 49 | ``` 50 | 就这样说吧,43寸触摸面板(不算按键,固定什么的,只算这块玻璃和旁边木板) 51 | 有工具的话500元以内就可以搞定了,省着些,细心些,避免浪费,可能三四百就结束了 52 | ``` 53 | 54 | 耗时:**可能较长** 55 | ``` 56 | 快递很慢是主要原因。 57 | 其次虽然操作都简单,但是裁切,贴装,引线,都是大量重复简单事情, 58 | 所以虽然简单,都是需要耐心,耗费时间可能较多一些 59 | ``` 60 | 效果:**大概是目前来说最好的自制法了吧,已测试一般运行,打歌没有啥问题, 61 |            主要是自制的玩家好像技术都是中等级别,主要是没大爹测试,测不到 62 |            性能极限(现在受限本方案测试的玩家个人水平,在官方机台也无法打 63 |            出更好成绩,更无法测试自制台上限,故目前本方案上限未知,并非方 64 |            案自身有问题)** 65 | ``` 66 | **不对制作效果做保证,以下内容为对制作效果的一种参考** 67 | **每个人的实现都不一样,每个人买到的材料也不一样,每个人成功与否,效果好不好肯定也不一样** 68 | 感应,手套触摸各方面都没有问题。 69 | 两位佬说,触摸灵敏度优于他们那边的机台 70 | 一位佬说,触摸灵敏度没有达到官机一根手指直立也能稳定感应的那么厉害 71 | 延迟,刷新率按照理论计算理论上优于机台上那块触摸面板 72 | 但是对于虚空触发(手不放上去,也会有自动点击的现象), 73 | 根据每个人做的不一样,显示器发出的干扰不一样,还是有一些的。 74 | 好像43寸这种情况,大约几分钟内分钟有个一下两下的? 75 | 虽然可能会少量影响心情,但是佬们表示好像并不影响打歌? 76 | 32寸以及32寸以下,这种情况好像没听说过有 77 | 并且虚空触发好像在经常触摸屏幕的情况下,会变少很多,或者几乎不发生 78 | 所以按照这样,打歌过程中应该是不会有影响的 79 | ``` 80 | 81 | ## 第二部分 注意事项和声明 82 | Under Wrinting 83 | 84 | **本教程仅仅为了以下目的:** 85 | 1. 不为追求完美的外观 86 | 2. 不为追求完美无缺的使用体验 87 | 3. 不为追求每个人都必须成功 88 | 4. 不追求绝对的高性能,做到基本13+能够正常打,再高性能不做保证(目前有用本方案14+ S评级的验证,受限于游玩者个人水平,目前无法确认最高性能在哪里(他在官机上也无法完成更高成绩)) 89 | 5. 在成本低,难度低的情况下做出一个**能用**的基本触摸面板 90 | 6. 故高价定制蚀刻面板等操作,不在本项目讨论范围内 91 | 7. 判定精准>美观性 我们不会为了美观而做某些方案触摸到漂亮的分区走线就会导致区块触发的蹭的方案,我们认为还原判定比美观要好 92 | 93 | ### 不保证每个人都能成功,失败或者效果差与本教程无关 94 | 本教程并非最好做法,只是万千做法的其中一个而已,如果你有更好的思路,欢迎分享出来帮助大家!(而非觉得自己很厉害就来喷这个方案,你很厉害可以发出来造福大家啊,而不是完全闭源,诶,我比你厉害,我比你好,但是就是不发,自己想想真正需要方案的玩家会赞同你吗,大家支持的是能帮助到大家的人,把方案开源,分享思路,推动进步,人人支持!) 95 | 我们的目的是为玩不到的玩家能玩到,并非自己做一个就不用去游戏厅花钱,若有游戏厅近,请支持官方机台。 96 | 97 | ## 第三部分 对于现在不同触屏大方向的对比 98 | 目前主流做法有以下几种: 99 | 100 | 1. 红外触屏框 101 | 2. 普通多点触控电容屏 102 | 3. 分区触控电容屏(与官方相同的实现方法) 103 | 104 | 以下进行对比 105 | 106 | #### 1. 红外触屏 107 | 采用横竖摆放大量红外对射LED和接收管的方式,依据光在均匀介质中沿直线传播的特点,手穿过光线,主控检测到阻挡后就会判断已经触摸上。 108 | 缺点:因为需要巨量的轮询xy轴相当多的接收管状态,此类屏幕一般延迟较高;因为是挡光形式的,设想两只手斜着平行放入触摸区域,因为挡光的问题,会被错误的识别,因而造成无法正常触发的问题;由于反馈给电脑,一整个大手上去会被识别成手中心一个触摸点,故只有中心位置一个区块会触发,造成严重的一个吃,特别是一些邪道不能用,不能糊,要避免,必须要用分离的手指打歌,并指都可能出问题。走普通hid触摸协议,windows下会显示触摸点,长按会出框右键等。 109 | 优点:凡不能透光的物体都能触发,根本不担心手套触摸;此类触摸框相当便宜,43寸也就四百以下?不仅可以用于mai,也可以用于其他地方。 110 | 改进:红外框具有读取触摸点长宽的能力,如果能把这点用好,就能基本估算手完全遮挡哪些区块,避免吃的现象发生(类似希沃、东方中原白板板擦识别功能)此思路目前未见有人做 111 | 由于目前延迟,吃,不能手掌多方面问题,我认为这不是三个方法中最好的方法。 112 | #### 2. 普通多点触控电容屏 113 | (跟现在普通手机或者平板触摸屏是一个东西) 114 | ~~没有详细了解过具体原理,以下是猜的~~ 115 | 大概是横竖许多条触摸条,同样通过xy双方向读取,与红外不同的是,此操作没有跟红外一样一挡光就全没了这种,所以各触摸点互不影响。同样,此方法触摸条不多,轮询较快,延迟低。 116 | 缺点:一个大触摸点类似手掌上去,最离谱的情况下也是会被认为是一个触摸点,跟红外一样,手掌覆盖的所有区块不能全部触发,因此跟红外一样会有一个严重的吃,特别是一些邪道不能用,不能糊,要避免,必须要用分离的手指打歌,并指都可能出问题。另外市售成品电容触摸外屏可能对手套触摸的支持存疑。价格可能较高。走普通hid触摸协议,windows下会显示触摸点,长按会出框右键等。 117 | 优点:延迟较低,不仅可以用于mai,也可以用于其他地方。不会受类似红外遮挡就挂的影响。 118 | 改进:部分电容屏幕也具有读取触摸点形状和大小的能力,虽然一个异形物体只会被识别成一个触摸点,但是实际上数据里面是有具体形状大小的,如果能把这点用好,就能大概计算手完全遮挡哪些区块,类似android9彩蛋画图,不过那个用的是电容屏压力感应功能,大差不差,如果你有LG G8(?不记得了),开发者模式打开触摸点显示那一类的,用手指换着接触面形状点击屏幕,可以看到屏幕对于触摸点形状大小的描绘,如果你有surface,打开surface诊断工具,到触摸点个数那块,也能体验到电容触屏对于形状大小识别方面的效果。 119 | 由于目前吃,不能手掌,手套可能不行多方面问题,我认为这不是三个方法中最好的方法。 120 | #### 2. 区块触摸电容触屏方案 121 | **目前认为是官方机台采用的方案** 122 | 缺点:没有现成售卖的低价成品,要低价实现,必须自己做,根据方案不同,可能存在不同的缺点,因此此处无法描述,但是吃之类的,不能邪道之类的缺点全无,大多都能做到官机体验,完全一样的判定等。只有区块可以触摸,不能用作普通触屏使用。一般需要距离显示屏一小段距离才能正常工作 123 | 优点:走原生通道,不经过windows触摸,没有显示触摸点,右键等奇葩情况。一般延迟极低。手接触到的区块全部可以同时触发。可以使用跟官方机台一样的手法,操作,不吃,可糊。价格低。官方类似实现方案。可用、灵敏的手套触摸 124 | 由于跟官方机台手感,手法可用一致,延迟低,手套触摸,我认为这不是三个方法中最好的方法。 125 | **以下制作就是我自己思路自行设计的区块电容触摸方案,只有这一个,红外的,普通电容的,这里不教,也没什么好教的,那些到手即用** 126 | 127 | 128 | 每日怨言 129 | ![dummy](pics2/IMG_20230711_100851.jpg) 130 | 131 | 132 | ## 第四部分 区块电容触摸屏设计总览 133 | **本部分目的:使读者明白总体结构,明白个大概,更好地理解制作难度,选择做还是不做;使读者知道整个基本框架是什么样子,大概都有什么部分;使读者知道大概需要什么材料,为下一部分的选材做铺垫** 134 | 135 | ![区块电容触摸屏设计总览1](pics2/touchall.jpg) 136 | **从上图可以看出,整体触摸面板结构还是非常简单的!** 137 | (~~删除线~~内容是新教程Preview版本编写时候写了又感觉不合适删减了的内容,留做参考但是主要内容一定会有新写法替代删除的内容而且写得更好,所以这部分内容一般选择直接跳过为好) 138 | ~~**同时可以看出,需要的材料基本有以下内容:**~~ 139 | ~~1. ITO导电膜(**单面带胶**(重要!!!我自己当时贪便宜没有带胶,回来自己上胶非常困难和丑,很难把厚度掌控好,很累很累,做出来非常难看!!))~~ 140 | ~~2. 漆包线~~ 141 | ~~3. mpr121模块 3-4 个(总共34个区块8A8B2C8D8E,每个mpr121从0-11共12个触摸点支持,故最少3个mpr足够,为了走线布线好走,目前大多选择4个)~~ 142 | ~~4. 固定漆包线到ito导电面的材料~~ 143 | ~~5. 透明板一块,建议正八边形,也可以自己选择,但是圆形很少有人用(难以固定)~~ 144 | ~~6. 普通连接线,连接mpr模块和单片机开发板(不在图片内)~~ 145 | ~~7. 单片机开发板~~ 146 | 147 | ~~**显然还需要很多工具对吧 ~~ 148 | ~~焊接系列**~~ 149 | ~~1. 调温电烙铁~~ 150 | ~~2. 焊锡丝~~ 151 | ~~3. 助焊剂(重要!!)~~ 152 | ~~4.(可选)维护/辅助用的工具,如高温海绵,吸锡带之类的焊接辅助用具~~ 153 | 154 | ~~**其他工具**~~ 155 | ~~1. 去除漆包线漆皮用的工具~~ 156 | ~~2. 螺丝刀等固定用的工具~~ 157 | 158 | ~~特殊工具~~ 159 | ~~部分先进做法如[自行蚀刻法]将会使用,暂时没有编写完对应做法,于是这里暂时不编写~~ 160 | 161 | **从此部分开始,因为现在可选做法很多,就一个区块引出就有好几种做法,每种做法所用材料不同,步骤不同,故以下内容每一章节会有多个分支,请注意选择自己需要的哪一个分支** 162 | 163 | 我们可以看出整体分为以下几个部分 164 | 1. 导电区块 165 | 2. 区块引出 166 | 3. 区块引出线固定 167 | 4. 触摸检测模块 168 | 5. 主控单片机(图中未拍到) 169 | 6. 基层透明板 170 | 7. 固定材料和大底板 171 | 172 | 以上所示内容现在有多种实现方式,故**现在展示主要划分,下文对每种做法详细说明,并教你如何选材**。因为实现方式不同,需要准备的材料也不同,故这里并不会说明具体材料,只有个大概。 173 | 174 | ## 第五部分 实现方式和材料选择选型指南 175 | 176 | **针对上文提出的七个部分,分别讨论具体实现方式和选材方向** 177 | **注意,部分做法是可选择性的,例如可以这一步选择A做法下一步选择B做法,自由组合,但是也有做法是一路到底的,例如这一步选择C做法以后所有都要选C来配合了** 178 | ### 1. 导电区块 179 | 180 | 导电区块说的是对于分区电容的一共34个区块,怎么实现让这几个区块导电且透明和怎么实现区块形状大小的限定 181 | 182 | 主要解决的是: 183 | 1. A用什么材料实现能导电还能透光 184 | 2. B怎么做出所需形状的导电区块 185 | 186 | 目前的主要实现方法: 187 | 188 | 首先我们知道,我们需要导电的区块依然透光能看见屏幕上面显示的什么。首先就是这种材料应该怎么选择,我搜集到的有以下方式 189 | #### 1. 导线画圈法(外源(看到别人这样做过,非本人思路)) 190 | 191 | 使用导电的线打圈制成类似一个面的形态,同时因为线间距大,可以透过光线,还可以看到屏幕 192 | A: 使用导线画圈,既导电还透光 193 | B: 画不同的外轮廓实现不同形状 194 | **理论可行,虽然没有已知测试证明此方法真的成功可用** 195 | ![mgxy1](pics2/mgxywzt_lineway.png) 196 | 197 | 成本:接近0 198 | 外观:不是很好看 199 | 成功率:未知 200 | 灵敏度:未知 201 | 难度:看起来很简单 202 | **本方案并非来自我团队设计或已经试验可行,故下文不会支持** 203 | #### 2. ITO裁切法 204 | ~~鄙人自己想出来的做法~~ 205 | 206 | 有一种东西叫做ITO导电膜,是在塑料离型膜上面做了一层氧化铟锡来导电,他基材是塑料非常便于裁切,透光性极佳,只有一点点微黄色忽略不计,成为我最开始选材时候找到的评估后觉得最好的材料 207 | 208 | A: ITO导电膜,既导电还透光 209 | B: 通过直接裁剪获取不同形状 210 | 211 | 通过裁切导电膜获取对应的单片区块 212 | ![dummy](pics2/caiqie003.png) 213 | 214 | 成本:便宜 215 | 外观:还好还好 216 | 成功率:只要细心裁切准确,成功率相当高 217 | 灵敏度:很好 218 | 难度:细心细心就很简单!!剪纸而已嘛 219 | 220 | 材料选型方向: 221 | 222 | 对于ITO膜的选择,目前大概只有俩问题 223 | 带胶还是不带胶?买多少方阻的? 224 | 225 | 带胶是一定要带胶的,怎么说都要带胶的,带胶膜好用又舒心((( 226 | 方阻目前测试150欧姆以下的均可,再大没有测试过。 227 | 据说4?张A4的ITO就足够,应该是45元*4 差不多吧,但是其实如果可以的话,可以这样来操作,可以便宜一些 228 | 如图: 229 | 230 | ![dummy](pics2/cheapito.png) 231 | 232 | ito膜一般都是$406mm宽度*裁切长度$,如果店家支持自定义长度,那么按照图片的摆放方式,使用约95元即可实现所有区块,按照道理来讲,可以三人合购一张等效1平方米的($406*2463$),然后理论上可以裁出3.8套43寸台用区块,按照3来计算,每人均价86元!! 233 | 234 | 235 | **ITO裁切法在下方引线处会分成两个类型来讲** 236 | 237 | #### 3. ITO自制蚀刻法 238 | 目前认为此方法如果真的做了完整的43寸大小这将是自制触摸最优解 239 | 在此这里提一嘴定制蚀刻法 240 | **定制蚀刻法** 241 | 通过在一片60x60左右大小的玻璃或ITO膜上,让工厂在上方预先做好分区和走线,这样完全没有裁切痕迹,也没有下2.区块引出的线的痕迹,非常漂亮,官方和某商业台大概是这样的做法,也有可能是磁控溅射,反正就是这一类工厂定制形式。 242 | 定制成本:**打样一片8000+** 243 | 根据本项目的目的,直接否决,成本难以接受 244 | **但是将分区和走线直接蚀刻好来达到这个完美的效果就只有这一种方法吗,我们要不要...** 245 | 联想在pcb打样巨贵没有现在JLC的价格的时候,我们要用pcb是怎么制作的呢...是不是,可以迁移运用一下... 246 | 参见 [思路引出](https://www.bilibili.com/video/BV1hV4y1r7ZV) 247 | **注意,请勿在非相关场合提及非相关内容,例如在我的其他视频底下谈论音游相关,或者在与音游无关的群因为我的存在而提起我在音游方面的项目,这真的会让在这些无关场合下其他人感到困惑和不解** 248 | 249 | 此方案只做了三个区块的验证,主要是作者实在贫穷,做实验的ITO膜还是群里的佬送的,工具是赞助的... 250 | 于是**此方案仅经过少量验证,未做一个大的完整的来验证** 251 | **此思路完全原创!!!!!** 252 | **图片里面的蚀刻已经接mpr121测试通过!** 253 | **此方法为试验期,下述教程可能在开始编写时不包括自制蚀刻的具体教程内容** 254 | 255 | 提示:ITO膜不只有$406*length$一种,还有$1250*length$,两人合购$1250*600$,再裁开$2 * 625*600$(((( 256 | 257 | ![dummy](pics2/20230710200504.jpg) 258 | 259 | **LATEX公式渲染可能存在问题,建议查看md文档原文,此写法在VSCODE自带md渲染器里不存在bug,但是github渲染会出错,会latex的大佬可以开个issue或者pullrequest帮忙解决下((,感激不尽** 260 | 261 | ![dummy](pics2/zizhishike1.jpg) 262 | 263 | 于是我们使用自制蚀刻法, 264 | 265 | 成本:单触摸屏带蚀刻工具共700内 266 | 外观:顶级完美(不仔细对光看不出区块) 267 | 成功率:未知 268 | 灵敏度:很好 269 | 难度:不难,弄明白就好 270 | 危险性*:需要戴手套操作化学试剂 271 | *:只在此方案存在 272 | todo 273 | 274 | ### 2. 区块引出 275 | 276 | 区块引出说的是对于已经划分出来的能导电的透明的区块,如何把区块引出到触摸面板边缘并连接触摸检测模块 277 | 278 | 目前大概也许好像是有三种比较常见的方法 279 | 280 | 主要解决的是: 281 | 282 | A用什么材料导电 283 | B怎么做的美观一些 284 | 285 | 目前大概也许有这三种办法 286 | **前两种对应前文ITO裁切法使用** 287 | **最后一种是ITO化学蚀刻法专属** 288 | 289 | #### 漆包线引线法 290 | 291 | **鄙人自己想的个人认为最简单的方法!** 292 | 293 | 使用漆包线进行引出,顾名思义 294 | 见下图(但是实际做的时候一定要理好线!) 295 | ![dummy](pics2/qbx.png) 296 | 297 | 很简单对吧~(chuni企鹅) 298 | 299 | **漆包线选型:** 300 | 301 | 材质: 铜?铝? 302 | 303 | 考虑到漆包线本身很细且都会挡光,屏幕开启状态下都是一条细细的黑线,线本身是银色的还是黄色的都无所谓,为了焊接舒服,选择铜的为优(铝不沾锡) 304 | 305 | 粗细? 306 | (以下内容来自设计群第一批成员自发整理,在此表示感谢) 307 | (以下内容为设计群洛梨&苦鱼试验巨量漆包线得出,在此表示感谢) 308 | 较细的漆包线(**推荐使用 0.1 0.13mm**的规格,有信心可以选用 0.07mm)。 309 | - 最好一头,就是统一贴 ito 膜上的,用脱漆剂统一一次性脱漆多根。 310 | - **使用脱漆剂务必注意安全**! 311 | - 首次使用建议带好手套、口罩做好个人防护,**接触到皮肤会有灼烧感**。 312 | - 第一次打开有出现**内含气体而炸出一些的情况**,请知悉。 313 | - **0.13 的可以火烧退漆和打磨退漆**,不必使用脱漆剂,更方便。 314 | - 细的漆包线不是老司机,不能刮漆,需要脱漆剂,比较麻烦。 315 | 316 | 优点: 317 | 1. 超级无敌简单,操作非常容易!! 318 | 2. 成本巨低!! 319 | 3. 线可以随意放位置,自由自在,可以距离区块和触摸平面距离加大防止线上的感应 320 | 321 | 缺点: 322 | 1. 明线不可避免的会能看得见,但是对比43寸,它真的很小很小很小很小根本不会注意到 ``` (引用)你星星方向都看不清楚还看线 打歌的时候哪有精力看线``` 323 | 324 | 325 | #### ITO裁切带线法 326 | (外源试验&思路平行) 327 | 在裁切ITO的时候不仅裁切一块区块,同时提前设计好走线并跟随ITO同时裁切出来 328 | 329 | 参见: 330 | 331 | ![itolineA](pics2/itolineA.png) 332 | ![itolineB](pics2/64487299ec4fd8f8f76f5ab4a3d3574613060190.png) 333 | ![itolineC](pics2/_9c71d0aeb05dcb9d64f227d082b27e66_-1674909351_IMG_20230629_113243.jpg) 334 | 335 | 图片应该就很明白了 336 | 337 | 338 | 选型参考上文ITO选型,因为没有什么特别新加入材料,所以就没有专门的选型指南 339 | 340 | 优点: 341 | 1. 没有明线,线是ITO本身,是透明的,比较美观,接近蚀刻的效果,**非常漂亮** 342 | 2. 线本身就是带背胶的膜,所以不用考虑任何固定,不用任何额外的胶,没有胶痕很美观,也不用操心固定 343 | 3. 整体是平的,没有线的突起,如果采用实验性双层做法,玻璃盖在平面显然比玻璃盖在线上要好 344 | 4. 据说ITO膜折射率和一些UV紫外胶水很类似,如果缝隙填胶,有可能可以让膜边界和本体不可见,可能可以做出蚀刻的效果 345 | 346 | 缺点: 347 | 1. 做起来麻烦,膜裁细线需要非常细心 348 | 2. 不能跟上面一样排版区块,需要考虑线的存在,这样,ITO膜上可能要加100CNY左右成本 349 | 3. 依然有ITO裁切边界的痕迹,没有做到蚀刻那种完全完美 350 | 351 | #### 蚀刻线 352 | 一个非常显然的结论是跟上面区块一起蚀刻出来就好了 353 | 优缺点跟上面那个区块蚀刻是一起的 354 | 355 | 356 | ### 3. 区块引出线固定 357 | 358 | 区块引出线固定说的是对于上述区块引出方式,若使用线等材料,怎么与导电区块间接触固定的实现方法 359 | 360 | 只有漆包线需要固定,膜线和蚀刻都没有这个需求 361 | 362 | 主要解决的是: 363 | 364 | A用什么材料固定,还要透明 365 | 366 | **注:目前还没找到完全无痕的固定方式** 367 | 368 | #### 透明胶带 369 | 老少皆宜,非常好理解对吧(( 370 | 不需要外加任何说明的简单 371 | 372 | 选型: 373 | 只要不是太差的胶带都可以,别自己掉了那种就行(( 374 | 买透明度高的,无色的会好看一些吧 375 | 376 | 优点: 377 | 1. 肉眼可见的简单 378 | 2. 便宜 379 | 380 | 缺点: 381 | 1. 裁切透明胶容易出现胶痕而且切透明胶还是有点麻烦 382 | 2. 透明胶普遍不是粘性特别特别高到不活动那种,有可能造成微量接触不良? 383 | 3. 美观度可能稍微有点..不过还是那句话``` (引用)你星星方向都看不清楚还看线 打歌的时候哪有精力看线``` 胶带也差不多,更何况透明 384 | 385 | #### 进阶透明胶带 386 | 387 | ![进阶透明胶带](pics2/_-132907346__e724d59b98bfc1cbadeffaf42d3683f8_-599726569_IMG_20230629_114720_0_wifi_0.jpg) 388 | 389 | 顾图思义 390 | 老少皆宜,非常好理解对吧(( 391 | 不需要外加任何说明的简单 392 | 393 | 优点: 394 | 1. 肉眼可见的简单 395 | 2. 便宜 396 | 3. 透明度高粘性强 397 | 4. 已经裁切好,无需二次裁切,没有胶痕,圆形观感好 398 | 5. 比普通透明胶稳固一些 399 | 400 | 缺点: 401 | 1. 依然还是能看出来胶带,但是美观度已经好很多 402 | 2. 也许还是有那么一neinei的不稳? 403 | #### UV胶法 404 | 405 | 顾名思义 406 | 407 | 啊,已经很多人做了但是都没有反馈回来具体选型和图片...只有告诉我,体验很好,很稳定.. 408 | 409 | 410 | 优点: 411 | 1. 完全稳固 412 | 413 | todo 414 | 415 | ### 4. 触摸检测模块 416 | 417 | 触摸检测模块是对于已经引出出来的区块,用什么模块/IC来对是否触摸做出检测并作为一定协议的信号与主控单片机通信 418 | 419 | 目前主要有以下选型 420 | 421 | #### MPR 121 422 | 423 | 价格:便宜 424 | 灵敏度:好 425 | 刷新率:好(与I2C速率有关,但是即使是最慢的读取方式,刷新率依然超过官方面板) 426 | 延迟:低(低于官方面板(使用此方案制作,打歌可能出现FAST巨量,考虑在程序里面加个队列增加延迟来解决问题) 427 | 生产状态:目前各大平台均有售卖,但是MPR121是已停产芯片 428 | 每片支持的触摸点数:12 429 | 总线: I2C 430 | 支持的地址切换数:4 431 | 电压(供电及IO):3.3v 432 | **严禁使用5v供电** 433 | 434 | 435 | **目前大多数人使用的都是此方案** 436 | **本教程提供的所有程序均基于mpr121** 437 | 438 | ![dummy](pics2/1688990326190.jpg) 439 | 440 | 此方案附加内容,地址切换教程: 441 | 442 | I2C总线通过地址分别不同设备,MPR121模块默认地址一般是0x5A,我们需要修改其他片的地址,让其工作在不同地址,这样才能一个单片机的一个总线连接多个MPR 443 | 444 | ARDUINO生态 开发板I2C总线已连接设备地址列出工具:[i2cdetect(arduino library)](https://github.com/mcauser/i2cdetect) 445 | 446 | 1. 称取一片分析纯的MPR121 447 | ![dummy](pics2/IMG_20230710_201123.jpg) 448 | 2. 翻到背面,切断ADD跳线,**务必保证切断同时不伤其他线路** 449 | ![dummy](pics2/IMG_20230710_201250.jpg) 450 | 3. 正面焊点,ADD短接GND,VCC,SDA,SCL分别获得地址0x5A,0x5B,0x5C,0x5D 451 | 452 | #### ILITEK 2117A0 453 | 454 | **官方面板触摸IC** 455 | 456 | 目前用这个的且被我知道的仅有一人,无法提供足量信息 457 | 458 | 价格:?? 459 | 灵敏度:官方同款IC 460 | 刷新率:官方同款IC 461 | 延迟:官方同款IC,但是不知道主控程序会不会影响 462 | 生产状态:目前国内各大平台均无售卖,需要海外代购,是否停产不知道 463 | 每片支持的触摸点数:?? 464 | 总线: I2C? 465 | 支持的地址切换数:不需要切换,一片IC电极总数已经足够 466 | 电压(供电及IO):?? 467 | 468 | #### 其他IC 469 | 市面上还有很多各种各样的触摸IC,但是出于都没试过,无法提供信息 470 | 471 | #### 其他事项 472 | 1. 触摸优化: 据某大佬提供,在触摸IC提供的电极接口上串联适当的电阻(几十k到几百k),可组成LC滤波(但是感觉是说错了,应该是RC滤波),增加触摸的稳定性,减少虚空触发等问题。(官方面板有此操作) 473 | 2. 高速总线走线提倡等长原则,即同一片触摸IC模块连接主控的两根信号线应该完全等长,避免数据传输错误或者无法传输。 474 | 3. 本教程提供的程序对于mpr121的调教基本可以适配大多解决方案,但是依然有人(30%)反映少量区块存在虚空触发问题,有能力的大佬建议通过修改mprsetup里的参数,调节mpr适配自己的作品。 475 | 476 | 477 | ### 5. 主控单片机(图中未拍到) 478 | 479 | 主控单片机说的是对于触摸检测好的信号,转换成可以连接电脑的USB/串口信号等用的芯片/开发板 480 | 481 | 考虑的有以下几点 482 | A 单片机性能,包括串口性能,I2C总线性能之类 483 | B 单片机电压(比如如果需要使用mpr121,则IO和供电电压需为3.3v) 484 | 485 | #### 首先讨论串口 486 | **这部分可能非常难懂,以作者语文将近不及格的表达水平来讲解,可能更难懂,不明白的可以不看讲解部分,看加粗部分即可** 487 | 这东西对于只知道普通串口的人比较难以理解,还有部分人借所谓9600波特率太慢来抹黑本项目,只能说,这种人可能连这些串口的原理,或者正常传输的条件都不知道。 488 | 489 | 目前主要有两种, 490 | ##### 一是走usb转串口芯片, 491 | 转变为TTL等信号,再连接单片机,此方法一般延迟较大,但是波特率是满足的,但是经过测试会影响性能。 492 | 代表:Arduino Nano 、UNO等 493 | **这个方案串口最高理论速度133.3333hz刷新率,延迟较高** 494 | 此方案讲解如下: 495 | 496 |
497 | 展开查看 498 |
499 | 
500 | 1. 电脑通过某种设备(板载RS232串口,USB转TTL串口(例如CH340))制造一个硬件串口,单片机一般自带硬件TTL串口
501 | 1. 双方通过串口控制信息初始化串口,包括波特率(传输速度),数据位x位,停止位x位等
502 | 2. 双方交叉连接,以预先被写死的串口控制信息传输串口数据信息,要求双方串口控制信息设置完全相同才能正常传输。不然假设一方以另外一方两倍的速度发送和接受,这边发两个bit那边在同样的时间接收一次,显然就会炸。
503 | 
504 | 那么,游戏程序本身内定串口控制信息是9600的速度,游戏程序打开串口,初始化电脑端为9600波特率,电脑告诉串口设备以9600速度在那两条串口TXRX数据线上发送和接收串口数据信息,那么远端单片机就必须以9600去配合,双方才能正确的传输信息  
505 | 所以这个9600实际上是游戏程序限制的,s公司在开发这个设备的时候就确定了这个波特率,所以不管是官方面板还是自制面板一般都是要使用这个波特率的(为什么要说一般呢,因为见下USB-CDC)
506 | 
507 | 
508 | **以下内容可能让您感到不适**
509 | 
510 | 有的人说“打开程序一看就知道这个方案肯定不行,波特率才9600那么慢,还好意思发出来”这样,不知道是真的不懂还是忽悠不知道串口这玩意的玩家来抹黑这个方案的。
511 | 有本事你用这种走真实存在的串口两条线的串口,不修改游戏的前提下,做一个大于9600波特率的。
512 | 或者说,按照你的说法,9600波特率,就是方案不行,那官方面板9600波特率,官方面板官方机台肯定不行,刷新速度那么慢,打不了大歌,官机只能打打12以下的小歌,大歌1414+打不了(((((  
513 | 就这么说吧,如果程序里面以115200速度打开串口去配合游戏程序,就像你写了个串口通信的程序,单片机程序里是115200,然后电脑串口监视器以9600波特率传输...额,这,但凡接触过串口的都知道这样必挂吧..如果我都说到这份上了还要问“你有什么证据证明官方是9600”,“9600那么慢,官方肯定不是9600,你这9600肯定不行”,我已经没话说了。
514 | 
515 | 
516 | 
517 |
518 | 519 | ##### 二是USB-CDC串口,USB-CDC 520 | 代表:atmega32u4( Arduino Leonardo , micro , sparkfun pro micro ) ,samd21,支持usb的esp32使用usb直连电脑并打开cdc功能,支持usb的stm32使用usb直连电脑并打开cdc功能等 521 | **这个方案最高理论串口方面限制速度166666.6666hz刷新率,延迟极小** 522 | 523 | 此方案讲解如下: 524 |
525 | 展开查看 526 |
527 | 
528 | 大家可能对这玩意不是很熟悉,但是其实大家可能接触过很多这种。  
529 | 叫名字不熟悉,那我说,atmega32u4的板子,samd21的板子之类的,走直连usb连到电脑上,电脑识别的串口就是所谓USBCDC串口,这样熟悉了吧。
530 | 你在这类板子上一般只能看见主控一个芯片,没有ch340等串口芯片
531 | 
532 | 我们知道官方程序里面设定的电脑以9600打开串口,其实这里可以算出官方理论最高屏幕触摸刷新率是多少,未经修改的游戏,触摸数据包每个是9个字节,也就是72个bit,9600波特率也就是9600bits/s,计算得到串口限制每秒最多133.3333个数据包,即官方最高理论极限是133.3333hz,实际上应该是达不到的,所以在这顺便也说一下,其实并不用担心用这个方案做出来的触摸面板的性能,因为官机的性能其实并不是很好,官机延迟大,刷新率低,顺便说一下,还有人说mpr121性能不够来说方案不行的,我只能说,它性能可能不是那么顶尖,但是至少够用,做出来纸面性能大于官方面板,官方面板能干的他都能干,我觉得这就足够了。  
533 | 
534 | 那么为什么说我们的方案的性能,包括刷新率,可以超过官方呢,不是说波特率都被限制到9600了吗?
535 | 
536 | 首先我们要知道9600波特率是在硬件那两条线上面传输的一个提前约定的速度。使用两条线那种传输方式,电脑先以一个高速的线路比如usb告诉usb转串口设备串口控制信息和串口数据信息,usb转串口依靠串口控制信息描述的速度等,在两条线上面发送和接收数据。说白了就是这个9600的速度限制的是那两条线上面的速度,实际上,电脑最本身,系统里面是不管这个速度的,那么如果我们的usb设备从拿到串口控制信息和串口数据信息之后就截胡了呢?
537 | 
538 | usbcdc就是这样一种东西,他提供给usb设备一种通讯方式,在电脑上显示为一个串口,usb设备可以是一个单片机一类,单片机告诉电脑,自己是一个cdc设备,电脑就把他识别为串口,并当作串口去处理他,这个单片机一类的东西自带usb能力,它接收串口控制信息和串口数据信息并进行自己所需的操作:它本身可以作为usb转串口使用,你可以编写程序,让这个设备接收到串口控制信息和串口数据信息之后,像一个usb转串口,ch340一类的东西一样,以串口控制信息的参数把串口数据信息从自身的硬件串口发送出去和接收后传给电脑(官方版arduino UNO的usb转串口芯片,atmega16u2就是这样使用的),当然,自己也可以直接内部处理数据并以usb速率12Mbit/s跟电脑以一个串口的通信方式通信。比如这个单片机可以是atmega32u4,游戏程序打开串口,初始化串口为9600,他拿到串口控制信息9600和串口数据信息之后,直接扔掉了串口控制信息9600,因为他不需要这个东西,这个东西是用来控制硬件两条线串口上面的传输的。因为不经过硬件两条线,他不受波特率等约束,他自身就直接跟电脑以usb12Mbit/s速度通信,他自己自身处理好数据,把数据就直接发给电脑了,速度?12Mbit/s,这样,不受9600的限制,进行传输,没有133.3333hz的理论限制,我们就可以做到超越官方的刷新率,同时没有经过usb或者电脑内置串口芯片转换rs232的步骤,直接使用低延迟的usb通信,延迟也做的比官方低。
539 | 
540 | 
541 | 
542 |
543 | 544 | 545 | 546 | CDC和普通usb转串口的讲解图片,详见读卡器说明文档最后面 547 | [读卡器传送门](https://github.com/HelloworldDk/stm32_aimereader) 548 | 549 | #### 然后我们考虑单片机自身计算性能,电压之类的 550 | 551 | i2c速度: 552 | 553 | 目前基于328p的nano uno等,应该是最慢的一批,基于32u4的,速度较好,使用目前通用程序这种比较慢的读取方式,依然有100hz刷新率,实测完全足够,鬼知道官机实际刷新率低到哪了。 554 | 进阶可以选择samd21,速度较快,达到140-160hz刷新率,超越官方理论极限 555 | 556 | 存储空间: 557 | 558 | samd21开发板碾压32u4和328p,以后要加队列加延迟的话,32u4内存难以胜任,但是samd21非常足够 559 | 560 | 电压: 561 | 562 | 基本每款板子都有对应的5v和3.3v版本,记得选择3.3v版本即可 563 | 564 | #### 总结和对制作的影响: 565 | 566 | 显然串口方面最好选择usb-cdc串口的板子,这就去掉了arduino nano之类的板子 567 | i2c方面 stm32有锅 568 | esp32类似的板子没测试过 569 | 考虑到综合来说 570 | 571 | 新手使用promicro(32u4)较稳,这东西速度略慢,因此对走线要求小,实际上测试100hz也足够打14+歌曲。**建议新手选择此款** 572 | 老手使用samd21比较好,这个刷新率足够快比较安心,但是对走线要求较高,线要略粗,焊接稳定,等长,才能保证高速i2c正常运行,目前有samd21新手用不起来的旧例 573 | 574 | 575 | 576 | ### 6. 基层透明板 577 | 578 | 基层玻璃说的是将区块等内容固定加固的面板和手接触的面板,可能这样说徒增抽象,实际上就是那块手摸到的透明(玻璃一类的)板,也是要把区块贴/做上去的透明(玻璃一类的)板 579 | 580 | 累死宝宝了,先把最推荐选项写进来,然后休息休息以后再补 581 | 582 | 最推荐选项:5-7mm钢化八边形玻璃板,尺寸根据不同的屏幕大小自行计算,非常小的台(20寸以下)可以考虑亚克力,大台禁止亚克力,尺寸越小的台,玻璃板可以越薄,不会打歌时候弯曲就行,保证上面贴的ito导电面跟屏幕显示器之间有大于等于1cm的稳定空隙(越小的台,空隙可以适当减小) 583 | 584 | 摘抄一段之前小批教程第一批成员帮忙整理的文档 585 | 感谢这位无私奉献并且markdown比我写得好的成员 586 | 587 | - 一张较薄的亚克力板或者玻璃板,尺寸至少覆盖圆形屏幕区域。 588 | - 此处感觉**玻璃容易碎和不好固定**,**亚克力容易划花和弯曲**,大家自行斟酌。**新教程更新:目前推荐全部使用玻璃** 589 | ##### 透明板厚度问题 590 | 591 | > 众所周知,我们触摸面板需要距离屏幕一段空气,保证触摸不被屏幕干扰,或尽量少被屏幕干扰。 592 | > 屏幕可以相当于一个导电物体,他里面有很多导电细丝,跟手一样。 593 | > 他靠近触摸区块,会触发触摸,所以我们要保持这块距离。 594 | > 595 | > 考虑亚克力,如果你施加力量于亚克力,他会弯曲,会导致面板在使用的时候不定期靠近屏幕。 596 | > 所以我们需要增加厚度或者换材料来避免这个弯曲,这就确定了**厚度的下限**,也就是最薄不能太薄。 597 | > 关于触摸,我们肯定想要,触摸区块电极能离手越近,越容易产生电容值变化。 598 | > 而触摸是隔着那个透明板操作的,透明板厚度决定手最近距离区块多近。 599 | > 如果太厚,就是太远,难以感应,这确定了**厚度的上限**,也就是最厚不能太厚。 600 | > 根据不同屏幕尺寸,14 寸的透明板面积肯定比 43 寸小。 601 | > 施加一样的力,根据人类智慧,造成影响也不会有 43 寸那么大。 602 | > 一片大亚克力肯定比小的更容易产生全局的弯曲,所以需要根据屏幕大小去选择厚度。 603 | > 除了亚克力还有玻璃,玻璃也是会弯曲的,虽然没有亚克力那么容易,但是要考虑他造成的影响。 604 | > 而且玻璃还要考虑一点,就是**可能会碎**,这个考虑一下。 605 | 606 | 607 | #### 新兴方案 608 | 609 | ##### 双层玻璃 610 | 611 | 先看图,以后解释 612 | 613 | ps:图右边是双层玻璃方案,左边是传统方案 614 | 615 | ![dummy](pics2/IMG_20230619_224416.jpg) 616 | 617 | todo 618 | 619 | ### 7. 固定材料和大底板 620 | 621 | 固定材料和大底板说的是最外面把基层透明板固定,也接驳外面整体固定架子的一块板子,这样说也是徒增抽象,可以看图就是指最外面那个黑色木板和金属固定件类似物体 622 | 623 | 这部分实际上不属于本方案,本方案专注于那块能触摸的玻璃的部分,也就是触摸面板本体,外面的固定,底板这些属于结构范畴,暂不属于教程部分。 624 | 625 | 其次我不会做结构,这部分可能要等别的大佬来写 626 | 627 | **此部分跳过和等待后续更新** 628 | 629 | todo 630 | 631 | ## 第六部分 触摸屏制作详细步骤 632 | 633 | 此主文档讲ITO裁切法相关详细步骤,对于其他方法,将开独立的markdown讲解 634 | 635 | 目前你在 **(主文档)ITO裁切法教程文档** 636 | 637 | 638 | 跳转: 639 | 1. [(主文档)ITO裁切法教程文档](2.md) 640 | 2. [(纯享版)ITO裁切法教程文档](orig1.md) 641 | 3. [完全原创ITO化学蚀刻法教程文档](che1.md) 642 | 4. [reservedpr](pr.md) 643 | 5. [reservedche2](che2.md) 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | #### 某个步骤 打印对照纸 652 | 653 | 对照纸一共有两个用途,第一个是用来和ito膜叠一起来给ito裁切提供参照,另一个是垫在玻璃下面在贴膜的时候对照 654 | 655 | 第一个很简单就不多说了,一共五个形状,一张A4纸大概也许就可以打印的开 656 | 657 | 第二个因为需要完整打印很大的一个面积,所以我们有以下一个常用方法 658 | **窗口打印** 659 | 把整个大图像分割成许多重叠窗口,打印然后拼起来 660 | 具体操作见[百度](https://jingyan.baidu.com/article/fec7a1e5b33df71190b4e790.html) 661 | 怎么拼起来,拼图,不是有重叠吗,透光对准然后拼起来粘起来就好啦 662 | 663 | 有一个常见问题 664 | **打印出来大小不对怎么办** 665 | 家用打印机对打印大小上可能没有那么准确,一般用途无妨但是对我们来说是非常有害的 666 | 667 | 但是每次打印之间要大要小比例一样,通过不断打印,修改图纸/打印缩放,打印测试,对照游戏test区块大小,不断修改缩放,就可以调出一个合适的补偿缩放比率,然后就可以啦 668 | 669 | ## 第七部分 触摸屏制作特别注意事项 670 | 671 | ### 先抄一波旧版教程严禁行为列表 672 | #### 本项目有14寸,15寸,43寸已有人制作成功,如果你没有成功,请不要急着喷项目,因为大有可能是你制作上的问题,以下是别的同志在制作过程 ~~自以为是~~ 中遇到的问题,我让其改正后均可解决。问题存在性和致命性均经过事实验证,不保证这样做一定会失败,也不保证不这样做一定会成功,但这样做大概率会失败。同时如果你想要找我指导或者提出issue,请确保你没有犯下述内容中的错误,否则拉黑不予处理。 673 | ``` 674 | 1.自以为是,擅自不按照教程执行,还觉得自己很对,觉得这样不影响。如果您对mpr之类的原理不熟悉,比如不知道他是个电容触摸传感器,没有注意,然后将触摸板或模块置于金属桌子或腿上测试失败者。还有不知道电容类传感器电极相关注意事项而使用自己的错误方法连接模块和电极等。 (解决:不熟悉的按照教程来,完全复刻,不容易出问题,您认为的影响不大,可能影响很大。) 675 | 2.使用杜邦线连接各设备,或者直接将线拧在一起来连接,将线芯跟mpr焊盘绑起来连接,如果杜邦线,连接方式不牢靠,松动,劣质,氧化严重,可能导致触摸板电极或mpr无故停止工作,数据异常。(原因:瞬间的电容值变化容易让mpr的自动适应算法无法处理,会导致mpr内部出错。而mpr数据线松动,可能导致mpr数据传输错误,或断点重启而未初始化。同时,公头杜邦线那根金属针如果直接接触电极,由于杜邦线自带塑料会让其倾斜,实际上连接会非常不稳定,只有一个似断非断的点状导电面接触脆弱的导电涂层,导致电气性能极差等)(解决:作者建议能焊接的线不要怕麻烦,全部进行焊接,实际上掌握了焊接,熟练的时候焊接比插线快。mpr引脚连接电极,mpr端焊接,另一端剥长皮打圈) 676 | 677 | 新教材加注:使用四根线并在一起那种xh接头,特别是带有固定结构的xh公头配母头,这种是可以的,链接很稳固 678 | 679 | 3.电极导线触及屏幕,屏幕内走线等有可能导电,相当于手去触摸,导致电极一直处于按下状态,mpr无法识别到底手按还是没按(解决方法:走线固定好,与电极一同距离屏幕有一段距离) 680 | 4.电极导线长度差距巨大,长的导线可能造成更大的电容值,短的导线电容值小,导致mpr电极间读数呈现一些高一些低,灵敏度设置极其复杂难以实现。(解决方法:尽量规整走线,用多长截多长,并让线间距离相等,不要过远过近,其次以较短的路径连接到mpr,可以让导线间差距缩到比较小) 681 | 5.将mpr所有引进包括电极插到面包板再插杜邦线引出,杜邦线说过不再提,面包板内部是许多条金属片,金属片具有一定面积,会让电极间产生不必要的电容,轻则影响读数,重则无法读数。(解决方法:建议用焊接线的方法,连接所有电路,并将整个电路固定在一张不导电的板上,等效于电路悬空不受干扰。而不使用其他连接方式) 682 | 6.尝试使用5v单片机,mpr电源/IO电压是2.5-3.6v,低则可能无法工作,高则可能直接烧坏mpr。目前大家能买到的mpr模块(上面仅由mpr,几个电容电阻组成)不带电压转换芯片,无法在5v下正常工作。目前没见到使用简易mpr板子配合5v单片机能正常工作的。(解决方法:使用3.3v单片机,或使用adafruit出品的mpr之类,自带电平转换,支持3.3-5v宽电压的版本。实际一片带电平转换的版本跟简易mpr的差价就超过了5v单片机跟3.3v的差价,所以还是买3.3v单片机合适)(下有常见单片机电压) 683 | 7.不会写程序,乱改程序还觉得自己很对,自己反省。(解决方案:小台直接使用sucareto开源的版本或者我开源的版本,大台自己学一学再整或者等我发大台参数) 684 | 8.找我问问题,指导或提issue,而不把自己改了什么东西告诉我,不按照教程做但隐瞒,我让你怎么处理你不按我要求处理,我让刷我测试程序告诉我数据你非要把程序改了再发我数据,让打狗却去逮鸡,还表现的得意洋洋,觉得自己很对,这种人再出现在我面前我直接拉黑。 685 | 9.切割导电膜误差大,两片触控区间缝隙小,可能会造成串区和数据异常。(解决方案:按照教程一步步来,打印对照纸来辅助裁切,切得缝隙间距不要一窄一宽。如果是大台一张a4打印不完,可以分多张打印,总之,尽量裁切准确,贴准确,让缝隙大小均等,避免问题) 686 | ``` 687 | ### 新教材另加注意事项 688 | 1. 若使用mpr121,必须使用3.3v单片机!!! 689 | 2. 高速总线一定不要长度相差过大!!!!尽量避免走线形成电感线圈 690 | 3. 优信电子samd21商品默认选项是个扩展版,不是开发板主板,购买请注意点到开发板上,别买个空扩展板回来!! 691 | 4. 漆包线链接ITO必须挂漆良好,一定要至少打一圈,否则触摸容易失败 692 | 5. 大台一定不要使用亚克力!!! 693 | 6. 如果做出成品卖给别人,请注意玻璃面板的固定!!!这东西很重很容易掉下来,已经出现大佬卖自己的成品半路玻璃掉了漆包线全断的惨案,好在保价赔了。 694 | 695 | **此处会把众人制作过程遇到的坑全部列出来,逐步收集和更新** 696 | 697 | ## 第八部分 开发环境搭建和程序烧录 698 | 699 | ### 开发环境搭建 700 | #### 下载安装IDE 701 | 目前本教程使用的**所有程序**均为**arduino生态**下的,故需要使用arduino兼容ide 702 | 703 | 可选使用官方ide,slober等各种ide操作 704 | 705 | 由于兼容ide较为冷门且增加很多不必要的配置麻烦,由于官方ide新版bug比沙漠里的沙子都多,**本教程仅支持官方ide旧版(1.x)的最新版(在1.x里面找最新的一个),使用其他IDE出现任何问题,均不会得到我们的任何关注,对于非1.x官方最新IDE情况下提issue等,可能会导致被拉黑,因为很烦很烦,明明有不容易出问题的不用,非要用容易出问题的,然后提一些换旧版ide根本不会出现的没有任何意义的问题,这本身就是十分浪费时间的** 706 | 707 | 认准**Arduino官网下载的最新版1.xIDE** 708 | 709 | ![dummy](pics2/arduinoided.png) 710 | 711 | #### IDE安装开发板包和库 712 | 713 | ##### 开发板包 714 | 715 | 如果使用的是类似arduino官方版本的开发板,例如使用的是基于mega32u4的开发板,均可选择[工具->开发板->Arduino AVR Boards->Arduino Leonardo],无需额外安装开发板包 716 | 717 | 如果使用的是samd21等非类似arduino官方的板子,需要安装对应的开发板包,一般卖板子的商家会提供附加开发板包json链接或开发板包安装教程 718 | 719 | 以SEEED XIAO SAMD21为例,[百度搜索](https://baidu.com),可以轻松找到 720 | 721 | ![dummy](pics2/samd211.png) 722 | 723 | 在此seeed官方提供的文档中,教你如何安装对应开发板包,跟着走即可,可见,现存大多教程,文档都是基于旧版1.xIDE的,在此使用2.xIDE,就会造成教程步骤不通的麻烦,而且,2.xIDE有时候在搜索库文件的时候都会出错,所以**务必使用1.xIDE** 724 | 725 | ![dummy](pics2/samd212.png) 726 | 727 | ##### 库 728 | 729 | 本项目主要使用到[Adafruit_MPR121](https://github.com/adafruit/Adafruit_MPR121)这个库 730 | 731 | 需要安装库才能通过编译,否则编译失败,提示找不到"Adafruit_MPR121.h" 732 | 733 | 此库已进入Arduino IDE库管理器,可以直接通过库管理器安装 734 | ![dummy](pics2/arduinolibrary1.png) 735 | ![dummy](pics2/arduinolibrary2.png) 736 | 安装即可使用,若提示还需一并安装其他库,一并安装即可 737 | 738 | 739 | ### 程序烧录 740 | 741 | 20寸以下可尝试Mai2TouchOK这个巨老程序,此程序没写区块分配,只能按照A-E 1-12顺序链接mpr和区块,此程序使用Touched一次性读取区块按下信息,刷新率巨高,1500hz,但是不建议用,这个程序如果不会自己改参数和测区块,完全不建议使用 742 | 743 | 20寸以上包括到43寸请使用newmap版本程序,此程序非常人性化,可以轻松调节哪个区块对应哪个mpr的哪个引脚,区块阈值可分别调节,非常的好用,缺点就是单独读取区块电极原始数据计算,速度较慢,SAMD21下140-160hz,32u4下100hz左右,但是也完全够用,不要担心,至少SAMD21已超过官方理论极限,100hz的32u4经过大佬测试打14+莫得问题 744 | 745 | #### 来自xyqyear的贡献 746 | 747 | 应该是可用的,但是我还没测(主要是本人没有43寸设备) 748 | 感谢xyqyear,为我们解决虚空触发的难题 749 | 原文转述: 750 | 751 | > 大佬您好,我在newmap的基础上把做了两个改进: 752 | > 第一个是把 用原始数据计算是否被按下 改成了 使用touched直接读取触摸状态寄存器的方式。这种方式可以利用mpr121的去抖动功能,使得数据更加稳定,可以减少虚空触发。 753 | 第二个是我阅读了mpr121的所有官方文档,包括datasheet和AN3899,AN3890,AN3891,AN3892以及AN3944。把mpr121的各项配置参数单独列了出来,做成了一个头文件,并且加上了详细的注释以及这些信息可以在何处找到,修改了一部分我觉得可以优化的参数。 754 | > 755 | > 我用这个我修改了之后的程序之后就几乎完全解决了虚空触发的问题。您看有没有时间过目一下。 756 | > 757 | > https://github.com/xyqyear/maimaiTouchControl 758 | 759 | 760 | 761 | 下载程序后,双击主ino打开即可 762 | 在ide顶栏的[工具->开发板]选择你的开发板 763 | 在ide顶栏的[工具->端口]选择对应的COM口,烧录即可 764 | 765 | **注意注意**:如果是SAMD21等板,选择开发板后,可能出现其他可选项,如图 766 | ![dummy](pics2/samd213.png) 767 | 768 | 这时候要随机应变,不同的板子弹出来的东西不一样,看好自己板子的特性,比如esp有不同内存大小等,选对,另外我们要使用USB-CDC串口的话,记得开USBCDC功能,像是SAMD21就直接选择好Arduino的USB Stack,esp32要选择CDC on boot打开之类。 769 | 770 | 部分板子如果编译不通过,可能需要 771 | 把 772 | ```#define SerialDevice Serial``` 773 | 改成 774 | ```#define SerialDevice SerialUSB``` 775 | 776 | 编译上传即可使用 777 | 778 | 上传好的使用方法:见[Sucareto/Mai2Touch](https://github.com/Sucareto/Mai2Touch)的Mai2Touch使用方法部分 779 | 780 | ## 第九部分 程序灵敏度和参数调试 781 | ## 第十部分 完成 782 | 783 | 784 | 785 | ## 编写时杂项(将会嵌入到上面的内容中) 786 | 787 | 788 | 789 | [Q&A] 790 | 791 | 792 | 793 | ![dummy](pics2/3dpicplacetip.png) 794 | -------------------------------------------------------------------------------- /tn/che1.md: -------------------------------------------------------------------------------- 1 | 2 | 目前你在**完全原创ITO化学蚀刻法教程文档** 3 | 4 | 跳转: 5 | 1. [(主文档)ITO裁切法教程文档](2.md) 6 | 2. [(纯享版)ITO裁切法教程文档](orig1.md) 7 | 3. [完全原创ITO化学蚀刻法教程文档](che1.md) 8 | 4. [reservedpr](pr.md) 9 | 5. [reservedche2](che2.md) 10 | 11 | ## 此文档还未开始编写 12 | 13 | #### 蚀刻基本步骤 14 | (dkmaiproj原创)蚀刻方法: 15 | ito导电面去掉保护膜,涂感光蓝油,风干 16 | 打印菲林,白色部分为需要留下的部分 17 | 菲林盖在ito带感光蓝油的导电面上,uv120秒 18 | 显影液处理直到不需要的部分表面感光蓝油全部溶解 19 | hcl(稀)-fecl3 蚀刻液 处理 20 | 清洗表面,后脱膜液处理,直到所有蓝油脱落 21 | 蚀刻完成 22 | (个人家庭可用简化原创思路,世界首发表,hwmug design版权所有) -------------------------------------------------------------------------------- /tn/che2.md: -------------------------------------------------------------------------------- 1 | 目前你在**reservedche2** 2 | 3 | 跳转: 4 | 1. [(主文档)ITO裁切法教程文档](2.md) 5 | 2. [(纯享版)ITO裁切法教程文档](orig1.md) 6 | 3. [完全原创ITO化学蚀刻法教程文档](che1.md) 7 | 4. [reservedpr](pr.md) 8 | 5. [reservedche2](che2.md) 9 | 10 | ## 此文档还未开始编写 -------------------------------------------------------------------------------- /tn/orig1.md: -------------------------------------------------------------------------------- 1 | 2 | 目前你在 **(纯享版)ITO裁切法教程文档** 3 | 4 | 跳转: 5 | 1. [(主文档)ITO裁切法教程文档](2.md) 6 | 2. [(纯享版)ITO裁切法教程文档](orig1.md) 7 | 3. [完全原创ITO化学蚀刻法教程文档](che1.md) 8 | 4. [reservedpr](pr.md) 9 | 5. [reservedche2](che2.md) 10 | -------------------------------------------------------------------------------- /tn/pics2/1688990326190.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/1688990326190.jpg -------------------------------------------------------------------------------- /tn/pics2/20230710200504.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/20230710200504.jpg -------------------------------------------------------------------------------- /tn/pics2/3dpicplacetip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/3dpicplacetip.png -------------------------------------------------------------------------------- /tn/pics2/64487299ec4fd8f8f76f5ab4a3d3574613060190.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/64487299ec4fd8f8f76f5ab4a3d3574613060190.png -------------------------------------------------------------------------------- /tn/pics2/IMG_20230619_224416.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/IMG_20230619_224416.jpg -------------------------------------------------------------------------------- /tn/pics2/IMG_20230710_201123.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/IMG_20230710_201123.jpg -------------------------------------------------------------------------------- /tn/pics2/IMG_20230710_201250.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/IMG_20230710_201250.jpg -------------------------------------------------------------------------------- /tn/pics2/IMG_20230711_100851.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/IMG_20230711_100851.jpg -------------------------------------------------------------------------------- /tn/pics2/_-132907346__e724d59b98bfc1cbadeffaf42d3683f8_-599726569_IMG_20230629_114720_0_wifi_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/_-132907346__e724d59b98bfc1cbadeffaf42d3683f8_-599726569_IMG_20230629_114720_0_wifi_0.jpg -------------------------------------------------------------------------------- /tn/pics2/_9c71d0aeb05dcb9d64f227d082b27e66_-1674909351_IMG_20230629_113243.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/_9c71d0aeb05dcb9d64f227d082b27e66_-1674909351_IMG_20230629_113243.jpg -------------------------------------------------------------------------------- /tn/pics2/arduinoidea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/arduinoidea.png -------------------------------------------------------------------------------- /tn/pics2/arduinoided.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/arduinoided.png -------------------------------------------------------------------------------- /tn/pics2/arduinolibrary1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/arduinolibrary1.png -------------------------------------------------------------------------------- /tn/pics2/arduinolibrary2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/arduinolibrary2.png -------------------------------------------------------------------------------- /tn/pics2/caiqie003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/caiqie003.png -------------------------------------------------------------------------------- /tn/pics2/cheapito.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/cheapito.png -------------------------------------------------------------------------------- /tn/pics2/itolineA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/itolineA.png -------------------------------------------------------------------------------- /tn/pics2/lineconnectall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/lineconnectall.png -------------------------------------------------------------------------------- /tn/pics2/mgxywzt_lineway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/mgxywzt_lineway.png -------------------------------------------------------------------------------- /tn/pics2/mprAddsel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/mprAddsel.jpg -------------------------------------------------------------------------------- /tn/pics2/qbx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/qbx.png -------------------------------------------------------------------------------- /tn/pics2/samd211.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/samd211.png -------------------------------------------------------------------------------- /tn/pics2/samd212.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/samd212.png -------------------------------------------------------------------------------- /tn/pics2/samd213.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/samd213.png -------------------------------------------------------------------------------- /tn/pics2/touchall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/touchall.jpg -------------------------------------------------------------------------------- /tn/pics2/zizhishike1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MuirH/dkmaiproj/e53c85547e9c193e890fc401cd448a603a79c541/tn/pics2/zizhishike1.jpg -------------------------------------------------------------------------------- /tn/pr.md: -------------------------------------------------------------------------------- 1 | 目前你在**reservedpr** 2 | 3 | 跳转: 4 | 1. [(主文档)ITO裁切法教程文档](2.md) 5 | 2. [(纯享版)ITO裁切法教程文档](orig1.md) 6 | 3. [完全原创ITO化学蚀刻法教程文档](che1.md) 7 | 4. [reservedpr](pr.md) 8 | 5. [reservedche2](che2.md) 9 | 10 | ## 此文档还未开始编写 --------------------------------------------------------------------------------