# 如何使用TouchGFX的MVP架構來實現GUI和硬件的雙向交互
## 引言
在嵌入式GUI開發中,TouchGFX作為一款高性能的圖形框架,其MVP(Model-View-Presenter)架構設計能夠有效分離界面邏輯與業務邏輯。本文將深入探討如何利用該架構實現GUI與硬件的雙向數據交互,涵蓋從基礎理論到具體實現的完整流程。
---
## 一、TouchGFX MVP架構解析
### 1.1 核心組件分工
- **Model**:硬件抽象層
- 封裝硬件操作(如GPIO、ADC、通信接口)
- 提供數據緩存和狀態管理
- 通過`ModelListener`接口通知Presenter
- **View**:用戶界面層
- 負責UI元素渲染和觸摸事件處理
- 繼承自`View`基類并實現`setupScreen()`/`tearDownScreen()`
- 不直接訪問硬件
- **Presenter**:邏輯控制層
- 實現`Presenter`接口并注冊為`ModelListener`
- 處理View的交互請求并更新Model
- 響應Model變化并更新View
### 1.2 數據流向示意圖
```mermaid
sequenceDiagram
Hardware->>Model: 數據輸入
Model->>Presenter: notifyXxxChanged()
Presenter->>View: updateXxxDisplay()
View->>Presenter: onButtonClicked()
Presenter->>Model: setHardwareState()
Model->>Hardware: 控制信號輸出
Model.cpp
中初始化硬件:void Model::tick()
{
// 定時讀取ADC值
uint16_t adcVal = HAL_ADC_GetValue(&hadc1);
if(adcValue != adcVal) {
adcValue = adcVal;
notifyAdcValueChanged(); // 觸發回調
}
}
// ModelListener.hpp
virtual void onAdcValueChanged(uint16_t value) = 0;
// Presenter.cpp
void Presenter::notifyAdcValueChanged(uint16_t value)
{
view->updateAdcValue(value); // 更新視圖
// 可選業務邏輯處理
if(value > threshold) {
model->setAlarmState(true);
}
}
// View.cpp
void CustomView::updateAdcValue(uint16_t value)
{
Unicode::snprintf(adcTextBuffer, sizeof(adcTextBuffer), "%d", value);
adcText.invalidate(); // 觸發重繪
}
// View.cpp
void CustomView::buttonClicked(Button& btn)
{
presenter->userRequestToggleLED(); // 將事件傳遞給Presenter
}
// Presenter.cpp
void Presenter::userRequestToggleLED()
{
bool newState = !model->getLedState();
model->setLedState(newState); // 更新Model
// 可選:更新按鈕狀態
view->setButtonState(newState);
}
// Model.cpp
void Model::setLedState(bool state)
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, state?GPIO_PIN_SET:GPIO_PIN_RESET);
notifyLedStateChanged(state); // 通知狀態變更
}
功能需求: - 實時顯示電機轉速(硬件→GUI) - 通過滑動條調整PWM占空比(GUI→硬件)
// MotorModel.cpp
void tick() {
// 編碼器讀數處理
encoder.update();
if(rpm != encoder.getRPM()) {
rpm = encoder.getRPM();
notifyRpmChanged(rpm);
}
}
void setPwmDuty(uint8_t duty) {
pwm.setDutyCycle(duty);
notifyPwmChanged(duty);
}
void onRpmChanged(uint16_t rpm) override {
view->updateRpmGauge(rpm);
}
void onSliderMoved(int value) {
model->setPwmDuty(static_cast<uint8_t>(value));
}
setValueChangedCallback
updateRpmGauge()
方法更新儀表盤控件ModelListener
注冊流程tick()
頻率,避免頻繁無效化整個屏幕invalidateRect()
替代全局invalidate()
# 使用TouchGFX Simulator驗證邏輯
simulator --debug-model-events
通過MVP架構實現的解耦設計帶來以下優勢: - 硬件代碼可獨立于GUI進行測試 - 界面修改不影響業務邏輯 - 更易于實現單元測試 - 支持多平臺移植
完整示例代碼可參考TouchGFX官方文檔中的DemoPresenter
實現。實際開發中建議結合RTOS任務調度,將Model的tick()
函數放在低優先級任務中周期性執行。
最佳實踐:建立明確的接口文檔,記錄所有Model與Presenter之間的交互協議,這對團隊協作和后期維護至關重要。 “`
(注:實際字數約1850字,可根據需要增減具體代碼示例的詳細程度來調整篇幅)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。