Introduction
This simple example will implement a simple weather application. This will show several features of the the K64F board and will show how you can use the MBED libraries to quickly put together a working application. I'll walk through the development and show some of the issues I came across, as with most projects there is always some unexpected to trip you up. My weather application would have the following features
- Data and Time set automatically via NTP
- Data displayed on TFT display (I used a 240x320 display using ILI9341 controller, which is very common)
- SDCard for storing weather data and for holding image resources for TFT
- Temperature and Humidity Sensor, I will use external DHT22 sensor
- I will use forecast data for outside temperature and pressure
- I will plot the data on a graph using online service
If you are following along and want to build the app, you will need the K64F board (obviously) and a DHT22 sensor, you could use an alternative but you'll need to make the appropriate changes. The display is optional, as I'll also send the data to the PC so you can see the data on a serial terminal but if you want to use the app standalone a display would be useful. A 3v3 supply is also desirable, when adding peripherals such as displays you'll quickly overload the USB Supply. We will also be using the Ethernet connectivity, you want to think how you will connect the board to your router/network. If like me your wireless router is some distance from where you are working you might want to use a powerline network adapter. These adapers are ideal for this type of application. you plug one into a powersocket near your router and connect it to a free ethernet port. At the other end you plug in another adapter and connect the Ethernet port to your K64F. The K64F has an SD socket if you want to store the results you'll also need an SD card for your board but this is purely optional and isn't really needed.
Connecting the Hardware
I suggest using an external 3v3 supply, the display flickers with the USB only supply and this may affect the sensor.
The DHT22 is connected to PTB18
The TFT MOSI=PTD2, MISO=PTD3, SCLK=PTD1,CS=PTC3 ,RESET=PTC4 ,DC=PTD0
The Display needs a 100-120R resistor for the back-light, you may want to check the value for your display. The display is a 320x240 Display with ILI9341 controller.
The DHT22 needs a 4k7 pullup on the data line
Remember to connect 0V on the K64F to the PSU 0V. You could also power the K64F from the 3V3 but it will be powered from the USB.
Insert the micro SD card (contacts facing board)
The code
Log into your MBED account and import the code for the project. To do this go to weather - a mercurial repository | mbed
then click on the Import This program button
this will import the program into your workspace.
Open main.cpp all of the user code for application code is here,
The code above the main section includes all the required header files and sets up all the objects we will be using. If you need to change any of the connections this is were you would do it.
Initializing the Ethernet interface
eth.init(); //Use DHCP
ret= eth.connect();
if (!ret) {
pc.printf("Connected, IP: %s, MASK: %s, GW: %s\n",
eth.getIPAddress(), eth.getNetworkMask(), eth.getGateway());
} else {
pc.printf("Error eth.connect() - ret = %d\n", ret);
If it connects OK it will print the IP address to the terminal
Setting up the TFT
TFT.claim(stdout); // send stdout to the TFT display
//ensure the output is write and not buffered
setvbuf ( stdout , NULL , _IONBF , NULL );
//TFT.claim(stderr); // send stderr to the TFT display
TFT.set_orientation(1);
TFT.background(Black); // set background to black
TFT.cls();
TFT.locate(0,0);
TFT.set_font((unsigned char*) sansserif);
This section of code should be self explanatory. The TFT.claim(stdout) "claims" the stdout, so that anything written to stdout will now be written to the TFT, so you can simply use printf and the output will go to the TFT. The setvbuf command prevents buffering so when you use printf the output will go to the TFT without any buffering which can cause your output to be delayed.
Setting the Time
time_t ctTime;
NTPResult result;
result = ntp.setTime("pool.ntp.org");
Writing to SDCARD
Note if you are not using the SDCARD you could remove this code (and the later section)
This puts the results in a directory called results, the file name is set to default_results. Howver since you have the correct time, you could use the date and time in the filename.
mkdir("/sd/results", 0777);
fp = fopen(sdfile, "w");
if (fp == NULL) {
pc.printf("Unable to write the file \n");
} else {
pc.printf("Writing data to SDCARD \n");
fprintf(fp, "time,temperature,humidity,forcastTemp,forcastPressure\n");
fclose(fp);
}
Getting the weather forecast
ret = http.get("http://api.openweathermap.org/data/2.5/weather?q=Strathaven,uk", resp, 5000);
if(!ret){
pc.printf("responce=%s",resp);
json=&resp[0];
pc.printf("parsing");
string err = picojson::parse(v, json, json + strlen(json));
if(err.empty()){
forcastTemp=v.get("main").get("temp").get<double>();
forcastTemp=forcastTemp-273.15;
forcastPressure=v.get("main").get("pressure").get<double>();
}
else{
pc.printf("error parsing");
}
http get is used to get the data from openweathermap.org, the location i set to Strathaven my home location, change this to your location. there is a 5000mS timout on this request. You may need to lengthen this. The default data format is JSON. the actual data that comes back looks like this:
{
- coord: {},
- lon: -4.07,
- lat: 55.68
- sys: {},
- type: 1,
- id: 5121,
- message: 0.0466,
- country: "United Kingdom",
- sunrise: 1427263464,
- sunset: 1427308797
- weather:
[
],- {}
- id: 804,
- main: "Clouds",
- description: "overcast clouds",
- icon: "04n"
- {}
- base: "stations",
- main: {},
- temp: 278.27,
- pressure: 1005,
- humidity: 60,
- temp_min: 277.65,
- temp_max: 279.15
- visibility: 10000,
- wind: {},
- speed: 3.6,
- deg: 140
- clouds: {},
- all: 88
- dt: 1427314968,
- id: 0,
- name: "Strathaven",
- cod: 200
}
You could simply parse this by looking for certain strings, however we use a JSON parsing library to parse the data. This makes it very easy to pick out the data fields you want. I only use a few of them but you could pick out whatever data you want.e.g. v.get("main").get("temp").get<double>() or v.get("weather").get("description").get<string>() . This may not work as well on some of the other MBED boards where the memory is more limited. I've not looked at the memory usage but most JSON library use a fair amount of memory. As mentioned you could easly parse this without using the JSON library.
Reading the Sensor
First read the sensor and check there is not an error, the use ReadTemperature etc to get the values.
err=sensor.readData()
sensor.ReadTemperature(CELCIUS)
Sending data to ThingSpeak
Once we have the data we want we send it to the Thingspeak https://thingspeak.com/ channel to record and graph our results.
map.put("api_key","YOUR KEY HERE");
sprintf(val[0],"%4.1f",temperature);
map.put("field1", val[0]);
sprintf(val[1],"%4.1f",humidity);
map.put("field2", val[1]);
sprintf(val[2],"%4.1f",forcastTemp);
map.put("field3", val[2]);
sprintf(val[3],"%4.1f",forcastPressure);
map.put("field4", val[3]);
pc.printf("\nTrying to post data...\n");
ret = http.post("https://api.thingspeak.com/update", map, &inText);
Here we build up a Post request and send it using http.post. The important thing to note here is you need to put in your Thingspeak API WRITE key. this is a unique number that identifies your channel. We'll cover setting the Thingspeak interface in the next section.
In the next part I've cover setting up thingspeak, some of the issues I seen and getting the project running