学习过程不易,发文共享以下学习过程~

先说说我的设计内容的组成:

目录

学习过程不易,发文共享以下学习过程~

1. STM32控制ESP8266获取网络时间

第一步:电脑控制ESP8266获取时间数据;

2. STM32基于获取到的时间使用定时器本地运行

3. 使用OLED显示时间数据,包括自定义的文字显示,图片显示,视频显示;

4. 完整的工程代码


1. STM32控制ESP8266获取网络时间

为了更好的理解原理,可以先从电脑通过串口控制ESP8266获取时间数据开始入手学习。

为此需要准备以下的软件和硬件

1.ESP8266-01S(其他ESP8266应该也可以)

2.一个烧录下载器

3.正点原子的串口助手

第一步:电脑控制ESP8266获取时间数据;

需要用ESP8266和电脑建立串口通讯,通过电脑给ESP8266发送AT指令。

插一句关于AT指令的介绍:

我的理解是 AT指令就是一句句的口令,你向ESP8266发出对应的指令,ESP8266就会根据你的指令做出相应的反应,当然AT指令是一系列提前编译好的官方指令,不是自己随意编写的!对于AT指令的学习,可以参考这篇文章~

玩转ESP8266-01——AT指令集  http://t.csdn.cn/1EZ0E

 Step1:将ESP8266和烧录下载器正确连接,再与电脑连接

烧录下载器和电脑

ESP8266和烧录下载器

 Step2:打开正点原子的串口助手,选择正确的端口号,波特率选择115200.(当然你要是电脑没有烧录下载器的驱动的话,电脑会识别不了这个设备,必须去安装CH340的驱动才行)

初始界面

正确连接的话,上述界面由设备的端口号。

Step3:提前新建好对应的AT指令,这里基于我的程序设计要求,新建如下指令即可。

AT                           //查询模块是否正常工作
AT+RST                       //模块复位
AT+RESTORE                   //恢复出厂设置
AT+CWMODE=1                  //设置WiFi模块的模式
AT+CIPMUX=0                  //设置模块为单路连接模式
AT+CWJAP="WIFI名称","密码"    //连接网络
AT+CIPSTART="TCP","192.168.666",80//连接TCP服务器,192.168.0.102是服务器IP,8080是服务器端口。
AT+CIPSTART="TCP","quan.suning.com",80  //或者 AT+CIPSTART="TCP","175.6.49.231",80
AT+CIPMODE=1                 //开启透传模式
AT+CIPSEND                   //开始发送数据
+++                          //退出透传模式

完成上述的准备工作之后,就可以点击打开串口、发送新行。

一般串口刚连接上会发送一些杂乱数据(应该是表示ESP8266准备好了通讯的意思,因为发来的消息最后面有个ready)

Step4:按照顺序一次的点击新建好的10条AT指令,当然速度不适宜太快,需要等ESP8266发送对应的回答之后才可以继续点击,每一次点击的 效果如下。


第一条指令:

第二条指令:


第三条指令:

第四条指令:


第五条指令:

第六条指令:


第八条指令:

第七条指令:


第九条指令:

第十条指令:

补充一下上面ESP8266返回来的数据说明:

第一张图片:如果返回来OK表示器件正确的连接了。

第二张图片:收到OK就表示复位成功,后面跟着的应该是一些ESP8266的自身信息。

第三张图片:将ESP8266切换为STA模式,作为一个设备去连接WIFI,关于ESP8266的工作模式可以看这个链接http://t.csdn.cn/4x1oA。

第四张图片:设置ESP8266为单路连接模式,返回OK表示开启成功。

第五张图片:注意这是表示将要连接的WIFI的名称和密码发送给ESP8266,要注意大小写,最好是用手机开热点,这样方便查看是否成功连接上,返回OK即连接成功。

第六张图片:如果返回来OK表示ESP8266开启透传模式,透传模式不懂的也可以看上面的链接。

第七张图片:通过苏宁去获取时间,这是苏宁的服务器地址,返回OK连接成功。

第八张图片:查询ESP8266是否准备发送就绪,出现一个>表示已就绪。

第九张图片:这是一个返回时间的链接,在浏览器输入网址浏览器即返回时间数据。

第十张图片:退出透传模式,要先关闭发送新行,然后多试几次,如果收到+++表示退出成功,这个时候再点击第一条指令,收到OK就验证了退出成功。

2. STM32基于获取到的时间使用定时器本地运行

了解了ESP8266获取时间的原理之后就可以开始编写STM32F103C8T6的工程了,

这里是使用一个ESP8266的库来开发ESP8266的,代码原文是这个~,感谢大佬的分享。

http://t.csdn.cn/L3M3nhttp://t.csdn.cn/L3M3n本来是想基于上述文章,写一个获取时间天气的课设的,在一番尝试之后,无果,临近检查,就只能复刻一下只获取时间数据了。

获取时间天气的JSON解析函数我也写了,为此特定去学了以下JSON解析,参考一篇知乎的文章写的,链接找不到了,贴出我的解析函数,大家可以帮我参考一下。

这里我仿照上面大佬的文章,将变量用 函数的方法返回到主函数,奈何还是有问题,有时间再经研究吧。

char id,city,guojia,zone,tianqi,code,temp,time;
//心知天气
void parse_seniverse_weather(void)
{cJSON *root;cJSON *results;cJSON *last_update;cJSON *loc_json, *daily_json;cJSON *forecast_json;char *loc_tmp, *weather_tmp, *update_tmp;root = cJSON_Parse((const char*)Time_buff);  //root就取得了json的数据if(root)  //如果取得{
//        printf("JSON格式正确:\n%s\n\n",cJSON_Print(root));    //输出json字符串results = cJSON_GetObjectItem(root, "results");  //寻找关键字一 results = cJSON_GetArrayItem(results,0);  //取出results数组里的第0个也就是第一个if(results)  //如果取得{loc_json = cJSON_GetObjectItem(results, "location");   //得到location键对应的值,是一个对象loc_tmp = cJSON_GetObjectItem(loc_json, "id") -> valuestring;  //取得IDid = *loc_tmp;  //注意这个地方可能出错,看读取出来的是什么loc_tmp = cJSON_GetObjectItem(loc_json, "name") -> valuestring;  //取得城市city = *loc_tmp;loc_tmp = cJSON_GetObjectItem(loc_json, "country") -> valuestring;  //取得国家guojia = *loc_tmp;loc_tmp = cJSON_GetObjectItem(loc_json, "timezone") -> valuestring;  //取得时区zone = *loc_tmp;daily_json = cJSON_GetObjectItem(results, "now");//原本是读取三天的,修改为读取现在的nowif(daily_json){forecast_json = cJSON_GetArrayItem(daily_json, 0);weather_tmp = cJSON_GetObjectItem(forecast_json, "text") -> valuestring;  //取得天气情况tianqi = *weather_tmp;weather_tmp = cJSON_GetObjectItem(forecast_json, "code") -> valuestring;  //取得code情况code = *weather_tmp;weather_tmp = cJSON_GetObjectItem(forecast_json, "temperature") -> valuestring;  //取得温度情况temp = *weather_tmp;}else
//                printf("daily json格式错误\r\n");last_update = cJSON_GetObjectItem(results, "last_update");update_tmp = last_update->valuestring;if(last_update){time = *update_tmp;}}else{//printf("results格式错误:%s\r\n", cJSON_GetErrorPtr());}}else{//printf("JSON格式错误\r\n");}cJSON_Delete(root);//最后释放空间cJSON_Delete(results);//最后释放空间
}

重点来了,我的课设的代码,其实和大佬的分享差不多。

#include "stm32f10x.h"
#include "sys.h"
#include "string.h"
#include "stdlib.h"
#include "esp8266.h"#include "usart2.h"#include "delay.h"
#include "init.h"/*用于保存小时,分钟,秒数的变量*/
int hour_return;//小时
int min_return; //分钟
int sec_return; //秒数//WIFI和密码·
#define ESP8266_WIFI_INFO       "AT+CWJAP=\"iQOO\",\"qyh12345678\"\r\n"//苏宁后台获取时间的API
#define Time_TCP        "AT+CIPSTART=\"TCP\",\"quan.suning.com\",80\r\n"
//苏宁后台获取时间GET报文
#define Time_GET        "GET http://quan.suning.com/getSysTime.do\r\n"//ESP8266数据存放
unsigned char esp8266_buf[300] = {0};
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;
//存放时间数据
unsigned char Time_buff[100];   //位数是随机确定的/**************************************************************************/
//函数作用:ESP8266_Init初始化函数
//函数名称:ESP8266_Init(void);
//内部参数:
//修改日期:2022年4月18日  下午16:18
/**************************************************************************/
void ESP8266_Init(void)
{ESP8266_Clear();//清除缓冲/*让WIFI退出透传模式 要发两次*/while(ESP8266_SendCmd("+++", ""));//这是一个死循环,目的结束透传模式/*让WIFI清除Flah*///printf("0.恢复出厂设置成功\r\n");while(ESP8266_SendCmd("AT+RESTORE\r\n", "OK"));//恢复出厂设置//初始AT应答,看wifi接线是否成功//printf("1.AT应答成功\r\n");while(ESP8266_SendCmd("AT\r\n", "OK"));////加一步ESP8266复位操作//printf("2.RST复位成功\r\n");ESP8266_SendCmd("AT+RST\r\n", "");delay_ms(500);ESP8266_SendCmd("AT+CIPCLOSE\r\n", "");//断开与服务器的连接delay_ms(500);///printf("3.CWMODE设置工作模式,保存到Flash\r\n");while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"));//没有CUR就是保存到Flash,AT+CWMODE_CUR设置模块工作模式为station,不保存到Flash//printf("4.AT+CIPMUX单连接模式设置成功\r\n");while(ESP8266_SendCmd("AT+CIPMUX=0\r\n", "OK"));//AT+CIPMUX=0 设置为单连接模式//printf("5.寻找对应的WIFI名称和密码\r\n");while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "WIFI GOT IP"));//printf("6.ESP8266_Init连接WIFI成功\r\n");
}/**************************************************************************/
//函数作用:获取苏宁后台时间
//函数名称:Get_current_time();
//内部参数:
/**************************************************************************/
void Get_current_time(void)
{ESP8266_Init();         //连接Wifi的ESP8266初始化ESP8266_Clear();while(ESP8266_SendCmd(Time_TCP, "CONNECT"));//printf("6.访问苏宁服务器成功 OK\r\n");while(ESP8266_SendCmd("AT+CIPMODE=1\r\n", "OK"));//开启透传模式//printf("7.开启透传模式成功 OK\r\n");/*sizeof(Time_GET),必须用sizeof函数,用strlen没有用*/ESP8266_SendData((u8 *)Time_GET, sizeof(Time_GET)); //发送AT+CIPSEND  以及 Time_GETESP8266_GetIPD_GET(200, Time_buff); //将串口数据取出来ESP8266_Clear();//清除缓存数据while(ESP8266_SendCmd("+++", ""));      /*退出透传模式,发送两次*///printf("9.退出透传模式成功 OK\r\n");}/*******************************************解析时间*************************************/
//代码来源于CSDN博客地址:https://blog.csdn.net/xgy516/article/details/119968124
/****************************************************************************************
年的首地址移动11位;
月份首地址移动15位;
日期首地址移动17位;
小时首地址移动19位;
分钟首地址移动21位;
秒钟首地址移动23位;
*/
#define  YEAR_ADD_DRES 11
#define  MOON_ADD_DRES 15
#define  DAYS_ADD_DRES 17#define  HOURS_ADD_DRES 19
#define  MINUTES_ADD_DRES 21
#define  SECONDS_ADD_DRES 23int DAYS, MOONS, YEARS, TIMES;
///**************************************************************************/
函数作用:解析苏宁时间函数
函数名称:cJSON_Time_Parse();
内部参数:
修改日期:2022年4月18日  下午22:11
///**************************************************************************/
void cJSON_Time_Parse(void)
{char *data_pt;char *day_string;char *moon_string;char *year_string;char *hour_string;char *minute_string;char *second_string;data_pt = strstr((const char *)Time_buff, (const char *)"sysTime1");  //寻找到时间结果的地址//    printf("%s\r\n",Time_buff);if(data_pt != NULL){day_string = data_pt + DAYS_ADD_DRES;          //日期地址moon_string = data_pt + MOON_ADD_DRES;         //月份地址year_string = data_pt + YEAR_ADD_DRES;        //年份地址hour_string = data_pt + HOURS_ADD_DRES;       //小时地址minute_string = data_pt + MINUTES_ADD_DRES;   //分钟地址second_string = data_pt + SECONDS_ADD_DRES;   //秒中地址//将时间信息传递给全局变量DAYS = Get_Day(day_string);MOONS = Get_Moonth(moon_string);YEARS = Get_Year(year_string);TIMES = Get_Times(hour_string, minute_string, second_string);hour_return = TIMES/3600;//小时min_return = (TIMES%3600)/60; //分钟sec_return = (TIMES%3600)%60+2; //秒数//printf("时间获取并处理成功\r\n");}else{//printf("时间获取失败\r\n");}
}//得到年函数(以年开始的字符串长度过长,因此使用不一样的方法)
//输入值是年位置的地址
//返回值是 整型的10进制四位数
int Get_Year(char *y)
{int year_return;char *year_temp;char year[5] = {0};char i;
//年的获取须要提取一次字符串,不然没法读取year_temp = y;for(i = 0; i < 4; i++){year[i] = *year_temp;year_temp ++;}year_return =  atoi(&year[0]);return year_return;
}//得到月份函数
//输入值是月份位置的地址
//返回值是 整型的10进制两位数
int Get_Moonth(char *m)
{int moonth_return;moonth_return = atoi(m) / 100000000; //取月份return moonth_return;
}//得到日期函数
//输入值是日期位置的地址
//返回值是 整型的10进制两位数
int Get_Day(char *d)
{int day_return;day_return = atoi(d) / 1000000; //取日期return day_return;
}//得到时间
//输入值是时间的位置的地址
//返回值是 整型的10进制的时间总秒数
int Get_Times(char *h, char *m, char *s)
{int time_return;int hour_return;int min_return;int sec_return;hour_return = atoi(h) / 10000; //取小时min_return = atoi(m) / 100; //取分钟sec_return = atoi(s);   //取秒数time_return = hour_return * 3600 + min_return * 60 + sec_return; //转换成总秒数return time_return;
}/*****************************************************************解析苏宁时间END********************************************************************************/
/*************************************************************************************************************************************************//**************************************************************************/
//函数作用:串口二中断函数
//函数名称:USART2_IRQHandler();
//内部参数:
//修改日期:2022年4月18日  下午4:18
/**************************************************************************/
void USART2_IRQHandler(void)
{if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断{if(esp8266_cnt >= sizeof(esp8266_buf)) esp8266_cnt = 0; //防止串口被刷爆esp8266_buf[esp8266_cnt++] = USART2->DR;//     USART_SendData(USART1,USART2->DR);      //让接收到的数据打印在串口一上USART_ClearFlag(USART2, USART_FLAG_RXNE);}
}
/**下面的代码来源于:*************************************************************************************************************************************************************************************    文件名:     esp8266.c** 作者:      张继瑞**   日期:      2017-05-08**    版本:      V1.0**  说明:      ESP8266的简单驱动**  修改记录:************************************************************************************************************************************************************************************
**/
//==========================================================
//  函数名称:    ESP8266_Clear
//
//  函数功能:    清空缓存
//
//  入口参数:    无
//
//  返回参数:    无
//
//  说明:
//==========================================================
void ESP8266_Clear(void)
{memset(esp8266_buf, 0, sizeof(esp8266_buf));esp8266_cnt = 0;}
//==========================================================
//  函数名称:    ESP8266_SendData
//
//  函数功能:    发送数据
//
//  入口参数:    data:数据
//              len:长度
//
//  返回参数:    无
//
//  说明:
//==========================================================
void ESP8266_SendData(unsigned char *data, unsigned short len)
{char cmdBuf[32];ESP8266_Clear();                               //清空接收缓存sprintf(cmdBuf, "AT+CIPSEND\r\n");      //发送命令if(!ESP8266_SendCmd(cmdBuf, ">"))              //收到‘>’时可以发送数据{//printf("8.开始处于透传发送状态!\r\n");/*发送请求数据*/Usart_SendString(USART2, data, len);      //发送设备连接请求数据}
}//==========================================================
//  函数名称:    ESP8266_GetIPD
//
//  函数功能:    copy天气数据到buff数组里面
//
//  返回参数:    平台返回的原始数据
//
//  说明:      copy天气数据到buff
//==========================================================unsigned char *ESP8266_GetIPD_GET(unsigned short timeOut, u8 *buff) //这里我用了一个全局变量将esp8266buf储存到这个全局变量里面
{do{delay_ms(5);}while(timeOut--);strcpy((char*)buff, (char*)esp8266_buf);return buff;
}//==========================================================
//  函数名称:    ESP8266_WaitRecive
//
//  函数功能:    等待接收完成
//
//  入口参数:    无
//
//  返回参数:    REV_OK-接收完成     REV_WAIT-接收超时未完成
//
//  说明:      循环调用检测是否接收完成
//==========================================================
_Bool ESP8266_WaitRecive(void)
{if(esp8266_cnt == 0)                           //如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数return REV_WAIT;if(esp8266_cnt == esp8266_cntPre)              //如果上一次的值和这次相同,则说明接收完毕{esp8266_cnt = 0;                          //清0接收计数return REV_OK;                              //返回接收完成标志}esp8266_cntPre = esp8266_cnt;                    //置为相同return REV_WAIT;                              //返回接收未完成标志}//==========================================================
//  函数名称:    ESP8266_SendCmd
//
//  函数功能:    发送命令
//
//  入口参数:    cmd:命令
//              res:需要检查的返回指令
//
//  返回参数:    0-成功    1-失败
//
//  说明:
//==========================================================
_Bool ESP8266_SendCmd(char *cmd, char *res)
{unsigned char timeOut = 250;Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));while(timeOut--){if(ESP8266_WaitRecive() == REV_OK)                          //如果收到数据{if(strstr((const char *)esp8266_buf, res) != NULL)     //如果检索到关键词{ESP8266_Clear();                                 //清空缓存return 0;}}delay_ms(10);}return 1;
}

另一个重头戏来了。

OLED显示!!

3. 使用OLED显示时间数据,包括自定义的文字显示,图片显示,视频显示;

OLED显示我参考了很多资料,修修改改还是完成的七七八八。

OLED显示有自定义的编写字库的软件,编写图片字库的软件,

取字模的软件用的是:

取字模

分离抽帧

完蛋!刚刚取找文件,发现我把文件删了,如果有人着急的话,我可以付费帮忙解决一下,很好用的,可以一键将所有图片按照名称分成一个个的记事本文件,只用复制粘贴即可。

看看实物效果先:

ikun

我的OLED.C文件

#include "stm32f10x.h"
#include "OLED_Font.h"/*引脚配置*/
#define OLED_W_SCL(x)       GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
#define OLED_W_SDA(x)       GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))/*引脚初始化*/
void OLED_I2C_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_Init(GPIOB, &GPIO_InitStructure);OLED_W_SCL(1);OLED_W_SDA(1);
}/*** @brief  I2C开始* @param  无* @retval 无*/
void OLED_I2C_Start(void)
{OLED_W_SDA(1);OLED_W_SCL(1);OLED_W_SDA(0);OLED_W_SCL(0);
}/*** @brief  I2C停止* @param  无* @retval 无*/
void OLED_I2C_Stop(void)
{OLED_W_SDA(0);OLED_W_SCL(1);OLED_W_SDA(1);
}/*** @brief  I2C发送一个字节* @param  Byte 要发送的一个字节* @retval 无*/
void OLED_I2C_SendByte(unsigned char  Byte)
{unsigned char  i;for (i = 0; i < 8; i++){OLED_W_SDA(Byte & (0x80 >> i));OLED_W_SCL(1);OLED_W_SCL(0);}OLED_W_SCL(1);   //额外的一个时钟,不处理应答信号OLED_W_SCL(0);
}/*** @brief  OLED写命令* @param  Command 要写入的命令* @retval 无*/
void OLED_WriteCommand(unsigned char  Command)
{OLED_I2C_Start();OLED_I2C_SendByte(0x78);      //从机地址OLED_I2C_SendByte(0x00);      //写命令OLED_I2C_SendByte(Command); OLED_I2C_Stop();
}/*** @brief  OLED写数据* @param  Data 要写入的数据* @retval 无*/
void OLED_WriteData(unsigned char  Data)
{OLED_I2C_Start();OLED_I2C_SendByte(0x78);      //从机地址OLED_I2C_SendByte(0x40);      //写数据OLED_I2C_SendByte(Data);OLED_I2C_Stop();
}/*** @brief  OLED设置光标位置* @param  Y 以左上角为原点,向下方向的坐标,范围:0~7* @param  X 以左上角为原点,向右方向的坐标,范围:0~127* @retval 无*/
void OLED_SetCursor(unsigned char  Y, unsigned char  X)
{OLED_WriteCommand(0xB0 | Y);                   //设置Y位置OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));   //设置X位置低4位OLED_WriteCommand(0x00 | (X & 0x0F));         //设置X位置高4位
}/*** @brief  OLED清屏* @param  无* @retval 无*/
void OLED_Clear(void)
{  unsigned char  i, j;for (j = 0; j < 8; j++){OLED_SetCursor(j, 0);for(i = 0; i < 128; i++){OLED_WriteData(0x00);}}
}/*** @brief  OLED显示一个字符* @param  Line 行位置,范围:1~4* @param  Column 列位置,范围:1~16* @param  Char 要显示的一个字符,范围:ASCII可见字符* @retval 无*/
void OLED_ShowChar(unsigned char  Line, unsigned char  Column, char Char)
{       unsigned char  i;OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);      //设置光标位置在上半部分for (i = 0; i < 8; i++){OLED_WriteData(OLED_F8x16[Char - ' '][i]);          //显示上半部分内容}OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);    //设置光标位置在下半部分for (i = 0; i < 8; i++){OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);      //显示下半部分内容}
}/*** @brief  OLED显示字符串* @param  Line 起始行位置,范围:1~4* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串,范围:ASCII可见字符* @retval 无*/
void OLED_ShowString(unsigned char  Line, unsigned char  Column, char *String)
{unsigned char  i;for (i = 0; String[i] != '\0'; i++){OLED_ShowChar(Line, Column + i, String[i]);}
}/*** @brief  OLED次方函数* @retval 返回值等于X的Y次方*/
unsigned int  OLED_Pow(unsigned int  X, unsigned int  Y)
{unsigned int  Result = 1;while (Y--){Result *= X;}return Result;
}/*** @brief  OLED显示数字(十进制,正数)* @param  Line 起始行位置,范围:1~4* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~4294967295* @param  Length 要显示数字的长度,范围:1~10* @retval 无*/
void OLED_ShowNum(unsigned char  Line, unsigned char  Column, unsigned int  Number, unsigned char  Length)
{unsigned char  i;for (i = 0; i < Length; i++)                           {OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');}
}/*** @brief  OLED显示数字(十进制,带符号数)* @param  Line 起始行位置,范围:1~4* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:-2147483648~2147483647* @param  Length 要显示数字的长度,范围:1~10* @retval 无*/
void OLED_ShowSignedNum(unsigned char  Line, unsigned char  Column, signed int  Number, unsigned char  Length)
{unsigned char  i;unsigned int  Number1;if (Number >= 0){OLED_ShowChar(Line, Column, '+');Number1 = Number;}else{OLED_ShowChar(Line, Column, '-');Number1 = -Number;}for (i = 0; i < Length; i++)                         {OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');}
}/*** @brief  OLED显示数字(十六进制,正数)* @param  Line 起始行位置,范围:1~4* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~0xFFFFFFFF* @param  Length 要显示数字的长度,范围:1~8* @retval 无*/
void OLED_ShowHexNum(unsigned char  Line, unsigned char  Column, unsigned int  Number, unsigned char  Length)
{unsigned char  i, SingleNumber;for (i = 0; i < Length; i++)                         {SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;if (SingleNumber < 10){OLED_ShowChar(Line, Column + i, SingleNumber + '0');}else{OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');}}
}/*** @brief  OLED显示数字(二进制,正数)* @param  Line 起始行位置,范围:1~4* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~1111 1111 1111 1111* @param  Length 要显示数字的长度,范围:1~16* @retval 无*/
void OLED_ShowBinNum(unsigned char  Line, unsigned char  Column, unsigned int  Number, unsigned char  Length)
{unsigned char  i;for (i = 0; i < Length; i++)                           {OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');}
}/*** @brief  OLED初始化* @param  无* @retval 无*/
void OLED_Init(void)
{unsigned int  i, j;for (i = 0; i < 1000; i++)           //上电延时{for (j = 0; j < 1000; j++);}OLED_I2C_Init();          //端口初始化OLED_WriteCommand(0xAE); //关闭显示OLED_WriteCommand(0xD5);  //设置显示时钟分频比/振荡器频率OLED_WriteCommand(0x80);OLED_WriteCommand(0xA8);   //设置多路复用率OLED_WriteCommand(0x3F);OLED_WriteCommand(0xD3);   //设置显示偏移OLED_WriteCommand(0x00);OLED_WriteCommand(0x40);    //设置显示开始行OLED_WriteCommand(0xA1);   //设置左右方向,0xA1正常 0xA0左右反置OLED_WriteCommand(0xC8); //设置上下方向,0xC8正常 0xC0上下反置OLED_WriteCommand(0xDA); //设置COM引脚硬件配置OLED_WriteCommand(0x12);OLED_WriteCommand(0x81);   //设置对比度控制OLED_WriteCommand(0xCF);OLED_WriteCommand(0xD9);   //设置预充电周期OLED_WriteCommand(0xF1);OLED_WriteCommand(0xDB);   //设置VCOMH取消选择级别OLED_WriteCommand(0x30);OLED_WriteCommand(0xA4); //设置整个显示打开/关闭OLED_WriteCommand(0xA6);   //设置正常/倒转显示OLED_WriteCommand(0x8D); //设置充电泵OLED_WriteCommand(0x14);OLED_WriteCommand(0xAF); //开启显示OLED_Clear();             //OLED清屏
}//          OLED_ShowCN(1+i*16,0,i);
//显示汉字 (x:横坐标  y:纵坐标  N:字数  S:字号)
void OLED_ShowCN(unsigned char x,unsigned char y,unsigned char N)
{unsigned char wm=0;unsigned int addr;addr= 32*N;OLED_SetCursor(y,x);  //设置起始光标,起始光标的位置时先y后x,for(wm=0;wm<16;wm++){OLED_WriteData( font[addr]);addr +=1;   }OLED_SetCursor(y+1,x);for(wm=0;wm<16;wm++){OLED_WriteData( font[addr]);addr +=1;    }
}// Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
// Description    : 显示BMP位图
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char S)
{unsigned int j=0;unsigned char x,y;if(y1%8==0)y = y1/8;elsey = y1/8 + 1;for(y=y0;y<y1;y++){OLED_SetCursor(y,x0);for(x=x0;x<x1;x++){switch(S){case 1:OLED_WriteData(gImage_init101[j++]);break;case 2:OLED_WriteData(gImage_init102[j++]);break;case 3:OLED_WriteData(gImage_init103[j++]);break;case 4:OLED_WriteData(gImage_init104[j++]);break;case 5:OLED_WriteData(gImage_init105[j++]);break;case 6:OLED_WriteData(gImage_init106[j++]);break;case 7:OLED_WriteData(gImage_init107[j++]);break;case 8:OLED_WriteData(gImage_init108[j++]);break;case 9:OLED_WriteData(gImage_init109[j++]);break;case 10:OLED_WriteData(gImage_init110[j++]);break;case 11:OLED_WriteData(gImage_init111[j++]);break;case 12:OLED_WriteData(gImage_init112[j++]);break;case 13:OLED_WriteData(gImage_init113[j++]);break;case 14:OLED_WriteData(gImage_init114[j++]);break;case 15:OLED_WriteData(gImage_init115[j++]);break;case 16:OLED_WriteData(gImage_init116[j++]);break;case 17:OLED_WriteData(gImage_init117[j++]);break;case 18:OLED_WriteData(gImage_init118[j++]);break;case 19:OLED_WriteData(gImage_init119[j++]);break;case 20:OLED_WriteData(gImage_init120[j++]);break;case 21:OLED_WriteData(gImage_init121[j++]);break;case 22:OLED_WriteData(gImage_init122[j++]);break;case 23:OLED_WriteData(gImage_init123[j++]);break;case 24:OLED_WriteData(gImage_init124[j++]);break;case 25:OLED_WriteData(gImage_init125[j++]);break;}}}
}void OLED_DrawBMP1(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char S)
{unsigned int j=0;unsigned char x,y;if(y1%8==0)y = y1/8;elsey = y1/8 + 1;for(y=y0;y<y1;y++){OLED_SetCursor(y,x0);for(x=x0;x<x1;x++){switch(S){case 1:OLED_WriteData(gImage_IMG00000[j++]);break;case 2:OLED_WriteData(gImage_IMG00001[j++]);break;case 3:OLED_WriteData(gImage_IMG00002[j++]);break;case 4:OLED_WriteData(gImage_IMG00003[j++]);break;case 5:OLED_WriteData(gImage_IMG00004[j++]);break;case 6:OLED_WriteData(gImage_IMG00005[j++]);break;case 7:OLED_WriteData(gImage_IMG00006[j++]);break;case 8:OLED_WriteData(gImage_IMG00007[j++]);break;case 9:OLED_WriteData(gImage_IMG00008[j++]);break;case 10:OLED_WriteData(gImage_IMG00009[j++]);break;case 11:OLED_WriteData(gImage_IMG00010[j++]);break;case 12:OLED_WriteData(gImage_IMG00011[j++]);break;case 13:OLED_WriteData(gImage_IMG00012[j++]);break;case 14:OLED_WriteData(gImage_IMG00013[j++]);break;case 15:OLED_WriteData(gImage_IMG00014[j++]);break;case 16:OLED_WriteData(gImage_IMG00015[j++]);break;case 17:OLED_WriteData(gImage_IMG00016[j++]);break;case 18:OLED_WriteData(gImage_IMG00017[j++]);break;case 19:OLED_WriteData(gImage_IMG00018[j++]);break;case 20:OLED_WriteData(gImage_IMG00019[j++]);break;case 21:OLED_WriteData(gImage_IMG00020[j++]);break;case 22:OLED_WriteData(gImage_IMG00021[j++]);break;case 23:OLED_WriteData(gImage_IMG00022[j++]);break;case 24:OLED_WriteData(gImage_IMG00023[j++]);break;case 25:OLED_WriteData(gImage_IMG00024[j++]);break;case 26:OLED_WriteData(gImage_IMG00025[j++]);break;case 27:OLED_WriteData(gImage_IMG00026[j++]);break;case 28:OLED_WriteData(gImage_IMG00027[j++]);break;case 29:OLED_WriteData(gImage_IMG00028[j++]);break;case 30:OLED_WriteData(gImage_IMG00029[j++]);break;case 31:OLED_WriteData(gImage_IMG00030[j++]);break;case 32:OLED_WriteData(gImage_IMG00031[j++]);break;case 33:OLED_WriteData(gImage_IMG00032[j++]);break;case 34:OLED_WriteData(gImage_IMG00033[j++]);break;case 35:OLED_WriteData(gImage_IMG00034[j++]);break;case 36:OLED_WriteData(gImage_IMG00035[j++]);break;}}}
}

OLED.H文件、

#ifndef __OLED_H
#define __OLED_Hvoid OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(unsigned char  Line, unsigned char  Column, char Char);
void OLED_ShowString(unsigned char  Line, unsigned char  Column, char *String);
void OLED_ShowNum(unsigned char  Line, unsigned char  Column, unsigned int  Number, unsigned char  Length);
void OLED_ShowSignedNum(unsigned char  Line, unsigned char  Column, signed int  Number, unsigned char  Length);
void OLED_ShowHexNum(unsigned char  Line, unsigned char  Column, unsigned int  Number, unsigned char  Length);
void OLED_ShowBinNum(unsigned char  Line, unsigned char  Column, unsigned int  Number, unsigned char  Length);
void OLED_ShowCN(unsigned char x,unsigned char y,unsigned char N);
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char S);
void OLED_DrawBMP1(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char S);#endif

字库文件太长了,不方便分享需要的话可以评论区私信我。

4. 完整的工程代码

这是本次的完整的工程代码文件,有需要的自取;

链接:https://pan.baidu.com/s/1jGXHAkab3jjR_Rd2WsBPcg?pwd=h8d5 
提取码:h8d5

第一次发文如果有不当的地方,欢迎指正。

码字不易,点个赞吧 =.=

ESP8266+STM32获取网络时间、OLED显示时间图片视频。相关推荐

  1. ESP8266读取网络时间TM1637显示时间

    ESP8266读取网络时间TM1637显示时间 // change next line to use with another board/shield #include <ESP8266WiF ...

  2. STM32中断中调用OLED显示出现OLED花屏

    STM32中断中调用OLED显示出现OLED花屏 在TIM5中断处理函数中,我写了OLED显示,经过DEBUG发现程序执行到OLED显示语句的时候,OLED就会花屏. //中断服务处理函数 void ...

  3. 基于STM32和ATH20实现OLED显示温湿度

    基于STM32和ATH20实现OLED显示温湿度 什么是OLED 一.主要代码 二. 硬件连接及结果 1.硬件连接 2.烧录显示 总结 参考文献 什么是OLED 有机电致发光器件(OLED)属于低电压 ...

  4. 0.96寸OLED显示汉字图片及简单GIF

    0.96寸OLED显示汉字图片及简单GIF 只是做一些简单显示,具体逻辑大家自行添加. 网上的OLED驱动很多,我懂的也不是很深,这里就不说了,我这里用的是中景园的驱动.这里重点说怎么改可以显示这些东 ...

  5. stm32 + ESP8266 wifi获取网络时间和天气 stm32天气预报

    大家遇到什么什么题,可以私聊我. 近期由于某些原因,玩了一下stm32+WiFi获取网络天气和网络时间.之前一直觉得这个东西会有点难度,其实,做完了才发现,其实那只是想象中的难而已.现在,将这几天的成 ...

  6. 基于ESP32的智能台灯-PWM网页调光-实时时间-OLED显示-语音闹钟-WEB远程操控

    具体的项目,我免费分享在我的项目里,供大家参考学习: chenyuhan1997/ESP32-SMART-WIFI-PWM-LED-ALARM-CLOCK: Desk lamp with PWM ad ...

  7. 基于STM32移植U8g2图形库——OLED显示(HAL库)

    前言:本文主要内容为将优秀的图形库U8g2移植到STM32单片机上,用于OLED显示精美UI.其实,目前GitHub上有需要优秀的开源GUI库,但是大部分的GUI解决方案并不适合0.96 OLED(1 ...

  8. Linux如何在任务栏显示时间,在MFC[转载]在MFC状态栏显示时间 状态栏显示时间

    c/c++ vc 在mfc状态栏显示时间,在VC的控件中有个Status bar可以在窗体状态栏中添加日期和时间.其实通过简单的代码,你就能创建一个有时钟显示的状态栏,并且还能设置时钟栏的显示方式.举 ...

  9. 基于stm32硬件IIC的oled显示

    一 stm32硬件IIC 硬件IIC特性架构 ①通讯引脚 查看对应开发板芯片的原理图可以查看对应IIC外设引脚的位置 这里代码采用的是stm32f103c8t6,硬件IIC的外设引脚为PB6 PB7, ...

最新文章

  1. mybatis对mapper.xml的解析(三)
  2. 25个Java机器学习工具库
  3. C语言简单题-找最大的字符串
  4. 谈谈如何利用 valgrind 排查内存错误
  5. android实现博客app,如何从零实现一个你的个人博客Android App?
  6. (八)cmockery中的calculator和run_tests函数的注释代码
  7. 面试突击第 3 期 | Redis 如何实现查询附近的人?视频实战版
  8. 服务器 linux mysql5.7修改密码,navicat远程登录不了
  9. 【D3.V3.js系列教程】--(十五)SVG基本图形绘制
  10. python创建对象_python对象
  11. ArcPy常用函数梳理
  12. CAD如何求曲线的交点?
  13. 常用的Unicode码表(汉字从A到Z、数字、英文)
  14. 香港流行乐黄金二十年——经典歌手(音乐人)全面回顾 二
  15. Ubuntu 编译XCB源码
  16. OpenHarmony LiteOS C-SKY指令集移植指北
  17. 组合投资的风险与收益概述
  18. 工作11年后一切归零
  19. APP测试的主要内容
  20. 运用KDJ交叉形态把握短期买卖点

热门文章

  1. 洛谷P1049: 装箱问题
  2. Linux音频驱动之一:音频驱动注册流程
  3. hbase本周知识点——邓慧斐
  4. vue报错:Error: [vuex] Do not mutate vuex store state outside mutation handlers.
  5. 20200110-01 RTC_RD_TIME: Invalid argument 实时时钟 NXP pcf 8563 hwclock 回复 解决办法
  6. 为什么数据库可以查询到值,java代码里面返回为null值
  7. C++中虚析构函数和纯虚析构函数
  8. 必须重视BCHC BitCherry分布式区电商新时代正在到来
  9. PDF文件添加水印怎么添加?只需要两步轻松添加水印
  10. js 鼠标事件总结 mouseover/mouseout 与mouseenter/mouseleave 傻傻分不清楚?