Fireduino 开源创意平台 立即购买

拥有双核Cortex-M3处理器,集成高质量音频Codec和WiFi模组,拥有良好的IOT扩展性能,完美兼容Arduino IDE和Arduino标准接口,并支持FireBlock图形化编程软件,是一款首选的编程启蒙教学平台,更是一款开源的创意原型平台。

Fireduino 网络万年历

更新时间:2017-09-26 阅读:2047

前言

Fireduino 网络万年历是一个可以通过wifi联网,通过NTP协议获取到网络时间,并且使用RTC运行时钟以及万年历显示的示例,其中万年历可以显示从1583开始的公历以及星期,并且可以通过按键翻阅日历。

操作流程

  1. 上电后进行TFT初始化和WIFI初始化,进行WIFI连接并且在TFT上进行提示。

  2. 通过网络NTP协议获取网络时间,并且写入到RTC中,如果NTP获取失败,将在星期右侧显示字符“-_-||”表示同步失败,下次同步成功后可以消除该状态。

  3. 进入“时钟”界面,在TFT上显示表盘、星期、日期以及时间。

  4. 短按按Mode键同步NTP网络时间。

  5. 长按Mode键后循环切换主显示界面,主要有"时钟"界面、"本月日历"界面以及"翻阅万年历"界面。

  6. "本月日历"界面显示年份、月份以及本月日历(包含星期)以及高亮显示今日位置,无切换界面外的按键响应。

  7. “翻阅万年历”界面可以通过按键翻阅日历。短按MODE 切换位,短按UP、DOWN调相应值,长按快速UP、DOWN调相应值。

硬件连接

Fireduino

Fireduino 作为主MCU,为驱动TFT、RTC、KEY等提供逻辑运行环境。

TFT

TFT 为显示设备,主要提供显示表盘以及时间字符、日历显示。
LCD SCH.jpg

RTC

RTC 是板载的RTC独立单元,用于保存和获取实时时间,使用的为HYM8563,挂载在I2C1 接口,Fireduino 为此提供了专门的RTC库可供直接使用。
Fireduino RTC SCH.jpg

按键

按键用于修改切换显示界面、同步NTP时间以及浏览日历。
Fireduino6 1.png

软件逻辑

界面

网络万年历主要分为如下几个界面

// status of display#define MODE_DISPLAY_TIME	0      //显示表盘、今日星期、日期以及时间#define MODE_DISPLAY_CAL	1      //显示本月日历#define	MODE_BROWSE_CAL		2      //翻阅日历

事件

事件由按键触发,为事件处理提供依据

#define EVENT_MODE		 1     //模式键抬起事件#define EVENT_UP		 2     // UP事件       #define EVENT_DOWN               3     // DOWN事件#define EVENT_MODE_CHANG 	 4     // 模式改变时间#define EVENT_MODE_CLICK	 5     //模式键按下事件

按键处理

本示例使用了3个按键,使用了pin 5、6、7,每20ms 扫描一次按键状态,支持长按和短按。

按键扫描

每20ms扫描一次。

void key_sacn(void){unsigned char pin_level = 0;if(digitalRead(5) == HIGH){
		pin_level |= KEY_MODE;}if(digitalRead(6) == HIGH){
		pin_level |= KEY_UP;}if(digitalRead(7) == HIGH){
		pin_level |= KEY_DOWN;} 
	key_trg = pin_level&(pin_level^key_count);
	key_count = pin_level;}

按键处理

根据状态,生成事件

void key_proc(void){if(key_trg & KEY_UP){
		event_key = EVENT_UP	;} 	if(key_count & KEY_UP){
		up_count++;if(up_count > 100){
			up_count = 80 + up_count_i;if(up_count_i++ >100){
				up_count_i = 100;}
			event_key = EVENT_UP;}}else{
		up_count = 0;
		up_count_i = 0;} }

显示处理

根据不同模式,显示不同界面。

  1. MODE_DISPALY_TIME 模式显示时钟表盘及今日星期、日期和时间。

  2. MODE_DISPALY_CAL 模式显示本月日历,显示年份、月份、星期以及高亮显示今日日期位置。

  3. MODE_BROWSE_CAL 模式显示可翻阅的日历,可修改年份和月份,修改的位会相应的闪烁。

事件处理

事件处理在按键处理之后,根据时间对于不同的处理。

void event_proc(void){if(event_key){switch(event_key){case EVENT_MODE :.....break;case EVENT_UP :.....                           
             break;case MODIFY_HOUR :.....                break;case EVENT_DOWN :.....              break;case EVENT_MODE_CHANG :.....   break;} event_key = 0;}}

绘图处理

void clear_all(void);                                //清除整个屏幕void clear_dial(void);                               //清除表盘void clear_time_pointer(void);                       //清除表指针void clear_time_txt(unsigned char flash_bit);        //清除时钟界面显示的文本void draw_dial(void);                                //绘制表盘void draw_time_pointer(RTCTime *time);               //绘制表指针void draw_time_txt(RTCTime *time);                   //绘制时钟界面显示文本void draw_cal(RTCTime *time);                        //绘制今日日历void draw_browse_cal(RTCTime *time);                 //绘制可翻阅日历

Arduino 程序结构

setup

  // initialize the serial port
  Serial.begin(115200);   // initialize the TFT Screen
  delay(1);
  TFTscreen.begin();
  Serial.println("TFTscreen init success"); 
  delay(1);
  // clear the screen with a pretty color
  TFTscreen.background(0, 0, 0);
  TFTscreen.setTextSize(1);
  TFTscreen.stroke(255,255,255);   // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) { 
    Serial.print("Attempting to connect to SSID: ");Serial.println(ssid); 
    TFTscreen.text("Connecting  ",28,70);TFTscreen.text("    ...     ",28,90);// Connect to network.status = WiFi.begin(ssid, pass);
  } 
  Serial.println("Connected to wifi");
  printWifiStatus();
  TFTscreen.fillRect(0,70,128,40,0);   // initialize UDP
  Serial.println("\nStarting connection to server...");
  Udp.begin(localPort);   // Init Wire and RTC will use I2C Interface
  Wire1.begin(); 
  getNtpTimeSuccess = 0;   // Get NTP time
  ntpTime();   // if failed ,note user
  if (!getNtpTimeSuccess)
  {
	  TFTscreen.stroke(255,0,0);
	  TFTscreen.textSize(1);
	  TFTscreen.text("get NTP Time",28,70);
	  TFTscreen.text("failed",46,80);
	  delay(3000);
	  TFTscreen.stroke(0,0,0);
	  TFTscreen.text("get NTP Time",28,70);
	  TFTscreen.text("failed",46,80);
	  TFTscreen.stroke(255,255,255);
	  TFTscreen.textSize(2);
  }
  else
	  RTC.setTime(&time);   // display the dial
  draw_dial();

loop

if(millis() > curr_ms){
		curr_ms = millis() + 250;//		displaytime();
		display_proc();}//20ms 检测一次按键状态if(millis() > curr_ms_key){
		curr_ms_key = millis() + 20;
		key_sacn();
		key_proc();
		event_proc(); 	}

示例程序

#include <TFT.h>  // Arduino LCD library#include "RTC.h"#include "WiFi.h"#include <WiFiUdp.h>#include "Wire.h" // define for calculate time#define SECONDS_IN_DAY          86400#define START_YEAR              1900#define TIME_ZONE               +8 // status of display#define MODE_DISPLAY_TIME	0#define MODE_DISPLAY_CAL	1#define	MODE_BROWSE_CAL		2//#define MODE_DGET_NTP_TIME_FAILD	3 // event of key#define EVENT_MODE			1#define EVENT_UP			2#define EVENT_DOWN          3#define EVENT_MODE_CHANG 	4#define EVENT_MODE_CLICK	5 // Key flag#define KEY_MODE	0x01#define KEY_UP		0x02#define KEY_DOWN	0x04 #define	UP_YEAR				0#define	DOWN_YEAR			1#define	UP_MON				2#define	DOWN_MON			3 // count ms of key pressunsigned int curr_ms;unsigned int curr_ms_key; // current statusunsigned char curr_mode;unsigned char event_key; // counts of key pressunsigned char mode_count;unsigned char up_count;unsigned char down_count; unsigned char mode_count_i;unsigned char up_count_i;unsigned char down_count_i; // flag of keysunsigned char key_trg;unsigned char key_count; unsigned char modif_bit = 0; // for display the monthstatic int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};String mon_list[] = {"   ","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; // WIFI informationint status = WL_IDLE_STATUS;char ssid[] = "Fireduino";  //  your network SSID (name)char pass[] = "12345678";       // your network password // Get NTP time statusunsigned char getNtpTimeSuccess; unsigned int localPort = 2390;      // local port to listen for UDP packets 
IPAddress timeServer(128, 138, 140, 44); // time-nw.nist.gov NTP server const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message 
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets // A UDP instance to let us send and receive packets over UDPWiFiUDP Udp; 
RTCTime time;RTCTime browseTime;String cal_char[6][7];String browse_cal_char[6][7]; 
TFT TFTscreen = TFT(); // function for WIFIvoid printWifiStatus(); // function for NTP Timeunsigned long sendNTPpacket(IPAddress& address); 
RTCTime * timeStamp2time(unsigned int timeStamp ,RTCTime *time); void ntpTime(void); // function for displayunsigned char Lcd_TimeX(unsigned char circle_x,unsigned char Length,unsigned char Angle);unsigned char Lcd_TimeY(unsigned char circle_y,unsigned char Length,unsigned char Angle);void clear_all(void);void clear_dial(void);void clear_time_pointer(void);void clear_time_txt(unsigned char flash_bit);void draw_dial(void);void draw_time_pointer(RTCTime *time);void draw_time_txt(RTCTime *time);void draw_cal(RTCTime *time);void draw_browse_cal(RTCTime *time); // function of key eventvoid key_sacn(void);void key_proc(void);void event_proc(void);void display_proc(void); void setup() {   // initialize the serial port
  Serial.begin(115200);   // initialize the TFT Screen
  delay(1);
  TFTscreen.begin();
  Serial.println("TFTscreen init success"); 
  delay(1);
  // clear the screen with a pretty color
  TFTscreen.background(0, 0, 0);
  TFTscreen.setTextSize(1);
  TFTscreen.stroke(255,255,255);   // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) { 
    Serial.print("Attempting to connect to SSID: ");Serial.println(ssid); 
    TFTscreen.text("Connecting  ",28,70);TFTscreen.text("    ...     ",28,90);// Connect to network.status = WiFi.begin(ssid, pass);
  } 
  Serial.println("Connected to wifi");
  printWifiStatus();
  TFTscreen.fillRect(0,70,128,40,0);   // initialize UDP
  Serial.println("\nStarting connection to server...");
  Udp.begin(localPort);   // Init Wire and RTC will use I2C Interface
  Wire1.begin(); 
  getNtpTimeSuccess = 0;   // Get NTP time
  ntpTime();   // if failed ,note user
  if (!getNtpTimeSuccess)
  {
	  TFTscreen.stroke(255,0,0);
	  TFTscreen.textSize(1);
	  TFTscreen.text("get NTP Time",28,70);
	  TFTscreen.text("failed",46,80);
	  delay(3000);
	  TFTscreen.stroke(0,0,0);
	  TFTscreen.text("get NTP Time",