ESP8266+STM32获取网络时间、OLED显示时间&图片&视频。

您所在的位置:网站首页 web显示时间 ESP8266+STM32获取网络时间、OLED显示时间&图片&视频。

ESP8266+STM32获取网络时间、OLED显示时间&图片&视频。

2024-06-09 10:21| 来源: 网络整理| 查看: 265

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

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

目录

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

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和烧录下载器正确连接,再与电脑连接

2dfdfbb1567b4f3d8d0f66976320e0c4.jpeg

烧录下载器和电脑

a85daf91437744a38c8f58d4e2a0d5c7.jpeg

ESP8266和烧录下载器

 

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

1b87385cb2d54c8083b1eddf1ec08ca6.png

初始界面

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

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发送对应的回答之后才可以继续点击,每一次点击的 效果如下。

234afc1e6a224d4ca1a70f6b25a4968c.png

第一条指令:

3103fd14ac35484c8b3fb3f9334ff732.png

第二条指令:

856f4c43245e4845b715afa65ce78270.png

第三条指令:

fc78e154d16743c28828b4a61ea046ed.png

第四条指令:

 

65f910f9da2b4a629a885800dbcde57d.png

第五条指令:

2fb3c0345fb64dcf8b825b47e7264ca0.png

第六条指令:

f5aad0845a22442ea98551b7825bca21.png

第八条指令:

99d0b64a810a4dd49314e9f90f2ac76c.png

第七条指令:

 

28b3c8df8dbd43cca5509e921e1aa7cc.png

第九条指令:

063fb794a3834416955db435fca89b03.png

第十条指令:

 

补充一下上面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; //取得ID id = *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");//原本是读取三天的,修改为读取现在的now if(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_GET ESP8266_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 23 int 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显示有自定义的编写字库的软件,编写图片字库的软件,

取字模的软件用的是:

a974b2bd25f445f98b92ef7e4eaa09f6.png

取字模

e0fec89b5c524718881e8181ff323792.png

分离抽帧

 

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

看看实物效果先:

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


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3