Arduino网络编程实战-OLED显示天气信息

OLED显示天气信息

Arduino Ethernet Shield V1 允许 Arduino 板连接到互联网。 它基于 Wiznet W5100ethernet 芯片(数据表)。 Wiznet W5100 提供支持 TCP 和 UDP 的网络 (IP) 堆栈。 它最多支持四个同时套接字连接。

本实例将演示获取天气JSON数据、数据解析、并在OLED中显示天气。
在这里插入图片描述

通过使用OLED显示天气信息主要由以下步骤组成:

1)请求天气信息,请参考:

2)解析天气JSON信息,请参考:

3)根据天气代码显示天气图片、城市名称、温度信息,请参考:

1、硬件准备

  • Arduino Mega2560 开发板一块
  • SD卡模块一个及SD卡一个
  • SSD1306 OLED屏幕一块
  • 数据线一条
  • 杜邦线若干

硬件接线,请关于前面相关文章,在这里不再做描述。

2、软件准备

3、代码实现

3.1 导入相关头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <SPI.h>
#include <Wire.h>
#include <Adafruit\_GFX.h>
#include <Adafruit\_SSD1306.h>
#include <SdFat.h>
#include <ArduinoJson.h>
#include <Ethernet.h>


#define SCREEN\_WIDTH 128 // OLED display width, in pixels
#define SCREEN\_HEIGHT 64 // OLED display height, in pixels

#define OLED\_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN\_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// SD\_FAT\_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
// SD卡文件系统格式类型
#define SD\_FAT\_TYPE 0
#define SD\_CS\_PIN 4
#define SPI\_CLOCK SD\_SCK\_MHZ(50)
#define SD\_CONFIG SdSpiConfig(SD\_CS\_PIN, DEDICATED\_SPI, SPI\_QUARTER\_SPEED)
#if SD\_FAT\_TYPE == 0
SdFat sd;
File file;
#elif SD\_FAT\_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD\_FAT\_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD\_FAT\_TYPE == 3
SdFs sd;
FsFile file;
#else // SD\_FAT\_TYPE
#error Invalid SD\_FAT\_TYPE
#endif // SD\_FAT\_TYPE

#define USE\_STATIC 1

byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
#if USE\_STATIC
IPAddress ip(192, 168, 0, 116);
#endif

unsigned char img_datas [1024] = {0};
const String beijing_fonts[] = {"fonts/cn\_bei.json","fonts/cn\_jing.json"};
const String weather_code_0 = "weather\_image\_configs/files/0@2x.json";
const String weather_temp_icon = "weather\_image\_configs/files/170@1x.json";
DeserializationError error;
int width,height,len;

3.2 OLED初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

// 串口初始化
Serial.begin(9600);
// OLED初始化
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}

// 显示欢迎屏幕
display.display();
// 清屏
display.clearDisplay();

// 设置字体
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font


3.3 网卡初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  // 初始化网卡
selectEthernet();
#if USE\_STATIC
Ethernet.begin(mac,ip);
#else
Ethernet.begin(mac);
#endif

if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
display.setCursor(0,0);
display.println("Ethernet Failed");
display.display();
while (true) {
delay(1);
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
display.clearDisplay();
display.setCursor(0,0);
display.println("Ethernet LinkOFF");
display.display();
while(true){
delay(1);
}
}

Serial.print("IP:");
Serial.println(Ethernet.localIP());
Serial.print("Subnet Mask:");
Serial.println(Ethernet.subnetMask());
Serial.print("Gateway:");
Serial.println(Ethernet.gatewayIP());
Serial.print("DNS Server:");
Serial.println(Ethernet.dnsServerIP());

display.clearDisplay();
display.setCursor(0,0);
display.print("IP:");
display.print(Ethernet.localIP());
display.display();

3.4 SD卡初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// SD卡初始化
selectSdcard();
// Initialize the SD.
if (!sd.begin(SD_CONFIG)) {
display.clearDisplay();
display.setCursor(0,16);
display.print("SDCard failed");
display.display();
sd.initErrorHalt(&Serial);
return;
}

//display.clearDisplay();
display.setCursor(0,16);
display.print("SDCard Inited");
display.display();
Serial.println("Initialized SD card...");

3.5 请求天气信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
selectEthernet();
// Connect to HTTP server
EthernetClient client;
client.setTimeout(10000);
Serial.println("Connecting....");
if (!client.connect("api.seniverse.com", 80)) {
Serial.println("Connection failed");
return;
}

Serial.println(F("Connected!"));
// Send HTTP request
client.println(F("GET /v3/weather/now.json?key=【你的API Key】&location=beijing&language=zh-Hans&unit=c HTTP/1.0"));
client.println(F("Host: api.seniverse.com"));
client.println("Content-Type: application/json");
client.println("Connection: close"); // or close
client.println("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36");
//client.print("Content-Length: ");
client.println("Connection: close");
client.println(F("Connection: close"));
if (client.println() == 0) {
Serial.println(F("Failed to send request"));
client.stop();
return;
}

// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(status);
client.stop();
return;
}

// Skip HTTP headers
char endOfHeaders[] = "\r\n\r\n";
if (!client.find(endOfHeaders)) {
Serial.println(F("Invalid response"));
client.stop();
return;
}

// Allocate the JSON document
// Use arduinojson.org/v6/assistant to compute the capacity.
//const size\_t capacity = 1024;//JSON\_OBJECT\_SIZE(3) + JSON\_ARRAY\_SIZE(2) + 60;
DynamicJsonDocument doc(2048);

// Parse JSON object
error = deserializeJson(doc, client);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f\_str());
client.stop();
return;
}
// Disconnect
client.stop();

3.6 解析天气信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 解析天气信息
serializeJson(doc, Serial);
Serial.println();
// Extract values
String id = doc["results"][0]["location"]["id"].as<String>();
String temp = doc["results"][0]["now"]["temperature"].as<String>();
String code = doc["results"][0]["now"]["code"].as<String>();
Serial.println(id);
Serial.println(temp);
Serial.println(code);

display.setCursor(0,0);
display.setTextSize(1); //设置字体大小
display.setTextColor(SSD1306_WHITE);//开像素点发光

3.7 显示天气城市名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
display.clearDisplay();
display.display();
selectSdcard();

// 解析并显示城市名称
if(id == "WX4FBXXFKE4F"){

for(int j = 0;j < 2;j++){

Serial.println(beijing_fonts[j].c\_str());
if (!file.open(beijing_fonts[j].c\_str(), O_RDWR)) {
Serial.println("open failed");
while(true);
}
error = deserializeJson(doc, file);

int width = doc["width"].as<int>();
int height = doc["height"].as<int>();
int len;
//serializeJson(doc, Serial);
memset(img_datas,0,1024);
Serial.print("data len:");
Serial.println(doc["datas"].as<JsonArray>().size());
len = doc["datas"].as<JsonArray>().size();
if(len > 0){
for(int i = 0;i < len;i++){
img_datas[i] = doc["datas"][i].as<unsigned char>();
}
display.drawBitmap(j \* 16, 0, img_datas, 16, 16, 1);
}
file.close();
// 绘制字符

}
}

3.8 显示天气温度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 解析并显示温度值及图标
display.setTextSize(4); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(32, 24); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font

display.print(temp.c\_str());
doc.clear();
Serial.println(weather_temp_icon.c\_str());
if (!file.open(weather_temp_icon.c\_str(), O_RDWR)) {
Serial.println("open failed");
while(true);
}
error = deserializeJson(doc, file);
width = doc["width"].as<int>();
height = doc["height"].as<int>();
memset(img_datas,0,1024);
Serial.print("data len:");
Serial.println(doc["datas"].as<JsonArray>().size());
len = doc["datas"].as<JsonArray>().size();
if(len > 0){
for(int i = 0;i < len;i++){
img_datas[i] = doc["datas"][i].as<unsigned char>();
}
file.close();
display.drawBitmap(64, 24, img_datas, 32, 32, 1);
}

3.9 显示天气代码图标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 解析并显示天气图标
if(code == "0"){
doc.clear();
Serial.println(weather_code_0.c\_str());
if (!file.open(weather_code_0.c\_str(), O_RDWR)) {
Serial.println("open failed");
while(true);
}
error = deserializeJson(doc, file);
width = doc["width"].as<int>();
height = doc["height"].as<int>();
//serializeJson(doc, Serial);
memset(img_datas,0,1024);
Serial.print("data len:");
Serial.println(doc["datas"].as<JsonArray>().size());
len = doc["datas"].as<JsonArray>().size();
if(len > 0){
for(int i = 0;i < len;i++){
img_datas[i] = doc["datas"][i].as<unsigned char>();
}
file.close();

display.drawBitmap(112, 0, img_datas, 16, 16, 1);
display.display();
}
}

4、运行结果

在这里插入图片描述

文章来源: https://iotsmart.blog.csdn.net/article/details/123050211