无线授时服务器接LED屏,超简单DIY~制作自动授时64*32 LED单色大屏时钟(开源)...

//D0 = GPIO16;

//D1 = GPIO5;

//D2 = GPIO4;        LED on esp8266

//D3 = GPIO0;can not download when connected to low

//D4 = GPIO2;

//D5 = GPIO14;

//D6 = GPIO12;

//D7 = GPIO13;

//D8 = GPIO15;  can not start when high input

//D9 = GPIO3; UART RX

//D10 = GPIO1; UART TX

//LED_BUILTIN = GPIO16 (auxiliary constant for the board LED, not a board pin);

#include

#include

#include

#include

#include

#include

#include

#include

u8g2_t u8g2;

#define timezone 8

unsigned long Cycle = 1000;//刷新间隔,微秒

unsigned long DisplayLight = 50;//亮度

const char* ssid = "wang";  //Wifi名称

const char* password = "12345678";  //Wifi密码

char *time_str;

char H1,H2,M1,M2,S1,S2;

unsigned long SecondsSinceStart = 0;

unsigned long TenthSecondsSinceStart = 0;

void TenthSecondsSinceStartTask();

void OnSecond();

void NonStopTask();

#define RowA D8                    //行信号,驱动138

#define RowB D7

#define RowC D6

#define RowD D5

#define STB D2         //595 刷新显示  SS  LAT

#define CLK D1         //时钟    SCK

#define OE D0                         //  使能

#define R1 D4          //上半屏列信号输出

#define R2 D3          //下半屏列信号输出

void setup()

{

delay(50);

Serial.begin(115200);

pinMode(RowA, OUTPUT);

pinMode(RowB, OUTPUT);

pinMode(RowC, OUTPUT);

pinMode(RowD, OUTPUT); //138片选

pinMode(OE, OUTPUT); //138 使能

pinMode(R1, OUTPUT);//595 数据

pinMode(R2, OUTPUT);//595 数据

pinMode(CLK, OUTPUT); //595 时钟

pinMode(STB, OUTPUT); //595 使能

WiFi.disconnect();

WiFi.mode(WIFI_STA);//设置模式为STA

byte mac[6];

WiFi.softAPmacAddress(mac);

printf("macAddress 0x%02X:0x%02X:0x%02X:0x%02X:0x%02X:0x%02X\r\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);

Serial.print("Is connection routing, please wait");

WiFi.begin(ssid, password); //Wifi接入到网络

Serial.println("\nConnecting to WiFi");

//如果Wifi状态不是WL_CONNECTED,则表示连接失败

unsigned char WiFiTimeOut = 0;

while (WiFi.status() != WL_CONNECTED) {

Serial.print(".");

delay(1000);    //延时等待接入网络

WiFiTimeOut++;

if (WiFiTimeOut>10)

{

break;

Serial.println("\nConnecting to WiFi Failed");

}

}

//设置时间格式以及时间服务器的网址

configTime(timezone * 3600, 0, "pool.ntp.org", "time.nist.gov");

Serial.println("\nWaiting for time");

while (!time(nullptr)) {

Serial.print(".");

delay(1000);

}

Serial.println("");

//开启OTA功能。除了第一次需要用USB下载,以后就可以使用WiFi下载程序了。

ArduinoOTA.onStart([]() {

String type;

if (ArduinoOTA.getCommand() == U_FLASH) {

type = "sketch";

} else { // U_SPIFFS

type = "filesystem";

}

// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()

Serial.println("Start updating " + type);

});

ArduinoOTA.onEnd([]() {

Serial.println("\nEnd");

});

ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {

Serial.printf("Progress: %u%%\r", (progress / (total / 100)));

});

ArduinoOTA.onError([](ota_error_t error) {

Serial.printf("Error[%u]: ", error);

if (error == OTA_AUTH_ERROR) {

Serial.println("Auth Failed");

} else if (error == OTA_BEGIN_ERROR) {

Serial.println("Begin Failed");

} else if (error == OTA_CONNECT_ERROR) {

Serial.println("Connect Failed");

} else if (error == OTA_RECEIVE_ERROR) {

Serial.println("Receive Failed");

} else if (error == OTA_END_ERROR) {

Serial.println("End Failed");

}

});

ArduinoOTA.begin();

Serial.println("Ready");

Serial.print("IP address: ");

Serial.println(WiFi.localIP());

u8g2_Setup_ssd1306_64x32_noname_f(&u8g2, U8G2_R0, NULL, NULL);  // init u8g2 structure

}

void hc138sacn(byte r)   //输出行线状态ABCD (A低,D高)

{

digitalWrite(RowA,(r & 0x01));

digitalWrite(RowB,(r & 0x02));

digitalWrite(RowC,(r & 0x04));

digitalWrite(RowD,(r & 0x08));

}

void DisplayOneLine()

{

//显示缓存扫描

static unsigned char row=0;

for (int i=0; i<64; i++)

{

digitalWrite(CLK,0);

digitalWrite(R1, ((u8g2.tile_buf_ptr[i%64+(row/8)*64]>>(row%8))&1));//发送上半屏

digitalWrite(R2, ((u8g2.tile_buf_ptr[i%64+(row/8)*64+128]>>(row%8))&1));//发送下半屏

digitalWrite(CLK,1);

}

hc138sacn(row);            //选行

digitalWrite(STB, 1);      //数据确认

digitalWrite(STB, 0);

if (DisplayLight>0)

{

digitalWrite(OE, 0);  //开启显示

}

delayMicroseconds(DisplayLight) ;  //亮度调节

digitalWrite(OE, 1);  //关闭显示

row++;

if (row>15)

{

row = 0;

NonStopTask();

}

}

unsigned long CurrentDisplayTime;

unsigned long LastDisplayTime;

void DisplayTimerTask()

{

CurrentDisplayTime = micros();

if (abs(CurrentDisplayTime - LastDisplayTime) > Cycle)

{

LastDisplayTime = CurrentDisplayTime;

DisplayOneLine();

}

}

void loop()

{

DisplayTimerTask();

}

void NonStopTask()

{

TenthSecondsSinceStartTask();

ArduinoOTA.handle();

}

void OnTenthSecond()

{

if (TenthSecondsSinceStart % 10 == 0)

{

OnSecond();

SecondsSinceStart++;

}

}

unsigned long LastMillis = 0;

void TenthSecondsSinceStartTask()

{

unsigned long CurrentMillis = millis();

if (abs(CurrentMillis - LastMillis) > 100)

{

LastMillis = CurrentMillis;

TenthSecondsSinceStart++;

OnTenthSecond();

}

}

char* WeekStr[7] = { "Sunday"

,"Monday"

,"Tuesday"

,"Wednesday"

,"Thursday"

,"Friday"

,"Saturday" };

void OnSecond()

{

static char sprint_buf[20];

time_t now = time(nullptr); //获取当前时间

//转换成年月日的数字,可以更加自由的显示。

struct   tm* timenow;

timenow = localtime(&now);

unsigned char tempHour = timenow->tm_hour;

unsigned char tempMinute = timenow->tm_min;

unsigned char tempSecond = timenow->tm_sec;

unsigned char tempDay = timenow->tm_mday;

unsigned char tempMonth = timenow->tm_mon + 1;

unsigned int tempYear = timenow->tm_year + 1900;

unsigned char tempWeek = timenow->tm_wday;

u8g2_ClearBuffer(&u8g2);//清空显存

u8g2_SetFont(&u8g2, u8g2_font_crox3t_tn);

//第一行大字,显示时间

sprintf(sprint_buf, "%02d:%02d:%02d"

, tempHour

, tempMinute

, tempSecond

);

u8g2_DrawStr(&u8g2, 3, 12, sprint_buf);

//第二行小字,显示日期

u8g2_SetFont(&u8g2, u8g2_font_IPAandRUSLCD_tf);//字体5*7

sprintf(sprint_buf, "%04d-%02d-%02d"

, tempYear

, tempMonth

, tempDay

);

u8g2_DrawStr(&u8g2, 0, 22, sprint_buf);

//第三行小字,显示星期

sprintf(sprint_buf, "%s"

, WeekStr[tempWeek]

);

u8g2_DrawStr(&u8g2, 0, 31, sprint_buf);

//显示中文的方法  但是这个屏幕最多只能显示八个汉字。本身这个源文件,必须是UTF-8格式

//u8g2_SetFont(&u8g2, u8g2_font_wqy16_t_gb2312);

//u8g2_DrawUTF8(&u8g2, 0, 14, "好好学习");

//u8g2_DrawUTF8(&u8g2, 0, 30, "天天向上");

}

本方案采用的是MCU+AT指令的形式开发,MCU是大家比较熟悉的意法半导体公司STM32F103C8T6,WiFi模块使用的是安信可ESP-12F,本方案是一个Demo设计,比较简单,仅实现了功能,算是一个抛砖引玉吧! 先上视频演示:https://v.youku.com/v_show/id_XNDE3OTE4MDY4NA==.html?spm=a2hzp.8244740.0.0 WiFi模块资料链:https://wiki.ai-thinker.com/esp8266 STM32F103C8芯片资料链:https://www.stmicroelectronics.com.cn/content/st_com/zh/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-mainstream-mcus/stm32f1-series/stm32f103/stm32f103c8.html#overview 硬件部分,由时钟电路+WiFi模块+MCU最小系统+OLED显示+稳压电路+按键电路组成,这里采用时钟电路是希望模块在断网后还能获取一个比较精准的时间,并且电路设计上增加了储能电容可以在断电一个月后保持时间数据不丢失,当然这里也可以用STM32里面的RTC时钟;OLED显示采用的是裸设计,使整体电路板一体化效果好些;其他电路都是参考开发板or硬件手册上设计的;硬件设计软件采用的是Altium Designer (13.0),原理图概略图如下图所示: 实物图如下图所示:(电路板是找厂家打样的,元器件是纯人工手焊) 软件部分,由底层驱动+WiFi联网+调用API口并解析数据+OLED显示组成;首先分析一波,这里面用到了MCU的USART、I2C*2、GPIO*2引脚资源,然后对应去找相关类似的例程,既然已经有轮子了,为何还要花时间去造轮子,当然是直改例程来的舒服。这里开发方式采用的是库函数开发,用的是STM32的标准库,对应找到了OLED显示的驱动资料、PCF8563的驱动资料、WiFi模组的驱动资料、按键输入的驱动资料;将它们整合到一个工程里面,然后更改里面的引脚配置等,就完成了整个设计的底层驱动。 WiFi联网,这里WiFi是设置成了STA模式(STA模式是啥,可自行问度娘),然后连手机开的热点(注意手机必须要能连上公网,即我们常用的互联网)。具体如何设置可以参考WiFi模块的AT指令集,AT指令集在上面WiFi模块资料里面有。手机开的WiFi热点的账号密码需要事先知道,并写入在程序里面,后续如果需要更改热点的账号密码,就需要更改程序。 天气和时间更新,即调用API口并解析数据,这里用到了两个API口,第一个是心知天气的天气实况数据获取,因为是免费版所以只能获取到天气现象和气温两项数据;第二个是Nowapi的北京时间数据获取。因为用到的两个API口是隶属于两个不同的服务器,所以程序上需要进行切换,连完这个服务器后需要断开连另一个服务器,比较麻烦。后面我发现其实Nowapi里面就有天气数据可以获取,完全可以通过只连这个服务器就实现天气和时间数据的更新。实现方法参考下面的网址,写比较详细。 心知天气:https://docs.seniverse.com/api/weather/now.html、服务器IP116.62.81.138(域名api.seniverse.com)、默认端口80 Nowapi:https://www.nowapi.com/api/life.time、服务器IP103.205.4.43(域名api.k780.com)、默认端口80 解析数据用的是比较简单的方法,因为需要解析的数据量不大,所以并没有移植cjson,直用strtok函数硬解。 OLED显示,OLED显示用的是I2C口,然后给的例程只有常用的标点符号和26个英文字母的字库,如果需要汉字还需要自己添加字库,一般是用到什么汉字就添加什么汉字的字库,然后用例程里面给的功能函数去实现显示。 显示资料:http://pan.baidu.com/s/1dFri9Vz 下图是用到的所有.c文件(除库函数之外) bsp_usart1.c是用来串口调试使用,可以打印在电脑串口调试助手上显示;bsp_SysTick.c是用来生成精准的延时函数,用于I2C通讯等对时序敏感的口;bsp_esp8266.c里面是对WiFi模块的一些初始化配置和WiFi的功能函数;Common.c里面是一些辅助函数;test.c里面是实现WiFi配网应用和API口调用及解析;oled.c里面显示的初始化配置和显示功能函数;bsp_pcf8563.c里面是时钟
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值