- /*
- * ESP8266_NTP_Time_Clock.ino
- * NTP Time Clock at ESP8266
- *
- */
- #include <TimeLib.h>
- #include <ESP8266WiFiMulti.h>
- #include <WiFiUdp.h>
- #define DEBUG_MODE 0
- ESP8266WiFiMulti wifiMulti;
- // WiFi connect timeout per AP. Increase when connecting takes longer.
- const uint32_t connectTimeoutMs = 5000;
- const char ssid[] = "OpenBSD"; // your network SSID (name)
- const char pass[] = "********"; // your network password
- // NTP Servers:
- static const char ntpServerName[] = "ntp.aliyun.com";
- // TimeZone
- const int timeZone = 8; // CST +8
- WiFiUDP Udp;
- unsigned int localPort = 8888; // local port to listen for UDP packets
- static const uint8_t crc_table[] = {
- 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31,
- 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
- 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9,
- 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
- 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1,
- 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
- 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe,
- 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
- 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16,
- 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
- 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80,
- 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
- 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8,
- 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
- 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10,
- 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
- 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f,
- 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
- 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
- 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
- 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef,
- 0xfa, 0xfd, 0xf4, 0xf3
- };
- time_t getNtpTime();
- void digitalClockDisplay();
- void printDigits(int digits);
- void sendNTPpacket(IPAddress &address);
- uint8_t crc8(uint8_t *p, uint8_t len);
- void setup()
- {
- WiFi.persistent(false);
- Serial.begin(115200);
- while (!Serial) ; // Needed for Leonardo only
- delay(250);
- Serial.println("I:ESP8266 NTP Time Clock");
- Serial.print("I:Connecting to ");
- Serial.println(ssid);
- // WiFi.begin(ssid, pass);
- // while (WiFi.status() != WL_CONNECTED) {
- // delay(500);
- // Serial.print(".");
- // }
- WiFi.mode(WIFI_STA);
- wifiMulti.addAP("OpenBSD", "13581882013");
- while (wifiMulti.run(connectTimeoutMs) != WL_CONNECTED) {
- delay(500);
- Serial.print(".");
- }
- Serial.println("OK");
- Serial.print("I:IP address is ");
- Serial.println(WiFi.localIP());
- Serial.println("I:Starting UDP");
- Udp.begin(localPort);
- Serial.print("I:Local port: ");
- Serial.println(Udp.localPort());
- Serial.println("I:waiting for sync");
- setSyncProvider(getNtpTime);
- setSyncInterval(300);
- }
- time_t prevDisplay = 0; // when the digital clock was displayed
- void loop()
- {
- if (timeStatus() != timeNotSet) {
- if (now() != prevDisplay) { //update the display only if time has changed
- prevDisplay = now();
- digitalClockDisplay();
- }
- }
- }
- uint8_t crc8(char *p, uint8_t len)
- {
- uint16_t i;
- uint16_t crc = 0x0;
- while (len--) {
- i = (crc ^ *p++) & 0xFF;
- crc = (crc_table[i] ^ (crc << 8)) & 0xFF;
- }
- return crc & 0xFF;
- }
- void digitalClockDisplay()
- {
- // digital clock display of the time
- // Serial.print(hour());
- // printDigits(minute());
- // printDigits(second());
- // Serial.print(" ");
- // Serial.print(day());
- // Serial.print(".");
- // Serial.print(month());
- // Serial.print(".");
- // Serial.print(year());
- // Serial.println();
- char timeStr[25] = {0};
- sprintf(timeStr, "T:%04d-%02d-%02d %02d:%02d:%02d ", year(), month(), day(), hour(), minute(), second());
- // Serial.println(timeStr);
- uint8_t crc = crc8(timeStr, strlen(timeStr));
- sprintf(timeStr, "%s%02X", timeStr, crc);
- Serial.println(timeStr);
- }
- void printDigits(int digits)
- {
- // utility for digital clock display: prints preceding colon and leading 0
- Serial.print(":");
- if (digits < 10)
- Serial.print('0');
- Serial.print(digits);
- }
- /*-------- NTP code ----------*/
- const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
- byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
- time_t getNtpTime()
- {
- IPAddress ntpServerIP; // NTP server's ip address
- while (Udp.parsePacket() > 0) ; // discard any previously received packets
- Serial.println("I:Transmit NTP Request");
- // get a random server from the pool
- WiFi.hostByName(ntpServerName, ntpServerIP);
- Serial.print("I:");
- Serial.print(ntpServerName);
- Serial.print(": ");
- Serial.println(ntpServerIP);
- sendNTPpacket(ntpServerIP);
- uint32_t beginWait = millis();
- while (millis() - beginWait < 1500) {
- int size = Udp.parsePacket();
- if (size >= NTP_PACKET_SIZE) {
- Serial.println("I:Receive NTP Response");
- Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
- unsigned long secsSince1900;
- // convert four bytes starting at location 40 to a long integer
- secsSince1900 = (unsigned long)packetBuffer[40] << 24;
- secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
- secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
- secsSince1900 |= (unsigned long)packetBuffer[43];
- return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
- }
- }
- Serial.println("E:No NTP Response :-(");
- return 0; // return 0 if unable to get the time
- }
- // send an NTP request to the time server at the given address
- void 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();
- }
该部分的代码,参考了Arduino IDE的8266例子中的:
在此基础上,进行了一些小的修改:
- 将WiFi连接部分,修改为了WiFiMul,这样就可以同时设置多组WiFi连接,更方便使用。
- 添加了查表计算CRC8的代码,以便接收端收到后进行校验,确保数据准确。不过,MM32L0136C7P不分,我没有使用到,大家有需要可以在接收后进行校验。
- 修改了信息的输出,正常信息使用I:开头,错误信息使用E:开头,时间信息使用T:开头,方便接收端进行解析
将以上代码烧录到ESP8266,然后打开串口终端,就可以收到启动的信息,以及时间信息:
测试验证完成,就可以连到MM32L0136C7P开发板上使用了。
2. MM32L0136C7P开发板
该部分的代码,参考了SLCD_ShowOnStop、UART_Tx_DMA_Interrupt_Rx_Interrupt。
UART_Tx_DMA_Interrupt_Rx_Interrupt实例,提供了中断收发数据的演示,基本不用修改,连引脚定义都是对应的,直接就可以使用了。
SLCD_ShowOnStop,则提供了显示数字和单位符号的演示,其中关键的调用如下:
- LCD_Clear():清屏
- LCD_DisplayNumber1(索引, '字符', 小数点标志):大号数字区域显示
- LCD_DisplayNumber2(索引, '字符', 小数点标志):小号数字区域显示
- LCD_DisplayUnit(索引, 显示标志):单位符号显示
大号数字显示:LCD_DisplayNumber1(索引, '字符', 小数点标志)
索引对应如下:
字符对应如下:
从上表中可知,除了0-9,还能显示一部分字母,但是不全,例如没有K,因为没法显示区分。
小数点标志,就表示是否显示小数点,0-不显示,1-显示
小号数字显示:LCD_DisplayNumber2(索引, '字符', 小数点标志)
索引对应如下:
小号区域的显示字符,演示代码只有0-9。当然,可以根据自己的需要进行扩展。
小数点标志和大号区域相同。
单位符号显示:LCD_DisplayUnit(索引, 显示标志)
索引有10个,对应下图:
{"S1 ", "S2 ", "S3 ", "S4 ", "S9 ", "T1 ", "W1 ", "C1 ", "C2 ", "C3 "};
时钟部分,要显示的:,使用的就是C2、C3,索引为8、9
最终,main.c的代码如下:
- ////////////////////////////////////////////////////////////////////////////////
- /// [url=home.php?mod=space&uid=288409]@file[/url] main.c
- /// [url=home.php?mod=space&uid=187600]@author[/url] AE TEAM
- /// [url=home.php?mod=space&uid=247401]@brief[/url] THIS FILE PROVIDES ALL THE SYSTEM FUNCTIONS.
- ////////////////////////////////////////////////////////////////////////////////
- // Define to prevent recursive inclusion
- #define _MAIN_C_
- // Files includes
- #include "delay.h"
- #include "slcd.h"
- #include "led.h"
- #include "uart_txdma_rx_interrupt.h"
- ////////////////////////////////////////////////////////////////////////////////
- /// @addtogroup MM32_Example_Layer
- /// @{
- ////////////////////////////////////////////////////////////////////////////////
- /// @addtogroup MAIN
- /// @{
- ////////////////////////////////////////////////////////////////////////////////
- /// @addtogroup MAIN_Exported_Constants
- /// @{
- #define GET_BIT(x, bit) ((x & (1 << bit)) >> bit) /* 获取第bit位 */
- #define APP_TITLE "I:MM32 NTP Net Clock\r\n"
- u8 gSendBuf[] = "I:yyyy-mm-dd HH:MM:SS\r\n";
- ////////////////////////////////////////////////////////////////////////////////
- /// [url=home.php?mod=space&uid=247401]@brief[/url] This function is main entrance.
- /// @param None.
- /// @retval 0.
- ////////////////////////////////////////////////////////////////////////////////
- s32 main(void)
- {
- u8 len;
- u16 times = 0;
-
- u16 year;
- u8 month,day,hour,minute,second;
- u8 crc;
- u8 buf[25] = {0};
-
- DELAY_Init();
- LED_Init();
- DELAY_Ms(100);
- //slcd_test();
- slcd_init();
-
- UART1_NVIC_Init(115200);
- NVIC_Configure(DMA1_Channel2_3_IRQn, 2, 0);
- UART1_SendString(APP_TITLE);
- DMA_NVIC_Send_Config(DMA1_Channel2, (u32)&UART1->TDR, (u32)gSendBuf, sizeof(gSendBuf)/sizeof(gSendBuf[0]));
-
- LCD_Clear();
-
- LCD_DisplayNumber2(0, '2', 0);
- LCD_DisplayNumber2(1, '0', 0);
- LCD_DisplayNumber2(2, '2', 0);
- LCD_DisplayNumber2(3, '2', 0);
- LCD_DisplayNumber1(0, '-', 0);
- LCD_DisplayNumber1(1, 'C', 0);
- LCD_DisplayNumber1(2, 'l', 0);
- LCD_DisplayNumber1(3, 'o', 0);
- LCD_DisplayNumber1(4, 'c', 0);
- LCD_DisplayNumber1(5, 'L', 0);
-
- DELAY_Ms(5000);
-
- while(1) {
- if(gUartRxSta & 0x8000) {
- //receive data length
- len = gUartRxSta & 0x3fff;
- if(len==0x1a && gUartRxBuf[0]=='T' && gUartRxBuf[1]==':') {
- sscanf(gUartRxBuf, "T:%04d-%02d-%02d %02d:%02d:%02d %2X", &year, &month, &day, &hour, &minute, &second, &crc);
- sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d\r\n", year, month, day, hour, minute, second);
- UART1_SendString(buf);
- LCD_DisplayNumber2(0, ((month/10)%10)?('0'+((month/10)%10)):' ', 0);
- LCD_DisplayNumber2(1, '0'+((month/1)%10), 0);
- LCD_DisplayNumber2(2, ((day/10)%10)?('0'+((day/10)%10)):'-', 0);
- LCD_DisplayNumber2(3, '0'+((day/1)%10), 0);
-
- LCD_DisplayNumber1(0, ((hour/10)%10)?('0'+((hour/10)%10)):' ', 0);
- LCD_DisplayNumber1(1, '0'+((hour/1)%10), 0);
- LCD_DisplayNumber1(2, '0'+((minute/10)%10), 0);
- LCD_DisplayNumber1(3, '0'+((minute/1)%10), 0);
- LCD_DisplayNumber1(4, '0'+((second/10)%10), 0);
- LCD_DisplayNumber1(5, '0'+((second/1)%10), 0);
-
- LCD_DisplayUnit(8,1);
- LCD_DisplayUnit(9,1);
-
- LED1_OFF();
- LED2_OFF();
- LED3_OFF();
- LED4_OFF();
- if(GET_BIT(second, 0)) {
- LED1_ON();
- }
- if(GET_BIT(second, 1)) {
- LED2_ON();
- }
- if(GET_BIT(second, 2)) {
- LED3_ON();
- }
- if(GET_BIT(second, 3)) {
- LED4_ON();
- }
- } else {
- DMA_NVIC_Send_Config(DMA1_Channel2, (u32)&UART1->TDR, (u32)gUartRxBuf, len);
- }
- gUartRxSta = 0;
- }
- else {
- times++;
- if(times % 5000 == 0) {
- UART1_SendString(APP_TITLE);
- }
- if(times % 500 == 0) UART1_SendString("I:Please input Data, End with Enter\r\n");
- if(times % 50 == 0){
- LED1_TOGGLE();
- LED2_TOGGLE();
- LED3_TOGGLE();
- LED4_TOGGLE();
- }
- DELAY_Ms(100);
- }
- }
- }
- /// @}
- /// @}
- /// @}
其中的逻辑也不复杂,具体如下:
- 初始化LED、SLCD、串口以及中断和DMA设置
- LCD清屏,然后显示”2022 - ClocL“,没有K,只好用大L代替了
- 然后就是检测接收状态了,收到了,且符合时间字符串的格式,则解析其中的年月日时分秒,然后显示到SLCD,并根据秒来确定对应的LED显示,实际上就是对应1、2、4、8
另外,还有下面两个地方的代码,需要修改:
修改其中LED对应引脚的配置,以对应MM32L0136C7P开发板。
五、实际效果
将以上MM32L0136C7P开发板的代码,使用Keil编译下载后,就可以看到具体效果了:
【以下播放,加快了速度】
六、代码分享
1. 官方演示代码:
MM32L0130_LibSamples_V020_1201.zip
(5.49 MB, 下载次数: 5)
2. 本应用代码:https://gitee.com/honestqiao/MM32_SLCD_NTP_Net_CLock
要使用本应用的代码,请先下载官方演示代码,并解压,然后将 MM32_SLCD_NTP_Net_CLock 目录放置到 MM32L0130_LibSamples_V020/MM32L0130_Samples/SLCD下,具体如下:
红色框柱的为关键代码,如果编译的时候提示找不到对应的文件,请自己添加一下到工程中。