[文章]

【HarmonyOS HiSpark Wi-Fi IoT 套件试用连载】八:天气显示

2021-1-5 23:15:18  330 鸿蒙系统 HarmonyOS HiSpark WiFi IoT
分享
2
上一次帖子,已经通过网络获取天气数据,但是还没显示到显示屏上。今天的帖子我写的是关于如何取模天气图片,并显示天气图标和天气数据。
一、ssd1306显存填充
显示板使用的OLED驱动芯片为SSD1306,我们来看看这款芯片的显存和该显存填充方式。下面是从SSD1303芯片手册上的截图,可以看得出它的显存是大小为128*64bit的RAM,并且分成为8页,PAGE0-PAGE7。显示板像素点大小为128*64,所以一个像素点对应RAM中的1bit。

GDDRAM.JPG
往RAM的某一位写入1或者0,该位对应的像素点就显示亮点或者不显示。但是它是按照什么顺序写入数据的。下面也是从芯片手册上的截图。
填充.JPG
可以看得出RAM填充顺序了 ,写入一个字节数据时,最低位数据写入一页中最上面那行,最高位写入一页中最下面那行。这样,使用取模软件取模图片或者字符时,我们才能知道按照什么顺序取模。之后再写相应代码,按照顺序把取模数据写入RAM中。

二、天气图标取模
首先当然是先在网络下载我们需要的天气图标,大小看你像显示多大区域的图标,我的是48*48大小图标,在OLED上显示大小也是48*48。
天气图标.JPG

我使用的是下面这款取模软件,我觉得图标取模不太好,不知道大家有没有推荐的。需要根据SSD1306进行取模软件的设置。比较重要的是取模方式的选择,这是跟SSD1306显示填充顺序对应的,我们需要选择列行式。其他数据点阵选择48,自定义格式选择C51。
设置.JPG

选择晴图标,生成如下数组。

取模.JPG
上面的小花就是太阳图标,是有点丑,先凑合用吧。

二、软件设计
1、显示天气图标
我们已经按照SSD1306显存填充顺序,取模好图片数据,接下来按照顺序把数据写入RAM就行了,代码如下。
  1. typedef enum
  2. {
  3.     QINGLOGO =0,
  4.     YINGLOGO,
  5.     DUOYULOGO,
  6.     YULOGO,
  7.     LEIYULOGO,
  8.     XUELOGO,
  9. }WEATHER_TYPE;
  10. void OLED_ShowWeather(uint8_t x,uint8_t y,WEATHER_TYPE type)
  11. {
  12.     unsigned char (*temp)[48];
  13.     //if(type ==qinglogo )
  14.         //temp=Qing48;
  15.     switch(type)
  16.         {
  17.             case    QINGLOGO:   temp=Qing48;break;
  18.             case    YINGLOGO:   temp=Yin48;break;
  19.             case    YULOGO:     temp=Yu48;break;
  20.             case    LEIYULOGO:  temp=LeiYu48;break;
  21.             case    DUOYULOGO:  temp=DuoYun48;break;
  22.             case    XUELOGO:    temp=Xue48;break;
  23.             default :
  24.              temp=Qing48;
  25.             break;
  26.     }
  27.     //OledSetPosition(x,y);
  28.     for(uint8_t i=0;i<6;i++){
  29.         OledSetPosition(x,y+i);
  30.         for(uint8_t j = 0;j<48;j++){
  31.             WriteData(temp[i][j]);
  32.         }
  33.     }
  34. }
复制代码
2、按键任务
OLED显示板上的两个按键,主要用于界面切换、获取实时时间、天气数据。增加了按键任务,主要进行这两个按键的处理。右边按键,按下后可以切换界面,现在设置有四个界面。在时间显示界面按下左键,会获取实时时间。在天气显示界面,按下左键会获取实时天气。
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdbool.h>
  4. #include "ohos_init.h"
  5. #include "cmsis_os2.h"
  6. #include "wifiiot_gpio.h"
  7. #include "wifiiot_gpio_ex.h"
  8. #include "wifiiot_pwm.h"
  9. #include "wifiiot_adc.h"

  10. #include "oled_ssd1306.h"

  11. #define analog_KEY_CHAN_NAME WIFI_IOT_ADC_CHANNEL_2

  12. typedef enum{
  13.     TIMESCREEN=0,
  14.     NOWSCREEN,
  15.     TOSCREEN,
  16.     ATOSCREEN,
  17. } SCREEN_STATUS;
  18. extern SCREEN_STATUS Now_Screen ;
  19. extern SCREEN_STATUS Last_Screen ;

  20. typedef enum{
  21.     GET_NORMAL =0 ,
  22.     GET_PROPRESS,
  23.     GET_SUC,
  24.     GET_FAIL,
  25. }GET_STATUS;

  26. GET_STATUS Get_Status = GET_NORMAL;
  27. GET_STATUS Last_Get_Status = GET_NORMAL;

  28. extern void getNtpTime(void);
  29. extern bool getWeather(void);

  30. static float ConvertToVoltage(unsigned short data)
  31. {
  32.     return (float)data * 1.8 * 4 / 4096; /* adc code equals: voltage/4/1.8*4096  */
  33. }

  34. static void KeyTask(void *arg)
  35. {
  36.     (void)arg;
  37.     unsigned short data = 0;

  38.     GpioInit();
  39.     static bool keyflag = false;
  40.     while(1)
  41.     {
  42.         AdcRead(ANALOG_KEY_CHAN_NAME, &data, WIFI_IOT_ADC_EQU_MODEL_4, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0);
  43.         float voltage = ConvertToVoltage(data);

  44.         if((voltage>0.45 && voltage<0.65)&&(!keyflag))
  45.         {
  46.             keyflag = true;
  47.             //OledShowString(16,7,"Sync time...",1);
  48.             //getNtpTime();
  49.             //OledFillScreen(0);
  50.             switch (Now_Screen){
  51.                 case TIMESCREEN:
  52.                 //OledShowString(16,7,"Sync time...",1);
  53.                 Get_Status = GET_PROPRESS;
  54.                 getNtpTime();
  55.                 //OledFillScreen(0);
  56.                 Get_Status = GET_SUC;
  57.                 break;
  58.                 case NOWSCREEN:
  59.                     //OledShowString(0,7,"Get Weather...",1);
  60.                     Get_Status = GET_PROPRESS;
  61.                     if(getWeather())
  62.                     //OledFillScreen(0);
  63.                     Get_Status = GET_SUC;
  64.                     else
  65.                     {
  66.                     //OledShowString(0,7,"Get fail...",1);
  67.                     Get_Status = GET_FAIL;
  68.                     }
  69.                 break;
  70.                 case TOSCREEN:
  71.                     Get_Status = GET_PROPRESS;
  72.                     if(getWeather())
  73.                      Get_Status = GET_SUC;
  74.                     else
  75.                     {
  76.                     Get_Status = GET_FAIL;
  77.                     }
  78.                 break;
  79.                 case ATOSCREEN:
  80.                     Get_Status = GET_PROPRESS;
  81.                     if(getWeather())
  82.                     Get_Status = GET_SUC;
  83.                     else
  84.                     {
  85.                     Get_Status = GET_FAIL;
  86.                     }
  87.                 break;

  88.                 default:
  89.                 break;
  90.             }
  91.         }
  92.         else if((voltage>0.9 && voltage<1)&&(!keyflag))
  93.         {
  94.             keyflag = true;
  95.             Now_Screen ++;
  96.             if(Now_Screen > ATOSCREEN)
  97.             {
  98.                 Now_Screen = TIMESCREEN;
  99.             }
  100.         }

  101.         if((!(voltage>0.45 && voltage<0.65)) && (!(voltage>0.9 && voltage<1))) {
  102.              keyflag = false;
  103.         }

  104.         usleep(300000);
  105.     }
  106. }

  107. static void KeyTaskHandle(void)
  108. {
  109.     osThreadAttr_t attr;
  110.     attr.name = "KeyTask";
  111.     attr.attr_bits = 0U;
  112.     attr.cb_mem = NULL;
  113.     attr.cb_size = 0U;
  114.     attr.stack_mem = NULL;
  115.     attr.stack_size = 4096;
  116.     attr.priority = osPriorityNormal+2;

  117.     if (osThreadNew(KeyTask, NULL, &attr) == NULL) {
  118.         printf("[KeyTaskHandle] Falied to create KeyTask!\n");
  119.     }
  120. }
  121. APP_FEATURE_INIT(KeyTaskHandle);
复制代码
3、 OLED任务修改
修改oled_demo.c内容。增加页面切换,获取时间、天气数据情况提示,显示天气数据和天气图标。

  1. typedef enum{
  2.     TIMESCREEN=0,
  3.     NOWSCREEN,
  4.     TOSCREEN,
  5.     ATOSCREEN,
  6. } SCREEN_STATUS;
  7. SCREEN_STATUS Now_Screen = TIMESCREEN;
  8. SCREEN_STATUS Last_Screen = TIMESCREEN;

  9. typedef enum{
  10.     GET_NORMAL =0 ,
  11.     GET_PROPRESS,
  12.     GET_SUC,
  13.     GET_FAIL,
  14. }GET_STATUS;
  15. extern GET_STATUS Get_Status ;
  16. extern GET_STATUS Last_Get_Status ;

  17. static uint8_t i=0;   

  18. static void TimeScreenDisp(void)
  19. {
  20. //OledShow
  21.         rtc_time_t mData;
  22.         OLED_ShowCHinese(0,3,0);//温
  23.         OLED_ShowCHinese(16,3,2);//度
  24.         OledShowChar(32,3,':',2);
  25.         sprintf((char *)TimeStr,"%02d",
  26.         (uint32_t)temperature);
  27.         OledShowString(40,3,(char *)TimeStr,2);
  28.         OLED_ShowCHinese(64,3,1);//湿
  29.         OLED_ShowCHinese(80,3,2);//度
  30.         OledShowChar(96,3,':',2);
  31.         sprintf((char *)TimeStr,"%02d",
  32.         (uint32_t)humidity);
  33.         OledShowString(104,3,(char *)TimeStr,2);
  34.         covUnixTimeStp2Beijing(timedata, &mData);
  35.         sprintf((char *)TimeStr,"%04d-%02d-%02d",
  36.         mData.ui8Year, mData.ui8Month, mData.ui8DayOfMonth);
  37.         OledShowString(24,0,(char *)TimeStr,1);
  38.         sprintf((char *)TimeStr,"%02d:%02d:%02d",
  39.         mData.ui8Hour,mData.ui8Minute,mData.ui8Second);
  40.         OledShowString(32,1,(char *)TimeStr,1);

  41.         if(Get_Status != Last_Get_Status)
  42.         {
  43.             Last_Get_Status = Get_Status;
  44.             switch ( Get_Status)
  45.             {
  46.             case GET_NORMAL:
  47.                 break;
  48.             case GET_PROPRESS:
  49.                 OledShowString(16,7,"Sync time...",1);
  50.                 break;
  51.             case GET_SUC:
  52.                 OledClearString(16,7,"Sync time...",1);
  53.                 OledShowString(16,7,"Sync Suc...",1);
  54.                 break;
  55.             case GET_FAIL:
  56.                 OledClearString(16,7,"Sync time...",1);
  57.                 OledShowString(16,7,"Sync fail...",1);
  58.                 break;
  59.             default:
  60.                 break;
  61.             }
  62.         }
  63. }

  64. static void DispWeather(uint8_t x, uint8_t y ,uint8_t code){
  65.         switch(code)
  66.         {
  67.             case 0:
  68.             case 1:
  69.             case 2:
  70.             case 3:
  71.                     OLED_ShowWeather(x,y,QINGLOGO);
  72.                     break;
  73.             case 4:
  74.             case 5:
  75.             case 6:
  76.             case 7:
  77.             case 8:
  78.                 OLED_ShowWeather(x,y,DUOYULOGO);
  79.                 break;
  80.             case 9:
  81.                
  82.             case 10:
  83.                 OLED_ShowWeather(x,y,YINGLOGO);
  84.                 break;
  85.             case 11:
  86.             case 12:

  87.                 OLED_ShowWeather(x,y,LEIYULOGO);
  88.                 break;
  89.             case 13:
  90.             case 14:
  91.             case 15:
  92.             case 16:
  93.             case 17:
  94.             case 18:
  95.             case 19:
  96.                 OLED_ShowWeather(x,y,YULOGO);
  97.                 break;
  98.             case 20:
  99.             case 21:
  100.             case 22:
  101.             case 23:
  102.             case 24:
  103.             case 25:
  104.                 OLED_ShowWeather(x,y,XUELOGO);
  105.                 break;
  106.             case 30:
  107.                 //OLED_ShowWeather(x,y,YULOGO);
  108.                 //break;
  109.             default:
  110.                 OLED_ShowWeather(x,y,QINGLOGO);
  111.             break;
  112.         }

  113. }

  114. extern weather weatherValue;
  115. static void  WeatherDisp(SCREEN_STATUS Screen){
  116.     switch (Screen)
  117.     {
  118.         case NOWSCREEN:
  119.             DispWeather(5, 1 ,weatherValue.nowcode);
  120.             OLED_ShowCHinese(56,0,9);//今
  121.             OLED_ShowCHinese(72,0,12);//天
  122.             sprintf((char *)DispStr,"%02d",
  123.             (uint32_t)weatherValue.nowtemp);
  124.             OledShowString(60,5,(char *)DispStr,2);
  125.             OLED_ShowCHinese(76,5,13);//天
  126.             sprintf((char *)DispStr,"%02d/%02d",
  127.             (uint32_t)weatherValue.low[Screen-1],(uint32_t)weatherValue.high[Screen-1]);
  128.             OledShowString(60,3,(char *)DispStr,2);
  129.             sprintf((char *)DispStr,"%d%%",
  130.             (uint32_t)weatherValue.humi[Screen-1]);
  131.             OledShowString(100,5,(char *)DispStr,2);
  132.             break;
  133.         case TOSCREEN:
  134.             DispWeather(5, 1 ,weatherValue.code[Screen-1]);
  135.             OLED_ShowCHinese(56,0,10);//明
  136.             OLED_ShowCHinese(72,0,12);//天
  137.             sprintf((char *)DispStr,"%02d/%02d",
  138.             (uint32_t)weatherValue.low[Screen-1],(uint32_t)weatherValue.high[Screen-1]);
  139.             OledShowString(60,3,(char *)DispStr,2);
  140.             sprintf((char *)DispStr,"%d%%",
  141.             (uint32_t)weatherValue.humi[Screen-1]);
  142.             OledShowString(70,5,(char *)DispStr,2);
  143.             break;
  144.         case ATOSCREEN:
  145.             DispWeather(5, 1 ,weatherValue.code[Screen-1]);
  146.             OLED_ShowCHinese(56,0,11);//后
  147.             OLED_ShowCHinese(72,0,12);//天
  148.             sprintf((char *)DispStr,"%02d/%02d",
  149.             (uint32_t)weatherValue.low[Screen-1],(uint32_t)weatherValue.high[Screen-1]);
  150.             OledShowString(60,3,(char *)DispStr,2);
  151.             sprintf((char *)DispStr,"%d%%",
  152.             (uint32_t)weatherValue.humi[Screen-1]);
  153.             OledShowString(70,5,(char *)DispStr,2);
  154.             break;
  155.         default:
  156.         break;   
  157.     }
  158.     if(Get_Status != Last_Get_Status)
  159.         {
  160.             Last_Get_Status = Get_Status;
  161.             switch ( Get_Status)
  162.             {
  163.             case GET_NORMAL:
  164.                 break;
  165.             case GET_PROPRESS:
  166.                 OledShowString(0,7,"Get Weather...",1);
  167.                 break;
  168.             case GET_SUC:
  169.                 OledClearString(0,7,"Get Weather...",1);
  170.                 OledShowString(0,7,"Get Suc...",1);
  171.                 i=0;
  172.                 break;
  173.             case GET_FAIL:
  174.                 OledClearString(0,7,"Get Weather...",1);
  175.                 OledShowString(0,7,"Get fail...",1);
  176.                 i=0;
  177.                 break;
  178.             default:
  179.                 break;
  180.             }
  181.         }
  182. }
  183. static void OledTask(void *arg)
  184. {
  185.     (void)arg;
  186.     GpioInit();
  187.     OledInit();
  188.     OledFillScreen(0x00);

  189.     while (1) {
  190.         if(Now_Screen != Last_Screen)
  191.         {
  192.             Last_Screen = Now_Screen;
  193.             OledFillScreen(0);
  194.             Get_Status = GET_NORMAL;
  195.             Last_Get_Status = GET_NORMAL;
  196.             i=0;
  197.         }

  198.         if((Get_Status == GET_FAIL) ||(Get_Status == GET_SUC))
  199.         {
  200.             i++;
  201.             if(i > 20)
  202.             {
  203.                 Get_Status = GET_NORMAL;
  204.                 i=0;

  205.                 switch(Now_Screen){
  206.                     case TIMESCREEN:
  207.                         OledClearString(16,7,"Sync time...",1);
  208.                         break;
  209.                     case NOWSCREEN:
  210.                         
  211.                     case TOSCREEN:

  212.                     case ATOSCREEN:
  213.                         printf("clear oled i = %d\n",i);
  214.                         OledClearString(0,7,"Get Weather...",1);
  215.                         break;
  216.                     default :
  217.                     break;

  218.                 }        
  219.             }
  220.         }

  221.         switch (Now_Screen){

  222.             case TIMESCREEN:
  223.             TimeScreenDisp();
  224.             break;

  225.             case NOWSCREEN:
  226.             WeatherDisp(NOWSCREEN);
  227.             break;

  228.             case TOSCREEN:
  229.             WeatherDisp(TOSCREEN);
  230.             break;

  231.             case ATOSCREEN:
  232.             WeatherDisp(ATOSCREEN);
  233.             break;

  234.             default:
  235.             break;   
  236.         }      
  237.          usleep(100000);
  238.     }
  239. }


复制代码
4、加入rtc.c
现在时间调整是通过每一秒时间戳加1,再把时间戳转化为北京时间,到达时间的更新。为了减少任务中因为其他函数存在,增加时间误差,所以单独创建一个任务来进行时间戳的调整。
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdbool.h>

  4. #include "ohos_init.h"
  5. #include "cmsis_os2.h"
  6. uint32_t timedata=1608362368;

  7. static void RtcTask(void *arg)
  8. {
  9.     (void)arg;
  10.     while(1)
  11.     {
  12.         timedata++;
  13.         sleep(1);
  14.     }
  15. }

  16. static void RtcTaskHandle(void)
  17. {
  18.     osThreadAttr_t attr;
  19.     attr.name = "RtcTask";
  20.     attr.attr_bits = 0U;
  21.     attr.cb_mem = NULL;
  22.     attr.cb_size = 0U;
  23.     attr.stack_mem = NULL;
  24.     attr.stack_size = 512;
  25.     attr.priority = osPriorityNormal;

  26.     if (osThreadNew(RtcTask, NULL, &attr) == NULL) {
  27.         printf("[RtcTaskHandle] Falied to create KeyTask!\n");
  28.     }
  29. }
  30. APP_FEATURE_INIT(RtcTaskHandle);
复制代码


5、修改BUILD.gn
修改OLED文件夹下的BUILD.gn文件,sources中加入keytask.c
  1.     sources = [
  2.         "oled_demo.c",
  3.         "oled_ssd1306.c",
  4.         "timeconv.c",
  5.         "envrionment_demo.c",
  6.         "aht20.c",
  7.         "wifi_connecter.c",
  8.         "getNTP.c",
  9.         "getweather.c",
  10.         "cjsonparse.c",
  11.         "keytask.c",
  12.         "rtc.c"
  13.     ]
复制代码
三、结果演示
按下右边按键,可以切换界面,有四个界面,分别为时间显示界面,今天、明天、后天天气显示界面。在时间显示界面按下左键,会获取实时时间,在天气显示界面,按下左键会获取实时天气,并且显示天气获取情况提示。
微信图片_20210105231135.jpg 微信图片_202101052311351.jpg 微信图片_202101052311352.jpg 微信图片_202101052311353.jpg 微信图片_202101052311354.jpg
四、总结
这一篇先写到这里,下一篇是关于通过一个公网的中转服务器,进行wifiiot和手机之间的远程数据传输

李元江 2021-1-5 23:16:53
演示视频,不知道能不能显示出来
2回复

举报

评论

您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发文章