智能家居控制系统
概述
项目地址:GitHub
基于 GEC 6818 开发板,使用 Linux 下 C 编程实现的智能家居控制系统。可实现实时采集并显示周围环境的数据,当数据高于或低于某一阈值时,执行不同的动作,如报警、亮灯。
代码文件结构:
说明:
- lcd.c — 打开/关闭屏幕、在屏幕上画点和画图
- bmp.c — 在屏幕上显示 bmp 图片
- word.c — 在屏幕上显示文本
- touch.c — 获取在屏幕上点按的坐标和手指滑动的方向
- uart.c — 获取并解析传感器数据、控制家具
环境准备
交叉编译
在一个环境下编译生成,适用于另一个环境下运行的可执行文件的过程。
由于 GEC6818 使用的是运行在 ARM 架构上的 Linux 操作系统,因此代码需要通过交叉编译才能正常运行在开发板上。
指令:arm-linux-gcc *.c -o main.out -lm -pthread
。由于项目代码中使用了数学函数和线程函数,因此在编译时需要链接这两个库,即 -lm
和 pthread
。
设置共享文件夹
实现 Windows 和虚拟机的文件互通。在 Windows 中编辑代码,在 Linux 中编译代码。
首先在 Windows 下创建项目工程文件夹(如 smart_home),把项目的代码都放入该文件夹中。
虚拟机设置 –> 选项 –> 共享文件夹 –> 总是启用 –> 添加 –> 选择 smart_home 作为共享文件夹 –> 确定。
Linux 中共享文件夹的路径: /mnt/hgfs/<共享文件夹名字>
,如 /mnt/hgfs/share
。共享文件夹的名字可在上一步中自由命名。
cd 进入共享文件夹路径后,交叉编译即可。
其他
使用 SecureCRT 连接 6818 开发板的操作系统。
烧录文件:rx <filename>
。
赋予 main.out 可执行权限:chmod +x main.out
或 chmod 0777 main.out
(超级权限)。
在 Linux 中查看函数的说明文档:man 命令。
man -f 函数名
— 查看页码及对应页的内容概要man 页码 函数名
— 查看指定页的详细内容- 键入
q
退出文档。
LCD显示屏
显色原理
6818 开发板 LCD 屏幕的分辨率:800*480 。
分辨率:单位面积内的像素点的个数。所以 800*480 表示一行有 800 个像素点, 总共有 480 行。
像素点(pixel) 是能够显示某种颜色的点。在屏幕上显示一个颜色,就是给对应的像素点一个颜色值。
各种各样的颜色都由三种基本颜色组成:Red Green Blue ,并用量化表示颜色的程度。
量化:数量化,数值大小表示程度,每种颜色的分量占 1 个字节,0255( 0x000xFF )。
Red Green Blue
0xFF 0x00 0x00 —> 0xFF0000 (正红色)
LCD 屏幕的每一个像素点占 4 个字节(a r g b),a 表示透明度。在后续的画点、画图、显示图片、显示字符中,对 LCD 屏幕的每一个像素点写入的颜色数据不必一定占满 4 个字节,如只写入 0xFF0000(3个字节),这种不指定透明度的情况下,默认透明度最大,即实际为 0xFF0000FF(4个字节)。
操作系统的作用
提供接口。在内存中开辟一块缓冲区,用来保存屏幕上每一个像素点的颜色值。应用程序只需要把要显示的颜色值写到这个缓冲区中即可,操作系统将根据写入的内容渲染屏幕。
这个缓冲区在 Linux 操作系统中称为帧缓冲(Frame Buffer)。帧缓冲设备是对具体图像硬件的一种抽象,它让上层应用不必关心底层硬件的实现细节。
6818 开发板屏幕对应的设备文件路径名为 /dev/fb0
,只需要把颜色值写入到 /dev/fb0
文件中,底层驱动就会把屏幕上对应的像素点显示对应的颜色。
文件IO
open
1 |
|
write
1 |
|
read
1 |
|
lseek
1 |
|
close
1 |
|
内存映射
使用 write 函数向 /dev/fb0
中写入颜色值的效率不高,因为:
- 系统拷贝缓冲区的数据到内存需要耗时间。
- write 是系统调用的函数,函数调用本身会有开销。
- 系统状态的切换(用户态和内核态)也有开销。
Frame Buffer 本身就是一块内存,在 C 语言中只要知道一个内存的地址,就可以通过指针去操作这个内存。如果能够获取到帧缓冲的首地址,那么每个像素点的位置只需要换算成相对首地址的偏移量即可。
如果 int *plcd
指向帧缓冲的首地址,那么 *plcd = 0xFF0000
就表示对第 0 行 0 列的像素点写入正红色,*(plcd+800) = 0xFF0000
表示对第 1 行第 1 列的像素点写入正红色。
1 |
|
实现开关屏幕 画点 画图
lcd.h
1 |
|
lcd.c
1 |
|
bmp图片
简介
bitmap 位图文件,是由 Microsoft 发明的一种无压缩的图片文件格式,每一个像素点的原始数据都保存图片文件中。
32 位 bmp 图片的像素点数据组成:a r g b
24 位 bmp 图片像素点数据组成:r g b
任何格式的图片都是由一个个的像素点组成的。在屏幕上显示图片,就是把图片的像素点的颜色数据解析出来,再将这些数据依次写入到屏幕上像素点即可。
文件格式
BITMAP文件头
保存文件的魔数、大小等数据,固定占 14 个字节。
DIB头
保存图片的宽、高、色深等数据,固定占 40 个字节。
宽度 width :偏移量 0x12 ,占 4 个字节。
1
2
3int width = 0;
lseek( fd, 0x12, SEEK_SET );
read( fd, &width, 4 );width>0 表示在 bmp 图片中每一行的像素点数据从左至右存放
width<0 表示每一行的像素点数据从右至左存放高度 height :偏移量 0x16 ,占 4 个字节。
height>0 从下至上保存每一行的像素点数据
height<0 从上至下保存每一行的像素点数据色深 depth :每个像素点所占的 bit 位数,偏移量 0x1C ,占 2 个字节。
depth=24 24位 bmp 图片
depth=32 32位 bmp 图片
像素数组
图像的数据区域,保存每一个像素点的颜色分量值 (bgr/bgra)。
- depth=24 –> bgr
- depth=32 –> bgra
偏移量:0x36 。
默认情况下, width>0 height>0 。排布顺序从下至上,从左至右。按行存放每一个像素点的颜色分量值
,但是每一行的字节数的必须是 4 的整数倍。
假设 width=10 depth=24 ,则一行有效的字节数为 abs(width)*(depth/8)=30 。但实际的字节数为 30+2 ,因为规定每一行的字节数的必须是 4 的整数倍,需要填充 2 个字节的无效数据 “赖子”。
实现在屏幕上显示bmp图片
bmp.h
1 |
|
bmp.c
1 |
|
字符取模
为了在屏幕上显示字符,需要先将字符用点阵表示,然后对点阵进行颜色渲染即可显示字符。
在网上找个工具生成,这里用的工具讲的原理我没看懂😅。不影响,照着它说的步骤着色就是了。
实现在屏幕上显示字符
word.h
1 |
|
word.c
1 |
|
触摸屏
原理
输入设备:键盘、鼠标、触摸屏、…
Linux 内核需要监听这些输入设备上的事件(event),然后做出相应的动作。
当我们去触摸屏幕、点击鼠标、按下按键等操作输入设备时,就会产生相应的输入事件,并写入设备对应的文件中。
输入设备对应的设备文件名为 /dev/input/eventX (X=0,1,2,...)
。在 6818 开发板上,触摸屏对应的设备文件名为 /dev/input/event0
。
不同的输入设备对应输入事件是不同的,但是 Linux 用了一个标准的事件结构体来描述输入事件。
1 |
|
获取手指触摸的坐标
1 | //1. open() 打开触摸屏 |
实现获取点按坐标和滑动方向
touch.h
1 |
|
touch.c
1 |
|
GY39传感器
简介
简介原理及使用说明参考官方手册。
传感器和开发板使用串口进行通信。6818 开发板的串口:/dev/ttySAC1
、/dev/ttySAC2
、/dev/ttySAC3
。
获取传感器采集的数据
1 | //串口初始化 |
家具控制
蜂鸣器和led灯
把 kobject_led.ko 驱动文件下载到开发板上,然后输入指令 insmod kobject_led.ko
加载驱动。
一旦加载成功,在系统的 /sys/kernel/gec_ctrl/
目录中会生成 led_d7 、led_d8 、led_d9 、led_d10 、led_all 、beep 几个文件。
操作方法:
1 |
|
播放MP3
madplay
命令用来播放指定的 MP3 音乐。
语法:
1 | madplay -Q xxx.mp3 //播放 |
system() 函数用来执行命令:
1 |
|
实现获取解析显示传感器数据 控制家具
uart.h
1 |
|
uart.c
1 |
|
功能整合
说明
开机显示主界面。
后台实时采集环境的参数并显示。
设定阈值,进行智能控制家具。
可以手动控制家具。
可以手动开关 BGM 。
线程函数
后台实时采集显示环境的参数并智能控制 和 手动控制家具,分别对应一个线程。
1 |
|
main.c
1 |
|