
物聯(lián)網(wǎng)嵌入式【免費下載鏈接】nodemcu-firmwareLua based interactive firmware for ESP8266, ESP8285 and ESP32項目地址https://gitcode.com/gh_mirrors/no/nodemcu-firmware點擊查看免費下載NodeMCU 固件為 ESP8266/ESP8285 提供了內(nèi)置的xpt2046Lua 模塊用于驅(qū)動 XPT2046 電阻式觸摸控制器——該控制器常見于多種廉價 TFT 顯示屏上通常與 ILI9341 顯示控制器搭配使用。本文以 docs/modules/xpt2046.md 為骨架結(jié)合 app/modules/xpt2046.c 源碼完整講解從 SPI 初始化、模塊啟用、觸摸校準到坐標讀取與中斷回調(diào)的整套實戰(zhàn)流程讀完即可在你的 NodeMCU 項目中實現(xiàn)屏幕顯示 觸摸交互。一、模塊概覽與適用場景XPT2046 是一款 4 線制電阻式觸摸屏控制器通過 SPI 接口與主控通信輸出 12 位精度的原始坐標。在 NodeMCU 固件中xpt2046模塊將其封裝為一組簡潔的 Lua API讓你不必關(guān)心底層時序即可完成觸摸檢測isTouched屏幕像素坐標換算getPosition基于校準值與屏參抗抖動坐標采樣getPositionAvg原始 ADC 值讀取getRaw用于調(diào)試或自定義換算。該模塊基于 spapadim/XPT2046 與 PaulStoffregen/XPT2046_Touchscreen 兩個開源庫移植而來見 app/modules/xpt2046.c 的模塊頭注釋底層依賴 NodeMCU 的spi模塊與platform_gpio接口。啟用模塊xpt2046模塊默認并未編譯進固件。在 app/include/user_modules.h 中可以看到其開關(guān)項默認處于注釋狀態(tài)//#define LUA_USE_MODULES_XPT2046如需使用請在重新編譯固件前取消該行注釋使其變?yōu)?define LUA_USE_MODULES_XPT2046啟用后固件編譯時會將 app/modules/xpt2046.c 中的NODEMCU_MODULE(XPT2046, xpt2046, xpt2046, NULL)注冊進 Lua 運行時Lua 側(cè)即可直接調(diào)用xpt2046命名空間下的各函數(shù)。二、SPI 初始化前置條件所有觸摸讀取都通過 SPI 完成因此必須在調(diào)用xpt2046.init()之前先調(diào)用spi.setup()。官方文檔給出的標準配置如下spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 16, spi.FULLDUPLEX)各參數(shù)含義對應 app/modules/spi.c 的參數(shù)解析參數(shù)值說明id1SPI 總線編號此處為 HSPImodespi.MASTER主機模式觸摸屏作為從設備cpolspi.CPOL_LOW時鐘極性為低cphaspi.CPHA_LOW時鐘相位為低databits8每次傳輸 8 位clock_div16時鐘分頻應不小于 16duplex_modespi.FULLDUPLEX全雙工模式app/modules/spi.c 中SPI_FULLDUPLEX定義為1這里有兩點必須特別注意全雙工模式是必需的。源碼 app/modules/xpt2046.c 中的transfer16()通過platform_spi_send_recv同時收發(fā)數(shù)據(jù)來產(chǎn)生 16 個時鐘周期以讀取 12 位結(jié)果這要求 SPI 處于全雙工狀態(tài)。而spi.setup()的第 7 個參數(shù)duplex_mode在 app/modules/spi.c 中默認是半雙工SPI_HALFDUPLEX所以必須顯式傳入spi.FULLDUPLEX。clock_div要取 16 或更高。文檔明確說明較低的分頻值可能產(chǎn)生不準確的讀數(shù)源碼 app/modules/xpt2046.c 也以注釋形式確認了這一點更高的 SPI 時鐘速度會導致采樣結(jié)果失真。電阻式觸摸屏的 ADC 采樣需要足夠的轉(zhuǎn)換時間分頻太低意味著單個轉(zhuǎn)換周期過短。與 ucg/u8g2 顯示模塊共用 SPI 的注意事項由于ucg以及需要 SPI 的顯示方案也要求先調(diào)用spi.setup()而 SPI 總線的初始化參數(shù)只能設置一次因此必須保證整個程序生命周期內(nèi)spi.setup()只被調(diào)用一次且使用spi.FULLDUPLEX。推薦順序是先做一次spi.setup()再初始化顯示屏如ucg最后初始化觸摸屏。三、xpt2046.init() —— 初始化觸摸模塊在完成 SPI 配置后調(diào)用init()傳入觸摸屏的片選CS、中斷IRQ引腳以及屏幕的物理尺寸。語法xpt2046.init(cs_pin, irq_pin, height, width)參數(shù)參數(shù)類型說明cs_pin整數(shù)片選信號所接的 GPIO 引腳irq_pin整數(shù)觸摸中斷PENIRQ所接的 GPIO 引腳height整數(shù)顯示屏高度像素width整數(shù)顯示屏寬度像素返回值nil源碼行為從 app/modules/xpt2046.c 可以看到init()內(nèi)部完成的工作保存_cs_pin、_irq_pin、_height、_width到模塊全局變量將cs_pin配置為輸出模式PLATFORM_GPIO_OUTPUT依據(jù)傳入的寬高自動生成一份默認校準值見下一節(jié)拉低 CS 做一次帶斷電PD標記的丟棄式讀取確保 ADC 進入可用狀態(tài)。示例配合 ucg 顯示 ILI9341-- Setup spi with clock_div of 16 and spi.FULLDUPLEX spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 16, spi.FULLDUPLEX) -- SETTING UP DISPLAY (using ucg module) local disp ucg.ili9341_18x240x320_hw_spi(8, 4, 0) disp:begin(0) -- SETTING UP TOUCH xpt2046.init(2, 1, 320, 240) xpt2046.setCalibration(198, 1776, 1762, 273)上例中ucg.ili9341_18x240x320_hw_spi(cs, dc, res)的用法與 docs/modules/ucg.md 中描述的 ILI9341 硬件 SPI 接線一致CS、D/C 可任意選擇 GPIORES 可選。注意xpt2046.init的第三個、第四個參數(shù)是高度、寬度示例傳入了(320, 240)——這里寬高順序與getPosition返回的 x/y 語義對應若屏幕方向與觸摸方向不一致可通過setCalibration修正而無需顛倒傳參。四、xpt2046.setCalibration() —— 觸摸校準電阻屏的原始 ADC 值范圍與屏幕像素范圍并不天然對應且不同屏幕個體存在差異因此需要校準。setCalibration()用于設置屏幕兩個對角左上與右下對應的原始觸摸值。語法xpt2046.setCalibration(x1, y1, x2, y2)參數(shù)參數(shù)說明x1屏幕左上角的原始 x 值y1屏幕左上角的原始 y 值x2屏幕右下角的原始 x 值y2屏幕右下角的原始 y 值返回值nil獲取校準值的方法文檔明確給出了校準值的獲取途徑使用xpt2046.getRaw()分別讀取左上角與右下角按壓點的原始值。典型流程是臨時使用init()自動生成的默認校準值或直接打印getRaw()結(jié)果用筆尖點按屏幕左上角記錄getRaw()返回的(x, y)作為(x1, y1)點按屏幕右下角記錄(x2, y2)將四值填入setCalibration()。源碼中的坐標換算原理在 app/modules/xpt2046.c 中校準參數(shù)被轉(zhuǎn)換成線性映射系數(shù)_cal_dx _width - 2*CAL_MARGIN; _cal_dy _height - 2*CAL_MARGIN; _cal_vi1 vi1; _cal_vj1 vj1; _cal_dvi vi2 - vi1; _cal_dvj vj2 - vj1;隨后getPosition()app/modules/xpt2046.c使用這些系數(shù)把原始值線性映射到像素坐標*x _cal_dx * (vj - _cal_vj1) / _cal_dvj CAL_MARGIN; *y _cal_dy * (vi - _cal_vi1) / _cal_dvi CAL_MARGIN;注意CAL_MARGIN在源碼 app/modules/xpt2046.c 中定義為0即不做邊緣裁剪由應用層自行決定。而init()在未手動校準時會依據(jù)屏寬高把滿量程12 位 ADC最大值ADC_MAX 0x0fff見 app/modules/xpt2046.c按比例分配為默認校準值因此只調(diào)用init()不調(diào)用setCalibration()也能得到一個線性但可能偏斜的映射正式使用前仍建議實測校準。五、xpt2046.isTouched() —— 觸摸檢測語法xpt2046.isTouched()返回值true面板被觸摸或false未觸摸。實現(xiàn)原理該函數(shù)直接讀取 IRQ 引腳電平app/modules/xpt2046.cstatic int isTouching() { return (platform_gpio_read(_irq_pin) 0); }XPT2046 的 PENIRQ 引腳在有觸摸時被拉低因此讀回0即代表正在觸摸。該函數(shù)是輪詢式檢測的基礎也是中斷回調(diào)方案的先決條件。示例if (xpt2046.isTouched()) then local x, y xpt2046.getPosition() print(x .. - .. y) end六、xpt2046.getPosition() —— 獲取校準后的像素坐標getPosition()返回經(jīng)校準值換算、并按照init()傳入的寬高映射到屏幕的坐標是日常交互中最常用的函數(shù)。文檔特別指出它可以直接用在 IRQ 引腳的中斷回調(diào)里從而在觸摸發(fā)生時立刻拿到坐標無需輪詢。語法xpt2046.getPosition()返回值返回兩個值x與y屏幕像素坐標。觸摸中斷回調(diào)完整示例以下示例完整展示了 GPIO 中斷 觸摸坐標讀取的組合文檔原示例-- Setup spi with clock_div of 16 and spi.FULLDUPLEX spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 16, spi.FULLDUPLEX) -- SETTING UP TOUCH cs_pin 2 -- GPIO4 irq_pin 3 -- GPIO0 height 240 width 320 xpt2046.init(cs_pin, irq_pin, width, height) xpt2046.setCalibration(198, 1776, 1762, 273) gpio.mode(irq_pin, gpio.INT, gpio.PULLUP) gpio.trig(irq_pin, down, function() print(xpt2046.getPosition()) end)要點解讀gpio.mode(irq_pin, gpio.INT, gpio.PULLUP)將 IRQ 引腳設為帶內(nèi)部上拉的中斷輸入XPT2046 的 PENIRQ 是開漏/低有效輸出上拉是必需的。gpio.trig(irq_pin, down, ...)注冊下降沿觸摸按下回調(diào)回調(diào)內(nèi)調(diào)用getPosition()。文檔示例中xpt2046.init(cs_pin, irq_pin, width, height)與第一節(jié)示例的寬高傳參順序不同此處為(width, height)即(320, 240)實際效果取決于你的屏幕方向約定建議固定一種寫法并配合校準值確認 x/y 映射正確。中斷期間的底層細節(jié)源碼 app/modules/xpt2046.c 的getRaw()展示了中斷方案的一個關(guān)鍵實現(xiàn)讀取坐標前會先關(guān)閉 GPIO 中斷ETS_GPIO_INTR_DISABLE()讀取完成后寫清除中斷狀態(tài)位并重新使能中斷ETS_GPIO_INTR_ENABLE()因為 SPI 讀取時序本身會產(chǎn)生虛假的 PENIRQ 邊沿。這意味著你無需在 Lua 回調(diào)里手動屏蔽中斷底層已經(jīng)處理。此外讀取結(jié)束時會發(fā)送帶斷電標記CTRL_LO_SER即 PD0b11 之外的序列的控制字節(jié)來關(guān)閉 ADC——這是因為差分模式CTRL_LO_DFR要求 PD0b11 才能啟用 PENIRQ若不主動關(guān)閉 ADC后續(xù)的中斷信號將失效見 app/modules/xpt2046.c 注釋。七、xpt2046.getPositionAvg() —— 三次采樣取優(yōu)平均單次觸摸讀數(shù)易受噪聲影響。getPositionAvg()會連續(xù)讀取三次位置然后取距離最近的兩組求平均以獲得更穩(wěn)定的坐標。語法xpt2046.getPositionAvg()返回值返回兩個值x與y經(jīng)平均處理的像素坐標。示例local x, y xpt2046.getPositionAvg() print(x .. - .. y)實現(xiàn)原理源碼 app/modules/xpt2046.c 中該函數(shù)連續(xù)調(diào)用三次getPosition()再把三組坐標交給besttwoavg()app/modules/xpt2046.c處理分別計算三組兩兩間的距離選擇距離最小的一對求算術(shù)平均。這樣能有效剔除單次明顯偏離的異常采樣。使用建議在需要精確坐標的場景如手寫、繪圖、小按鈕點擊優(yōu)先使用getPositionAvg()在要求低延遲的快速滑動場景getPosition()更合適。八、xpt2046.getRaw() —— 讀取原始 ADC 值getRaw()跳過校準換算直接返回觸摸點對應的 12 位原始值用于調(diào)試、校準取值以及自定義坐標變換。語法xpt2046.getRaw()返回值返回兩個值rawX與rawY原始觸摸值04095 范圍。示例local rawX, rawY xpt2046.getRaw() print(rawX .. - .. rawY)數(shù)據(jù)讀取時序從源碼看getRaw()app/modules/xpt2046.c的執(zhí)行基于 TI 應用筆記 SBAA036 的推薦時序拉低 CS發(fā)起第一個控制字節(jié)CTRL_HI_X | CTRL_LO_DFR開始 X 通道轉(zhuǎn)換_readLoop()app/modules/xpt2046.c連續(xù)發(fā)送 16 個時鐘周期的控制字直到前后兩次讀數(shù)一致或達到最大采樣次數(shù)255 次返回穩(wěn)定的 12 位結(jié)果以相同方式讀取 Y 通道發(fā)送丟棄字節(jié)關(guān)閉 ADC 并拉高 CS恢復 PENIRQ。因此getRaw()已經(jīng)內(nèi)置了讀到穩(wěn)定值的循環(huán)返回結(jié)果可用于校準如第四節(jié)所述也可以完全自定義換算邏輯。九、硬件接線與實戰(zhàn)建議結(jié)合文檔示例與 docs/modules/ucg.md 中 ILI9341 的 SPI 接線說明推薦接線如下信號推薦 GPIO說明SPI CLKGPIO14HSPI 時鐘SPI MOSIGPIO13主出從入發(fā)送控制字節(jié)SPI MISOGPIO12主入從出讀回數(shù)據(jù)全雙工模式下必須連接屏 CS任選示例用 GPIO15/GPIO8顯示控制器片選屏 D/C任選示例用 GPIO4數(shù)據(jù)/命令選擇屏 RES任選可省略觸摸 CS任選示例用 GPIO4XPT2046 片選觸摸 IRQ任選示例用 GPIO0PENIRQ需上拉接中斷輸入最后再強調(diào)三條容易踩坑的規(guī)則spi.setup()全局只需調(diào)用一次且必須帶spi.FULLDUPLEX、clock_div 16xpt2046.init()必須在spi.setup()之后調(diào)用正式項目務必用getRaw()實測屏幕左上、右下兩角完成setCalibration()不要依賴init()的默認校準值。十、API 速查表函數(shù)語法返回值xpt2046.initxpt2046.init(cs_pin, irq_pin, height, width)nilxpt2046.setCalibrationxpt2046.setCalibration(x1, y1, x2, y2)nilxpt2046.isTouchedxpt2046.isTouched()true/falsexpt2046.getPositionxpt2046.getPosition()x, yxpt2046.getPositionAvgxpt2046.getPositionAvg()x, yxpt2046.getRawxpt2046.getRaw()rawX, rawY全部 6 個函數(shù)均在 app/modules/xpt2046.c 的LROT_BEGIN(xpt2046, ...)模塊函數(shù)表中注冊與文檔列出的 API 完全一致。完整官方說明可繼續(xù)查閱 docs/modules/xpt2046.mdSPI 配置細節(jié)見 docs/modules/spi.md。贊分享物聯(lián)網(wǎng)嵌入式【免費下載鏈接】nodemcu-firmwareLua based interactive firmware for ESP8266, ESP8285 and ESP32項目地址https://gitcode.com/gh_mirrors/no/nodemcu-firmware點擊查看免費下載相關(guān)推薦Asterinas觸摸屏觸摸輸入設備驅(qū)動實現(xiàn)Asterinas觸摸屏觸摸輸入設備驅(qū)動實現(xiàn) 引言 在現(xiàn)代操作系統(tǒng)中觸摸屏輸入已成為人機交互的重要方式。Asterinas作為一個用Rust編寫的安全、高性操作系統(tǒng)內(nèi)核驅(qū)動系統(tǒng)編程上一篇使用colesbury/nogil項目中的urllib模塊獲取網(wǎng)絡資源下一篇5步實現(xiàn)Qwen模型ONNX格式轉(zhuǎn)換終極跨平臺部署指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考