溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于 RT-Thread 的“數(shù)碼小精靈”設計與實現(xiàn)是怎樣的

發(fā)布時間:2021-12-17 15:25:30 來源:億速云 閱讀:213 作者:柒染 欄目:互聯(lián)網(wǎng)科技

基于 RT-Thread 的“數(shù)碼小精靈”設計與實現(xiàn)是怎樣的,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

一、概述

隨著近年來智能化設備的不斷增長,平板電腦、智能數(shù)字音視頻播放器、移動數(shù)碼相機等各類數(shù)碼產(chǎn)品,正越來越受到城鄉(xiāng)居民歡迎。特別是“云生活”讓人們對數(shù)碼產(chǎn)品有了更多需求,加上互聯(lián)網(wǎng)技術、5G 技術、智能化新產(chǎn)品、新型分期消費模式等的出現(xiàn),讓數(shù)碼產(chǎn)品消費熱潮涌動。      

本設計為基于 RT-Thread 的“數(shù)碼小精靈”設計,硬件采用了以 BK7252 為主控芯片的麻雀一號開發(fā)板開發(fā)。BK7252 , 是一款高性能 WiFi 模塊,采用高集成的無線射頻芯片,內部集成 2.4GHz Wi-Fi 1T1R 先進技術,支持攝像頭圖像輸出,擁有最佳的功耗性能、射頻性能、穩(wěn)定性、通用性和可靠性,適用于各種應用和不同產(chǎn)品需求。模塊內部擁有 512KB 內嵌 RAM 和 4Mbyte Flash 空間,CPU 主頻高達 180Mhz。


基于 RT-Thread 的“數(shù)碼小精靈”設計與實現(xiàn)是怎樣的


本設計在此基礎上主要實現(xiàn)了以下功能,包括天氣和疫情數(shù)據(jù)更新顯示、MP3 音樂播放器以及數(shù)碼拍照相機的功能。其中 MP3 播放器具有音量調節(jié),播放/停止控制和歌曲切換的功能;數(shù)碼相機將拍照圖片進行 LCD 屏顯示,同 時具有 SD 卡存儲和 OneNet 云平臺存儲功能。該產(chǎn)品可以充當家庭數(shù)碼助理的角色,因此取名“數(shù)碼小精靈”。同時本作品完成的過程中參考了部分網(wǎng)絡資料和網(wǎng)友的思路,在此一并表示感謝。

   

二、RT-Thread 使用情況概述

本設計基于麻雀一號開發(fā)板 SDK 進行開發(fā),其 RT-Thread 為 3.1.0 版本。

基于 RT-Thread 的“數(shù)碼小精靈”設計與實現(xiàn)是怎樣的

圖 1 RT-Thread 版本


在 RT-Thread 系統(tǒng)上的設備注冊列表,其中主要使用了 rtc,sd0,w0,sound,uart1 等設備。使用到的 RT-Thread 組件包括了 FinSH 控制臺,虛擬文件系統(tǒng),POSIX 接口。在軟件包上面涉及到網(wǎng)絡工具及 NetUtils,WebClient,cJSON,EasyFlash,rt_ota,TJpgDec,Player 等。


基于 RT-Thread 的“數(shù)碼小精靈”設計與實現(xiàn)是怎樣的

圖2設備注冊列表

   

三、硬件框架


 

基于 RT-Thread 的“數(shù)碼小精靈”設計與實現(xiàn)是怎樣的


麻雀一號開發(fā)板外設資源豐富,但資源相當豐富,集成 WiFi、BLE、攝像頭、音頻揚聲器、MIC 錄音、TF 卡座、五向按鍵、還有一個 1.44 寸的 LCD 屏,使用常見的 TypeC 接口作為供電和調試串口,預留支持鋰電池供電接口。


本設計的人機交互部分主要利用了開發(fā)板的五向按鍵和 LCD 顯示屏,其中按鍵用于功能選擇,數(shù)據(jù)刷新以及音樂播放控制功能。


普通模式下:“ ←”: 音樂播放  、“?”:天氣和疫情數(shù)據(jù)刷新  、 “→”:相機拍照

音樂播放模式下:“↑”:音量加 、“↓”:音量減 、“←”:下一曲 、“?”:停止播放


設備聯(lián)網(wǎng)采用 WIFI 連接,上電自動連接網(wǎng)絡。數(shù)據(jù)顯示 LCD 進行顯示,同時設備接有 SD 進行相機拍照的存儲。此外照片同時可以通過 WIFI 上傳至OneNet 云平臺,進行遠端網(wǎng)頁或者手機等智能終端進行查看。    
   

四、軟件框架說明


系統(tǒng)軟件流程框圖如下圖所示,設備上電后啟動 RT-Thread 操作系統(tǒng),同 時進行相關硬件設備的初始化操作,如 LCD 顯示屏,音頻揚聲器,以及掛在SD 卡到文件系統(tǒng)等操作,之后進行設備的網(wǎng)絡連接。網(wǎng)絡連接后輸入應用程序啟動命令進行程序啟動,LCD 顯示歡迎界面,接下來用戶可以通過五向按鍵進 行功能選擇,主要是天氣疫情數(shù)據(jù)更新顯示、MP3 播放器功能以及數(shù)碼相機的功能。相機拍照后會進行本地 SD 卡數(shù)據(jù)存儲以及 OneNet 云端存儲。  

基于 RT-Thread 的“數(shù)碼小精靈”設計與實現(xiàn)是怎樣的


 

   

五、軟件模塊說明


 

1. 設備聯(lián)網(wǎng)

設備聯(lián)網(wǎng)主要使用到了 RT-Thread 組件中的 wlan 驅動程序實現(xiàn),上電初始化完成后在主程序中查詢 wlan 無線設備,并根據(jù)用戶配置的 SSID 和PASSWORD 進行 WIFI 網(wǎng)絡的連接。該部分的具體代碼實現(xiàn)如下所示:

 1static int iot_station_connect(char *ssid, char *passwd) {
2rt_err_t result = RT_EOK;
3struct rt_wlan_info info;
4struct rt_wlan_device *wlan;
5rt_tick_t tick = 0;
6wlan = (struct rt_wlan_device *)rt_device_find(WIFI_DEVICE_STA
7_NAME);
8if (!wlan)
9{
10rt_kprintf("no wlan:%s device\n", WIFI_DEVICE_STA_NAME);
11return -1; }
12result = rt_wlan_init(wlan, WIFI_STATION);
13rt_wlan_register_event_handler(wlan, WIFI_EVT_STA_CONNECTED, i
14ot_wlan_sta_connected_event);
15rt_wlan_register_event_handler(wlan, WIFI_EVT_STA_DISCONNECTED
16, iot_wlan_sta_disconnected_event);
17rt_wlan_info_init(&info, WIFI_STATION, SECURITY_WPA2_AES_PSK,
18ssid);
19result = rt_wlan_connect(wlan, &info, passwd);
20rt_wlan_info_deinit(&info);
21return result;
22}
 


2. NTP 網(wǎng)絡時間同步

網(wǎng)絡時間同步主要思路就是通過調用網(wǎng)絡工具包中的 ntp 同步函數(shù)來實現(xiàn),通過創(chuàng)建獨立時間同步線程,達到定時同步網(wǎng)絡時間的目的。該部分使用時需要啟用 RT-Thread 中的 RTC 功能。相關代碼如下:  
 1{
2time_t cur_time = ntp_sync_to_rtc();
3if (cur_time)
4{
5rt_kprintf("Get local time from NTP server: %s", ctime((const t
6ime_t*) &cur_time));
7rt_kprintf("The system time is updated. Timezone is %d.\n", NTP
8_TIMEZONE);
9} }
10static rt_thread_t tid1 = RT_NULL;
11static void ntcthread1_entry(void * parameter) {
12while ((1))
13{
14time_t cur_time = ntp_sync_to_rtc();
15if (cur_time)
16{
17rt_kprintf("Get local time from NTP server: %s", ctime((const tim
18e_t *) &cur_time));
19rt_kprintf("The system time is updated. Timezone is %d.\n", NTP_T
20IMEZONE);
21break; }
22else
23{
24rt_thread_mdelay(1000);
25} } }
26void NTCThreadInit(void) {
27if (tid1 != RT_NULL)
28{
29rt_kprintf("ntc thread still run\n");
30return; }
31rt_kprintf("NTC thread init\n");
32tid1 = rt_thread_create("NTC",
33ntcthread1_entry, RT_NULL,
34THREAD_STACK_SIZE,
35THREAD_PRIORITY, THREAD_TIMESLICE);
36if (tid1 != RT_NULL)
37rt_thread_startup(tid1);
38}
 
 
 
3. 天氣疫情數(shù)據(jù)更新      

該部分主要是利用了 webclient 工具包的功能,通過調用天氣和疫情數(shù)據(jù)API 接口獲取相關 Json 數(shù)據(jù),并利用 CJson 工具包進行返回 Json 數(shù)據(jù)的解析。最后通過 LCD 進行數(shù)據(jù)顯示。相關代碼如下:

  1#define GET_URI "http://www.weather.com.cn/data/sk/%s.html" //
 2獲取天氣的 API
 3#define GET_FY2020_URI "http://www.dzyong.top:3005/yiqing/total" //疫情
 4數(shù)據(jù) API
 5void get_weather(int argc, char **argv) {
 6rt_uint8_t *buffer = RT_NULL;
 7int resp_status;
 8struct webclient_session *session = RT_NULL;
 9char *weather_url = RT_NULL;
10int content_length = -1, bytes_read = 0;
11int content_pos = 0;
12char *city_name = rt_calloc(1,255);
13/* 為 weather_url 分配空間 */
14weather_url = rt_calloc(1, GET_URL_LEN_MAX);
15if (weather_url == RT_NULL)
16{
17rt_kprintf("No memory for weather_url!\n");
18goto __exit;
19}
20if(argc == 1) {
21strcpy(city_name, AREA_ID);
22}
23else if (argc == 2) {
24strcpy(city_name, argv[1]);
25}
26/* 拼接 GET 網(wǎng)址 */
27rt_snprintf(weather_url, GET_URL_LEN_MAX, GET_URI, city_name);
28/* 創(chuàng)建會話并且設置響應的大小 */
29session = webclient_session_create(GET_HEADER_BUFSZ);
30if (session == RT_NULL)
31{
32rt_kprintf("No memory for get header!\n");
33goto __exit;
34}
35/* 發(fā)送 GET 請求使用默認的頭部 */
36if ((resp_status = webclient_get(session, weather_url)) != 200) {
37rt_kprintf("webclient GET request failed, response(%d) error.\n", resp_
38status);
39goto __exit;
40}
41/* 分配用于存放接收數(shù)據(jù)的緩沖 */
42buffer = rt_calloc(1, GET_RESP_BUFSZ);
43if (buffer == RT_NULL)
44{
45rt_kprintf("No memory for data receive buffer!\n");
46goto __exit;
47}
48content_length = webclient_content_length_get(session);
49if (content_length < 0) {
50/* 返回的數(shù)據(jù)是分塊傳輸?shù)? */
51do
52{
53bytes_read = webclient_read(session, buffer, GET_RESP_BUFSZ);
54if (bytes_read <= 0) {
55break; } }while (1); }
56else
57{
58do
59{
60bytes_read = webclient_read(session, buffer,
61content_length - content_pos > GET_RESP
62_BUFSZ ?
63GET_RESP_BUFSZ : content_length - conte
64nt_pos);
65if (bytes_read <= 0) {
66break; }
67content_pos += bytes_read;
68}while (content_pos < content_length);
69}
70/* 天氣數(shù)據(jù)解析 */
71weather_data_parse(buffer);
72__exit:
73/* 釋放網(wǎng)址空間 */
74if (weather_url != RT_NULL)
75rt_free(weather_url);
76/* 關閉會話 */
77if (session != RT_NULL)
78webclient_close(session);
79/* 釋放緩沖區(qū)空間 */
80if (buffer != RT_NULL)
81rt_free(buffer);
82if(city_name != RT_NULL)
83rt_free(city_name);
84}
85/* 天氣數(shù)據(jù)解析 */
86void weather_data_parse(rt_uint8_t *data) {
87uint8_t temp[100];
88cJSON *root = RT_NULL, *object = RT_NULL, *item = RT_NULL;
89root = cJSON_Parse((const char *)data);
90if (!root)
91{
92rt_kprintf("No memory for cJSON root!\n");
93return; }
94object = cJSON_GetObjectItem(root, "weatherinfo");
95item = cJSON_GetObjectItem(object, "city");
96rt_kprintf("\ncity :%s ", item->valuestring);
97lcd_clear(BLACK);
98item = cJSON_GetObjectItem(object, "temp");
99rt_kprintf("\ntemp :%s ", item->valuestring);
100rt_sprintf(temp,"溫度: %s",item->valuestring);
101lcd_disp_str_en_ch(0,20,temp,BLACK,WHITE);
102item = cJSON_GetObjectItem(object, "WD");
103rt_kprintf("\nwd :%s ", item->valuestring);
104item = cJSON_GetObjectItem(object, "WS");
105rt_kprintf("\nws :%s ", item->valuestring);
106item = cJSON_GetObjectItem(object, "SD");
107rt_kprintf("\nsd :%s ", item->valuestring);
108rt_sprintf(temp,"濕度: %s",item->valuestring);
109lcd_disp_str_en_ch(0,40,temp,BLACK,WHITE);
110item = cJSON_GetObjectItem(object, "time");
111rt_kprintf("\ntime :%s \n", item->valuestring);
112item = cJSON_GetObjectItem(object, "AP");
113rt_kprintf("\nap :%s ", item->valuestring);
114rt_sprintf(temp,"氣壓: %s",item->valuestring);
115lcd_disp_str_en_ch(0,60,temp,BLACK,WHITE);
116item = cJSON_GetObjectItem(object, "WSE");
117rt_kprintf("\nwse :%s ", item->valuestring);
118rt_sprintf(temp,"風力: %s",item->valuestring);
119lcd_disp_str_en_ch(0,80,temp,BLACK,WHITE);
120if (root != RT_NULL)
121cJSON_Delete(root);
122}
123/* 疫情數(shù)據(jù)解析 */
124void fy2020_data_parse(rt_uint8_t *data) {
125uint8_t temp[100];
126cJSON *root = RT_NULL, *object = RT_NULL, *item = RT_NULL;
127root = cJSON_Parse((const char *)data);
128if (!root)
129{
130rt_kprintf("No memory for cJSON root!\n");
131return; }
1324. 音樂播放模塊
133該部分的功能主要通過使用 player 軟件包的接口函數(shù)實現(xiàn),包括音樂播
134放,停止,歌曲切換以及音量控制等功能。該部分的部分代碼如下圖所示:
135cJSON *dataArray = cJSON_GetObjectItem(root,"data"); //取數(shù)組
136int arraySize = cJSON_GetArraySize(dataArray); //取數(shù)組大小
137cJSON *dataList = dataArray->child;
138while(dataList != RT_NULL)
139{
140rt_kprintf("\ndiagnosed :%d \n", cJSON_GetObjectItem(dataList,"diagn
141osed")->valueint);
142rt_kprintf("\ndeath :%d \n", cJSON_GetObjectItem(dataList,"death")->
143valueint);
144rt_kprintf("\ncured :%d \n", cJSON_GetObjectItem(dataList,"cured")->
145valueint);
146rt_kprintf("\ndate :%s \n", cJSON_GetObjectItem(dataList,"date")->va
147luestring);
148//LCD 屏打印信息
149rt_sprintf(temp,"累計確
150診: %d",cJSON_GetObjectItem(dataList,"diagnosed")->valueint);
151lcd_disp_str_en_ch(0,120,temp,BLACK,WHITE);
152rt_sprintf(temp,"累計死
153亡: %d",cJSON_GetObjectItem(dataList,"death")->valueint);
154lcd_disp_str_en_ch(0,140,temp,BLACK,WHITE);
155rt_sprintf(temp,"累計治
156愈: %d",cJSON_GetObjectItem(dataList,"cured")->valueint);
157lcd_disp_str_en_ch(0,160,temp,BLACK,WHITE);
158rt_sprintf(temp,"更新時
159間: %s",cJSON_GetObjectItem(dataList,"date")->valuestring);
160lcd_disp_str_en_ch(0,180,temp,BLACK,WHITE);
161dataList = dataList->next; 
162}
 


4. 音樂播放模塊

該部分的功能主要通過使用 player 軟件包的接口函數(shù)實現(xiàn),包括音樂播放,停止,歌曲切換以及音量控制等功能。該部分的部分代碼如下圖所示:  
 1LCDShowMusic();
2rt_sprintf(music,"/sd/music/%d.mp3",count);
3rt_kprintf(" key left is press ...\r\n");
4rt_kprintf("//////////////////////////// player_play \n");
5player_stop();
6player_set_uri(music);
7player_play();
8player_status = 1;
9count++;
10if(count >= 8)
11count = 0;
12rt_kprintf("//////////////////////////// player_play end \n");
 
 
 
5. 相機功能實現(xiàn)  

該部分主要通過 IPC 事件獲取相機采集圖像數(shù)據(jù),并將采集到的圖像數(shù)據(jù)經(jīng)過 TJpgDec 軟件包進行解碼后在 LCD 進行顯示,同時會將相機數(shù)據(jù)通過寫文件的形式存儲到 SD 卡,通過 HTTP 協(xié)議推送到 OneNet 云平臺。

 1void take_photo(void) //手動拍照
2{
3//創(chuàng)建攝像頭接收一幀圖片的事件
4session.event = rt_event_create("vt_event", RT_IPC_FLAG_FIFO);
5camera_start(); //開啟攝像頭傳輸照片
6tvideo_capture(1);
7rt_event_recv(session.event, SEND_FRAME_EVENT, RT_EVENT_FLAG_OR | RT_EVE
8NT_FLAG_CLEAR, RT_WAITING_FOREVER, RT_NULL);
9int fd, res;
10time_t cur_time;
11struct tm *cur_tm;
12char time_now[50]; //保存文件到 sd 卡指定路徑
13/* output current time */
14cur_time = time(RT_NULL);
15cur_tm = localtime(&cur_time);
16rt_sprintf(time_now, "%04d-%02d-%02d-%02d-%02d-%02d",cur_tm->tm_year + 19
1700, cur_tm->tm_mon + 1, cur_tm->tm_mday, cur_tm->tm_hour, cur_tm->tm_min, cur
18_tm->tm_sec);
19rt_sprintf(file_name, "/sd/images/%s.jpg", time_now);
20rt_kprintf("name = %s \n", file_name);
21fd = open(file_name, O_WRONLY | O_CREAT);
22if (fd >= 0) {
23write(fd, session.buf, session.total_len);
24close(fd);
25rt_kprintf("save %s ok!!!\n", file_name);
26res = Decode_Jpg(file_name);
27rt_kprintf("res = %d\n", res);
28}
29else
30{
31rt_kprintf("save pic failed!!!\n");
32}
33//拍照數(shù)據(jù)上傳
34webclient_post_pic(session.buf, session.total_len);
35tvideo_capture(0);
36}
37MSH_CMD_EXPORT(take_photo,take_photo);

關于基于 RT-Thread 的“數(shù)碼小精靈”設計與實現(xiàn)是怎樣的問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業(yè)資訊頻道了解更多相關知識。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI