1@page homepage 首页信息屏
2# 实验介绍
3本章主要介绍首页信息屏的实现,作为第一页,首页信息实现了类手机的界面,其中包含了丰富的内容。
41)产品名称
52) 版本信息
63) 系统状态,系统时间,WIFI连接,蓝牙连接。
74) IP地址
8#### 显示效果
9界面显示效果如下:
10
11<div align=center>
12    <img src="https://img.alicdn.com/imgextra/i3/O1CN01MhNElU1M8fCNezy7v_!!6000000001390-2-tps-1200-800.png" style="zoom:50%;" />
13</div>
14
15
16
17本章包含的内容非常多,通过本章的学习,可以学到多个知识点,比如OLED的驱动显示,ADC获取电量信息,Wi-Fi连接状态获取等等。
18# 涉及知识点
19
20- ADC的配置以及使用
21- OLED的使用
22- Wi-Fi配网
23- 系统时钟获取(NTP网络对时)
24
25# 开发环境准备
26## 硬件
27    开发用电脑一台
28    HAAS EDU K1 开发板一块
29    USB2TypeC 数据线一根
30
31## 软件
32### AliOS Things开发环境搭建
33    开发环境的搭建请参考 @ref HaaS_EDU_K1_Quick_Start (搭建开发环境章节),其中详细的介绍了AliOS Things 3.3的IDE集成开发环境的搭建流程。
34
35### HaaS EDU K1 DEMO 代码下载
36    HaaS EDU K1 DEMO 的代码下载请参考 @ref HaaS_EDU_K1_Quick_Start (创建工程章节),其中,
37    选择解决方案: 基于教育开发板的示例
38    选择开发板: haaseduk1 board configure
39
40### 代码编译、烧录
41    参考 @ref HaaS_EDU_K1_Quick_Start (3.1 编译工程章节),点击 ✅ 即可完成编译固件。
42    参考 @ref HaaS_EDU_K1_Quick_Start (3.2 烧录镜像章节),点击 "⚡️" 即可完成烧录固件。
43
44
45# 各实验介绍
46## OLED开发与显示
47### OLED背景介绍
48OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display,OELD)。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
49LCD都需要背光,而OLED不需要,因为它是自发光的。这样同样的显示,OLED效果要来得好一些。以目前的技术,OLED的尺寸还难以大型化,但是分辨率确可以做到很高。
50### 硬件设计
51在本实验中,OLED作为一个小板固定在前面板上,中间通过排线与主板相连。
52本实验采用的OLED屏有以下特点:
531)模块为单色显示、黑底白字
542)显示尺寸为1.3寸
553)高分辨率,该模块的分辨率为132*64
564)硬件接口采用SPI总线接口
57
58
59板载OLED原理图:
60
61<div align=center>
62    <img src="https://img.alicdn.com/imgextra/i4/O1CN01gZptiv1Bun2rnrAxi_!!6000000000006-2-tps-1052-1162.png" style="zoom:50%;" />
63</div>
64 
65
66<div align=center>
67    <img src="https://img.alicdn.com/imgextra/i1/O1CN01fE0Xyc1IsgXFTHDm8_!!6000000000949-2-tps-594-388.png" style="zoom:50%;" />
68</div>
69
70
71### 软件设计
72关于OLED的详细原理介绍以及使用,请参考第三章OLED部分。这里主要介绍如何使用,从原理图的得知,OLED连接的主板的SPI0,采用的是4线SPI模式。
73#### 初始化
74首先初始化SPI0,这个可以在总入口函数中找到:
75solutions/eduk1_demo/app_start.c
76```c
77sh1106_init();
78```
79sh1106_init 初始化包含了SPI0的初始化以及GPIO初始化。
80```c
81uint8_t sh1106_init(void)
82{
83    uint8_t err_code;
84
85    err_code = hardware_init();
86    if (err_code != 0) {
87        return err_code;
88    }
89
90    command_list();
91
92    return err_code;
93}
94```
95#### 显示部分
96代码位于solutions/eduk1_demo/k1_apps/homepage/homepage.c
97以显示版本信息为例:
98```c
99OLED_Clear(); // 清屏函数
100OLED_Show_String(40, (12 + 4) * 1, "HaaS EDU", 12, 1); / 将字符串填入显示缓存
101snprintf(image_version, 21, "VER: %s", BUILD_VERSION); // 格式化字符串
102OLED_Show_String(33, (12 + 4) * 2, image_version, 12, 1); // 将格式化后的字符串-
103																													//版本信息填入缓存
104OLED_Refresh_GRAM(); // 刷新显存到屏幕上
105```
106
107
108## ADC操作与电量获取
109### 背景介绍
110ADC即模拟数字转换器(英语:Analog-to-digital converter)是用于将模拟形式的连续信号转换为数字形式的离散信号的一类设备。与之相对的设备成为数字模拟转换器(DAC)。
111典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。然而,有一些模拟数字转换器并非纯的电子设备,例如旋转编码器,也可以被视为模拟数字转换器。
112### 硬件设计
113原理图如下:
114
115<div align=center>
116    <img src="https://img.alicdn.com/imgextra/i4/O1CN01vwWwcp1qAtbVBGzet_!!6000000005456-2-tps-790-552.png" style="zoom:50%;" />
117</div>
118
119
120<div align=center>
121    <img src="https://img.alicdn.com/imgextra/i4/O1CN01RhdcEn1GyykObx9kd_!!6000000000692-2-tps-1866-570.png" style="zoom:50%;" />
122</div>
123 
124电压检测主要需要注意如下几点:
1251、电压检测使用的是MCU的GADC1通道。
1262、带USB供电时,检测点电压恒定为为4.8~5.2V之间,切换为电池供电时(断掉USB供电),电压浮动在3.65V~4.2V之间,此时电量标志才会有变化。
1273、因为GADC量程有限,电压检测采用分频,如原理图所示,ADC实测值约为VOLT的1/3,加上ADC内阻的损耗,实际比值为3.208。
128
129### 软件设计
130#### 驱动初始化
131在 AliOS Things 3.3中,对ADC的操作才用了VFS的方式,开发者只需要open相应的device设备,通过提供的到的IOCTL接口,完成start、get,stop等一系列动作。
132
133```c
134// open相应的adc设备
135snprintf(name, sizeof(name), "/dev/adc%d", index);
136fd = open(name, 0);
137// start adc 设备
138if (fd >= 0) {
139        ret = ioctl(fd, IOC_ADC_START, sampling_cycle);
140        usleep(1000);
141        adc_arg.value = 0;
142        adc_arg.timeout = 500000; // in unit of us
143}
144```
145
146#### 获取电压值
1471、读取十次,
1482、去掉最大最小值,然后取平均。
149```c
150    for (int32_t i = 0; i < 10; i++) {
151        ret = ioctl(fd, IOC_ADC_GET_VALUE, (unsigned long)&adc_arg);
152        test_sum += adc_arg.value;
153
154        /* the min sampling voltage */
155        if (test_min >= adc_arg.value) {
156            test_min = adc_arg.value;
157        }
158        /* the max sampling voltage */
159        if (test_max <= adc_arg.value) {
160            test_max = adc_arg.value;
161        }
162    }
163    usleep(1000);
164    ret = ioctl(fd, IOC_ADC_STOP, 0);
165    close(fd);
166
167    test_avrg = (test_sum - test_min - test_max) >> 3;
168    LOGD(EDU_TAG, "the samping volage is:%dmv\n", test_avrg);
169    test_avrg *= 3.208;
170    *volage = test_avrg;
171```
172#### 返回电量等级
173实际电压值为ADC*3.208,然后根据这个值返回不同的level,主要分为五档,分别是0%,25%,50
174%,75%,100%。
175```c
176
177    if (test_avrg > 4100)
178    {
179        *level = 4;
180    }
181    else if ((test_avrg > 3980) && (test_avrg < 4100))
182    {
183        *level = 3;
184    }
185    else if ((test_avrg > 3850) && (test_avrg < 3980))
186    {
187        *level = 2;
188    }
189    else if ((test_avrg > 3700) && (test_avrg < 3850))
190    {
191        *level = 1;
192    }
193    else if (test_avrg < 3700)
194    {
195        *level = 0;
196    }
197```
198看到代码很多人可能会有疑问,为什么4100毫伏到4200毫伏代表100%,4100毫伏到3980毫伏代表75%,并不是一个线性的值。其实原因很简单,锂电池的电池放电曲线不是一个线性的。
199
200
201#### 显示图标
202显示不同单色电池图标代码如下:
203```c
204if (0 == get_battery(&battery_level))
205{
206  //printf("get_battery success %d\n", battery_level);
207  OLED_Icon_Draw(110, 0, &icon_battery_20_12[battery_level], 0);
208}
209
210```
211
212
213## 系统Wi-Fi以及网络对时
214### 背景介绍
215
216#### Wi-Fi
217Wi-Fi这个名词想必大家都不陌生,就是联网的代名词。简单来说Wi-Fi(WirelessFidelity)是一种网络传输标准,与蓝牙技术一样,它同属于短距离无线技术。随着网络的应用普及,它给人们带来极大的方便,也因此得到了广泛应用,Wi-Fi让我们随时随地、的上网成为可能。
218经常在路由器的包装中看到802.11b/g/n 2.4Ghz这类字样,那么这个是什么来的?这个是无线网络通信的标准,IEEE 802.11是现今无线局域网通用的标准,它是由电气和电子工程师协会(IEEE)所定义的。后面的这些后缀是协议迭代的版本号。
219
220#### 2.4GHz频段
221
2221. 802.11b/g/n中桂东 Wi-Fi无线电可以在2.4 GHz频带中传输,共有14个可用信道,工作频率范围是2.402GHz - 2.483Ghz。中国可用13个信道(1-13)。每相邻的2个信道之间的频宽就是5Mhz。如果使用信道1,频宽为20Mhz,则信道2,3,4,5都被占用。
223
2242. 每个信道的带宽为22MHz,不过有效带宽只有20MHz,为了减少相邻信道的干扰,两侧预留1MHz的带宽边界。
2253. 只有三个频道(1、6和11)不共享频率空间。
226#### 5GHz频段
227
228
2291. 802.11a/n/ac中规定Wi-Fi无线电可以在5GHz频带中传输,共有25个可用信道。中心频率范围5.150GHz-5.850GMz,中国可以使用的信道有低信道36,40, 44, 48, 52, 56, 60, 64, 高信道149,153,157, 161, 165。信道之间没有重叠。
2301. 每个频宽为20MHz,如果使用信道149,当要用80Mhz时,则153,157,161都要被占用。
231
232
233
234#### 系统时钟获取(SNTP网络对时)
235在界面左上角显示的就是当前的系统时间,HaaS EDU K1本身没有带RTC芯片,所以不能自动保存时间。
236那么如何获取准确的时间呢?这里就需要用到SNTP协议,SNTP是基于NTP协议的。
237#### SNTP协议
238简单网络时间协议(Simple Network Time Protocol),由NTP改编而来,主要用来同步因特网中的计算机时钟。在 RFC2030 中定义。
239SNTP协议采用客户端/服务器的工作方式,可以采用单播(点对点)或者广播(一点对多点)模式操作。SNTP服务器通过接收GPS信号或自带的原子钟作为系统的时间基准。单播模式下,SNTP客户端能够通过定期访问SNTP服务器获得准确的时间信息,用于调整客户端自身所在系统的时间,达到同步时间的目的。广播模式下,SNTP服务器周期性地发送消息给指定的IP单播地址或者IP多播地址。SNTP客户端通过监听这些地址来获得时间信息。
240### 硬件设计
241本实验所用到的Wi-Fiy硬件模块已经包含在MCU之中,不需要额外提供。
242### 软件设计
243#### Wi-Fi模块
244AliOS Things中关于Wi-Fi部分也已经封装成了netmgr组件,eduk1_demo的package.yaml已经默认包含。
245```c
246depends:
247  - netmgr: dev_aos
248```
249代码位于solutions/eduk1_demo/app_start.c
250```c
251event_service_init(NULL);
252
253netmgr_service_init(NULL);
254event_subscribe(EVENT_NETMGR_DHCP_SUCCESS, wifi_event_cb, NULL);
255```
256event_service_init(NULL), event_service 初始化。
257netmgr_service_init netmgr服务初始化,主要包含CLI的注册,WIFi设备创建,相关信号量以及task的初始化,Wi-Fi硬件初始化等。
258event_subscribe(EVENT_NETMGR_DHCP_SUCCESS, wifi_event_cb, NULL);这里则是注册了wifi_event的回调函数。
259#### 使用Wi-Fi
260当前可以通过代码配置或者命令行的形式配置将WI-FI名称(SSID)以及密码配置到EDU中。
261
262填入SSID以及密码
263```c
264netmgr -t wifi -c haas-open 12345678
265```
266
267手动保存ssid和password到文件系统中。
268```c
269netmgr -t wifi -b 1
270```
271
272重启之后,手动重新连接。
273```c
274netmgr -t wifi -a 1
275```
276#### 网络对时(SNTP)
277edu在连接网络之后,就会自动获取网络对时。并更新到本地时钟。
278
279<div align=center>
280    <img src="https://img.alicdn.com/imgextra/i3/O1CN01T0ht7Z21GM6JjwbrD_!!6000000006957-2-tps-2702-222.png" style="zoom:50%;" />
281</div>
282
283此时如果需要获取系统时间,直接调用系统函数clock_gettime即可。
284```basic
285struct tm *info;
286struct timespec tv;
287
288/* 获取 GMT 时间 */
289clock_gettime(CLOCK_REALTIME, &tv);
290info = gmtime(&tv);
291
292snprintf(tmp, 21, "%2d:%02d", (info->tm_hour + 8) % 24, info->tm_min);
293OLED_Show_String(0, 12 * 0, tmp, 12, 1);
294```
295
296
297