内容发布更新时间 : 2024/12/22 23:36:43星期一 下面是文章的全部内容请认真阅读。
interger.h 数据类型定义
option 可选的外部功能(比如支持中文等) 与平台相关的代码(需要用户提供)是:
diskio.c FATFS 和disk I/O 模块接口层文件
FATFS 模块在移植的时候,我们一般只需要修改 2 个文件,即 ffconf.h和 diskio.c。模块的所有配置项都是存放在 ffconf.h 里面,我们可以通过配置里面的一些选项,来满足自己的需求。接下来介绍几个重要的配置选项。
(1).数据类型:在integer.h里面去定义好数据的类型。这里需要了解所用的编译器的数据类型,并根据编译器定义好数据类型。
(2).配置:通过ffconf.h 配置FATFS 的相关功能,以满足系统的需要。函数编写:打开 diskio.c,进行底层驱动编写,一般需要编写6 个接口函数如图5.3:
disck_readdisck_initializediskio.cdisck_statusdisck_writedisck_ioctlget_fattime
图5.3 FatFs接口函数
如通过以上步骤就可以完成对FatFs文件系统的移植。
5.4 GUI程序的设计
图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉上更易于接受。
本系统移植了周立功公司开发的GUI,用来设计系统的操作界面,TFT彩屏大量使用了GUI内的相关函数。为适应系统需要,做了一定的裁剪。底层驱动
- 24 -
程序函数定义在GUI文件夹中的“LCD.C”和“GUI_BASIC.C”中,具体如下:
void LCD_Init(void);
//初始化 //开显示
void LCD_DisplayOn(void); void LCD_DisplayOff(void); void LCD_Clear(u16 Color);
//关显示
//清屏
void LCD_DrawPoint(u16 x,u16 y,u16 c);
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color);
//填充单色
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue); u16 LCD_ReadReg(u8 LCD_Reg); void LCD_WriteRAM_Prepare(void); void LCD_WriteRAM(u16 RGB_Code); void LCD_Scan_Dir(u8 dir);
//设置屏扫描方向
void LCD_Display_Dir(u8 dir); //设置屏幕显示方向
extern void GUI_RectangleFill(uint32 x0, uint32 y0, uint32 x1, uint32 y1, TCOLOR color);//画填充矩形
extern void GUI_Rectangle(uint32 x0, uint32 y0, uint32 x1, uint32 y1, TCOLOR color);//画矩形
extern void GUI_CircleFill(uint32 x0, uint32 y0, uint32 r, TCOLOR color);//画填充圆
extern void GUI_Line(uint32 x0, uint32 y0, uint32 x1, uint32 y1, TCOLOR color);//画线
在对液晶操作前应调用“LCD_Init”对液晶初始化,然后再进行其他操作。
5.5主要功能的实现原理
系统开机之后首先进行硬件的初始化,以及触摸屏的校准。随后系统跳转到桌面状态进入主界面,首先加载表盘显示时间,然后系统一直检测桌面图标的按下状态,当用户按下按键以后,系统会停留在while(!TPEN());语句用于松手检测,以防止系统在用户按下按键时发生多次跳转。当用户松开手后则跳转到相应的功能界面没有按键按下则停留在桌面状态每过一秒则把时间刷新一次。 本系统最关键的状态转换代码如下:
while(1) {
- 25 -
Switch (State_Machine) {
case 0: State_Machine = State0_Calendar();break;//万年历 case 1: State_Machine = State1_Clock();break;//闹钟 case 2: State_Machine = State2_Stopwatch();break;//计时器 case 3: State_Machine = State3_Map();break;//地图
case 4: State_Machine = State4_Drawing_Board();break;//画板 case 5: State_Machine = State5_Pedometer();break;//计步 case 6: State_Machine = State6_zhuomian();//桌面 } } 5.5.1万年历
系统内设的万年历可以提供阳历显示、农历显示、二十四节气、生肖、以及实时的时分秒时间,并且可以提供时间的更改。日历支持的范围是1901年-2099年,主要依靠算法完成,支持农历。下面将介绍万年历的实现方法:
在主界面的状态下点击万年历图标,此时系统会检测到触摸屏有按键按下,在按键松开后系统会自动跳转到万年历界面,首先加载UI界面,然后系统会进入一个循环,在此循环中不断检测秒钟标志位是否被置为’1’,当检测到秒钟标志位被置为‘1’时,此时系统会调用RTC_Gettime函数从RTC寄存器中获得UNIX时间戳,通过计算后把时间戳的信息转化为年月日时分秒存到systmtime时间结构体中。接着,系统继续调用Time_Display_yang、Time_Display_yin、RTC_display_lcd、RTC_display_lcd2等函数计算得到当前的阳历、阴历、节气、生肖、以及实时的时间并显示到LCD上,系统在while循环中不断检测按键的状态,并且每过一秒就将时间刷新一次。
当用户点击设置按钮时系统跳转到设置界面,时间的输入关键用到了一个字符数组keystore[MAX_KEY_NUM],用户每输入一个数字,系统就会把数字对应的字符存入这个数组中并且实时的显示出来。用户输入时间后点击确定,系统自动判定时间是否完整以及合法性,当时间合法时系统调用Time_Adjust函数将时间转化为UNIX时间戳存入RTC寄存器,当时间非法时点击确定按钮系统不会有反应。当用户点击返回按钮时,系统跳转到界面状态。
- 26 -
主要用到的函数如下:
void Time_Adjust(struct rtc_time *tm);//时间调整 void RTC_CheckAndConfig(void);//RTC检测与配置
void RTC_Settime(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);//RTC时间设置
void RTC_NVICConfig(void); //RTC中断配置
void RTC_Gettime(struct rtc_time *tm); //RTC时间戳获得
u8 GetChinaCalendar(u16 year,u8 month,u8 day,u8 *p); //公农历转换 void GetSkyEarth(u16 year,u8 *p); //由公历日期得到甲子年
void GetChinaCalendarStr(u16 year,u8 month,u8 day,u8 *str);//输入公历日期得到农历字符串
u8 GetJieQi(u16 year,u8 month,u8 day,u8 *JQdate); //获得节气信息 u8 GetJieQiStr(u16 year,u8 month,u8 day,u8 *str);//获得节气字符串 u8 Get_phonekeyvalue(u32 x,u32 y); //获得按键值 u8 calender_config_mode(void); //日历配置模式
void Show_keynum(u32 count,u32 lenth,unsigned char ch[]); //按键值的显示 u8 State0_Calendar(void); //万年历状态函数
RTC_display_lcd(80,10,BLUE ,WHITE ,16,1); //显示年月日 RTC_display_lcd2(88,32,BLUE ,WHITE ,16,1);// 显示时分秒 详细代码参见附录二。 5.5.2秒表
本系统设计的秒表可以提供最多八个时间记录,最小计时时间为秒,且支持后台运行,系统采用STM32的TIM2定时器来做。STM32总共有八个定时器,其中TIM1与TIM8为高级定时器,TIM1与TIM7为基本定时器,其他为通用定时器。通用定时器的主要功能包括:
(1).16位向上、向下、向上/向下自动装载计数器。
(2).16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值。
(3).四个独立通道:输入捕获、输出比较、PWM生成、单脉冲模式输出。 (4).使用外部信号控制定时器和定时器互连的同步电路。
- 27 -
(5).如下事件发生时产生中断/DMA:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发);触发事件(计数器启动、停止、初始化或者由内部/外部触发计数);输入捕获;输出比较
下面将介绍万年历的实现方法:
在主界面的状态下点击秒表图标,系统检测到触摸屏有按键按下,在按键松开后自动跳转到秒表界面,此时系统会首先加载UI界面并且在while循环中不断检测按键的状态,当用户点击开始按钮时,秒表开始自动计时,并且把开始按钮变成暂停按钮,计时的源代码主要如下:
if(sec_flag==1) { sec_flag=0; sec++; if(sec>59) { sec=0; min++; if(min>59) { min=0; hour++; if(hour==24) hour=0; }
}
}
在while循环中系统一边记录总时间,一边计算相对时间。总时间用来记录从开始计时以来的总时间,相对时间用来记录从按下计次按钮到当前经过的时间。然后系统调用Draw_Text函数,将两个时间打印在屏幕上。
我设置了一个变量s_t_flag用来标志当前的计时状态。当s_t_flag为‘1’时表示当前为计时状态,系统在定时器中断中将秒标志sec_flag置位,系统正常计时。当s_t_flag为‘0’时,表示当前为暂停状态,系统计时暂停。
当用户点击计次按钮时系统将调用big_time_save函数记录下按下按钮时刻的总时间用来计算计次时间。计次时间计算公式如(5.1)所示:
计次时间=总时间-上次点击计次时总时间 (5.1)
- 28 -