前一篇完成了界面开发,这一篇我们把界面与单片机RTC硬件联合起来。
首先打开STM32CubeMX进行配置。
打开外部低频时钟。
配置RTC模块
修改时钟树
点击生成代码,回到软件进行开发。
暂时我们只关注时间的读取,主要涉及两个函数
读取时间
HAL_StatusTypeDef HAL_RTC_GetTime(const RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
读取日期
HAL_StatusTypeDef HAL_RTC_GetDate(const RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
普通模式
首先我们先聊一下普通的界面开发模式,界面与逻辑控制混合到一起。
这种方式很简单,只要在界面里面动手脚就可以了
mainView.cpp
#include <gui/main_screen/mainView.hpp>
mainView::mainView()
{
}
#ifndef SIMULATOR
#include "main.h"
extern RTC_HandleTypeDef hrtc;
RTC_TimeTypeDef GetTime;
RTC_DateTypeDef GetData;
#endif
void mainView::setupScreen()
{
#ifndef SIMULATOR
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
analogHours = GetTime.Hours;
analogMinutes = GetTime.Minutes;
analogSeconds = GetTime.Seconds;
#endif
mainViewBase::setupScreen();
}
void mainView::tearDownScreen()
{
mainViewBase::tearDownScreen();
}
void mainView::handleTickEvent()
{
tickCounter++;
if (tickCounter % 60 == 0)
{
if (++analogSeconds >= 60)
{
analogSeconds = 0;
if (++analogMinutes >= 60)
{
analogMinutes = 0;
if (++analogHours >= 24)
{
analogHours = 0;
}
}
}
// Update the clocks
analogClock.setTime24Hour(analogHours, analogMinutes, analogSeconds);
}
}
代码都很好懂,这里主要介绍一下SIMULATOR宏,主要用来限定代码的运行范围。
当我们只希望代码在模拟器运行的时候就
#ifdef SIMULATOR
// 代码
#endif
不希望代码在模拟器运行的时候
#ifndef SIMULATOR
// 代码
#endif
这个宏就可以实现加入用户控制硬件逻辑,但是又不影响原本的界面开发。
编译下载到板卡中,运行正常。试试vs仿真,也是正常运行。
MVP模式
接下来聊一下MVP开发。
MVP是TouchGFX建议的一种代码架构,全称是Model-View-Presenter,主要实现用户代码-UI界面-UI逻辑分离的一种开发模式。
下面进行代码编写
Model.hpp
#ifndef MODEL_HPP
#define MODEL_HPP
#include <stdint.h>
class ModelListener;
class Model
{
public:
Model();
void bind(ModelListener* listener)
{
modelListener = listener;
}
void tick();
void getRTCTime(int *hours, int *minutes, int *seconds);
protected:
ModelListener* modelListener;
};
#endif // MODEL_HPP
Model.cpp
#include <gui/model/Model.hpp>
#include <gui/model/ModelListener.hpp>
#ifndef SIMULATOR
#include "main.h"
extern "C"
{
extern RTC_HandleTypeDef hrtc;
}
#endif
Model::Model() : modelListener(0)
{
}
void Model::tick()
{
}
void Model::getRTCTime(int *hours, int *minutes, int *seconds)
{
*hours = 0;
*minutes = 0;
*seconds = 0;
#ifndef SIMULATOR
RTC_TimeTypeDef GetTime;
RTC_DateTypeDef GetData;
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
*hours = GetTime.Hours;
*minutes = GetTime.Minutes;
*seconds = GetTime.Seconds;
#endif
}
这一部分是Model内容,主要实现对接RTC部分(至于为啥没用日期却又读了日期呢?因为ST RTC一直有个bug,不这样读,RTC就装死给你看)。
mainPresenter.hpp
#ifndef MAINPRESENTER_HPP
#define MAINPRESENTER_HPP
#include <gui/model/ModelListener.hpp>
#include <mvp/Presenter.hpp>
using namespace touchgfx;
class mainView;
class mainPresenter : public touchgfx::Presenter, public ModelListener
{
public:
mainPresenter(mainView& v);
/**
* The activate function is called automatically when this screen is "switched in"
* (ie. made active). Initialization logic can be placed here.
*/
virtual void activate();
/**
* The deactivate function is called automatically when this screen is "switched out"
* (ie. made inactive). Teardown functionality can be placed here.
*/
virtual void deactivate();
virtual ~mainPresenter() {}
void getTime(int *hours, int *minutes, int *seconds);
private:
mainPresenter();
mainView& view;
};
#endif // MAINPRESENTER_HPP
mainPresenter.cpp
#include <gui/main_screen/mainView.hpp>
#include <gui/main_screen/mainPresenter.hpp>
mainPresenter::mainPresenter(mainView& v)
: view(v)
{
}
void mainPresenter::activate()
{
}
void mainPresenter::deactivate()
{
}
void mainPresenter::getTime(int *hours, int *minutes, int *seconds)
{
model->getRTCTime(hours, minutes, seconds);
}
这一部分是Presenter内容,用于对接Model,为View提供接口。
mainView.cpp
#include <gui/main_screen/mainView.hpp>
mainView::mainView()
{
}
void mainView::setupScreen()
{
presenter->getTime(&analogHours, &analogMinutes, &analogSeconds);
mainViewBase::setupScreen();
}
void mainView::tearDownScreen()
{
mainViewBase::tearDownScreen();
}
void mainView::handleTickEvent()
{
tickCounter++;
if (tickCounter % 60 == 0)
{
if (++analogSeconds >= 60)
{
analogSeconds = 0;
if (++analogMinutes >= 60)
{
analogMinutes = 0;
if (++analogHours >= 24)
{
analogHours = 0;
}
}
}
// Update the clocks
analogClock.setTime24Hour(analogHours, analogMinutes, analogSeconds);
}
}
这一部分是View内容,调用Presenter里面的函数配置时钟时间。
编译下载到板卡中,运行正常。试试vs仿真,也是正常运行。