描述
一、ssd1306显存填充
显示板使用的O
LED驱动
芯片为SSD1306,我们来看看这款芯片的显存和该显存填充方式。下面是从SSD1303芯片手册上的截图,可以看得出它的显存是大小为128
*64bit的RAM,并且分成为8页,PAGE0-PAGE7。显示板像素点大小为128*64,所以一个像素点对应RAM中的1bit。
往RAM的某一位写入1或者0,该位对应的像素点就显示亮点或者不显示。但是它是按照什么顺序写入数据的。下面也是从芯片手册上的截图。
可以看得出RAM填充顺序了 ,写入一个字节数据时,最低位数据写入一页中最上面那行,最高位写入一页中最下面那行。这样,使用取模软件取模图片或者字符时,我们才能知道按照什么顺序取模。之后再写相应代码,按照顺序把取模数据写入RAM中。
二、天气图标取模
首先当然是先在网络下载我们需要的天气图标,大小看你像显示多大区域的图标,我的是48*48大小图标,在OLED上显示大小也是48*48。
我使用的是下面这款取模软件,我觉得图标取模不太好,不知道大家有没有推荐的。需要根据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]);
-
}
-
}
-
}
复制代码
2、按键任务
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"
-
-
#define analog_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);
复制代码
3、 OLED任务修改
修改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 void WeatherDisp(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);
-
}
-
}
-
-
-
复制代码
4、加入rtc.c现在时间调整是通过每一秒时间戳加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
-
sources = [
-
"oled_demo.c",
-
"oled_ssd1306.c",
-
"timeconv.c",
-
"envrionment_demo.c",
-
"aht20.c",
-
"wifi_connecter.c",
-
"getNTP.c",
-
"getweather.c",
-
"cjsonparse.c",
-
"keytask.c",
-
"rtc.c"
-
]
复制代码
三、结果演示
按下右边按键,可以切换界面,有四个界面,分别为时间显示界面,今天、明天、后天天气显示界面。在时间显示界面按下左键,会获取实时时间,在天气显示界面,按下左键会获取实时天气,并且显示天气获取情况提示。
四、总结
这一篇先写到这里,下一篇是关于通过一个公网的中转服务器,进行wifiiot和
手机之间的远程数据
传输。
打开APP阅读更多精彩内容