本文来源电子发烧友社区,作者:李元江, 帖子地址:https://bbs.elecfans.com/jishu_2026438_1_1.html
上一次帖子,已经通过网络获取天气数据,但是还没显示到显示屏上。今天的帖子我写的是关于如何取模天气图片,并显示天气图标和天气数据。
一、ssd1306显存填充
上一次帖子,已经通过网络获取天气数据,但是还没显示到显示屏上。今天的帖子我写的是关于如何取模天气图片,并显示天气图标和天气数据。
显示板使用的OLED驱动芯片为SSD1306,我们来看看这款芯片的显存和该显存填充方式。下面是从SSD1303芯片手册上的截图,可以看得出它的显存是大小为128*64bit的RAM,并且分成为8页,PAGE0-PAGE7。显示板像素点大小为128*64,所以一个像素点对应RAM中的1bit。
往RAM的某一位写入1或者0,该位对应的像素点就显示亮点或者不显示。但是它是按照什么顺序写入数据的。下面也是从芯片手册上的截图。
可以看得出RAM填充顺序了 ,写入一个字节数据时,最低位数据写入一页中最上面那行,最高位写入一页中最下面那行。这样,使用取模软件取模图片或者字符时,我们才能知道按照什么顺序取模。之后再写相应代码,按照顺序把取模数据写入RAM中。
二、天气图标取模
我使用的是下面这款取模软件,我觉得图标取模不太好,不知道大家有没有推荐的。需要根据SSD1306进行取模软件的设置。比较重要的是取模方式的选择,这是跟SSD1306显示填充顺序对应的,我们需要选择列行式。其他数据点阵选择48,自定义格式选择C51。
选择晴图标,生成如下数组。
上面的小花就是太阳图标,是有点丑,先凑合用吧。
二、软件设计
1、显示天气图标
我们已经按照SSD1306显存填充顺序,取模好图片数据,接下来按照顺序把数据写入RAM就行了,代码如下。
- typedef enum
- {
- QINGLOGO =0,
- YINGLOGO,
- DUOYULOGO,
- YULOGO,
- LEIYULOGO,
- XUELOGO,
- }WEATHER_TYPE;
- void OLED_ShowWeather(uint8_t x,uint8_t y,WEATHER_TYPE type)
- {
- unsigned char (*temp)[48];
- //if(type ==qinglogo )
- //temp=Qing48;
- switch(type)
- {
- case QINGLOGO: temp=Qing48;break;
- case YINGLOGO: temp=Yin48;break;
- case YULOGO: temp=Yu48;break;
- case LEIYULOGO:temp=LeiYu48;break;
- case DUOYULOGO:temp=DuoYun48;break;
- case XUELOGO: temp=Xue48;break;
- default :
- temp=Qing48;
- break;
- }
- //OledSetPosition(x,y);
- for(uint8_t i=0;i<6;i++){
- OledSetPosition(x,y+i);
- for(uint8_t j = 0;j<48;j++){
- WriteData(temp[i][j]);
- }
- }
- }
OLED显示板上的两个按键,主要用于界面切换、获取实时时间、天气数据。增加了按键任务,主要进行这两个按键的处理。右边按键,按下后可以切换界面,现在设置有四个界面。在时间显示界面按下左键,会获取实时时间。在天气显示界面,按下左键会获取实时天气。
- #include
- #include
- #include
- #include "ohos_init.h"
- #include "cmsis_os2.h"
- #include "wifiiot_gpio.h"
- #include "wifiiot_gpio_ex.h"
- #include "wifiiot_pwm.h"
- #include "wifiiot_adc.h"
-
- #include "oled_ssd1306.h"
-
- #defineanalog_KEY_CHAN_NAME WIFI_IOT_ADC_CHANNEL_2
-
- typedef enum{
- TIMESCREEN=0,
- NOWSCREEN,
- TOSCREEN,
- ATOSCREEN,
- } SCREEN_STATUS;
- extern SCREEN_STATUS Now_Screen ;
- extern SCREEN_STATUS Last_Screen ;
-
- typedef enum{
- GET_NORMAL =0 ,
- GET_PROPRESS,
- GET_SUC,
- GET_FAIL,
- }GET_STATUS;
-
- GET_STATUS Get_Status = GET_NORMAL;
- GET_STATUS Last_Get_Status = GET_NORMAL;
-
- extern void getNtpTime(void);
- extern bool getWeather(void);
-
- static float ConvertToVoltage(unsigned short data)
- {
- return (float)data * 1.8 * 4 / 4096; /* adc code equals: voltage/4/1.8*4096*/
- }
-
- static void KeyTask(void *arg)
- {
- (void)arg;
- unsigned short data = 0;
-
- GpioInit();
- static bool keyflag = false;
- while(1)
- {
- AdcRead(ANALOG_KEY_CHAN_NAME, &data, WIFI_IOT_ADC_EQU_MODEL_4, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0);
- float voltage = ConvertToVoltage(data);
-
- if((voltage>0.45 && voltage<0.65)&&(!keyflag))
- {
- keyflag = true;
- //OledShowString(16,7,"Sync time...",1);
- //getNtpTime();
- //OledFillScreen(0);
- switch (Now_Screen){
- case TIMESCREEN:
- //OledShowString(16,7,"Sync time...",1);
- Get_Status = GET_PROPRESS;
- getNtpTime();
- //OledFillScreen(0);
- Get_Status = GET_SUC;
- break;
- case NOWSCREEN:
- //OledShowString(0,7,"Get Weather...",1);
- Get_Status = GET_PROPRESS;
- if(getWeather())
- //OledFillScreen(0);
- Get_Status = GET_SUC;
- else
- {
- //OledShowString(0,7,"Get fail...",1);
- Get_Status = GET_FAIL;
- }
- break;
- case TOSCREEN:
- Get_Status = GET_PROPRESS;
- if(getWeather())
- Get_Status = GET_SUC;
- else
- {
- Get_Status = GET_FAIL;
- }
- break;
- case ATOSCREEN:
- Get_Status = GET_PROPRESS;
- if(getWeather())
- Get_Status = GET_SUC;
- else
- {
- Get_Status = GET_FAIL;
- }
- break;
-
- default:
- break;
- }
- }
- else if((voltage>0.9 && voltage<1)&&(!keyflag))
- {
- keyflag = true;
- Now_Screen ++;
- if(Now_Screen > ATOSCREEN)
- {
- Now_Screen = TIMESCREEN;
- }
- }
-
- if((!(voltage>0.45 && voltage<0.65)) && (!(voltage>0.9 && voltage<1))) {
- keyflag = false;
- }
-
- usleep(300000);
- }
- }
-
- static void KeyTaskHandle(void)
- {
- osThreadAttr_t attr;
- attr.name = "KeyTask";
- attr.attr_bits = 0U;
- attr.cb_mem = NULL;
- attr.cb_size = 0U;
- attr.stack_mem = NULL;
- attr.stack_size = 4096;
- attr.priority = osPriorityNormal+2;
-
- if (osThreadNew(KeyTask, NULL, &attr) == NULL) {
- printf("[KeyTaskHandle] Falied to create KeyTask!n");
- }
- }
- APP_FEATURE_INIT(KeyTaskHandle);
修改oled_demo.c内容。增加页面切换,获取时间、天气数据情况提示,显示天气数据和天气图标。
- typedef enum{
- TIMESCREEN=0,
- NOWSCREEN,
- TOSCREEN,
- ATOSCREEN,
- } SCREEN_STATUS;
- SCREEN_STATUS Now_Screen = TIMESCREEN;
- SCREEN_STATUS Last_Screen = TIMESCREEN;
-
- typedef enum{
- GET_NORMAL =0 ,
- GET_PROPRESS,
- GET_SUC,
- GET_FAIL,
- }GET_STATUS;
- extern GET_STATUS Get_Status ;
- extern GET_STATUS Last_Get_Status ;
-
- static uint8_t i=0;
-
- static void TimeScreenDisp(void)
- {
- //OledShow
- rtc_time_t mData;
- OLED_ShowCHinese(0,3,0);//温
- OLED_ShowCHinese(16,3,2);//度
- OledShowChar(32,3,':',2);
- sprintf((char *)TimeStr,"%02d",
- (uint32_t)temperature);
- OledShowString(40,3,(char *)TimeStr,2);
- OLED_ShowCHinese(64,3,1);//湿
- OLED_ShowCHinese(80,3,2);//度
- OledShowChar(96,3,':',2);
- sprintf((char *)TimeStr,"%02d",
- (uint32_t)humidity);
- OledShowString(104,3,(char *)TimeStr,2);
- covUnixTimeStp2Beijing(timedata, &mData);
- sprintf((char *)TimeStr,"%04d-%02d-%02d",
- mData.ui8Year, mData.ui8Month, mData.ui8DayOfMonth);
- OledShowString(24,0,(char *)TimeStr,1);
- sprintf((char *)TimeStr,"%02d:%02d:%02d",
- mData.ui8Hour,mData.ui8Minute,mData.ui8Second);
- OledShowString(32,1,(char *)TimeStr,1);
-
- if(Get_Status != Last_Get_Status)
- {
- Last_Get_Status = Get_Status;
- switch ( Get_Status)
- {
- case GET_NORMAL:
- break;
- case GET_PROPRESS:
- OledShowString(16,7,"Sync time...",1);
- break;
- case GET_SUC:
- OledClearString(16,7,"Sync time...",1);
- OledShowString(16,7,"Sync Suc...",1);
- break;
- case GET_FAIL:
- OledClearString(16,7,"Sync time...",1);
- OledShowString(16,7,"Sync fail...",1);
- break;
- default:
- break;
- }
- }
- }
-
- static void DispWeather(uint8_t x, uint8_t y ,uint8_t code){
- switch(code)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- OLED_ShowWeather(x,y,QINGLOGO);
- break;
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- OLED_ShowWeather(x,y,DUOYULOGO);
- break;
- case 9:
- case 10:
- OLED_ShowWeather(x,y,YINGLOGO);
- break;
- case 11:
- case 12:
-
- OLED_ShowWeather(x,y,LEIYULOGO);
- break;
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- case 18:
- case 19:
- OLED_ShowWeather(x,y,YULOGO);
- break;
- case 20:
- case 21:
- case 22:
- case 23:
- case 24:
- case 25:
- OLED_ShowWeather(x,y,XUELOGO);
- break;
- case 30:
- //OLED_ShowWeather(x,y,YULOGO);
- //break;
- default:
- OLED_ShowWeather(x,y,QINGLOGO);
- break;
- }
-
- }
-
- extern weather weatherValue;
- static voidWeatherDisp(SCREEN_STATUS Screen){
- switch (Screen)
- {
- case NOWSCREEN:
- DispWeather(5, 1 ,weatherValue.nowcode);
- OLED_ShowCHinese(56,0,9);//今
- OLED_ShowCHinese(72,0,12);//天
- sprintf((char *)DispStr,"%02d",
- (uint32_t)weatherValue.nowtemp);
- OledShowString(60,5,(char *)DispStr,2);
- OLED_ShowCHinese(76,5,13);//天
- sprintf((char *)DispStr,"%02d/%02d",
- (uint32_t)weatherValue.low[Screen-1],(uint32_t)weatherValue.high[Screen-1]);
- OledShowString(60,3,(char *)DispStr,2);
- sprintf((char *)DispStr,"%d%%",
- (uint32_t)weatherValue.humi[Screen-1]);
- OledShowString(100,5,(char *)DispStr,2);
- break;
- case TOSCREEN:
- DispWeather(5, 1 ,weatherValue.code[Screen-1]);
- OLED_ShowCHinese(56,0,10);//明
- OLED_ShowCHinese(72,0,12);//天
- sprintf((char *)DispStr,"%02d/%02d",
- (uint32_t)weatherValue.low[Screen-1],(uint32_t)weatherValue.high[Screen-1]);
- OledShowString(60,3,(char *)DispStr,2);
- sprintf((char *)DispStr,"%d%%",
- (uint32_t)weatherValue.humi[Screen-1]);
- OledShowString(70,5,(char *)DispStr,2);
- break;
- case ATOSCREEN:
- DispWeather(5, 1 ,weatherValue.code[Screen-1]);
- OLED_ShowCHinese(56,0,11);//后
- OLED_ShowCHinese(72,0,12);//天
- sprintf((char *)DispStr,"%02d/%02d",
- (uint32_t)weatherValue.low[Screen-1],(uint32_t)weatherValue.high[Screen-1]);
- OledShowString(60,3,(char *)DispStr,2);
- sprintf((char *)DispStr,"%d%%",
- (uint32_t)weatherValue.humi[Screen-1]);
- OledShowString(70,5,(char *)DispStr,2);
- break;
- default:
- break;
- }
- if(Get_Status != Last_Get_Status)
- {
- Last_Get_Status = Get_Status;
- switch ( Get_Status)
- {
- case GET_NORMAL:
- break;
- case GET_PROPRESS:
- OledShowString(0,7,"Get Weather...",1);
- break;
- case GET_SUC:
- OledClearString(0,7,"Get Weather...",1);
- OledShowString(0,7,"Get Suc...",1);
- i=0;
- break;
- case GET_FAIL:
- OledClearString(0,7,"Get Weather...",1);
- OledShowString(0,7,"Get fail...",1);
- i=0;
- break;
- default:
- break;
- }
- }
- }
- static void OledTask(void *arg)
- {
- (void)arg;
- GpioInit();
- OledInit();
- OledFillScreen(0x00);
- while (1) {
- if(Now_Screen != Last_Screen)
- {
- Last_Screen = Now_Screen;
- OledFillScreen(0);
- Get_Status = GET_NORMAL;
- Last_Get_Status = GET_NORMAL;
- i=0;
- }
-
- if((Get_Status == GET_FAIL) ||(Get_Status == GET_SUC))
- {
- i++;
- if(i > 20)
- {
- Get_Status = GET_NORMAL;
- i=0;
-
- switch(Now_Screen){
- case TIMESCREEN:
- OledClearString(16,7,"Sync time...",1);
- break;
- case NOWSCREEN:
- case TOSCREEN:
-
- case ATOSCREEN:
- printf("clear oled i = %dn",i);
- OledClearString(0,7,"Get Weather...",1);
- break;
- default :
- break;
-
- }
- }
- }
-
- switch (Now_Screen){
-
- case TIMESCREEN:
- TimeScreenDisp();
- break;
-
- case NOWSCREEN:
- WeatherDisp(NOWSCREEN);
- break;
-
- case TOSCREEN:
- WeatherDisp(TOSCREEN);
- break;
-
- case ATOSCREEN:
- WeatherDisp(ATOSCREEN);
- break;
-
- default:
- break;
- }
- usleep(100000);
- }
- }
现在时间调整是通过每一秒时间戳加1,再把时间戳转化为北京时间,到达时间的更新。为了减少任务中因为其他函数存在,增加时间误差,所以单独创建一个任务来进行时间戳的调整。
- #include
- #include
- #include
-
- #include "ohos_init.h"
- #include "cmsis_os2.h"
- uint32_t timedata=1608362368;
-
- static void RtcTask(void *arg)
- {
- (void)arg;
- while(1)
- {
- timedata++;
- sleep(1);
- }
- }
-
- static void RtcTaskHandle(void)
- {
- osThreadAttr_t attr;
- attr.name = "RtcTask";
- attr.attr_bits = 0U;
- attr.cb_mem = NULL;
- attr.cb_size = 0U;
- attr.stack_mem = NULL;
- attr.stack_size = 512;
- attr.priority = osPriorityNormal;
-
- if (osThreadNew(RtcTask, NULL, &attr) == NULL) {
- printf("[RtcTaskHandle] Falied to create KeyTask!n");
- }
- }
- APP_FEATURE_INIT(RtcTaskHandle);
5、修改BUILD.gn
修改OLED文件夹下的BUILD.gn文件,sources中加入keytask.c
按下右边按键,可以切换界面,有四个界面,分别为时间显示界面,今天、明天、后天天气显示界面。在时间显示界面按下左键,会获取实时时间,在天气显示界面,按下左键会获取实时天气,并且显示天气获取情况提示。
四、总结
这一篇先写到这里,下一篇是关于通过一个公网的中转服务器,进行wifiiot和手机之间的远程数据传输。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
wi-fi
+关注
关注
14文章
2113浏览量
124333 -
HarmonyOS
+关注
关注
79文章
1967浏览量
30027 -
HiSpark
+关注
关注
1文章
156浏览量
6904
发布评论请先 登录
相关推荐
Wi-Fi 8要来了!未来Wi-Fi技术演进方向揭秘
产品销售中,虽然Wi-Fi 7产品的销量份额快速从年初的个位数百分比增长至14%,但Wi-Fi 6产品的销量份额依然稳定在60%左右。如果从存量设备来看,那么Wi-Fi 7路由器的占比将远远小于这个数。 智能手机等终端设备已
Wi-Fi 7与Wi-Fi 6E有什么区别
也许很多人还在考虑是否要将使用的Wi-Fi设备升级到Wi-Fi 6或Wi-Fi 6E,而这些标准的继任者却已经开始“登堂入室”了。Wi-Fi 7是新一代
IR900 Wi-Fi联网的配置过程
, 通过SSID扫描可以查看;输入密码,点击保存;
在SSID扫描页面中查看是否连接成功, 如果没有请检查认证方式、加密方式、密码是否输入正确;
Wi-Fi扫描显示“已连接”,进入“快速向导-新建WAN
发表于 07-25 06:09
未来的Wi-Fi路由器
转载自——钟林谈芯 没有创新就没有未来,Wi-Fi路由器也是如此。 进入2024年以后,Wi-Fi路由器市场变得更加艰难,利润大幅下滑,BOM成本价高于市场价,接不接订单,都陷入两难。 国内主芯片
DA16200 超低功耗 Wi-Fi 模块开发套件 Pro数据手册
电子发烧友网站提供《DA16200 超低功耗 Wi-Fi 模块开发套件 Pro数据手册.rar》资料免费下载
发表于 05-30 17:53
•1次下载
DA16200 超低功耗 Wi-Fi 模块开发套件数据手册
电子发烧友网站提供《DA16200 超低功耗 Wi-Fi 模块开发套件数据手册.rar》资料免费下载
发表于 05-30 17:13
•0次下载
验证物联网Wi-Fi HaLow用例的MM6108-EKH08开发套件来啦
验证物联网Wi-Fi HaLow用例的MM6108-EKH08开发套件来啦 MM6108-EKH08开发套件专为验证物联网Wi-Fi HaLow用例而设计。该
Wi-Fi HaLow和传统Wi-Fi的区别
Wi-Fi HaLow和传统Wi-Fi的区别 Wi-Fi是一种无线网络技术,可以连接到互联网或局域网,为用户提供无线上网的便利。随着科技的发展和互联网的普及,Wi-Fi也在不断演进和
康普携手Wi-Fi联盟,RUCKUS Wi-Fi 7系列接入点成Wi-Fi
康普高级副总裁兼网络、智能蜂窝和安全解决方案总裁Bart Giordano对此表示: “我们非常荣幸能与Wi-Fi Alliance形成长期合作伙伴关系,将我们的RUCKUS Wi-Fi 7 接入点平台作为Wi-Fi CERT
BT Wi-Fi模式是否可以通过ModustoolBox对套件进行编程来实现?
想配置用于分析 CYW43439 的 CY8CPROTO-062S2-43439 原型开发套件。
浏览文档我无法弄清楚如何在不同的 Wi-Fi 和蓝牙模式(电源模式、连接模式等)下配置套件。
在
发表于 01-22 06:19
Wi-Fi 6和Wi-Fi 5之间有哪些区别呢?
Wi-Fi 6和Wi-Fi 5之间有哪些区别呢? Wi-Fi 6和Wi-Fi 5是无线局域网标准的两个版本,它们之间存在很多区别。Wi-Fi
评论