设计背景
天气预报已然无法满足我们对天气预测的需求,
所以想要通过动手制作一个可以预测天气的装置。
因为想到天气就想到了云,所以用了云的外观。
制作过程
产品所需要的模块和传感器。
运用3D建模,制作大概的模型图。
确定好尺寸在犀牛里画出产品的外观线框图,再进行激光切割。
切割完毕后按图所示固定相对应的传感器和显示屏,折出外形。
成品图十分酷炫,通上电源就可以使用了。
下面是详细的编程过程。
WIFI.h
// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ 2 // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT 9
#define ADAFRUIT_CC3000_CS 10
#define WLAN_SECURITY WLAN_SEC_WPA2
#define IDLE_TIMEOUT_MS 1000
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,SPI_CLOCK_DIV2); // you can change this clock speed but DI
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
uint32_t ip;
Adafruit_CC3000_Client www;
/**************************************************************************/
/*!
@brief Tries to read the IP address and other connection details
*/
/**************************************************************************/
void freeMem(char* message)
{
extern unsigned int __heap_start, *__brkval;
unsigned int v;
Serial.print(message);
Serial.print(":");
Serial.println((unsigned int) &v - (__brkval == 0 ? (unsigned int) &__heap_start : (unsigned int) __brkval));
}
bool displayConnectionDetails(void) {
uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;
if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv)) {
Serial.println(F("\r\nUnable to retrieve the IP Address!"));
return false;
}
else {
Serial.print(F("\nIP Addr: "));
cc3000.printIPdotsRev(ipAddress);
Serial.print(F("\nNetmask: "));
cc3000.printIPdotsRev(netmask);
Serial.print(F("\nGateway: "));
cc3000.printIPdotsRev(gateway);
Serial.print(F("\nDHCPsrv: "));
cc3000.printIPdotsRev(dhcpserv);
Serial.print(F("\nDNSserv: "));
cc3000.printIPdotsRev(dnsserv);
Serial.println();
return true;
}
}
bool voCC3000_get_dhcp() {
bool cache;
for(int a=0;a<15;a++) {
Serial.println(F("Request DHCP"));
if(!cc3000.checkDHCP()) {
cache=false;
delay(1000); // ToDo: Insert a DHCP timeout!
}
else {
cache=true;
break;
}
}
if(!cache)
return false;
else {
for(int a=0;a<2;a++) {
/* Display the IP address DNS, Gateway, etc. */
if (! displayConnectionDetails()) {
cache=false;
delay(500);
}
else {
cache=true;
break;
}
}
return cache ? true :false;
}
}
bool voCC3000_get_server_ip() {
ip = 0;
// Try looking up the website's IP address
Serial.print(WEBSITE);
Serial.print(F(" -> "));
for(int a=0;a<2;a++) {
if (! ip) {
Serial.println(F("\r\n While ing "));
if (! cc3000.getHostByName(WEBSITE, &ip))
Serial.println(F("Couldn't resolve!"));
delay(500);
}
else
break;
}
Serial.println(cc3000.getHostByName(WEBSITE, &ip));
cc3000.printIPdotsRev(ip);
Serial.println(F(" "));
return ip ? true :false;
}
bool voCC3000_reconnect() {
cc3000.reboot();
//----------------------------------------------------------
cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
//----------------------------------------------------------
if(!voCC3000_get_dhcp())
return false;
else {
if(!voCC3000_get_server_ip())
return false;
else
return true;
}
}
bool voCC3000_ping(float temp, float humi, float light, float pm25, float etoh) {
String dataToSend;
String my_app_kit_id=APP_KIT; //设备ID号
char buf[10];
Serial.println("**************************post to Service******************************************");
www = cc3000.connectTCP(ip, WEBSITEPORT);
Serial.println("Ping");
if (www.connected()) {
Serial.println(F("Connected"));
www.print("POST ");
www.print(WEBPAGE);
www.println(" HTTP/1.1");
www.print(F("Host: "));
www.println(WEBSITE);
www.print("Accept: *");
www.print("/");
www.println("*");
dataToSend="{\"my_app_kit_id\":";
dataToSend+="\""+my_app_kit_id+"\"";
dataToSend+=",\"Temperature\":";
dtostrf(temp,1,2,buf);
dataToSend+="\""+String(buf)+"\"";
dataToSend+=",\"Humidity\":";
dtostrf(humi,1,2,buf);
dataToSend+="\""+String(buf)+"\"";
dataToSend+=",\"Light\":";
dtostrf(light,1,2,buf);
dataToSend+="\""+String(buf)+"\"";
dataToSend+=",\"PM\":";
dtostrf(pm25,1,2,buf);
dataToSend+="\""+String(buf)+"\"";
dataToSend+=",\"Air Pollution\":";
dtostrf(etoh,1,2,buf);
dataToSend+="\""+String(buf)+"\"";
dataToSend+="}";
Serial.println(dataToSend);
www.println("Content-Type: application/json");
www.print("Content-Length: ");
www.println(dataToSend.length());
www.println();
www.print(dataToSend);
Serial.println(F("Sent"));
return true;
}
else
return false;
}
void voCC3000_rec() {
String returnStateData;
String stateValue;
int start=0;
int end=0;
Serial.println(F("---------Data start-------------"));
unsigned long lastRead = millis();
while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
while (www.available()) {
char c = www.read();
returnStateData+=c;
lastRead = millis();
}
}
www.close();
Serial.print("all:");
Serial.println(returnStateData);
start=returnStateData.indexOf('{');
returnStateData=returnStateData.substring(start,returnStateData.length());
//returnStateData.toCharArray(json_string,returnStateData.length());
start=returnStateData.indexOf("\"Status\":");
if(start>0) {
end=returnStateData.indexOf("\"}");
returnStateData=returnStateData.substring(start+10,end);
Serial.println(returnStateData);
//Serial.println(statusChar);
//stateValue=statusChar;
stateValue=returnStateData;
// aJsonObject* jsonObject = aJson.parse(json_string);
// aJsonObject* statusPrt = aJson.getObjectItem(jsonObject , "Status");
//stateValue=statusChar;
stateValue=returnStateData;
// Serial.println(statusPrt->valuestring);
// stateValue=statusPrt->valuestring;
if(stateValue=="true") {
Serial.println("ONONON");
// s_data='1';
// digitalWrite(ledPin, HIGH);
}
else {
Serial.println("OFFOFFOFF");
// s_data='0';
// digitalWrite(ledPin, LOW);
}
}
returnStateData="";
Serial.println(F("---------Data end-------------"));
}
bool voCC3000_init(int _voCC3000_init)
{
//1/4----------------------------------------------------------
Serial.println(F("\n......CC3000_init"));
switch(_voCC3000_init)
{
case 0:
{
Serial.println("\n 1/4 begin");
if (!cc3000.begin())
{
Serial.println("\n 1/4 begin ERROR");
return false;
}
else
{
Serial.println("1/4 begin OK");
return true;
}
}
break;
case 1:
{
Serial.println("\n 2/4 connect AP READY");
if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY))
{
Serial.println("2/4 connect AP ERROR");
Serial.println(F("Failed!"));
return false;
}
else
{
Serial.println("\n2/4 connect AP OK");
return true;
}
}
break;
case 2:
{
Serial.println("\n 3/4 dhcp READY");
if(!voCC3000_get_dhcp())
{
Serial.println("3/4 dhcp ERROR");
Serial.println(F("Failed!"));
return false;
}
else
{
Serial.println("3/4 dhcp OK");
return true;
}
}
break;
case 3:
{
Serial.println("\n 4/4 server READY");
if(!voCC3000_get_server_ip())
{
Serial.println("4/4 server ERROR");
Serial.println(F("Failed!"));
return false;
}
else
{
Serial.println("4/4 server OK");
return true;
}
}
break;
}
}
void setup_wifi() {
bool sta;
osd_setup(1,"INIT WIFI");
if(voCC3000_init(0))
{
osd_setup(2,"CONNECT AP");
if(voCC3000_init(1))
{
osd_setup(3,"GET DHCP");
if(voCC3000_init(2))
{
osd_setup(4,"GET SERVER");
if(voCC3000_init(3))
sta = true;
else
sta = false;
}
else
sta = false;
}
else
sta = false;
}
else
sta = false;
if(!sta)
osd_setup(0,"NET ERROR");
//----------------------------
osd_setup(5,"INIT SENSOR");
}
void updateWeatherData(float temp, float humi, float light, float pm25, float etoh) {
bool NET_WEBSITE_sta;
NET_WEBSITE_sta=voCC3000_ping(temp,humi,light,pm25,etoh);
if(NET_WEBSITE_sta)
{
Serial.println("\n ---UPDATA OK---");
voCC3000_rec();
}
else
{
Serial.println("\n --UPDATA ERROR--");
cc3000.reboot();
freeMem("==============Step A");
if(voCC3000_init(1))
{
freeMem("==============Step B");
if(voCC3000_init(2))
{
freeMem("==============Step C");
if(voCC3000_init(3))
NET_WEBSITE_sta = true;
else
NET_WEBSITE_sta = false;
}
else
NET_WEBSITE_sta = false;
}
else
NET_WEBSITE_sta = false;
freeMem("==============Step D");
}
}
Sensor.h
#include
AM2321 am2321;
SoftwareSerial pmSerial(4,5); //PM2.5传感器通讯软串口
float sensorTemp; //温度值
float sensorHumi; //湿度值
float sensorPM25; //pm2.5浓度
float sensorLight; //光照强度
float sensorEtoh; //空气质量
//读取pm2.5传感器
float PM25(){
int data_s = 0; //串口接收数据
int num = -1; //串口接收数据计数
int sum = 0; //校验和
int cal[5]; //接收数据缓存
float dustDensity = 0; //PM2.5浓度
pmSerial.begin(2400); //首先启动软串口
pmSerial.flush(); //清空串口缓存
while(1)
{
if(pmSerial.available() > 0) //串口缓存有数据
{
data_s = pmSerial.read(); //读取串口缓存数据
if(data_s == 0xAA) //得到数据帧起始位
{
num = 0; //开始计数
}
else if(num >= 0)
{
num++; //读到数据,计数+1
cal[num-1] = data_s; //数据保存到缓存中
if(num == 6) //读到数据帧最后一位
{
sum = cal[0] + cal[1] + cal[2] + cal[3]; //计算校验和
if(sum == cal[4] && cal[5] == 0xFF) //校验和匹配,数据帧最后一位为0xFF,说明接收的数据帧正常
{
dustDensity = (cal[0]*256 + cal[1])*(5.0/1024)*550; //计算PM2.5浓度,单位ug/m3
}
else //接收的数据不正常
{
dustDensity = 0; //浓度清零
}
break;
}
}
}
}
pmSerial.end(); //关闭软串口
return dustDensity; //返回值
}
//更新传感器数据
void SensorUpdate() {
//获取pm2.5浓度
// sensorPM25 = PM25();
//获取温度,湿度
am2321.read();
sensorTemp = am2321.temperature / 10.0;
sensorHumi = am2321.humidity / 10.0;
//获取光照强度
sensorLight = map(analogRead(A0), 0, 1023, 0, 255);
//获取空气质量
sensorEtoh= map(analogRead(A2), 0, 1023, 0, 30);
}
Oled.h
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); //设置OLED型号
//-------字体设置,大、中、小
#define setFont_L u8g.setFont(u8g_font_7x13)
#define setFont_M u8g.setFont(u8g_font_fixed_v0r)
#define setFont_S u8g.setFont(u8g_font_chikitar)
//温度计图案
const unsigned char bmp_tem[] U8G_PROGMEM =
{
0xE0,0x81,0x30,0x83,0x10,0x82,0x10,0x82,0x10,0xFA,0x10,0x82,
0x10,0x82,0x10,0xFA,0x10,0x82,0xD0,0x82,0xD0,0xFA,0xD0,0x82,
0xD0,0x82,0xD0,0xFA,0xD0,0x82,0xD0,0x82,0xD0,0xFA,0xD0,0x82,
0xD0,0x82,0xD8,0x86,0xC4,0x88,0xF2,0x93,0xFB,0xB7,0xF9,0xA7,
0xFD,0xAF,0xFD,0xAF,0xF9,0xA7,0xFA,0x97,0xF2,0x93,0xC4,0x88,
0x18,0x86,0xF0,0x83
};
//水滴图案
const unsigned char bmp_hum[] U8G_PROGMEM =
{
0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x80,0x03,0x08,0x80,0x03,0x18,0x80,0x07,0x1C,
0xC0,0x07,0x3C,0xC0,0x07,0x3E,0xE0,0x0F,0x3E,0xE0,0x0F,0x7A,0xF0,0x1F,0x7B,0xF8,
0x1F,0x72,0xF8,0x1F,0x3E,0xF8,0x3F,0x1C,0xFC,0x3F,0x00,0xFC,0x7F,0x00,0xFE,0x7F,
0x00,0xFE,0x7F,0x00,0xFE,0x7F,0x00,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0xFF,0xFF,0x00,
0xF3,0xFF,0x00,0xF2,0x7F,0x00,0xE6,0x7F,0x00,0xC6,0x7F,0x00,0x0E,0x3F,0x00,0x3C,
0x1E,0x00,0xF8,0x1F,0x00,0xE0,0x07,0x00,0x80,0x01
};
//显示函数
void osd_setup(int _osd_setup,char* _osd_text) {
u8g.firstPage();
do {
setFont_L;
u8g.setPrintPos(4, 30);
u8g.print(_osd_text);
u8g.drawFrame(0,48,128,14);
if(_osd_setup)
u8g.drawBox(0+2,48+2,map(_osd_setup,0,5,0,128-4),14-4);
}
while( u8g.nextPage() );
}
//显示函数
void volcd(float temp, float humi, float light, float pm25, float etoh) {
u8g.firstPage();
do {
u8g.setDefaultForegroundColor();
u8g.drawXBMP( 4, 1, 15, 32, bmp_tem);
u8g.drawXBMP( 70, 2, 24, 30, bmp_hum);
setFont_M; //设置字体为大
u8g.setPrintPos(20, 16); //设置文字开始坐标
u8g.print("`C ");
setFont_L; //设置字体为大
u8g.setPrintPos(20, 32); //设置文字开始坐标
u8g.print(temp , 1); //温度
setFont_M; //设置字体为大
u8g.setPrintPos(100, 16); //设置文字开始坐标
u8g.print("%");
setFont_L; //设置字体为大
u8g.setPrintPos(100, 32); //设置文字开始坐标
u8g.print(humi , 0); //湿度
setFont_L; //设置字体
u8g.setPrintPos(4, 49); //设置文字开始坐标
u8g.print(light , 0); //光照强度
setFont_M; //设置字体
u8g.print(" Lux");
setFont_L; //设置字体
u8g.setPrintPos(4, 63); //设置文字开始坐标
u8g.print(pm25 , 1); //光照强度
setFont_M; //设置字体
u8g.print(" ug/m3");
setFont_L; //设置字体
u8g.setPrintPos(80, 49); //设置文字开始坐标
u8g.print(etoh , 0); //光照强度
setFont_M; //设置字体
u8g.print(" ppm");
setFont_M; //设置字体为大
u8g.setPrintPos(80, 63); //设置文字开始坐标
u8g.print(" LED:");
}
while( u8g.nextPage() );
}
void volcdsetup(char* zi,unsigned int x,unsigned int y) {
//#ifdef OLED
u8g.firstPage();
do {
setFont_L;
u8g.setPrintPos(x, y);
u8g.print(zi);
}
while( u8g.nextPage() );
//#endif
}
Def.h
//#define WIFI_CC3000
#define WLAN_SSID "AZURE" //WIFI网络名
#define WLAN_PASS "azure001" //WIFI密码
#define WEBSITE "mcotton.microduino.cn" //服务器网址
#define WEBSITEPORT 8080 //服务器端口号
#define APP_KIT "TLcrn6vaAahjnvKR2" //设备ID号#define APP_KIT "YourDeviceID" //设备ID号
#define WEBPAGE "/api/v1.0/d"
#define WEBUTTONPAGE "/api/v1.0/ce"
立即注册