开发者学堂课程【HaaS 智能硬件开发训练营:如何制作一个水平仪】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/832/detail/13960
如何制作一个水平仪
内容介绍
一、如何制作一个水平仪
二、HAAS 硬件生态解决方案
一、如何制作一个水平仪
1.一个简单水平仪的组成
一般而言,最简单的水平仪由三部分组成,第一个组成部分是传感单元最常见的是三轴加速度剂,三轴加速度计可以测量物体在立体空间三维上各个方向上的加速度,由于地球引力,物体会受到地球的引力,所以常常引力是Z方向,当一个物体处于水平位置时,只有在这Z轴时会受到重力加速度,在 xy 轴水平方向上没有任何的加速度,可以判断为为水平状态,如果有一定倾角时,由于重力的加速度会在某一个 x 或 y 轴上面就会有一个分量,在其他方向上也会有重力加速度,可以判断为不是水平状态,这就是三轴加速度计测量物体是否水平的原理。需要一个 MCU 中央处理器单元获得是否水平的结果,MCU 的作用是从三轴加速度计中将三轴的加速度数据读取出来,有了数据就可以进行判断,为了更加直观的知道究竟是否水平,需要有一个显示的单元,使用 OLED,是一个比较常见的显示屏,有了三个组件之后,可以做一个简单的水平仪。HAAS EDO 天生集成了这三种东西。
可以使用 HAAS EDO 来制作一个简单的水平仪。
2.OLED 开发流程
任何期限开发不外乎这四步,第一步是了解器件,了解器件最常见的方式就是通过器件的生产厂商给出的 datasheet,datasheet 就是器件的说明书,对器件做了最权威、最专业的说。了解器件以后可以做原理图并且做出他的电路板,有了硬件基础以后,就可以编写驱动的代码,驱动的代码可以获得传感器的数据或者驱动 OLED 进行显示,到底应该显示什么需要应用代码,应用代码一般都是一个业务逻辑的代码,到底是显示一只鸭子还是显示一个小球由应用代码进行决定,这就是一般器件开发的流程。
3.OLED 显示屏
OLED ( Organic Light - Emitting Diode )有机电激光显示
也称为有机发光半导体,属于一种电流型的有机发光器件,是通过载流子的注入和复合而致发光的现象,发光强度与注入的电流成正比。
OLED 在电场的作用下,阳极产生的空穴和阴极产生的电子就会发生移动,分别向空穴传输层和电子传输层注入,迁移到发光层。当二者在发光层相遇时,产生能量激子,从而激发发光分子最终产生可见光。
关于发光显示原理不做过多的介绍,只要知道与 LC 一样,是一个用来显示的器件就可以了,了解一个器件最好的方式是去看厂商给出的 date sheet,来看 HAAS EDO key one 上的 OLED,得知 date sheet 是怎样的。HAAS EDO key one上的 OLED 驱动的芯片是 SH1106,OLED 最重要的是驱动芯片,通过芯片可以进行操作。date sheet 介绍屏幕为一个132×64 dot matrix 屏。
首先第一部分的内容是 features,也就是整体功能的介绍,这一部分基本把这个器件最核心的参数或者功能描述出来,第一个部分是他支持最大132×64dot matrix panel 屏幕并且内部集成了对应的132×64bits SRAM,接下来介绍操作的电压和电流以及与 MCU 之间所采用通信的接口到底有哪几种,大概有五种,分别是6800,8080,三线或者四线的 SPI,最后一种是I2C,有可编程的刷新内容,256-step contrast control on monochromne passive OLED panel表示有256个对比度的调节,是一个单色的 OLED 显示。
下面是第一公号表示
ucpdunsuG3 BMed M07
Sleep mode :5yA
VDD1=0V,VDD2=3.0V-4.2V:5uA
VDD1.2=0V. VPP =64V-14.0V:5uA
适宜温度范围很广,在-40℃ 到+85℃ 都能够工作,封装有多厚,整个都是对器件最大致的描述。接下来是基础的介绍,SH1106是一个132×64的分辨率的 OLED 显示屏,非常适合用于在一个非常宽的范围在可穿带应用中,例如手机的一个子显示计算器 MP3,这里讲解了是什么用于什么。
这是内部结构图,不进行详细讲解。边缘伸出来的是器件对外部迎角。接下来是迎角的描述,第一部分是电源相关的迎角,然后驱动方面相关的迎角,还有总线连接的迎角,非常重要,在编程或者电路设计与此息息相关,
Symbol |
I/O |
Description |
||||||||||||||||||||||||
CL |
This pad is the system clock input . When internal clock is enabled , this pad shauld be Left open . The internal clock is output from this pad . When interal oscilalor is disabled , this pad receives display ckock signal from extemal cock scurce |
|||||||||||||||||||||||||
CLS |
I |
This is the intemal clock enable pad CLS =" H : Internal oscilator circui is enabled . CLS = L " Intemal oscilator circuit is disabled ( requires extemal input ). When CLS = T ”. an external clock source must be connected to the CL pad for normal operation . |
||||||||||||||||||||||||
IM0 IM1 IM2 |
I |
These are the MPU intertace mode select pads .
|
||||||||||||||||||||||||
CS |
I |
This pad is the chip select input . When CS = L , then the chip select becomes active , and dalalcornmand IiO is enatbled . |
||||||||||||||||||||||||
RES |
I |
This isa reset sigpnal inpul pad . When RES set to L ", the settings are initialized . The reset operalion is performed by the RES signal level . |
||||||||||||||||||||||||
AD |
I |
This is the Data / command control pad that deermines whether the data bits are data or a command . A0=" H ; the inpuls al D0 la D7 aro traated as display data A0= L *: the inpuls at DO to D7 are transferred to tha command rogisters . In IC interface , this pad serves as SAD to distinguish the different address of OLED driver . |
||||||||||||||||||||||||
WR (R/W) |
I |
This is a MPU interfacB input pad . Whan conneced to an B080 MPU , this is aclive LOW . This pad connects lo the 808O MPU WR sgnal . The signals on the dala bus are lalched al the rising edge of the WR signal . When carinected to a 6600 Series MPU : This is the readiwrile control signal input termnal . When R / W = HP : Read . When R / W =L3Write. |
||||||||||||||||||||||||
RD (E) |
I |
This is a MPU interfaee input pad When connecledIo an 0000s0nesMPU. i 话 active LOW , This padis connected to Ihe pf the B060 series MMPu , and the data bus is in an output status wihen this signal isL ”. Mhen connected lo a6800 series MPU , his is active HIGH . This is used as an enable cock input of the 6800 series MPU Mhen RD = H : Enable When RD =84 Disable |
||||||||||||||||||||||||
D0·D7 (SCL) (SI/SDA) |
I |
This is an 8- bitbi - directional data bus that connects to an B - bit or 16-bit standard MPU dala bus When the serial interface is selected , then D0 serves as the serial clock input pod (5CL) and D1 serwes as the serial date input pad ( SI ). Al this time ,D2 to D7 are sel lo high impedance When the c interface is selected , then D0 serves as the serial clock input pad ( SCL ) and D1 serves asthe seral data input pad (SDA1). At this time ,D2 to D7 are set to high impedance |
第一个 CL 是一个 IO 说明是 input 和output是可输入,可输出的,这一个迎角是系统的输入,也就相当于做系统时钟。第二个 CLS 表示当他为高时,内部的监正就是使能的,当它为L低时,内部的监正是关闭的。IM0,IM1,IM2这三个是输入的接口,用来确定到底和 MPU 接口选用的是I2C,SPI,还是6800,8080。接下来是 CS,CS 接口是一个片选接口,当为低时,芯片可以使能,命令和数据可以进行传输。reset 是复位接口,大概就是这么多,下面还有很多这样的接口,不进行一一介绍了。这些就是它的 config,outline,位置图。
接下来讲解它的功能性,功能性介绍是非常重要的,例如第一个是讲与微处理之间的 interface 选择接口,通过三个数据进行决定到底是选择 SPI 还是I2C。下面会详细介绍每一种连接方式具体的说明,这里可能会用到三线的 SPI。
这就是的实序,片选拉低以后选中,数据就会再传,并且传输的频率根据时钟来决定。
接下来是I2C的说明,不进行详细讲解,后面会做一个总结。
接下来是一些常见的设置,页面地址,包括行地址,这里面写的很清楚
画了一个示意图告诉132×64的点阵到底是怎么排布的,什么样的区域会分为页一页二页三,每一行到底是怎样的,这是一个监证。
接下来是很重要的部分,command 命令它包含一个命令集,命令非常多,大概会有设置 display start line 就是设置从哪一行开始,各种设置都会在命令集中,有9 10 12 14,24个命令页,命令表将其综合起来,命令后面实序图。
刚开始是对上电和初始实序,先看一下说明,最开始电源是关闭的,一开始将电源打开,然后将 RES 文件设为低,设低以后再将它拉高,这就已经初始化完成。然后进入初始化状态,在设置最开始的初始码再清它的 RAM 到0,将屏幕打开再去发送让显示的用户数据。具体的时序图在下面。
电源上电,做一次 reset,再做一些command和data传输,不仅有 power on 的还有一些 poweroff 各种的实序。
接下来也很重要,是参考应用的连接图 MCU,也就是电的参考设计。
做原理图时,最重要的是要参考这里面的列出来的示意图并且会针对每一种连接方式给出相应的示意图,例如上面这个是8080接口的示意图,下面分别是6080,SPI 示意图。
可以看到 SPI 示意图左面是 MPU 或者是 MCU,右面是 sh 1106,其实可以看到它的迎角是非常多的,但是这里面有MPU 相连的或者可编程的接口其实并不多,大概只有五个,其他的很多接口要么接地直接挂电源,很多都不需要与MCU 进行连接,后面在原理图中同样能够看到这样的特性。
最后是 SPEC 的历史修改了多少版,每一版都做了什么样的修改,现在已经将一份 data sheet 完整的走了一遍。
已经了解了 OLED,并且了解了 data sheet,根据这个 data sheet 最后做出来的硬件。
上面列出了做出的硬件,左上角是 OLED 显示器的正面图,左下角是背面图,可以看到这个屏出来的排线是非常多的,但是真正需要接到主板上的线是卡口上的线,红色宽度的卡口会用排线连接起来大概就是这么多。具体的定义在右上角的原理图,可以看到除了SPI这个接口以外还有I2C,其实是因为这个OLED的模块上不但有 OLED,上面还用了光感传感器,用来检测光感,光感传感器最好是I2C 的接口,所以将坐在这个板子上,所以可以看到既有 SPI 接口又有I2C接口。OLED 的驱动芯片是 SH1106,使用的接口是 SPI,分辨率是132×64,显示的尺寸是1.3寸,显示的颜色为白色单色只有一个白色,工作电压是3.3V 或者五伏,这里使用的是3.3V。
4.OLED-SPI 接口说明
SPI 接口一般有4根引脚
(1)主设备输出( MOSI / Master Out Slave In )
(2)主设备输入( MISO / Master In Slave Out )
(3)数据时( SCLK )
(4)片选( CS / Chip Select )*
实际上使用 OLED 模块时,只需要向它写入数据即可( MOSI / Master Out Slave In ),不需要接收来自它的数据( MISO / Master In Slave Out ),因此省去了 MISO 引脚。
只有唯一的 OLED 器件,片选引脚被直接拉低( CS / Chip Select ),所以实际上对于 SPI通信只用到了时钟( SCLK )引脚与 MOSI 引脚。
OLED 驱动中使用到了另一个引脚 DC ,它用于区分器件接收的信息是数据( Data )还是指令( command )。
主设备一般指 MCU,主设备输出,OLED 输入进行显示。主设备输入是指 OLED 进行输出到主设备上面。如果一个板子上面有很多的 OLED 挂在同一个总线上,就需要通过片选来告诉到底现在操作是哪一个 OLED,假设在系统上面有四个 OLED 挂在同一个总线上,其中三个 OLED 片选端是支高的,只有其中一个片选是支低的,那所有的数据或者命令都发给片选支低的,通过片选的引脚可以去操作多个,这就是原理。
有了这些看一下原理图
原理是从标号是一开始对应的,对应的地方表示两个相连,实际上大概只有四个相连,SPI 用了两个一个数据一个clock,一个是判断它是 command 还是 data,还有一个是复位。最终的 OLED 接线图用了四个接口,第一个是reset用来复位,第二个是一个 data 或 command 选择的接口,拉高时传输的是数据,拉低时传输的是指令,第三个是时钟信号,第四个是串行数据信号,后面两个是 SPI 中的,总的来说就是这样一个设置,至此,整个硬件的设置已经完成,接下来进入如何对它进行驱动这样一个软件的事情,在弄懂 oled 软件设置前,先需要讲明白到底是一个怎样的操作方式,不是随便乱来的,是有一种方法的。
5.OLED-扫描方式
前面讲到 OLED 是132×64这样一个点阵,这么多的像素每个像素占一个 bit,可以是零或者是一,零代表是暗,一代表是亮这样的方式。如何驱动这么大的点阵来显示,每一个像素占一个 bit,数据传输与字节传输,扫描方式可以有以下几种,第一种是逐行是,整个屏幕一行一行进行显示,先将第一行扫描完在扫描第二行,第三行一次进行扫描。第二种方式是逐列式,顾名思义,一列一列进行扫描,先把第一列扫完,再扫描第二列。第三种方式是行列式,这个需要讲解一下,由于都是数字的传输,是字节进行传输,一个字节代表八个像素,如果是行进行扫描就是一行八个像素,这里面不是在行里面走而是向列里面走,先八个像素扫描一行,在八个像素,扫描下面一行,逐次把左面这一行扫了,在扫偏右边这一排,依次这样,这就是行列式。第四种方式是列行式,那一行是顾名思义是把一个字节的数放在第一列,再放在最上面的第二列里面,在放在最上面的第三列里面,依次将上面的部分填满,再填下面一部分。
这里使用的实际上是列行式
6.OLED-sh1106扫描方式
Sh1106将整个屏幕的132×64这个点分为了八个页面,具体分割方式,向下数八个像素点,高度作为一个页面,直接页面将横全部吃光,向右整个一行八行算一个页面,下面的八行算另外一个页面,方式是从上到下共八个页面,从左到右,132列。
7.OLED-sh1106数据填充流程
现在看一下数据怎样做填充,假设代码中存放 ole d 屏幕数据的数组,是一个二维的数组,有八行,132列。
首先设置页的地址到底要写第几页,在设置行的地址到底要写第几行,指定位置以后就可以进行读写的操作,具体看下图。
从头开始写,就设置行页面的地址和列页面的地址,将 bute0写在相应的地方,byte1写在相应的地方一次向右将第一个配区填满,然后再将第二个配区填满。以此类推,就可以填满整个屏幕,这是填充数据的一种方式。
8.OLED-设置 page 和 column
这里面涉及到几个最重要的 command,在 data sheet 中看到涉及到了很多的 command,这里面列举出了三个非常重要的,设置列的低四位,设置行的高四位,以及设置 page 的地址
command |
code |
function |
||||||||||
A0 |
RD |
WR |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
||
1.Set Column Address 4 lower bits |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
Lower column address |
Sets 4 lower bits of column address of display RAM in register .( POR =00H) |
|||
2. Set Column Address 4 higher bits |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
Higher column address |
Sets 4 higher bits of column address of display RAM in register .( POR =10H) |
|||
12. Set Page Address |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
page address |
Specifies page address to load display RAM data to page address register .( POR =B0H) |
首先要把定位到哪里数据发给 sh1006,首先应该发 B0,B1代表1011,怕格局就是1表示要从 page 一开始写,到底是从 page 一的第几行开始写高位和低位都填0,就是从零开始。0000,上面是00下面是10,把三个命令发给sh 1006,这就知道整个唯一的一处 byte,可以通过设置 page 的地址和 column 的地址可以确定整个 RAM 的唯一 byte,每个 page 包含了八行,132列,美术有一个 byte,其实是纵向填充每页中的一列。有一个非常关键的点是每个显示数据读或者写命令都会使指定的 column 地址递增(+1),这样可以连续访问 MPU 显示数据。由于列地址与页面地址无关,因此当从页面0最后一列83H 移至页面一第一列00h 时必须重新指定页面地址和列地址。通过持续写入数据和变换页地址,就能够将整个屏幕填充为想要的图像。
看起来有一点点的抽象,到底应该怎么做向下看。
9.OLED-刷新整屏示例代码
这里想怎样刷新整个屏幕,假设刷新屏幕的数据保存在buffer里,是一个132×8的数组。有八个 page132行,显示时定义了一个显示方法,首先做一个针对每一个 page 做一个 for 循环,这里是把64整数除以八,从0~7,先对page一个页地址,这里是对进行或操作,其实是从零开始。再对他进行一个列的操作,分别是高低位。写完 page 地址以后,接下来就要去写列的地址,列的地址都是从零开始,因为前面讲的有一条特性是每一次进行读写时,列的地址都会递增。所以其实只要每次把每个 page 的地址第一个列写好复位,从最左面这一列开始写,每次写下去都会自增。这里又定义了一个数组将 buffer 数据放在这里面,再将数据依次写入到芯片 RAM 中传输给 sh1006,这样就把整个想要显示的数据全部发给他了。
self . bufer = bytearray ( self . pages * self . width )#132行*8 page ( width =132, pages =8, height =64)
def show ( self ):
for page in range ( self . height I8):#设置页地址
self . write _ cmd ( SET _ PAGE _ ADDRESs I page )#设置列地址的低位
self . write _ cmd ( LOW _ cOLUMN _ ADDRESS ) #设置列地址的高位
self . write _ cmd ( HIGH _ COLUMNLADDRESs )
page _ buffer = bytearray ( self . width )
for i in range ( self . width ):
page _ bufer [= self . bufer [ self . width * page + i ] #填充 buffer
self . write _ data ( page _ bufer )#传输 buffer 中的数据
这是整个显示的流程。到底 buff 里面的数据应该如何获取实际上这个方法有点笨,就是把一个像素,一个像素点画出来,比如这个 buffer 里面我们知道每一个都代表着一个像素,如果要画一个圆,就大概会知道都定义了哪些像素点需要进行写,哪些不需要写,这里面就有一个画像素点的函数,后面再代码里面也会进行详细的讲解。
// Functions for MVL5B format
STATIC void mvlsb _ setpixell const mp _ obj _ framebuf _ t * fb , unsigned int x , unsigned int y ,uint32_ t col ){
size _ t index =( y >3)* fb -> stride + X ;uint8_ t offset = y &0x07;
((uint8_ t *) fb -> buf )[ index ]=((uint8_ t *) fb -> buf )[ index ]&~(0x01< offset )) I (( col !=0)<< offset );
}
实际上很简单,就是将你要设置的数据填到8端口对应的位置上面去,做了很多次设置这样的操作,这个 buff里面就会变成想要显示的图片,到这个地方,理论部分已经讲解完毕,下面讲解怎么实现编码,以及如何在开发板上将效果跑出来。
三、HAAS 硬件生态解决方案
前面讲完了理论部分,接下来进入实战环节。将使用 HAAS EDO key one 来制作一个简单的水平仪。
1.HAAS Python 开发环境搭建
了解 HAAS 都知道 HAAS 最大的特色是轻应用,它可以使用 Python/JS 这些简单的语言来做物联网的开发,这使得很多前端的或者互联网的从业人员都能够很轻松的进行物联网的开发。
现在看一下如何搭建 Python 开发环境,首先要下载 Python 的部件,在安装相关的ide插件,再将部件稍入的HAAS EDOkey one 开发板上,在 IDE 里编写 Python 脚本,再将脚本推送到开发板上进行运行,如果开发板是之前的并没有烧好 Python 部件,有非常多的文档帮助烧录 Python 部件,首先可以看到有两个大的平台,第一个是 HAAS技术社区https // blog . csdn . net / HaaSTech。
点进去,这是在 CSDN 上的社区,目前有两百多篇文章。可以看到有一个轻应用的专栏,有非常多的轻应用,这里有使用 HAAS studio 开发 Python 轻应用说明,告诉大家如何使用 HAAS studio 开,并且还有很多 JavaScript的案例,同样也有很多 Python 的案例,例如温速度上云是上次训练营讲到的案例以及很多 bad Apple,传感器案例,mqt1,AI的案例,千里传音这些案例。另外 Python 轻应用还有专门的文档库
httpS : Ig . aliCdn .COmHaaSAIPythonD0CguICKStart/ inaeX . ntm,这里面有很多 Python 相关的文档说明,例如官方的部件都放在这里。点到HAAS eduK1进到这里会介绍怎样烧录部件,这里提供了 MacOS 环境下面的部件烧录HAAS EDUK1这个固件,另外一个是 Windows 环境下的固件,包括了固件包以及一些相关的工具照着操作就能够烧录好自己的固件,并且也阐述了验证的方法。环境的搭建就讲到这里。
2.制作水平仪-应用代码
最重要实现的水平仪效果是如下图所示。
会做出一个水平仪,中间有一个小球会在里面滚动,如果水平小球就会进入圆圈之中,如果不平就会在圆圈的外面,这是一个效果的展示。现在直接通过 ide 给大家演示如何去制作这样的一个简易的水平仪,IDE 是 VScode,新建一个VS code 窗口,这个就是 HAAS studio 上节课已经讲述如何进行应用,例如现在选择 Python 轻应用,是三合一的,可以做 C/CC++开发,Java script 开发也可以做 Python 开发,这里选择 Python 开发,点击创建项目,保存的工作路径是/ Users / ali - xuqingjiang / aos _ work _ circle,选择硬件类型为 HAAS EDUK1,解决方案有提供的一些现有的解决方案,第一个是 gpio 的,第二个是温速度上云,第三个是播报音像,这里选择 gyroscope,点击立即创建提交,现在就已经创建,创建成功后,solution 会有一个 main.py,这就是将这个工程现有的代码已经出来了,陀螺仪小球所需要的代码是短短三十多行,还包括注释,备注,现在将代码下载到开发板上试运营一下,首先需要串口线将开发板与电脑进行连接上电,这是一个假的编译,再选择下载,会弹出本地更新还是在线更新,这里选择本地更新,然后会弹出串口,因为这个 EDU K1接上以后串口是最后一个选择15000,提示进行重启设备,现在按一下重启。这时就开始下载了,快就下载完了。小的屏幕上小球已经显示出来,动一下小球就会偏向一侧,这样就可以判定 EDU K1是不是在水平的状态,然后就做好了一个陀螺仪小球。这是演示的效果,再看一下代码。
import sh1106
import utime
from driver import SPI from driver import GPI0
from mpu605Q
import MPU6050
mpu6050Dev=MPU6050()mpu6050Dev. open ("mpu60504)mpu6050Dev. init (
print ("'mpu6050 init finished ")
spi0= SPI (
spi0.open(" oled _ spi ") gpio _ dc =GPI0(
9pio_ dc . open (“ oled _ dc ") gpio _ res =GPI00)
gpio _ res . open (" oLed _ res ")
display =sh1106.SH1106_ SPI ( width =132, height =64, spi =spi0, dc = gpio _ dc , res = gpio _ res )
# display . init _display0
ac = I ]
while ( True ):
ac =mpu6050Dev. get _ Accelerometer ()
# print ("mpu6050 acc is :", ac [ o ], ac [1, ac [21)
display . fill (0)
# display . fill _ circle (50,30,20,0xAF)
# display . draw _ circle (90,30,20,2,0xAF) display . draw _ circle (66,32,10,1,1)
display . fill _ circle ( int (66- ac [0]/250), int (32+ ac [1l/500),8,1)
display . show ()
# display . test ()mpu6050Dev. close ()
print (" test mpu6050 success !")
代码很简单,只有一个 main.py,第一个是昨天课程所讲的 mpu6050这个芯片是一个六组的传感器,进行 open然后Init,这时需要去将它显示出来,这个屏是一个 SPI 的屏,所以这里面 new 了一个 SPI 的东西,也将它进行open,另外前面讲到会有 DC 和 reset 这两个 gpio 口,所以也进行了 open,去 new 了一个 sh 1106SPI 这样的一个类,说明这是一个 SPI 这样接口的 OLED 屏,然后传入一个参数132×64的像素,接口是之前创建的 SPI0,然后将这几个接口传入进去,下面就是一个 while 循环,通过传感器得到三轴加速度计的值,然后在屏幕上进行差除掉,画出一个圆,这个圆就是外框的圆,用来叼进东西,再画一个实心的圆,其实就是填满一个圆。这里面就会将三轴加速度计的取到三个轴的数据填在其中,这样的效果只需用到x轴,y轴。因为是水平仪,在水平方向上。如果他们两个的值得到的都是零,这里x轴的坐标,也就是圆心的坐标与上面一模一样,就会重叠。如果得到的不是零,就会有一个偏量。最后就是将这个显示出来。
3.Python 轻应用 OLED 模块
实际上 Python 轻应用 OLED 模块实验中涉及到了好几个东西,首先底下是 OLED 硬件,也就是屏幕,上面会有一个spi.py,Python 轻应用上的SPI的功能就是 SPI 总线的功能,OLED 这个器件叫 sh1106.有一个专门的文件进行控制,并且这里面还会用到 framebuf,framebuf 是 MicroPython 里面帧缓冲区操作的一个类,了解 HAAS 知道其实 Python 轻应用其实使用的是 main Python 这样的框架,framebuf 提供一个可用于创建位图可发送到显示器的通用帧缓冲区,与底下 OLED 显示或者什么显示都是无关的,是一个纯软件的东西,可以显示单色的 OLED 上,也可以显示 rgp 那种复杂的图形。刚才给大家演示的就是应用代码,会用到 sh1106这样一个 Python 的代码,接下来除了给大家介绍应用代码,还会详细走读一下底下的这几段代码。
切到 OLED,这里切一个完整代码的路径。main.py 是刚才的应用程序,大家肯定会好奇sh最主要的 sh1106在哪里,刚才创建了一个类,SH1106_SPI 就是这个类,这里可以看到它是一个集成 sh1106的类,它除了有 SPI 这个子类,还有I2C 子类,就取决于使用哪种接口,前面讲到这里使用的是 spi 接口,看一下 sh1106的副类,上面是传感器的定义,器件传感器的定义。
register definitions
SET _ SCAN _ DIR = const (0xc0)
LOW _ COLUMN _ ADDRESS = const (0x00)
HIGH _ COLUMN _ ADDRESS = const (0x10) SET _ PAGE _ ADDRESS = const (0xB0) SET _ CONTRAST = const (0x81)
SET _ ENTIRE _ ON = const (0xa4) SET _ NORM _ INV = const (0xa6) SET _ DISP const (0xae)
SET _ MEM _ ABDR = const (0x20)
SET _ cOL _ ADDR = const (0x21)
SET _ PAGE _ ADDR = const (0x22)
SET _ DISP _ START _ LINE = const (0x40) SET _ SEG _ REMAP = const (0xa0)
SET _ MUX _ RATIO = const (0xa8) SET _ COM _0UT_ DIR = const (0xc0) SET _ DISP _0FFSET= const (0xd3) SET _ COM _ PIN _ CFG = const (0xda) SET _ DISP _ CLK _ DIV = const (0xd5) SET _ PRECHARGE = const (0xd9)
class SH1106:
def
init self , width , height ): self . width = width
self . height = height
self . pages = self . height 1/8
self . buffer = bytearray ( self . pages * self . width ) fb = framebuf . FrameBuffer (
self . buffer , self . width , self . height , framebuf . MVLSB ) self . framebuf = fb
# set shortcuts for the methods of framebuf
self . fill = fb . fill
self . fill _ rect = fb . fill _ rect self . hline = fb . hline
self . vline = fb . vline
self . line = fb . line
self . rect = fb . rect
首先看一下构造函数,这里会定义它的像素宽和高132×64,分成八个页,这里非常重要的一句是这里用了 framebuf并且将这里面新建的一个数组 buf 传进去,所有想要显示在屏幕的数据最终都是先填充在 buffer 里面,并且frame buffer 这个模式是单色的模式得到fb后面非常多的地方都会用到,fill 的函数其实就是 frame buffer 里面fill函数,pixel函数也是来自于 frame buffer,图形的,显示文字的都是来自于 frame buffer 里面。
接下来是对 OLED 显示器进行初始化,将些一堆的 command 依次的送到器件上面去。差除在进行显示
def
init _ displayl ( self ):
self . reset ()
for cmd in (
SET _ DISP I 0x00,
SET _ DISP _ CLK _ DIV ,0x80,#设置时钟分频因子
SETMUX _RATI0, self . height -1,#设置驱动路数路数默认0x3F(1/64)
SET _ DISP TOFFSET ,0x00,#设置显示偏移偏移默认为0
SET _ DISP _ START _ LINE I 0x00,#设置显示开始行15:01
SET _ CHARGE _ PUMP ,0x14,#电荷泵设置bit2,开启/关闭
#设置内存地址模式[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
SET _ MEM _ ADDR ,0x02,
SET _ SEG _ REMAP I 0x01,#段重定义设置,bit0:0,0->0;1,0->127;
#关闭显示
#设置 COM 扫描方向;bit3:0,普通模式;1,重定义模式 COM [ N -1]-> COMO ; N :驱动路数 SET _ COM _ OUT _ DIR I 0x08,
SET _ cOM _ PIN _ CFG ,0x12,#设置 COM 硬件引脚配置[
SET _ PRECHARGE ,0xf1,#设置预充电周期[3:0], PHASE 1;[7:4], PHASE 2;
#设置 VcOMH 电压倍率[6:4]000,0.65* VcC ;001,0.77* VcC ;011,0.83* VcC ; SET _ VCOM _ DESEL ,0x30,
SET _ CONTRAST ,0xff,#对比度设置默认0x7F(范围1~255,越大越亮) SET _ ENTIRE _ ON ,#全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) SET _ NORM _ INV ,
SET _ DISPI 0x01);#开启显示 self . writq _ cmd ( cmd )
self . filL (1)
self . show (
[5:4]配置
#设置显示方式;bit0:1,反相显示;0,正常显示
重点看SPI中的东西,SPI里面也有一个构造函数
class SH1106_ SPI (SH1106): spi . open
def
init ( self , width , height , spi , uL , I 可 MUI に,=낼 UneI
self . spi = spi
self . dc = dc self . res = res
self . cs = Cs
super (). init _( width , height )
def write _ cmd ( self , cmd ):
if self . cs is not None :
self . cs . write (1)
self . dc . write (0)
self . cs . write (0)
self . spi . write ( bytearray (「 cmdl )) self . cs . write (1)
self , dc . write (0)
self . spi . write ( bytearray ( IcmdJ ))
def write _ data ( self , Ibuf ):
if self . cs is not None ;
self . cs . write (1)
self . dc . write (1)
self . cs . write (0)
传输 command 和传输 data 是不一样的,主要取决于 CS 这个片选没有用,实际上是先对写一个零告诉是command,通过 spi 接口将它里面的数据 command 传给 OLED,如果写 data 对 DC 写一个1告诉 data 来了,然后spi将data写过去,这是最终传入到 LED 上的数据,通过这两个方式实现。
上面会填充一些假如 frame buffer 里面有一些函数没有,这里会做一些扩充,例如 fillC 口,C 口就是一个画圆,填充一个圆,这里其实用了 frame buffer 写像素,最终通过一个点,一个点将像素填在里面形成一个圆。换一个圆其实很简单,刚才讲了填充两个实心的圆,如果先换一个大的圆填上一个实心的,再把小一点的圆擦除掉,就成了一个只有边框的圆就不是一个实心的,也就是屏幕能看到中间的那一部分。这里面他们之间差了一个 w,半径差了一个w,圆心是一样的。这样就可以将它画出来了。
def draw _ circle ( self ,×0,y8,, W , c ):
seUr . fil _ circle (x0,y0, r , c )
self . fill _ circle (x0,y0, r - W ,0)
具体 SPI write 在 Mac Python 框架里面,有 open,有 read,有 sendreceive,close 函数
def open ( type ):
1NU
打开并根据 board . json 配置实例: param type :对象类型
: returns :0:成功,其他:失败: raises 0SError: EINVAL
1IWI
pass
def write ( dataBuffer ):
III
通过 SPI 发送数据,该函数为阻塞函数, SPI 发送完成后才会返回
: param dataBuffer :待写入的数据: returns :0:成功,其他:失败: raises 0SError: EINVAL
INIi
pass
def read ( dataBuffer ):
N
读取指定 bytes 的 SPI 数据,该函数为阻塞函数,读取到指定 bytes 的数据后才会返回
: param dataBuffer :读出来数据的存储空间: returns :0:成功,其他:失败
iraises 0SError: EINVAL
NII
pass
def sendRecv ( writeDataBuffer , readDataBuffer ):
1IHII
通过 SPI 发送数据阻塞发送数据,发送完后,再阻塞读取指定 bytes 的数据
: param writeDataBuffer :待写入的数据
: param readDataBuffer :读出来数据的存储空间: returns :0:成功,其他:失败
: raises 0SError: EINVAL
1IlII
pasS
def close ()
1IN日
关闭实例
: pa ram 空:
: returns :0;成功,其他:失败: raises 0SError: EINVAL
1II
具体的实现会在 Mac Python C 的代码中实现。frame buffer在modframebuf . c components / pyengine / engine / extmod 中,实际上这里面涉及到框架的东西会相对复杂一点。之前看到会 new 一个 frame buffer,通过像素点到这里。现在讲一下这个是怎么来的,首先有这样几种类型,单色的,rgb 的,JS 各种类型的。mvlsb 几个方法都在这里,例如设置像素点,在frame buffer的buffer里面进行设置它的某一个像素点,对坐标定位换算,张代码并不复杂,逻辑关系也比较简单。其实就是外面传来一个 buffer,然后对这个 buffer 数据进行操作,后面也会对这个buffer数据进行显示出来。
STATIC mp _ framebuf _ P _ t formats []={
[ FRAMEBUF _ MVLSB ]= mvLsb _ set 中 ixel , mvLsb _ getpixel , mvLsb _ fill _ rect ,
[ FRAMEBUF _RGB565]={rgb565_ setpixel ,rgb565_ getpixel ,rgb565_ fill _ rect ),
[ FRAMEBUF _GS2_ HMSB ]=gs2_ hmsb _ setpixel ,gs2_ hmsb _ getpixel ,gs2_ hmsb _ filLrect ,
[ FRAMEBUF _GS4_ HMSB ]=fgs4_ hmsb _ setpixel ,gs4_ hmsb _ getpixel ,gs4_ hmsb _ fil _ rect },[ FRAMEBUF _GS8]=gs8_ setpixel ,gs8_ getpixel ,gs8_ fil _ rect },
[ FRAMEBUF _ MHLSB ]={ mono _ horiz _5etpixel, mono _ horiz _ getpixel ,
mono _ horiz _ fill _ rect },
[ FRAMEBUF _ MHMSB ]={ mono _ horiz _ setpixel , mono _ horiz _ getpixeL , mono _ horiz _ fill _ rect },
// Functions for MVLSB format
STATIC void mvlsb _ setpixel ( const p _ obj _ framebuf _ t * fb , unsigned int ×, unsigned int y ,uint32_ t col )
size _ t index =( y >>3)* fb -> stride +×;uint8_ t offset = y &0x07;
((uint8_ t *) fb buf )[ index ]=(((uint8_ t *) fb -> buf )[ index ]&~(0x01<< offset )) I (( col !=0)<<(
STATIC uint32_ t mvlsb _ getpixel ( const mp _ obj _ framebuf _ t * fb , unsigned int ×, unsigned int y ){
return (((uint8_ t *) fb -> buf )[( y >>3)* fb -> stride +×->>( y &0x07))&0x01;
STATIC void mvlsb _ fill _ rect ( const mp _ obj _ framebuf _ t * fb , unsigned int ×, unsigned int y , unsigned int
while ( h --){
uint8_ t =&((uint8_ t *) fb -> buf )( y >>3)* fb -> stride + x ];uint8_ t offset = y &0x07;
for ( unsigned int wW = W ; wW ;-- ww ){
* bE (* b &~(0x01<< offset )) ( Col !=0)<< offset )
4.HAAS 物联网设备云端一体开发框架
HAAS开发框架,HAAS 物联网设备云端一体开发的框架就是希望不用关心底层的实现,而且使用搭积木的方式就可以开发自己的物联网应用,这里面分了很多层,最底下的就是硬件积木层,它包括一些标准的硬件,例如 HAAS开发板EDU K1,也包括一些生态的积木,很多传感器,屏的类型。在硬件积木之上是物联网操作系统alios things,在Python 里面是不可见的,因为 Python 在上面,Os 是自研的,具有完全的知识产权的物联网操作系统,也有专门的团队进行维护和新功能的开发。Os上面会有很多的软件积木,包括 linkSDK 是联网的,OTA 进行升级的,传感器,网络,WiFi,多媒体等各种各样能见到的物联网应用在这里都有对应的软件积木。在上面一层就是 HAAS 轻应用,它包括两种,一种是今天介绍的Python轻应用,还有一种是 JavaScript 轻应用,目的是让用户专注在自己的业务很简单的使用户应用于自己习惯的就能做物联网开发。最上面的就是云端服务,包括阿里系的达摩院,淘宝,各种钉钉等。之前了解过的,可以看到还有许多 AI 的服务,包括老板来了,还有通信识别等。后面也会有视频做这样的展示。
5.HAAS 硬件积木
智能硬件为课程重点,展开看一下智能硬件的积木。首先开发版和模组,第一个是 HAAS100的开发板,是推出来的最早的几块开发板之一,是一个通用的或者做智能影音的开发板,并且非常适合应用在工业,农业,器件规格都非常高。第二个 HAAS200开发板,是一个 WiFi,蓝牙 IoT 的仪器,性价比非常高,做传统的lt的开发非常合适。第三个是 HAAS600开发板,它是4G cat.1开发板,大家都知道2G,3G 退网以后4G cat.1具有非常广阔的应用场景,这个开发板天生联网了,在使用场景上非常广泛,可以在官网上进行了解。第六个是 HAAS600以及 HAAS201模组,当使用这些开发板做一些原型设计时,可以快速的使用这些模组进行快速的量产,并且相对成本来讲也是比较低廉的。第五个是 HAAS EDU K1互联网教育开发板,是新手去做物联网开发与学习的神器,不但有丰富的传感器还有屏,课程也见识到了想搭建一个简易的水平仪能够轻松的做到。除了开发版以后生态中还有很多硬件积木库,包括各种传感器,显示屏,小器件,都会有,并且生态库越来越丰富。也希望广大开发者来一个贡献扩充硬件积木库。
四、HAAS云端一体案例
1.老板来了
把摄像头藏在工位上面,然后监视的 EDU 就在座位上面,这样就可以打游戏了,等老板来了就会识别出老板的头像,然后进行报警,并且可以与钉钉联动。这是老板来了的案例,是云端一体的案例。
2.播报音箱
之前是用 HAAS EDUK1打造了一个音箱,这里面使用 HAAS100同样可以打造音箱,首先按照屏幕中的相关提示或者文档连接好硬件,连接好以后将Python官网中的播报音箱的代码拷贝到 IDE上,一个播报音箱的代码只有不到80行,所以说非常的少。下载代码,然后可以推送到设备上并且执行,然后可以听到设备已经收到代码并执行,提示传音服务已经连接好。现在在等待发送一个指令进行播报,可以使用 Python sdk 发送一条指令,发送的内容是支付宝到账100元,现在进行执行。可以听到文字转化成指令,进行语音播报出来。可以将金额再改一下。修改金额以后,这个1万元也进行了播报。这样一个完整的播报音箱就做好了。
3.如何使用 hass 开发自己的智能硬件
使用 HAAS 去开发自己的智能硬件,流程是首先去官网 HAAS 社区去了解解决方案,如果有需要的解决方案,可以直接使用这个解决方案,解决方案是开源的并且完全免费的。如果想要的智能硬件超出解决方案,可以使用积木进行搭出智能硬件出来,首先去选择一个合适的智能硬件的积木,选好硬件积木以后去选择软件积木。最后如果是云端一体的,就选择云端的积木,将组合成自己的智能硬件。