RM新时代网站-首页

電子發(fā)燒友App

硬聲App

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示
創(chuàng)作
電子發(fā)燒友網(wǎng)>電子資料下載>電子資料>Nerd無線電子寵物開源設(shè)計(jì)

Nerd無線電子寵物開源設(shè)計(jì)

2022-11-22 | zip | 0.15 MB | 次下載 | 2積分

資料介紹

描述

如果你有一只物聯(lián)網(wǎng)寵物,它會(huì)吃什么?WiFi SSID,當(dāng)然!

Nerd 是一種無線電子寵物,它通過收集 WiFi SSID 以及一些休息和陽光來生存。

為了讓它茁壯成長,你必須平衡離線和在線模式與光明和黑暗,以確保它有一個(gè)適當(dāng)?shù)娜粘3?睡-書呆子程序。

如果沒有 WiFi 太久,它將使用其內(nèi)置的壓電揚(yáng)聲器以摩爾斯電碼發(fā)送 SOS。離線時(shí)間越長,蜂鳴聲越多。

簡而言之

書呆子將每半小時(shí)醒來一次以掃描周圍的網(wǎng)絡(luò)。如果它檢測(cè)到新網(wǎng)絡(luò),它將存儲(chǔ)它們并在低功耗模式下重新進(jìn)入睡眠狀態(tài)(以節(jié)省電池壽命)。否則它會(huì)用蜂鳴器發(fā)出噪音來抱怨,直到你喂它或把它放在黑暗中。

它還會(huì)通過連接到您的 wifi 網(wǎng)絡(luò)了解何時(shí)在家。在家時(shí),Nerd 將能夠連接到互聯(lián)網(wǎng)并獲取當(dāng)前時(shí)間和日期。

如果超過兩天不喂,它會(huì)急劇死亡,發(fā)出很大的噪音。

成分

  • 蜂鳴器
  • 電池

學(xué)習(xí)目標(biāo)

  • 管理完整的 WiFi 功能
  • 在閃存中存儲(chǔ)數(shù)據(jù)
  • 管理低功耗模式

想知道更多?

教程是讓您熟悉 MKR1000 和 IoT 的一系列實(shí)驗(yàn)的一部分。所有實(shí)驗(yàn)都可以使用 MKR IoT Bundle 中包含的組件構(gòu)建。

  • 書呆子

設(shè)立董事會(huì)

為了實(shí)現(xiàn)所有功能,我們將使用以下庫:

  • WiFi101 //連接到互聯(lián)網(wǎng)并掃描網(wǎng)絡(luò)
  • FlashStorage // 保存值,以便它們不會(huì)在每次重新啟動(dòng)時(shí)被擦除
  • RTCZero // 管理時(shí)間觸發(fā)事件
  • ArduinoLowPower //節(jié)省電池電量
  • WiFiUdp // 從互聯(lián)網(wǎng)上獲取時(shí)間和日期

您可以按照本指南中的說明從庫管理器下載它們。

掃描 WiFi 網(wǎng)絡(luò)

書呆子渴望網(wǎng)絡(luò)!

掃描網(wǎng)絡(luò)非常簡單, 只需上傳此示例草圖或轉(zhuǎn)到> 示例 > WiFi101 > ScanNetworksAdvanced以獲得更多擴(kuò)展版本。

#include  
#include  
void setup() { 
 //Initialize serial and wait for port to open: 
 Serial.begin(9600); 
 while (!Serial) { 
   ; // wait for serial port to connect. Needed for native USB port only 
 } 
 // scan for existing networks: 
 Serial.println(); 
 Serial.println("Scanning available networks..."); 
 listNetworks(); 
} 
void loop() { 
 delay(10000); 
 // scan for existing networks: 
 Serial.println("Scanning available networks..."); 
 listNetworks(); 
} 
void listNetworks() { 
 // scan for nearby networks: 
 Serial.println("** Scan Networks **"); 
 int numSsid = WiFi.scanNetworks(); 
 if (numSsid == -1) 
 { 
   Serial.println("Couldn't get a WiFi connection"); 
   while (true); 
 } 
 // print the list of networks seen: 
 Serial.print("number of available networks: "); 
 Serial.println(numSsid); 
 // print the network number and name for each network found: 
 for (int thisNet = 0; thisNet < numSsid; thisNet++) { 
   Serial.print(thisNet + 1); 
   Serial.print(" SSID: "); 
   Serial.println(WiFi.SSID(thisNet)); 
   Serial.flush(); 
 } 
 Serial.println(); 
} 

在閃存中存儲(chǔ)值

當(dāng)然,您不希望書呆子每次沒電時(shí)就死掉!

為了避免這種行為,我們將在閃存中保存一些變量(作為食物量),以便即使在電路板關(guān)閉并再次打開后也可以檢索它們。

您可以使用以下方法了解基本功能:

示例 > FlashStorage > FlashStoreAndRetrieve

我們將保存網(wǎng)絡(luò)的名稱,以便書呆子只吃一次,我們還將使用保存這些 SSID 的數(shù)組來計(jì)算它在白天吃的食物量。

保存在閃存中的值將在電路板重置后保留,但不會(huì)在新草圖的上傳后保留。每次上傳新草圖時(shí),閃存也會(huì)被清空。

此草圖將掃描網(wǎng)絡(luò)并將 SSID 保存在閃存中。

#include  
#include  
#include  
#define MAGIC_NUMBER 0x7423  // arbitrary number to double check the saved SSID 
#define MaxNet 30  // max amount of network to be saved  
int PosToBeSaved = 0; // Variable used to navigate the array of networks 
int daily_amount_of_food = 12; // The amount of food per day needed to survive 
// Struct of variable to be saved in flash memory 
typedef struct { 
 int magic; 
 boolean valid[MaxNet]; 
 char SSIDs[MaxNet][100]; 
} Networks; 
FlashStorage(my_flash_store, Networks); 
Networks values; 
void setup() { 
 Serial.begin(115200); 
 while(!Serial); // wait until the Serial montior has be opened 
 delay(2000); 
 values = my_flash_store.read(); // Read values from flash memory 
 if (values.magic == MAGIC_NUMBER) { // If token is correct print saved networks 
   Serial.println("saved data:"); 
   Serial.println(""); 
   for (int a = 0; a < MaxNet; a++) { 
     if (values.valid[a]) { 
       Serial.println(values.SSIDs[a]); 
     } else { 
       PosToBeSaved = a; 
     } 
   } 
 } 
} 
void loop() { 
 // Temporarly save the number of networks 
 int networks_already_saved = PosToBeSaved; 
 getNetwork(); 
 if (PosToBeSaved >= daily_amount_of_food) { 
   Serial.println("Enough food for today"); 
 } 
 delay(5000); 
} 
// Feed the Nerd with networks's SSID 
void getNetwork() { 
 // scan for nearby networks: 
 Serial.println("\n*Scan Networks*\n"); 
 int numSsid = WiFi.scanNetworks(); 
 delay(1000); 
 if (numSsid == -1) 
 { 
   Serial.println("There are no WiFi networks here.."); 
 } else { 
   Serial.print("number of available networks: "); 
   Serial.println(numSsid); 
   // print the network number and name for each network found: 
   for (int thisNet = 0; thisNet < numSsid; thisNet++) { 
     Serial.print("SSID: "); 
     Serial.println(WiFi.SSID(thisNet)); 
     delay(500); 
     char* net = WiFi.SSID(thisNet); 
     bool canBeSaved = true; 
     // check if the network has already been saved 
     for (int a = 0; a < PosToBeSaved ; a++) { 
       if (values.valid[a]) { 
         if (strncmp(net, values.SSIDs[a], 100) == 0 || strnlen(net, 100) == 0) { 
           Serial.println("Not saved"); 
           canBeSaved = false; 
         } 
       } 
     } 
     // Store ssid name 
     if (canBeSaved && PosToBeSaved < MaxNet) { 
       if (strlen(net) + 1 < 100 && strlen(net) > 0) { // check if the SSID name fits 100 bytes 
         memset(values.SSIDs[PosToBeSaved], 0, sizeof(values.SSIDs[PosToBeSaved])); // set all characters to zero 
         memcpy(values.SSIDs[PosToBeSaved], net, strlen(net) + 1); // copy "net" to values.SSDs[thisNet] 
         values.valid[PosToBeSaved] = true; 
         values.magic = MAGIC_NUMBER; 
         my_flash_store.write(values); 
         Serial.println(String(values.SSIDs[PosToBeSaved]) + " saved in position " + String(PosToBeSaved)); 
         PosToBeSaved ++; 
       } 
       else { 
         Serial.println(" network skipped"); 
       } 
     } 
   } 
 } 
} 

請(qǐng)注意我們?nèi)绾味x可以保存的最大網(wǎng)絡(luò)數(shù)量,以避免內(nèi)存空間問題:

#define MaxNet 30  
int PosToBeSaved = 0; 

已用于導(dǎo)航保存網(wǎng)絡(luò)名稱的數(shù)組并測(cè)量已吃的食物量。

管理時(shí)間

我們可以將實(shí)時(shí)時(shí)鐘 (RTC) 的功能與 WiFi 相結(jié)合,以獲取當(dāng)前時(shí)間和日期,然后設(shè)置板的內(nèi)部時(shí)鐘。通過這種方式,我們可以在很長一段時(shí)間內(nèi)觸發(fā)基于時(shí)間的事件,而無需使用millis() 當(dāng)您必須將毫秒轉(zhuǎn)換為天時(shí)可能會(huì)很棘手的函數(shù)。

我們將從網(wǎng)絡(luò)時(shí)間協(xié)議(NTP) 時(shí)間服務(wù)器獲取時(shí)間,然后使用它設(shè)置 RTC。請(qǐng)注意,收到的時(shí)間采用紀(jì)元格式,即自 1970 年 1 月 1 日以來的秒數(shù)。

您可以從example > WiFi101 > WiFiUdpNtpClient運(yùn)行基本草圖

在下面的草圖中,我們將事物放在一起:掃描網(wǎng)絡(luò)功能和與時(shí)間相關(guān)的功能。

  • bool atHome = false; 用于觸發(fā) WiFi 連接,因此請(qǐng)求服務(wù)器獲取時(shí)間。
  • check_home() 用于掃描所有可用網(wǎng)絡(luò)并查看其中一個(gè)是否為家庭 WiFi 網(wǎng)絡(luò)。
  • connect_WiFi() 然后調(diào)用,它將板連接到 WiFi,觸發(fā)對(duì)服務(wù)器的請(qǐng)求并打印當(dāng)前時(shí)間。
  • rtc.setEpoch(epoch + GMT); 用于以紀(jì)元格式以當(dāng)前時(shí)間啟動(dòng) RTC,修改 GMT 變量以將時(shí)間調(diào)整為您當(dāng)前的時(shí)區(qū)。
#include  
#include  
#include  
#include  
#include  
WiFiUDP udp; 
WiFiUDP Udp; 
RTCZero rtc; 
#define MAGIC_NUMBER 0x7423  // arbitrary number to double check the saved SSID 
#define MaxNet 30  // max amount of network to be saved  
const char* home_ssid = SECRET_SSID;    //  your network SSID (name) 
const char* password = SECRET_PSWD;  // your network password 
int PosToBeSaved = 0; // Variable used to navigate the array of networks 
int daily_amount_of_food = 12; // The amount of food per day needed to survive 
bool atHome = false; 
// Struct of variable to be saved in flash memory 
typedef struct {   
 int magic; 
 boolean valid[MaxNet]; 
 char SSIDs[MaxNet][100]; 
 int alive_days; 
 int last_time_feeded; 
} Networks; 
FlashStorage(my_flash_store, Networks); 
Networks values; 
void setup() { 
 Serial.begin(115200); 
 delay(2000); 
 rtc.begin(); // enable real time clock functionalities 
 values = my_flash_store.read(); // Read values from flash memory 
 if (values.magic == MAGIC_NUMBER) { // If token is correct print saved networks 
   Serial.println("saved data:"); 
   Serial.println(""); 
   for (int a = 0; a < MaxNet; a++) { 
     if (values.valid[a]) { 
       Serial.println(values.SSIDs[a]); 
     } else { 
       PosToBeSaved = a; 
     } 
   } 
 } 
} 
void loop() { 
   if(!atHome) check_home(); 
   // Temporarly save the number of networks 
   int networks_already_saved = PosToBeSaved;    
   getNetwork(); 
if (PosToBeSaved >= daily_amount_of_food) {  
  Serial.println("Enough food for today");  
}  
} 
void check_home() { 
 int numSsid = WiFi.scanNetworks(); 
 if (numSsid != -1) { 
   for (int thisNet = 0; thisNet < numSsid; thisNet++) { 
     delay(100); 
     if (strncmp(WiFi.SSID(thisNet), home_ssid, 100) == 0) { 
       Serial.println("Yay, I'm home \n"); 
       atHome = true; 
       connect_WiFi(); 
     } 
   } 
 } 
} 
void connect_WiFi() { 
 if (WiFi.status() != WL_CONNECTED) { 
   while (WiFi.begin(home_ssid, password) != WL_CONNECTED) { 
     delay(500); 
   } 
   Serial.println("WiFi connected \n"); 
   GetCurrentTime(); 
   printTime(); 
 } 
} 
// Feed the Nerd with networks's SSID 
void getNetwork() { 
 // scan for nearby networks: 
 Serial.println("*Scan Networks*"); 
 int numSsid = WiFi.scanNetworks(); 
 delay(1000); 
 if (numSsid == -1) 
 { 
   Serial.println("There are no WiFi networks here.."); 
 } else { 
   Serial.print("number of available networks: "); 
   Serial.println(numSsid); 
   // print the network number and name for each network found: 
   for (int thisNet = 0; thisNet < numSsid; thisNet++) { 
     Serial.print("SSID: "); 
     Serial.println(WiFi.SSID(thisNet)); 
     delay(500); 
     char* net = WiFi.SSID(thisNet); 
     bool canBeSaved = true; 
     // check if the network has already been saved 
     for (int a = 0; a < PosToBeSaved ; a++) {  
       if (values.valid[a]) { 
         if (strncmp(net, values.SSIDs[a], 100) == 0 || strnlen(net, 100) == 0) {  
           Serial.println("Not saved"); 
           canBeSaved = false; 
         } 
       } 
     } 
     // Store ssid name 
     if (canBeSaved && PosToBeSaved < MaxNet) {  
       if (strlen(net) + 1 < 100 && strlen(net) > 0) { // check if the SSID name fits 100 bytes 
         memset(values.SSIDs[PosToBeSaved], 0, sizeof(values.SSIDs[PosToBeSaved])); // set all characters to zero 
         memcpy(values.SSIDs[PosToBeSaved], net, strlen(net) + 1); // copy "net" to values.SSDs[thisNet] 
         values.valid[PosToBeSaved] = true; 
         values.last_time_feeded = rtc.getEpoch(); 
         values.magic = MAGIC_NUMBER; 
         my_flash_store.write(values); 
         Serial.println(String(values.SSIDs[PosToBeSaved]) + " saved in position " + String(PosToBeSaved)); 
         PosToBeSaved ++; 
       } 
       else { 
         Serial.println(" network skipped"); 
       } 
     } 
   } 
 } 
} 
/************************************************* 
 Start an UDP connection to get the time in unix, 
 then set the real time clock (rtc) 
************************************************/ 
unsigned int localPort = 2390;      // local port to listen for UDP packets 
IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server 
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message 
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets 
const int GMT = 1 * 60 * 60; //change this to adapt it to your time zone   hours*minutes*seconds 
unsigned long epoch; 
void GetCurrentTime() { 
 int numberOfTries = 0, maxTries = 6; 
 do { 
   epoch = readLinuxEpochUsingNTP(); 
   numberOfTries++; 
 } 
 while ((epoch == 0) || (numberOfTries > maxTries)); 
 if (numberOfTries > maxTries) { 
   Serial.print("NTP unreachable!!"); 
   while (1); 
 } 
 else { 
   Serial.print("Epoch received: "); 
   Serial.println(epoch); 
   rtc.setEpoch(epoch + GMT); 
   Serial.println(); 
 } 
} 
unsigned long readLinuxEpochUsingNTP() 
{ 
 Udp.begin(localPort); 
 sendNTPpacket(timeServer); // send an NTP packet to a time server 
 // wait to see if a reply is available 
 delay(1000); 
 if ( Udp.parsePacket() ) { 
   Serial.println("NTP time received"); 
   // We've received a packet, read the data from it 
   Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer 
   //the timestamp starts at byte 40 of the received packet and is four bytes, 
   // or two words, long. First, esxtract the two words: 
   unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); 
   unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 
   // combine the four bytes (two words) into a long integer 
   // this is NTP time (seconds since Jan 1 1900): 
   unsigned long secsSince1900 = highWord << 16 | lowWord; 
   // now convert NTP time into everyday time: 
   // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: 
   const unsigned long seventyYears = 2208988800UL; 
   // subtract seventy years: 
   Udp.stop(); 
   return (secsSince1900 - seventyYears); 
 } 
 else { 
   Udp.stop(); 
   return 0; 
 } 
} 
// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress & address) 
{ 
 // set all bytes in the buffer to 0 
 memset(packetBuffer, 0, NTP_PACKET_SIZE); 
 // Initialize values needed to form NTP request 
 // (see URL above for details on the packets) 
 packetBuffer[0] = 0b11100011;   // LI, Version, Mode 
 packetBuffer[1] = 0;     // Stratum, or type of clock 
 packetBuffer[2] = 6;     // Polling Interval 
 packetBuffer[3] = 0xEC;  // Peer Clock Precision 
 // 8 bytes of zero for Root Delay & Root Dispersion 
 packetBuffer[12]  = 49; 
 packetBuffer[13]  = 0x4E; 
 packetBuffer[14]  = 49; 
 packetBuffer[15]  = 52; 
 // all NTP fields have been given values, now 
 // you can send a packet requesting a timestamp: 
 Udp.beginPacket(address, 123); //NTP requests are to port 123 
 Udp.write(packetBuffer, NTP_PACKET_SIZE); 
 Udp.endPacket(); 
} 
void printTime() { 
 // Print date... 
 Serial.print(rtc.getDay()); 
 Serial.print(" / "); 
 Serial.print(rtc.getMonth()); 
 Serial.print(" / "); 
 Serial.print(rtc.getYear()); 
 Serial.print("\t"); 
 // ...and time 
 print2digits(rtc.getHours()); 
 Serial.print(": "); 
 print2digits(rtc.getMinutes()); 
 Serial.print(": "); 
 print2digits(rtc.getSeconds()); 
 Serial.println(""); 
} 
void print2digits(int number) { 
 if (number < 10) { 
   Serial.print("0"); 
 } 
 Serial.print(number);

實(shí)現(xiàn)當(dāng)前時(shí)間允許我們使用像這樣的簡單函數(shù)來管理 Nerd 的生死:

 if(rtc.getEpoch() - values.last_time_fed >= 86400*2){ 
 // complain and eventually die :(
 } 

其中86400 是一天中的秒數(shù), values.last_time_fed 是以紀(jì)元格式存儲(chǔ)的時(shí)間值,其中 Nerd 上次被喂食并以紀(jì)元格式rtc.getEpoch() 返回當(dāng)前時(shí)間

低功耗模式

我們可以使用低功耗模式讓我們的電路板進(jìn)入睡眠狀態(tài)。這意味著它將禁用其大部分功能(包括 WiFi)以節(jié)省電池電量。

由于我們希望 Nerd 定期醒來,我們可以輕松設(shè)置一個(gè)計(jì)時(shí)器:

#include "ArduinoLowPower.h" 
int sleeping_time = 5000; // 5 seconds 
bool awake = true; 
void setup() { 
 Serial.begin(9600); 
 LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, WakeUp, CHANGE); 
 pinMode(LED_BUILTIN, OUTPUT); 
} 
void loop() { 
 if (awake) { 
   digitalWrite(LED_BUILTIN, HIGH); 
   delay(500); 
   digitalWrite(LED_BUILTIN, LOW); 
   delay(500); 
 } 
 awake = false; 
 Serial.println("going to sleep"); 
 LowPower.sleep(sleeping_time); 
} 
void WakeUp() { 
 Serial.println("awake"); 
 awake = true; 
} 

請(qǐng)注意,該WakeUp() 函數(shù)附加到中斷,這意味著它不能包含任何包含延遲的代碼。但是我們可以設(shè)置布爾變量來觸發(fā)循環(huán)中的事件。


下載該資料的人也在下載 下載該資料的人還在閱讀
更多 >

評(píng)論

查看更多

下載排行

本周

  1. 1山景DSP芯片AP8248A2數(shù)據(jù)手冊(cè)
  2. 1.06 MB  |  532次下載  |  免費(fèi)
  3. 2RK3399完整板原理圖(支持平板,盒子VR)
  4. 3.28 MB  |  339次下載  |  免費(fèi)
  5. 3TC358743XBG評(píng)估板參考手冊(cè)
  6. 1.36 MB  |  330次下載  |  免費(fèi)
  7. 4DFM軟件使用教程
  8. 0.84 MB  |  295次下載  |  免費(fèi)
  9. 5元宇宙深度解析—未來的未來-風(fēng)口還是泡沫
  10. 6.40 MB  |  227次下載  |  免費(fèi)
  11. 6迪文DGUS開發(fā)指南
  12. 31.67 MB  |  194次下載  |  免費(fèi)
  13. 7元宇宙底層硬件系列報(bào)告
  14. 13.42 MB  |  182次下載  |  免費(fèi)
  15. 8FP5207XR-G1中文應(yīng)用手冊(cè)
  16. 1.09 MB  |  178次下載  |  免費(fèi)

本月

  1. 1OrCAD10.5下載OrCAD10.5中文版軟件
  2. 0.00 MB  |  234315次下載  |  免費(fèi)
  3. 2555集成電路應(yīng)用800例(新編版)
  4. 0.00 MB  |  33566次下載  |  免費(fèi)
  5. 3接口電路圖大全
  6. 未知  |  30323次下載  |  免費(fèi)
  7. 4開關(guān)電源設(shè)計(jì)實(shí)例指南
  8. 未知  |  21549次下載  |  免費(fèi)
  9. 5電氣工程師手冊(cè)免費(fèi)下載(新編第二版pdf電子書)
  10. 0.00 MB  |  15349次下載  |  免費(fèi)
  11. 6數(shù)字電路基礎(chǔ)pdf(下載)
  12. 未知  |  13750次下載  |  免費(fèi)
  13. 7電子制作實(shí)例集錦 下載
  14. 未知  |  8113次下載  |  免費(fèi)
  15. 8《LED驅(qū)動(dòng)電路設(shè)計(jì)》 溫德爾著
  16. 0.00 MB  |  6656次下載  |  免費(fèi)

總榜

  1. 1matlab軟件下載入口
  2. 未知  |  935054次下載  |  免費(fèi)
  3. 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
  4. 78.1 MB  |  537798次下載  |  免費(fèi)
  5. 3MATLAB 7.1 下載 (含軟件介紹)
  6. 未知  |  420027次下載  |  免費(fèi)
  7. 4OrCAD10.5下載OrCAD10.5中文版軟件
  8. 0.00 MB  |  234315次下載  |  免費(fèi)
  9. 5Altium DXP2002下載入口
  10. 未知  |  233046次下載  |  免費(fèi)
  11. 6電路仿真軟件multisim 10.0免費(fèi)下載
  12. 340992  |  191187次下載  |  免費(fèi)
  13. 7十天學(xué)會(huì)AVR單片機(jī)與C語言視頻教程 下載
  14. 158M  |  183279次下載  |  免費(fèi)
  15. 8proe5.0野火版下載(中文版免費(fèi)下載)
  16. 未知  |  138040次下載  |  免費(fèi)
RM新时代网站-首页