好的,直接上程序。第一套方案的程序:
/*
/* Arduino UNO+w5100+Adafruit_TFTLCD图形LCD显示屏
/* 功能:每天晚上24时9秒,自动软复位,上http://time.nist.gov网校准时间,并在图形显示屏上显示
*/
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
#include <MsTimer2.h>
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
unsigned int localPort = 8888; // local port to listen for UDP packets
char timeServer[] = "time.nist.gov"; // time.nist.gov NTP server
char server[] = "www.baidu.com"; ////
EthernetClient client;////
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
EthernetUDP Udp;
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
unsigned long s;//小时
unsigned long f;//分钟
unsigned long m;//秒
unsigned long s1;//小时数字变化
unsigned long f1;//
unsigned long m1;//
boolean bj=1;//
boolean sj=1;//小时数字变化标记,以便消隐
boolean fj=1;//分钟数字变化标记
boolean mj=1;//秒数字变化标记
int temperature=0;
int tempe=0;
char strvalue[3];//用于存放天气状况的值,区别不同天气主要是看
//https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/aladdin/img/new_weath/bigicon/8.png中".png"前的数字
//这个数字从1-24,即最小1个字符,最大2个字符
void setup()
{
Serial.begin(9600);
while (!Serial) {
;
}
tft.reset();
uint16_t identifier = tft.readID();
identifier=0x9341;
tft.begin(identifier);
tft.setRotation(1);//设置显示屏显示的方向,1代表旋转一个90度,如果是2则旋转2个90度,即180度
tft.setTextSize(4);tft.setTextColor(WHITE);
if (Ethernet.begin(mac) == 0) {
//Serial.println("Failed to configure Ethernet using DHCP");
for (;;)
;
}
Udp.begin(localPort);
MsTimer2::set(1000, flash); // 每秒调用一次 flash函数进行计时
tft.fillScreen(0x0056);//设置屏幕底色
}
void(*resetFunc)(void)=0;//系统重启命令,必须放在loop前面,否则会报错
void loop()
{
sw();
while(1){
xsfm();
if((s==0 && f==0 && m==9)||(s==1 && f==10 && m==2)||(s==5 && f==30 && m==2)||(s==14 && f==10 && m==2)||
(temperature==tempe)){
MsTimer2::stop();//temperature==tempe主要是为了检查下载温度值的有效性,因为最低、最高温度不可能相等
delay(1300);
resetFunc();//软启动系统,达到自动校时的目的
delay(30);
}
}
}
void htx1(int x,int y){//多云,以下参数是按照x=50,y=180设计的
tft.fillCircle(x,y,20,WHITE);//中上大圆
tft.fillCircle(x-20,y+10,13,WHITE);//左下中圆
tft.fillCircle(x+20,y+10,10,WHITE);//右下小圆
tft.fillCircle(x+20,y+10,7,0x0056);//擦除右下小圆内的线
tft.fillCircle(x-20,y+10,10,0x0056);//擦除左下中圆内的线
tft.fillCircle(x, y,17, 0x0056);//擦除中上大圆内的线
}
void htx2(int x,int y){//睛
for(int i=0;i<8;i+=1){
tft.drawLine(x,y, cos(i*0.7853982)*30+x,sin(i*0.7853982)*30+y, WHITE);//以x,y点为圆心,每45度画一条长度为30的直线
delay(2);
}
tft.fillCircle(x,y,20,0x0056);//擦除中间的线条
delay(2);
tft.fillCircle(x,y,15,WHITE);//画太阳的轮廓
tft.fillCircle(x,y,12,0x0056);//擦除太阳中间的色块
}
void htx3(int x,int y){//雪
for(int i=0;i<8;i+=1){
tft.drawLine(x-20,y-10, cos(i*0.7853982)*12+x-20,sin(i*0.7853982)*12+y-10, WHITE);//以x,y点为圆心,每45度画一条长度为30的直线
tft.drawLine(x+10,y+10, cos(i*0.7853982)*12+x+10,sin(i*0.7853982)*12+y+10, WHITE);
delay(2);
}
}
void htx4(int x,int y){//雨加雪
tft.drawLine(x-20,y-20,x-35,y+20,WHITE);
tft.fillCircle(x-24,y,5,0x0056);
for(int i=0;i<8;i+=1){
tft.drawLine(x+10,y, cos(i*0.7853982)*20+x+10,sin(i*0.7853982)*20+y, WHITE);
delay(2);
}
}
void htx5(int x,int y){//雨
tft.drawLine(x-18,y-20,x-33,y+20,WHITE);
tft.drawLine(x-20,y-20,x-35,y+20,WHITE);
tft.fillCircle(x-25,y,5,0x0056);
tft.drawLine(x,y-20,x-15,y+20,WHITE);
tft.drawLine(x+2,y-20,x-13,y+20,WHITE);
tft.fillCircle(x-4,y,5,0x0056);
tft.drawLine(x+22,y-20,x+7,y+20,WHITE);
tft.drawLine(x+20,y-20,x+5,y+20,WHITE);
tft.fillCircle(x+16,y,5,0x0056);
}
void htx6(int x,int y){//阴有小雨
tft.fillCircle(x,y-10,18,WHITE);//中上大圆
tft.fillCircle(x-18,y,11,WHITE);//左下中圆
tft.fillCircle(x+18,y,8,WHITE);//右下小圆
tft.fillCircle(x+18,y,6,0x0056);//擦除右下小圆内的线
tft.fillCircle(x-18,y,9,0x0056);//擦除左下中圆内的线
tft.fillCircle(x, y-10,16, 0x0056);//擦除中上大圆内的线
tft.fillCircle(x-5,y+18,3,WHITE);//擦除左下中圆内的线
tft.fillCircle(x+15,y+25,3,WHITE);//擦除左下中圆内的线
}
void sw(){//上网自动校准时间
if (client.connect(server, 80)) {
// Serial.println("connected");
client.println("GET /baidu?word=天气预报 HTTP/1.0");
client.println();
}
else {
//Serial.println("connection failed");
resetFunc();//软启动系统,达到重新上网的目的
}
if (client.connected()) {
//__________________________________________________________________________________//读取星期和日期
if (client.find("class=\"op_weather4_twoicon_date\">")){//表示从网页源代码的class="op_weather4_twoicon_date">处开始读
for(int i=0;i<118;i++){
Serial.println(client.read());
delay(1);
} //将读取指针移到“周二”字样的“周”字处
delay(1);
int a=client.read();//读取“周二”字样“二”处的汉字的第一个字节
int b=client.read();//读取“周二”字样“二”处的汉字的第二个字节
int c=client.read();//读取“周二”字样“二”处的汉字的第三个字节
int d=a+b+c;//将代表汉字的三个字节相加,以简便的方法判断是星期几
String xc="";
switch(d){
case 540://星期一
xc="Mon";
break;
case 554://星期二
xc="Tues";
break;
case 549://星期三
xc="Wed";
break;
case 539://星期四
xc="Thur";
break;
case 562://星期五
xc="Fri";
break;
case 535://星期六
xc="Sat";
break;
case 546://星期日
xc="Sun";
break;
default:
break;
}
int mm=client.parseInt();//源代码开始处向下读,出现的第1个阿拉伯数字,定义为月份变量。
int dd=client.parseInt();//源代码开始处向下读,出现的第2个阿拉伯数字,定义为日期变量。
int cm=client.parseInt();//源代码开始处向下读,出现的第2个阿拉伯数字,定义为当前温度。
tft.setCursor(20, 30); tft.print(mm); tft.print("/"); tft.print(dd);//
tft.setCursor(150, 30); tft.print(xc);//tft.print("Week ");
}
//__________________________________________________________________________________//读取天气状况
if (client.find("/www/aladdin/img/new_weath/bigicon/")){
char tq1=client.read();//读取第一个字符
// Serial.println(tq1);
strvalue[0]=tq1;//取出第一个字符放在数组中
char tq2=client.read();//再读取一个字符
if(isDigit(tq2)){//判断这个字符是“0-9”的字符
strvalue[1]=tq2;//如果是“0-9”之间的字符则放放数组
strvalue[2]=0;//最后在数组中加一个终止字符0
}
else{
strvalue[1]=0;//如果第二个读数不是“0-9”之间的字符,则数组中加一个终止字符0
}
int ln=atoi(strvalue);//将数组转化成int
//Serial.println(ln+2);//试验是否转化成功
if (ln==1||ln==2||ln==5||ln==6||ln==7){//表示晴
htx2(70,190);
}
if (ln==3||ln==4){//表示多云
htx1(70,190);
}
if (ln==8||ln==9||ln==10){//表示小雨、阴有雨
htx6(70,190);
}
if (ln==11||ln==12||ln==13){//表示中雨、暴雨、雷阵雨
htx5(70,190);
}
/*
if (ln==14){//表示雨+雪
htx4(70,190);
}
if (ln==17||ln==18||ln==19||ln==20){//表示小雪中雪暴雪
htx3(70,190);
} */
}
//__________________________________________________________________________________//读取最低、最高温度
if (client.find("class=\"op_weather4_twoicon_temp\">")){
tempe=client.parseInt();
temperature=client.parseInt();
tft.setCursor(140, 180);tft.setTextColor(WHITE); //tft.print("Temp ");
tft.print(temperature); tft.print("-"); tft.print(tempe);
tft.setCursor(260, 160); tft.setTextSize(3); tft.print(".");tft.setCursor(280, 180); tft.setTextSize(4); tft.print
("C");//
}
client.stop();
client.flush();
delay(1200);
//__________________________________________________________________________________//从服务器读取时分秒
sendNTPpacket(timeServer); // 给http://time.nist.govsend 服务器发送NTP包,请求下载时间
delay(1000);
if ( Udp.parsePacket() ) {//假如收到了数据包
Udp.read(packetBuffer, NTP_PACKET_SIZE);
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);//时间戳开始于40字节,4个字节转换成长整数
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
unsigned long secsSince1900 = highWord << 16 | lowWord;//这就是1900年到现在的NTP时间(单位为秒)
const unsigned long seventyYears = 2208988800UL;//1900年1月1日到1970年1月1日的秒数
unsigned long epoch = secsSince1900 - seventyYears;//1970年1月1日到现在的秒数
s=(epoch % 86400L) / 3600; //每天86400秒,余数中有一个3600秒就是一个小时
s=s+8;//北京时间是东八区,与格林治天文时间正好差8个小时
if (s>=24) {
s=s-24;
}
f=(epoch % 3600) / 60; //每分钟3600秒,除以60分钟的余数就为分钟
m=epoch % 60; //60的余数即为当前时间的秒数
}
bj=0;
MsTimer2::start();
}
}
void flash(){//Arduino计时
m=m+1;
mj=0;
if(m==60){
m=0;
f=f+1;
fj=0;
if(f==60) {
s=s+1;
sj=0;
f=0;
if(s==24){
s=0;
}
}
}
}
void xsfm(){//显示时分秒
tft.setTextSize(5);
xs();//显示小时
tft.print(":");
xf();//显示分钟
tft.print(":");
xm(); //显示秒
}
void xs(){//显示时
if(sj==0){
tft.fillRect(40, 100, 100,40, 0x0056); //在显示小时的位置画一个与底色相同的长方形,从而达到清屏的目的
sj=1;
}
if(sj==1){
tft.setCursor(40,100);tft.setTextColor(WHITE);
if(s<10){
tft.print("0"); tft.print(s);}
else
{tft.print(s); }
}
}
void xf(){//显示分
if(fj==0){
tft.fillRect(130,100, 100,40, 0x0056); //在显示分钟的位置画一个与底色相同的长方形,从而达到清屏的目的
fj=1;
}
if(fj==1){
tft.setCursor(130, 100);tft.setTextColor(WHITE);
if(f<10){
tft.print("0"); tft.print(f);}
else
{tft.print(f); }
}
}
void xm(){//显示秒
if(mj==0){
tft.fillRect(220, 100, 100,40, 0x0056); //在显示秒数字的位置画一个与底色相同的长方形,从而达到清屏的目的
mj=1;
}
if(mj==1){
tft.setCursor(220, 100);tft.setTextColor(WHITE);
if(m<10){
tft.print("0"); tft.print(m);}
else
{tft.print(m); }
}
}
unsigned long sendNTPpacket(char* address)
{
memset(packetBuffer, 0, NTP_PACKET_SIZE);
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
Udp.beginPacket(address, 123);
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
这个方案有几点不是太好,一是月日周从网页中提取,一旦网页改版,就会出错。二是校对时间时,系统必须重启。第二套方案,就把以上问题解决了。下次再发第二套的程序吧! |