提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
基于AliO Things智能环境监控系统。可以通过连接阿里云实现远程计算机对周围环境进行监控。依托开发板上的环境监测传感器采集环境信息并显示,并进行异常报警。通过上云,实现监测系统的远端控制和查询。
提示:以下是本篇文章正文内容,下面案例可供参考
1.1 通过按键可以控制系统的LED灯,表示系统状态;
1.2 通过屏幕显示传感器的采集数据;
1.3 控制蜂鸣器进行监测异常报警;
1.4 借助ADC转换器采集电压值并显示;
1.5 借助光强传感器、红外距离传感器、温湿度传感器采集环境数据,并显示;
1.6 通过云端控制系统,并实现系统状态的查询。
当使用vscode软件编译之后,如果出现如图2- 1- 1即可表示创建的项目已完成了正常编译。
实例程序如图2- 1- 2。编写完成之后,先点击编译,再点击烧录。点击烧录之后,当出现图2- 1- 3之后,说明程序已经正常完成了烧录。
HaaS EDUk1板载了三个可编程LED,分别是L1, L2, L3, 分别为红、绿、蓝三个单色灯。
typedef struct {
uint8_t port; /*gpio的引脚号/端口号*/
gpio_config_t config; /*gpio的配置信息*/
void *priv; /*私有数据*/
} gpio_dev_t;
流水灯具体分为两步,第一步是对led灯进行初始化,第二步就是在循环当中按照顺序依次点亮和熄灭对应的led灯。
第一步:我们使用结构体pio_dev_t分别定义led1,led2,led3这三个变量。随后通过查询开发版手册查询到端口号和配置信息,我们对定义的变量进行初始化操作。初始化操作后使用hal_gpio_init(&变量名)保存操作。保存完成之后,我们的led初始化就已经完成了。如图2- 2- 3。
第二步:项目中hal_gpio_output_high(&变量名)hal_gpio_output_low(&变量名)函数分别控制的led灯亮和灭。我们在while(1)循环中按照依次对不同led灯进行点亮或者熄灭,两个灯亮灭之间要使用延时函数aos_msleep(延时时间)使得人眼可以观察到(防止余晖效应)。最后无限循环下去就可以实现本次的流水灯实验。如图2- 2- 4。
编码按键:由专门的硬件进行驱动,生成了键码值或者是键值对。
非编码按键:由软件编程进行控制。
分析原理图:
当按键被按下时,检测到引脚是一个低电平
当按键未被按下时,检测到引脚是一个高电平
电容:去滤波、充放电的作用
电阻:当按键未按下时,检测到是一个高电平
此实验中采用中断的方式
HaaS EDU k1板载了四个可编程按键,分别是K1, k2, K3, K4四个按键对应的GPIO如图2- 3- 1。
蜂鸣器是一种非常简单的发声器件,播放使用的扬声器不同,蜂鸣器只能播放较为简单的频率。
从驱动原理上区分,蜂鸣器可以分为无源蜂鸣器和有源蜂鸣器。这里的“源”,指的就是有无驱动源。
有源蜂鸣器:内部有rc震荡电路,只需要给控制引脚一个高电平即可,内部的rc震荡电路就会产生方波.这个方波控制线圈是否吸合薄片,从而决定是否发声。
无源蜂鸣器:内部没有rc震荡电路,需要给控制引脚一个方波,它就可以发声了。
PWM定义: 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,通过调节占空比,就可以调节脉冲宽度(脉宽时间) ,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。
PWM频率: 是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);也就是说一秒钟PWM有多少个周期。其脉冲示意图如
单位: Hz
表示方式: 50Hz 100Hz
如果频率为50Hz ,也就是说一个周期是20ms 那么一秒钟就有 50次PWM周期
占空比:是一个脉冲周期内,高电平的时间与整个周期时间的比例
单位: % (0%-100%)
表示方式:20%
首先对蜂鸣器进行初始化,初始化函数如图2- 3- 2。初始化之后我们调用hal库里面的函数hal_pwm_start()和hal_pwm_stop(),如图2- 3- 3。当程序烧录成功之后,我们可以听到蜂鸣器实现了报警功能。
1、HaaS EDU K1 自带了一块1.3寸132*64的OLED屏幕,黑底白字.芯片采用SH1106,使用SPI驱动。
2、OLED,即有机发光二极管(Organic Light-Emitting Diode)。OLED 由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板等优异之特性。
与LCD相比,LCD需要背光,同样的显示,OLED 效果要来得好一些,OLED分辨率可以做到很高。
四种扫描方式:逐行扫描、逐列扫描、列行式扫描、行列式扫描。此屏幕采用的是列行式的扫描方式。四种扫描方式如图2- 4- 1。本屏幕采用方式示意图,如图2- 4- 2。
将取模软件进行解压并注册。注册完成之后,我们可以看到如图2- 4 -3,我们使用取模软件,对自己想要生成图片进行取模。
我们使用取模软件得到自己想要的图像数组。随后我们调用初始化函数sh1106_init()和屏幕清理函数OLED_Clear(),对屏幕进行预处理。最后我们使用void OLED_Show_Uimge(uint8_t *Name,int leftx,int lefty,int rightx,int righty)函数,我们进行编译和烧录就可以在屏幕上看到取模后的图片。
#include "aos/init.h"
#include "board.h"
#include
#include
#include
#include
#include
//按ctrl+s进行保存或者是跳转到其他界面
//将此头文件选中之后按f12键进行跳转,或者是
//选中头文件点击右键选择跳转到定义
#include //gpio的头文件
#include //引脚号
#include //pwm的头文件
#include //sh1106芯片的头文件
#include //iic总线通信协议
#include //adc转换器
#define PORT 1
#define DEVADDR 0x40
#define DATA 0x00
//定义一个全局结构体变量
i2c_dev_t IIC1;
//采用主模式获取温湿度函数
void temphumi_data(float *TTmp,float *HHui){
//为结构体变量进行赋值
IIC1.port = PORT;
IIC1.config.address_width = I2C_HAL_ADDRESS_WIDTH_7BIT; //寻址模式7位
IIC1.config.dev_addr = DEVADDR; //设备地址
IIC1.config.freq = I2C_BUS_BIT_RATES_400K; //通信速度
IIC1.config.mode = I2C_MODE_MASTER; //主模式
IIC1.priv = NULL; //无私有数据
//保存初始化
hal_i2c_init(&IIC1);
//iic主模式发送数据
uint8_t data = DATA;
uint8_t buf[4] = {0};
//保存温湿度的临时变量
int temp = 0;
int humi = 0;
hal_i2c_master_send(&IIC1,DEVADDR,&data,1,1000);
aos_msleep(1000); //保证数据完整性
//iic主模式接收数据
hal_i2c_master_recv(&IIC1,DEVADDR,buf,4,1000);
//将数据进行拼接保存到临时变量中
temp = (buf[0] <<8)+ buf[1];
humi = (buf[2] <<8)+ buf[3];
//将数据进行转换
*TTmp = ((165.0f * (float)temp) / 65535.0f) - 40.0f;
*HHui = (100.0f * (float)humi) / 65535.0f;
}
//相对于是main函数,是应用程序入口函数
int application_start(int argc, char *argv[])
{
float tempp,humii;
//防止程序跑飞
while (1) {
temphumi_data(&tempp,&humii);
//%.2f和%0.2f等价的,保留两位小数
printf("temp:%.2f humi:%.2f\n",tempp,humii);
aos_msleep(1000);
};
}
ADC转换器将模拟量转换成数据量,模拟量是连续的,数字量是离散的。如图2- 6- 1。
int32_t hal_adc_init(adc_dev_t *adc);
功能:adc硬件初始化接口
参数:
adc:adc的设备
返回值:
0:成功 非0:失败
typedef struct {
uint8_t port; /*adc的端口号*/
adc_config_t config; /*adc的配置信息 */
void *priv; /*私有数据*/
} adc_dev_t;
typedef struct {
uint32_t sampling_cycle; /*adc的采样周期*/
} adc_config_t;
int32_t hal_adc_value_get(adc_dev_t *adc, uint32_t *output,
uint32_t timeout);
功能:获取adc的采样数据
参数:
adc:adc的设备
output:采样数据
timeout:超时时间(毫秒)
#define HAL_WAIT_FOREVER 0xFFFFFFFFU
返回值:
0:成功 非0:失败
int32_t hal_adc_finalize(adc_dev_t *adc);
功能:取消ADC硬件接口初始化
参数:
adc:adc的设备
返回值:
0:成功 非0:失败
我们先对ADC模块初始化,如图2- 6- 2。初始化之后,直接调用int32_t hal_adc_value_get(adc_dev_t *adc, uint32_t *output,uint32_t timeout);函数就可以在终端上看到打印的电压信息。
本实验的主要结果是通过I2C总线控制光强度传感器AP3216C对环境光强度及物体接近情况进行测量并获取环境光强度及是否有物体靠近,然后通过OLED显示屏将读取到的光强度、接近程度、红外信息显示在HaaS EDU K1的屏幕上。
AP3216C工作模式介绍
根据AP32 16C的datasheet说明,在正常工作时,它共有3种工作模式:
ALS模式
在这种模式下,AP3216C只对光强度进行量测
PS+IR模式
在这种模式下,AP3216C只对接近程度进行量测
AL S+PS+IR模式
在这种模式下,AP3216C会同时对光强度及接近程度进行测量
void ap3216c_init(void);
功能:光照传感器的初始化函数
参数:无参数
返回值:无返回值
uint16_t ap3216c_read_ambient_light(void);
功能:获取光照值
参数:无参数
返回值:光照的数据
uint16_t ap3216c_read_ps_data(void);
功能:获取距离值
参数:无参数
返回值:距离的数据
uint16_t ap3216c_read_ir_data(void);
功能:获取红外值
参数:无参数
返回值:红外的数据
#include "aos/init.h"
#include "board.h"
#include
#include
#include
#include
#include
//按ctrl+s进行保存或者是跳转到其他界面
//将此头文件选中之后按f12键进行跳转,或者是
//选中头文件点击右键选择跳转到定义
#include //gpio的头文件
#include //引脚号
#include //pwm的头文件
#include //sh1106芯片的头文件
#include //iic总线通信协议
#include //adc转换器
//相对于是main函数,是应用程序入口函数
int application_start(int argc, char *argv[])
{
int data[3] = {0};
uint8_t light[50] = {0};
uint8_t ps[50] = {0};
uint8_t ir[50] = {0};
//调用初始化函数
ap3216c_init();
sh1106_init();
//防止程序跑飞
while (1) {
//获取光照值
data[0] = ap3216c_read_ambient_light();
//获取距离值
data[1] = ap3216c_read_ps_data();
//获取红外值
data[2] = ap3216c_read_ir_data();
sprintf(light,"light:%d",data[0]);
sprintf(ps,"ps:%d",data[1]);
sprintf(ir,"ir:%d",data[2]);
OLED_Clear();
OLED_Show_String(5,5,light,12,1);
OLED_Show_String(5,25,ps,12,1);
OLED_Show_String(5,45,ir,12,1);
OLED_Refresh_GRAM();
aos_msleep(1000);
};
}
第一步:新建项目,如图2- 8 -1;
第二步:创建项目,如图2- 8 - 2;
第三步:创建物模型,如图2- 8 - 3;
最后,调试程序,如图2- 8 - 4。
#include "aos/init.h"
#include "board.h"
#include
#include
#include
#include
#include
//按ctrl+s进行保存或者是跳转到其他界面
//将此头文件选中之后按f12键进行跳转,或者是
//选中头文件点击右键选择跳转到定义
#include //gpio的头文件
#include //引脚号
#include //pwm的头文件
#include //sh1106芯片的头文件
#include //iic总线通信协议
#include //adc转换器
//相对于是main函数,是应用程序入口函数
int application_start(int argc, char *argv[]) {
int data[3] = {0}; uint8_t ps[50] = {0};
uint8_t ir[50] = {0}; uint8_t light[50] = {0};
//调用初始化函数
ap3216c_init();
sh1106_init();
//防止程序跑飞
while (1) {
//获取光照值
data[0] = ap3216c_read_ambient_light();
//获取距离值
data[1] = ap3216c_read_ps_data();
//获取红外值
data[2] = ap3216c_read_ir_data();
sprintf(light,"light:%d",data[0]);
sprintf(ps,"ps:%d",data[1]);
sprintf(ir,"ir:%d",data[2]);
OLED_Clear();
OLED_Show_String(5,5,light,12,1);
OLED_Show_String(5,25,ps,12,1);
OLED_Show_String(5,45,ir,12,1);
OLED_Refresh_GRAM();
aos_msleep(1000);
};
}
#include "aos/init.h"
#include "board.h"
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 0 //pwm的端口号
//定义结构体变量
pwm_dev_t buz;
void buz_init () {
buz.port = PORT; //端口号
buz.config.duty_cycle = 0.1; //占空比10%
buz.config.freq = 1000; //频率 1000
buz.priv = NULL;
hal_pwm_init(&buz); //保存初始化
}
int application_start (int argc, char *argv[])
{
buz_init (); //蜂鸣器初始化
while(1)
{
//实现蜂鸣器功能
hal_pwm_start(&buz);
aos_msleep(500);
hal_pwm_stop(&buz);
aos_msleep(500);
}//防止程序跑飞
}
蜂鸣器发出间断的声音。
void temphumi_data(float *TEMP, float *HUMI) {
IIC1.port = PORT;
IIC1.config.address_width = I2C_HAL_ADDRESS_WIDTH_7BIT;
IIC1.config.dev_addr = DEVADDR;
IIC1.config.freq = I2C_BUS_BIT_RATES_400K;
IIC1.config.mode = I2C_MODE_MASTER;
IIC1.priv = NULL;
hal_i2c_init(&IIC1);
aos_msleep (1000); //保存数据完整性
uint8_t data = DATA;
uint8_t buf[4] = { 0 };
int temp = 0; //温度
int humi = 0; //湿度
hal_i2c_master_send(&IIC1, DEVADDR, &data, 1, 1000);
aos_msleep (1000); //保存数据完整性
hal_i2c_master_recv(&IIC1, DEVADDR, buf, 4, 1000);
temp = (buf[0] << 8) | buf[1];
humi = (buf[2] << 8) | buf[3];
*TEMP = ((165.0f * (float)temp) / 65535.0f) - 40.0f;
*HUMI = (100.0f * (float)humi) / 65535.0f;
}
int application_start (int argc, char *argv[])
{
int data = 0; //采样数据
adc_dev_t adc1;
adc1.port = PORT; //端口号
adc1.config.sampling_cycle = 100; //采样周期
adc1.priv = NULL;
hal_adc_init(&adc1); //保存数据
while(1)
{
hal_adc_value_get(&adc1, &data, HAL_WAIT_FOREVER);
data = data * 3;
printf("data = %.2f\n", (float)data / 1000);
aos_msleep(1000);
} //防止程序跑飞
}
int application_start (int argc, char *argv[])
{
int data[3] = { 0 };
uint8_t data_0[20], data_1[20], data_2[20];
get_led1_init();
ap3216c_init();
sh1106_init();
while(1)
{
data[0] = ap3216c_read_ambient_light();
data[1] = ap3216c_read_ps_data();
data[2] = ap3216c_read_ir_data();
sprintf(data_0, "light:%d\n", data[0]);
sprintf(data_1, "ps:%d\n", data[1]);
sprintf(data_2, "ir:%d\n", data[2]);
if (data[0] > 1000) {
hal_gpio_output_high(&led1);
} else {
hal_gpio_output_low(&led1);
}
OLED_Clear();
sh1106_show_string(5, 5, data_0, 12, 1);
sh1106_show_string(5, 25, data_1, 12, 1);
sh1106_show_string(5, 45, data_2, 12, 1);
printf("light:%d, ps:%d, ir:%d\n", data[0], data[1], data[2]);
OLED_Refresh_GRAM();
aos_msleep(1000);
}//防止程序跑飞
}
在完成这个项目的过程中,我学习到了许多与嵌入式开发和物联网相关的知识和技能。以下是我在整个项目中所学到的主要内容:
刚开始,通过学习整个项目的构架,我了解了各个模块的功能和彼此间的关系。通过使用VSCode软件,我学会了如何搭建开发环境,并成功地创建了示例项目并进行了正常的编译操作。这为我更好地理解项目的需求和目标提供了基础。
在搭建好开发环境之后,老师带领我们复习了与项目相关的C语言基础知识,包括语法、函数和指针等。这些知识对我理解项目代码和进行开发工作非常有帮助。我还通过连接开发版成功实现了程序的烧录,加深了对硬件与软件之间交互的理解。
接着,通过了解GPIO和项目中各个接口函数的作用,我成功地实现了LED流水灯以及通过按键控制LED闪烁的功能;通过利用PWM来控制蜂鸣器,我实现了警报功能。通过调用#include
在项目的过程中也不是一帆风顺的,我也遇到了一些挑战和问题。例如,在配置VSCode时,由于环境变量的问题导致程序一直无法正常编译。通过老师的指导,我最终解决了编译问题;另外,刚开始使用显示屏时,遇到了图片无法完全显示的问题,最后通过正确设置取模软件的参数,我成功地解决了这个问题;在调用中断函数时,遇到了无法正常调用的情况。最后发现是函数体内的参数设定有误,修改后问题得以解决。
通过本次项目开发提高了我对硬件模块和接口的应用能力,我不仅解决了具体的问题,还在实践中获得了宝贵的经验和教训。我学会了更加仔细地检查和分析代码,排除错误的可能性。同时,我也提高了解决问题的能力和自信心,明白了遇到困难时要积极主动地寻求帮助,并且善于与他人合作共同解决问题。这些经验将对我的未来学习和工作具有持久的影响。