本影片介紹了Raspberry Pi Pico 2 W對SNTP和RTC功能的實作。相同的程式碼可以在 Pico W 上運行。
專案的UI使用LVGL函式庫(TFT display & Rotary Encoder)
LwIP SNTP application API在專案中包裝程一組Libarary提供三個 functions:
bool pico_sntp_enable(int8_t tz);
bool pico_sntp_get_system_time_timeout_ms(uint32_t ms);
bool pico_sntp_restart_timeout_ms(int8_t tz, uint32_t ms);
Pico 2與Pico 使用RTC的Hardware 不一樣,新的aon_timer_xxx這組的api適用於RP2040與RP2350,詳細說明可參閱RP2040與RP2350 datasheet。
其他詳細內容與成果展示影片,附於文末。
成果影片:
程式碼:
sntp_lib:
- CMakeLists.txt
add_library(sntp_lib INTERFACE)
target_sources(sntp_lib INTERFACE
${CMAKE_CURRENT_LIST_DIR}/sntp_lib.c
)
target_include_directories(sntp_lib INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(sntp_lib INTERFACE
pico_aon_timer
pico_lwip_sntp
)
- sntp_lib.c
#include "stdio.h"
#include "pico/stdlib.h"
#include "sntp_lib.h"
#include "lwip/apps/sntp.h"
#include "pico/aon_timer.h"
//SNTP
static bool ntp_datetime_ok=false;
static int8_t sntp_timezone;
void sntp_set_system_time(u32_t sec)
{
char buf[32];
struct tm current_time_val;
time_t current_time = (sec+sntp_timezone*60*60);
struct tm* p= gmtime(¤t_time);
aon_timer_set_time_calendar(p);
ntp_datetime_ok=true;
}
bool pico_sntp_enable(int8_t tz) {
sntp_timezone = tz;
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org"); //SNTP_SERVER_DNS (lwipop.h)
//ip_addr_t ntpserver;
//ipaddr_aton("118.163.81.63", &ntpserver);
//sntp_setserver(0, &ntpserver);
sntp_init();
if (!sntp_enabled()) {
printf("sntp not enable\n");
return false;
}
return true;
}
bool pico_sntp_get_system_time_timeout_ms(uint32_t ms) {
absolute_time_t curTime = get_absolute_time();
bool ret = false;
while (absolute_time_diff_us(curTime, get_absolute_time()) < ms*1000) {
if (ntp_datetime_ok) {
ret = true;
break;
} else {
sleep_ms(100);
}
}
return ret;
}
bool pico_sntp_restart_timeout_ms(int8_t tz, uint32_t ms) {
sntp_stop();
if (pico_sntp_enable(tz)) {
return pico_sntp_get_system_time_timeout_ms(ms);
} else {
return false;
}
}
- sntp_lib.h
#ifndef __SNTP_LIB__
#define __SNTP_LIB__
bool pico_sntp_enable(int8_t tz);
bool pico_sntp_get_system_time_timeout_ms(uint32_t ms);
bool pico_sntp_restart_timeout_ms(int8_t tz, uint32_t ms);
#endif
- CMakeLists.txt(root)
# Generated Cmake Pico project file
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
set(USERHOME $ENV{USERPROFILE})
else()
set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.1.1)
set(toolchainVersion 13_3_Rel1)
set(picotoolVersion 2.1.1)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if (EXISTS ${picoVscode})
include(${picoVscode})
endif()
# ====================================================================================
set(PICO_BOARD pico_w CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)
project(pico2w_clock_ht C CXX ASM)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(pico2w_clock_ht pico2w_clock_ht.c display.c)
pico_set_program_name(pico2w_clock_ht "pico2w_clock_ht")
pico_set_program_version(pico2w_clock_ht "0.1")
# Modify the below lines to enable/disable output over UART/USB
pico_enable_stdio_uart(pico2w_clock_ht 1)
pico_enable_stdio_usb(pico2w_clock_ht 0)
# Add the standard library to the build
target_link_libraries(pico2w_clock_ht
pico_stdlib
pico_aon_timer
hardware_pio
hardware_timer
)
# Add the standard include files to the build
target_include_directories(pico2w_clock_ht PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)
# Add any user requested libraries
target_link_libraries(pico2w_clock_ht
pico_cyw43_arch_lwip_threadsafe_background
)
target_compile_definitions(pico2w_clock_ht PRIVATE
WIFI_SSID="$ENV{WIFI_SSID}"
WIFI_PASSWD="$ENV{WIFI_PASSWD}"
)
add_subdirectory(pico_lvgl)
add_subdirectory(sntp_lib)
add_subdirectory(aht10_lib)
target_link_libraries(pico2w_clock_ht
pico_lvgl
sntp_lib
aht10_lib
)
pico_add_extra_outputs(pico2w_clock_ht)
- pico2w_clock_ht.c
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "hardware/pio.h"
#include "pico/aon_timer.h"
#include "pico_lvgl.h"
#include "sntp_lib.h"
#include "display.h"
#include "aht10.h"
#define TFT_PIO pio0
#define TFT_SM 2
#define TFT_SDI_GPIO 9
#define TFT_CSX_DCX_SCK_GPIO 6 // CSX=8, DCX(A0)=7, SCK=6, SIDE_SET
#define TIME_ZONE 8
#define AHT10_I2C_PORT i2c0
#define AHT10_SDA 16
#define AHT10_SCL 17
bool timer_callback(repeating_timer_t* rt) {
display_clock_meter();
return true;
}
bool aht10_callback(repeating_timer_t* rt) {
display_ht();
return true;
}
int main()
{
stdio_init_all();
gpio_init(ALARM_BUZZER_PIN);
gpio_set_dir(ALARM_BUZZER_PIN, true);
gpio_put(ALARM_BUZZER_PIN, false);
pico_lvgl_tft_init(TFT_PIO, TFT_SM, TFT_SDI_GPIO, TFT_CSX_DCX_SCK_GPIO);
tft_set_orientation(TFT_ORIENTATION_LANDSCAPE_MIRROR);
pico_lvgl_display_init(5);
pico_lvgl_encoder_init(true);
struct tm dt;
dt.tm_year = 2025-1900;
dt.tm_mon = 3;
dt.tm_mday = 1;
dt.tm_hour = 0;
dt.tm_min = 0;
dt.tm_sec = 0;
if (!aon_timer_start_calendar(&dt)) {
show_msgbox("Error", "Start RTC error");
return 1;
}
char msgbuff[100];
// Initialise the Wi-Fi chip
if (cyw43_arch_init()) {
printf("Wi-Fi init failed\n");
show_msgbox( "Error", "Wi-Fi init failed");
return -1;
}
// Enable wifi station
cyw43_arch_enable_sta_mode();
printf("Connecting to Wi-Fi...\n");
show_msgbox("Message", "Connecting to Wi-Fi...");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect.\n");
close_msgbox();
show_msgbox("Error", "failed to connect.");
return 1;
} else {
printf("Connected.\n");
// Read the ip address in a human readable way
uint8_t *ip_address = (uint8_t*)&(cyw43_state.netif[0].ip_addr.addr);
sprintf(msgbuff, "IP address %d.%d.%d.%d", ip_address[0], ip_address[1], ip_address[2], ip_address[3]);
printf("%s\n",msgbuff);
close_msgbox();
show_msgbox( "Message", msgbuff);
sleep_ms(2000);
close_msgbox();
}
// enable SNTP
if (!pico_sntp_enable(TIME_ZONE)) {
show_msgbox("Error", "Enable SNTP Error");
return -1;
}
show_msgbox("Message", "Getting NTP Time...");
if (pico_sntp_get_system_time_timeout_ms(20000)) {
struct tm dt;
aon_timer_get_time_calendar(&dt);
sprintf(msgbuff, "Date:%04d-%02d-%02d\nTime:%02d:%02d:%02d\n", dt.tm_year+1900, dt.tm_mon+1, dt.tm_mday,
dt.tm_hour, dt.tm_min, dt.tm_sec);
close_msgbox();
show_msgbox("Info", msgbuff);
} else {
printf("sntp time out\n");
close_msgbox();
show_msgbox("Info", "Restarting SNTP");
if (!pico_sntp_restart_timeout_ms(TIME_ZONE, 20000)) {
close_msgbox();
show_msgbox("Info", "Get NTP Time timeout");
return -1;
} else {
close_msgbox();
struct tm dt;
aon_timer_get_time_calendar(&dt);
sprintf(msgbuff, "Date:%04d-%02d-%02d\nTime:%02d:%02d:%02d\n", dt.tm_year+1900, dt.tm_mon+1, dt.tm_mday,
dt.tm_hour, dt.tm_min, dt.tm_sec);
show_msgbox("Info", msgbuff);
}
}
close_msgbox();
draw_screens(); // draw analog clock screen and Alarm setting screen
lv_disp_load_scr(clock_scr); // load clock screen as default
repeating_timer_t rt;
add_repeating_timer_ms(-1000, timer_callback, NULL, &rt);
//init AHT10 sensor and read Temperature/Humidity every 5 seconds
aht10_init(AHT10_I2C_PORT, AHT10_SDA,AHT10_SCL);
repeating_timer_t rt_ht;
add_repeating_timer_ms(-5000, aht10_callback, NULL, &rt_ht);
while (true) {
lv_timer_handler();
sleep_ms(10);
}
}
沒有留言:
張貼留言