本文章介紹Raspberry Pi Pico W c-sdk,使用lwIP的HTTP Client Application 存取openweathermap網站的氣象資料,顯示在TFT LCD上。
使用httpc_get_file_dns function取得 網站資料。分別設定三個callback function:
1: httpc_result_fn:
本文章介紹Raspberry Pi Pico W c-sdk,使用lwIP的HTTP Client Application 存取openweathermap網站的氣象資料,顯示在TFT LCD上。
本文章介紹Raspberry Pi Pico W使用lwIP library 每6小時透過NTP校正RTC時鐘,並以Digital or Analog Clock方式透過ILI9341 TFT LCD時間,畫面上顯示WiFi連線狀態,當網路中斷後重新連線時立即做一次網路校時。
一、建立專案
安裝pico-project-generator程式,以圖行化產生專案初始內容。
~$ pico_project.py --gui
使用LwIP library 需要lwipopts.h檔案,將該檔案先複製到pico_project.py相同目錄下。
~$ cp pico-examples/pico_w/lwipopts_examples_common.h <pico-project.py directory>/lwipopts.h
二、週期檢視的程式碼:
三、NTP data format:
四、成果影片
五、程式碼
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "hardware/rtc.h"
#include "time.h"
#include "lwip/dns.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "modules/ili9341_tft/ili9341.h"
#include "fonts/font_fixedsys_mono_24.h"
#include "fonts/font48.h"
#include "fonts/font36.h"
#include "fonts/wifi.h"
#include "fonts/wifi_off.h"
#include "fonts/clock.h"
#include "math.h"
#define WIFI_SSID "your-SSID"
#define WIFI_PASS "your-WIFI_PASSWORD"
#define NTP_SERVER "pool.ntp.org"
#define NTP_PORT (123)
bool showAnalog=true;
/* RFC 1305
NTP timestamps are represented as a 64-bit unsigned fixed-
point number, in seconds relative to 0h on 1 January 1900. The integer
part is in the first 32 bits and the fraction part in the last 32 bits.*/
#define NTP_DELTA (2208988800) // seconds between 1 Jan 1900 and 1 Jan 1970
#define NTP_MSG_LEN (48) // ignore Authenticator (optional)
typedef struct NTP_TIME_T {
ip_addr_t ntp_ipaddr;
struct udp_pcb *ntp_pcb;
bool ntp_server_found;
absolute_time_t ntp_update_time;
int tcpip_link_state;
} NTP_TIME;
NTP_TIME net_time;
uint8_t wday[7][10] = {"Sunday", "Monday","Tuesday","Wednesday", "Thursday", "Friday", "Saturday"};
void get_ntp_time();
void set_wifi_status_icon(int status) {
if (status == CYW43_LINK_UP) {
ili9341_draw_bitmap(270, 20, &wifi);
} else {
ili9341_draw_bitmap(270, 20, &wifi_off);
}
}
int64_t alarm_ntp_update_cb(alarm_id_t alarm_id, void* param) {
cancel_alarm(alarm_id);
get_ntp_time();
}
void ntp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) {
NTP_TIME* ntp_time = (NTP_TIME*)arg;
uint8_t mode=pbuf_get_at(p,0)& 0x07; // LI[2], VN[3], MODE[3], mode(0x04): server
uint8_t stratum = pbuf_get_at(p,1); // straum
uint8_t ts[4]={0};
uint32_t sec_offset;
if (port == NTP_PORT && ip_addr_cmp(&net_time.ntp_ipaddr, addr) && p->tot_len == NTP_MSG_LEN && mode == 0x04 && stratum != 0) {
pbuf_copy_partial(p, ts, sizeof(ts), 40);
sec_offset = ((uint32_t)ts[0])<<24 | ((uint32_t)ts[1])<<16 | ((uint32_t)ts[2])<<8 | ((uint32_t)ts[3]);
uint32_t temp = sec_offset - NTP_DELTA+8*60*60; //UTC+8
time_t utc_sec_offset = temp;
struct tm *utc = gmtime(&utc_sec_offset);
datetime_t rtc_time;
rtc_time.year=utc->tm_year+1900;
rtc_time.month= utc->tm_mon+1;
rtc_time.day = utc->tm_mday;
rtc_time.hour = utc->tm_hour;
rtc_time.min = utc->tm_min;
rtc_time.sec = utc->tm_sec;
rtc_time.dotw = utc->tm_wday;
if (!rtc_set_datetime(&rtc_time)) printf("set rtc error\n");
//printf("got ntp response: %02d/%02d/%04d %02d:%02d:%02d\n", utc->tm_mday, utc->tm_mon + 1, utc->tm_year + 1900,
// utc->tm_hour, utc->tm_min, utc->tm_sec);
ntp_time->ntp_update_time = make_timeout_time_ms(21600000); //6*60*60*1000
add_alarm_at(ntp_time->ntp_update_time, alarm_ntp_update_cb, arg, false);
}
pbuf_free(p);
}
void ntp_init_data() {
net_time.ntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
net_time.ntp_server_found=false;
net_time.tcpip_link_state = CYW43_LINK_DOWN;
if (!net_time.ntp_pcb) {
printf("alloc udp_new error\n");
return;
}
udp_recv(net_time.ntp_pcb, ntp_recv_cb, &net_time);
}
void get_ntp_time() {
cyw43_arch_lwip_begin();
struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, NTP_MSG_LEN, PBUF_RAM);
uint8_t *req = (uint8_t *) pb->payload;
memset(req, 0, NTP_MSG_LEN);
req[0] = 0x1b; // 0x00 011 011 (LI:00, VN:3(version), MODE:3 (client))
udp_sendto(net_time.ntp_pcb, pb, &net_time.ntp_ipaddr, NTP_PORT);
pbuf_free(pb);
cyw43_arch_lwip_end();
}
void dns_cb(const char *name, const ip_addr_t *ipaddr, void *arg) {
NTP_TIME* ntime = (NTP_TIME*)(arg);
ntime->ntp_ipaddr=*ipaddr;
printf("ntp server:%s\n", ipaddr_ntoa(&ntime->ntp_ipaddr));
ntime->ntp_server_found = true;
}
void digitColck(datetime_t *dt) {
char buf[100];
sprintf(buf, "%04d-%02d-%02d", dt->year,dt->month,dt->day);
ili9341_draw_string_withbg(80,20, buf, 0x0000,0xffff,&font36);
sprintf(buf, "%02d:%02d:%02d", dt->hour,dt->min,dt->sec);
ili9341_draw_string_withbg(10,80, buf, 0x001f,0xffff,&font48);
ili9341_draw_string_withbg(20,190, wday[dt->dotw], 0xf800,0xffff,&font_fixedsys_mono_24);
}
void analogClock(datetime_t *dt) {
double ang;
static int offx_h=0, offy_h=0;
static int offx_m=0, offy_m=0;
static int offx_s=0, offy_s=0;
static int pre_offx_h=0, pre_offy_h=0;
static int pre_offx_m=0, pre_offy_m=0;
static int pre_offx_s=0, pre_offy_s=0;
// hour hand
ang=(((dt->hour)%12)*60+dt->min)*M_PI/360-M_PI/2;
offx_h = 50*cos(ang);
offy_h = 50*sin(ang);
// minute hand
ang=((dt->min)*60+dt->sec)*M_PI/1800-M_PI/2;
offx_m = 70*cos(ang);
offy_m = 70*sin(ang);
// second hand
ang = (dt->sec*M_PI)/30.0-M_PI/2;
offx_s = 80*cos(ang);
offy_s = 80*sin(ang);
//clear clock hands
ili9341_draw_line_width(159-pre_offx_s/7,119-pre_offy_s/7, 159+pre_offx_s, 119+pre_offy_s, 1,0xffff);
ili9341_draw_circle(159+pre_offx_s, 119+pre_offy_s,3,0xffff);
ili9341_draw_line_width(159-pre_offx_m/7,119-pre_offy_m/7, 159+pre_offx_m, 119+pre_offy_m, 1,0xffff);
ili9341_draw_circle(159+pre_offx_m, 119+pre_offy_m,3,0xffff);
ili9341_draw_line_width(159-pre_offx_h/7,119-pre_offy_h/7, 159+pre_offx_h, 119+pre_offy_h, 3,0xffff);
//redraw clock hands
//hour
ili9341_draw_line_width(159-offx_h/7,119-offy_h/7, 159+offx_h, 119+offy_h, 3,0x0000);
//min
ili9341_draw_line_width(159-offx_m/7,119-offy_m/7, 159+offx_m, 119+offy_m, 1,0x001f);
ili9341_draw_circle(159+offx_m, 119+offy_m,3,0x001f);
//sec
ili9341_draw_line_width(159-offx_s/7,119-offy_s/7, 159+offx_s, 119+offy_s, 1,0xf800);
ili9341_draw_circle(159+offx_s, 119+offy_s,3,0xf800);
pre_offx_h = offx_h;pre_offy_h=offy_h;
pre_offx_m = offx_m;pre_offy_m=offy_m;
pre_offx_s = offx_s;pre_offy_s=offy_s;
ili9341_draw_fill_circle(159,119,5,0xff00);
}
bool repeat_timer_cb(repeating_timer_t *rt) {
static datetime_t dt;
rtc_get_datetime(&dt);
if (showAnalog)
analogClock(&dt);
else
digitColck(&dt);
/*
if (dt.sec == 0) {
ili9341_fill_rect(6,6,309, 229, 0xffff);
set_wifi_status_icon(net_time.tcpip_link_state);
showAnalog = !showAnalog;
if (showAnalog)
ili9341_draw_bitmap(49,9, &clock_bg);
}
*/
return true;
}
int main()
{
stdio_init_all();
rtc_init();
cyw43_arch_init();
ili9341_init();
ntp_init_data();
// border
ili9341_draw_rect(0,0,320, 240, 0x07e0);
ili9341_draw_rect(1,1,318, 238, 0x07e0);
ili9341_draw_rect(2,2,316, 236, 0x07e0);
ili9341_draw_rect(3,3,314, 234, 0x07e0);
ili9341_draw_rect(4,4,312, 232, 0x0000);
ili9341_draw_rect(5,5,310, 230, 0x0000);
//analog clock background bitmap
ili9341_draw_bitmap(49,9, &clock_bg);
set_wifi_status_icon(net_time.tcpip_link_state);
cyw43_arch_enable_sta_mode();
/* connect to wifi*/
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASS, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
printf("Wifi connect timeout!\n");
return 0;
}
int wait_secs = 0;
while (wait_secs < 10) {
net_time.tcpip_link_state = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
if (net_time.tcpip_link_state != CYW43_LINK_UP) {
wait_secs++;
if (wait_secs == 10) {
printf("Can not get ip address\n");
return 0;
}
sleep_ms(1000);
} else {
break;
}
}
set_wifi_status_icon(net_time.tcpip_link_state);
/* get ntp server ip address */
int dns_ret;
absolute_time_t timeout = make_timeout_time_ms(20000);
while (!net_time.ntp_server_found && absolute_time_diff_us(get_absolute_time(), timeout) > 0) {
dns_ret = dns_gethostbyname(NTP_SERVER, &net_time.ntp_ipaddr, dns_cb, &net_time);
if (dns_ret == ERR_OK) break;
sleep_ms(1000);
}
if(!net_time.ntp_server_found) {
printf("NTP server not found!\n");
return 0;
}
get_ntp_time();
repeating_timer_t rt;
add_repeating_timer_ms(-1000, repeat_timer_cb, &net_time, &rt);
int tcpip_stat;
while(1) {
sleep_ms(10000);
tcpip_stat = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
if (tcpip_stat != net_time.tcpip_link_state) {
net_time.tcpip_link_state = tcpip_stat;
if (net_time.tcpip_link_state == CYW43_LINK_UP) {
get_ntp_time();
}
set_wifi_status_icon(net_time.tcpip_link_state);
}
}
return 0;
}