项目5 智 能 安 防 项目5 本项目通过鸿蒙App控制Hi3861开发板,连接HCSR04超声波传感器,实现智能安防系统。 5.1总体设计 本部分包括系统架构和系统流程。 5.1.1系统架构 系统架构如图51所示,Hi3861开发板与外设引脚连线如表51所示。 图51系统架构 表51Hi3861开发板与外设引脚连线 Hi3861开发板HCSR04超声波光敏传感器蜂鸣器OLED串口屏 5VVCCVCCVCCVCC GNDGNDGNDGNDGND GPIO11Trig/// GPIO12Echo/// GPIO10/DO// GPIO5//I/O/ GPIO13///SCL GPIO14///SDA 板载LED/// 5.1.2系统流程 系统流程如图52所示。 图52系统流程 5.2模块介绍 本项目由VSCode和DevEco Studio开发,包括超声波测距、光敏感知、蜂鸣器控制、OLED显示、WiFi模块、OneNET云平台和前端模块。下面分别给出各模块的功能介绍及相关代码。 5.2.1超声波测距 该模块主要利用超声波模块进行测距,将GPIO11设置为输出,每个周期给Trig引脚发送20~50μs的脉冲,激发超声波模块发出8组超声波,当接收到返回信号时,Echo产生相应的高电平脉冲,脉冲的宽度、声波与返回时间有关,之后便可以计算距离,相关代码如下: float GetDistance(void) { static unsigned long start_time = 0, time = 0; float distance = 0.0; IotGpioValue value = IOT_GPIO_VALUE0; unsigned int flag = 0; //超声波传感器Trig为GPIO11,Echo为GPIO12 IoTGpioSetDir(HI_IO_NAME_GPIO_12, IOT_GPIO_DIR_IN); IoTGpioSetDir(HI_IO_NAME_GPIO_11, IOT_GPIO_DIR_OUT); //触发Trig IoTGpioSetOutputVal(HI_IO_NAME_GPIO_11, IOT_GPIO_VALUE1); hi_udelay(20); IoTGpioSetOutputVal(HI_IO_NAME_GPIO_11, IOT_GPIO_VALUE0); //检测Echo高电平时间 while (1) { IoTGpioGetInputVal(HI_IO_NAME_GPIO_12, &value); if ( value == IOT_GPIO_VALUE1 && flag == 0) { start_time = hi_get_us(); flag = 1; } if (value == IOT_GPIO_VALUE0 && flag == 1) { time = hi_get_us() -start_time; start_time = 0; break; } } //计算距离 distance = time * 0.034 / 2; printf("[Distance]:%f.\r\n",distance); return distance; } 5.2.2光敏感知 通过光敏电阻感知外界光强,当外界光强低于某个阈值时,则传感器的DO口会给出一个高电平,根据是否接收到高电平判断板载LED亮灭。 #define LED_TEST_GPIO 9//使用hispark_pegasus开发板 void GetLight(void) { IotGpioValue value = IOT_GPIO_VALUE0; //初始化LED的GPIO IoTGpioInit(LED_TEST_GPIO); //设置为输入/输出 IoTGpioSetDir(LED_TEST_GPIO, IOT_GPIO_DIR_OUT); //设置光敏传感器的DO口 IoTGpioSetDir(HI_IO_NAME_GPIO_10, IOT_GPIO_DIR_IN); if(led_flag==2){ IoTGpioSetDir(LED_TEST_GPIO, 1); //LED亮 } else{ IoTGpioGetInputVal(HI_IO_NAME_GPIO_10, &value); if ( value == IOT_GPIO_VALUE1 ) { IoTGpioSetDir(LED_TEST_GPIO, 1); //LED亮 led_flag = 1; printf("on\n"); } if (value == IOT_GPIO_VALUE0 ) { IoTGpioSetDir(LED_TEST_GPIO, 0); //LED灭 led_flag = 0; printf("off\n"); } } } 5.2.3蜂鸣器控制 通过简单的高低电平控制声响。 void BeepRing(void) { //初始化GPIO IoTGpioInit(HI_IO_NAME_GPIO_5); //设置为输出 IoTGpioSetDir(HI_IO_NAME_GPIO_5, IOT_GPIO_DIR_OUT); //GPIO复用 hi_io_set_func(HI_IO_NAME_GPIO_5,HI_IO_FUNC_GPIO_5_GPIO); //输出低电平 IoTGpioSetOutputVal(HI_IO_NAME_GPIO_5,0); beep_flag=0; printf("BeepRing\n"); } void BeepStop(void) { //初始化GPIO IoTGpioInit(HI_IO_NAME_GPIO_5); //设置为输出 IoTGpioSetDir(HI_IO_NAME_GPIO_5, IOT_GPIO_DIR_OUT); //GPIO复用 hi_io_set_func(HI_IO_NAME_GPIO_5,HI_IO_FUNC_GPIO_5_GPIO); //输出高电平 IoTGpioSetOutputVal(HI_IO_NAME_GPIO_5,1); beep_flag=1; printf("BeepStop\n"); } 5.2.4OLED显示 SSD1306逻辑功能代码如下: void OLED(void) { IoTGpioInit(HI_IO_NAME_GPIO_13); IoTGpioInit(HI_IO_NAME_GPIO_14); hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA); hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL); IoTI2cInit(0, OLED_I2C_BAUDRATE); usleep(20*1000); ssd1306_Init(); ssd1306_Fill(Black); ssd1306_SetCursor(0, 0); if(distance_flag==0){ ssd1306_DrawString("Be Carefully!", Font_11x18, White); ssd1306_UpdateScreen(); printf("test1"); } else{ ssd1306_DrawString("Safe", Font_11x18, White); ssd1306_UpdateScreen(); printf("test2"); } } 5.2.5WiFi模块 WiFi连接相关代码如下: void wifi_wpa_event_cb(const hi_wifi_event *hisi_event) { if (hisi_event == NULL) return; switch (hisi_event->event) { case HI_WIFI_EVT_SCAN_DONE: printf("WiFi: Scan results available\n"); break; case HI_WIFI_EVT_CONNECTED: printf("WiFi: Connected\n"); netifapi_dhcp_start(g_lwip_netif); wifi_ok_flg = 1; break; case HI_WIFI_EVT_DISCONNECTED: printf("WiFi: Disconnected\n"); netifapi_dhcp_stop(g_lwip_netif); hi_sta_reset_addr(g_lwip_netif); break; case HI_WIFI_EVT_WPS_TIMEOUT: printf("WiFi: wps is timeout\n"); break; default: break; } } int hi_wifi_start_connect(void) { int ret; errno_t rc; hi_wifi_assoc_request assoc_req = {0} rc = memcpy_s(assoc_req.ssid, HI_WIFI_MAX_SSID_LEN + 1, "OCF24", 8); if (rc != EOK) { return -1; } //热点加密方式 assoc_req.auth = HI_WIFI_SECURITY_WPA2PSK; //热点密码 memcpy(assoc_req.key, "xxxxxxxx", 8); ret = hi_wifi_sta_connect(&assoc_req); if (ret != HISI_OK) { return -1; } return 0; } int hi_wifi_start_sta(void) { int ret; char ifname[WIFI_IFNAME_MAX_SIZE + 1] = {0}; int len = sizeof(ifname); const unsigned char wifi_vap_res_num = APP_INIT_VAP_NUM; const unsigned char wifi_user_res_num = APP_INIT_USR_NUM; unsigned intnum = WIFI_SCAN_AP_LIMIT; ret = hi_wifi_sta_start(ifname, &len); if (ret != HISI_OK) { return -1; } ret = hi_wifi_register_event_callback(wifi_wpa_event_cb); if (ret != HISI_OK) { printf("register wifi event callback failed\n"); } g_lwip_netif = netifapi_netif_find(ifname); if (g_lwip_netif == NULL) { printf("%s: get netif failed\n", __FUNCTION__); return -1; } //开始扫描附近的WiFi热点 ret = hi_wifi_sta_scan(); if (ret != HISI_OK) { return -1; } sleep(5); hi_wifi_ap_info *pst_results = malloc(sizeof(hi_wifi_ap_info) * WIFI_SCAN_AP_LIMIT); if (pst_results == NULL) { return -1; } //将扫描到的热点结果进行存储 ret = hi_wifi_sta_scan_results(pst_results, &num); if (ret != HISI_OK) { free(pst_results); return -1; } //打印扫描到的所有热点 for (unsigned int loop = 0; (loop < num) && (loop < WIFI_SCAN_AP_LIMIT); loop++) { printf("SSID: %s\n", pst_results[loop].ssid); } free(pst_results); //开始接入热点 ret = hi_wifi_start_connect(); if (ret != 0) { return -1; } return 0; } void wifi_sta_task(void *arg) { arg = arg; //连接热点 hi_wifi_start_sta(); while(wifi_ok_flg == 0) { usleep(30000); } usleep(2000000); 5.2.6OneNET云平台 本部分包括创建账号、创建产品、添加设备和相关代码。 1. 创建账号 登录网页https://open.iot.10086.cn/passport/reg/,按要求填写注册信息后进行实名认证。 2. 创建产品 进入Studio平台后,在全部产品服务中选择多协议接入。 单击“添加产品”按钮,在弹出页面中按照提示填写产品信息。本项目采用MQTT协议接入,如图53所示。 图53创建产品 3. 添加设备 单击“设备管理”,选择“添加设备”,按照提示填写相关信息,如图54所示。 图54添加设备 4. 相关代码 下面给出实现连接OneNET云平台及整个系统的逻辑控制代码。 void onenet_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size) { printf("recv data is %.*s\n", recv_size, recv_data); strcpy(temp1, (char *)(recv_data)); //暂存recv data int messageCode = (temp1[2] - '0') ; printf("messageCode is %d\n", messageCode); if(messageCode==0){ BeepStop(); printf("Beep\n"); } if(messageCode==1){ IoTGpioSetDir(LED_TEST_GPIO, 1); //LED亮 led_flag = 2; printf("LED ON\n"); } if(messageCode==2){ IoTGpioSetDir(LED_TEST_GPIO, 1); //LED灭 led_flag = 0; printf("LED OFF\n"); } *resp_data = NULL; *resp_size = 0; } int onenet_test(void) { device_info_init(ONENET_INFO_DEVID, ONENET_INFO_PROID, ONENET_INFO_AUTH, ONENET_INFO_APIKEY, ONENET_MASTER_APIKEY); onenet_mqtt_init(); onenet_set_cmd_rsp_cb(onenet_cmd_rsp_cb); IoTWatchDogDisable(); while (1) { GetLight(); temp = GetDistance(); OLED(); //连续判断,防止错判 if(temp<3){ count++; } else{ count=0; } if(temp<3&&count>3){ BeepRing(); //蜂鸣器响 printf("[Beep]:%d.\r\n",beep_flag); distance_flag=0; printf("[person]:%d.\r\n",distance_flag); } else{ BeepStop(); //蜂鸣器不响 printf("[person]:%d.\r\n",distance_flag); distance_flag=1; } //上传至OneNET if (onenet_mqtt_upload_digit("person", distance_flag) < 0) { printf("upload has an error, stop uploading"); //break; } else { printf("buffer : {\"person\":%d} \r\n", distance_flag); } sleep(1); } return 0; } 5.2.7前端模块 本部分包括界面设计和发送POST请求。 1. 界面设计 <?xml version="1.0" encoding="utf-8"?> <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:alignment="horizontal_center" ohos:orientation="vertical"> <Text ohos:id="$+id:text_type_get" ohos:height="60vp" ohos:width="match_parent" ohos:text_alignment="center" ohos:layout_alignment="horizontal_center" ohos:text="GET请求" ohos:text_size="30vp" /> <Text ohos:id="$+id:text_type_post" ohos:height="60vp" ohos:text_alignment="center" ohos:width="match_parent" ohos:background_element="#ed6262" ohos:layout_alignment="horizontal_center" ohos:text="POST请求" ohos:text_size="30vp" /> <ScrollView ohos:height="match_parent" ohos:width="match_parent" > <DirectionalLayout ohos:height="match_parent" ohos:width="match_parent"> <Text ohos:id="$+id:text_result" ohos:height="match_parent" ohos:multiple_lines="true" ohos:text_alignment="center" ohos:width="match_parent" ohos:layout_alignment="horizontal_center" ohos:text="显示结果" ohos:text_size="20vp" /> </DirectionalLayout> </ScrollView> </DirectionalLayout> 2. 发送POST请求 package com.example.afinal.slice; import com.example.afinal.ResourceTable; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.components.Component; import ohos.agp.components.Text; import okhttp3.*; import java.io.IOException; public class MainAbilitySlice extends AbilitySlice { //private static AbilityForm textResult; Text TextGet, TextPost, textResult; private boolean status; final String cloud_url = "http://api.heclouds.com/cmds?device_id=962845387"; @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); TextGet = findComponentById(ResourceTable.Id_text_type_get); TextPost = findComponentById(ResourceTable.Id_text_type_post); textResult = findComponentById(ResourceTable.Id_text_result); TextGet.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { OkHttpClient client = new OkHttpClient(); Request.Builder requestBuilder = new Request.Builder(); requestBuilder.addHeader("api-key","CT0J7NvniU4E5hsdH4emD=FzKs0="); HttpUrl.Builder urlBuilder = HttpUrl.parse("http://api.heclouds.com/devices/962845387/datapoints").newBuilder(); //todo接口链接 urlBuilder.addQueryParameter("datastream_id", "temperature"); //参数 urlBuilder.addQueryParameter("limit","4"); //密钥 requestBuilder.url(urlBuilder.build()); Call call = client.newCall(requestBuilder.build()); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { //todo失败回调需要回到主线程显示结果 getUITaskDispatcher().asyncDispatch(new Runnable() { @Override public void run() { textResult.setText(e.getMessage()); } }); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { String result = response.body().string(); //处理界面需要切换到界面线程处理 getUITaskDispatcher().asyncDispatch(new Runnable() { @Override public void run() { textResult.setText(result); } }); } } }); } }); TextPost.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { textResult.setText("post can be pressed"); OkHttpClient client = new OkHttpClient(); FormBody body = new FormBody.Builder() .add("temperature", "77")//日期参数 .build(); Request request = new Request.Builder() .header("api-key", "CT0J7NvniU4E5hsdH4emD=FzKs0=") .url("http://api.heclouds.com/cmds?device_id=962845387") .post(body) .build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { //失败回调需要回到主线程显示结果 getUITaskDispatcher().asyncDispatch(new Runnable() { @Override public void run() { textResult.setText(e.getMessage()); } }); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { String result = response.body().string(); //处理界面需要切换到界面线程处理 //失败回调需要回到主线程显示结果 getUITaskDispatcher().asyncDispatch(new Runnable() { @Override public void run() { textResult.setText(result); } }); } } }); } }); } 5.3产品展示 Hi3861开发板的实现效果如图55所示,串口监视器效果如图56所示,鸿蒙App的实现效果如图57所示。 图55Hi3861开发板实现效果 图56串口监视器效果 图57App页面效果 5.4元件清单 完成本项目所需的元件及数量如表52所示。 表52元件清单 元件/测试仪表数量元件/测试仪表数量 面包板1个光敏模块1个 Hi38611个蜂鸣器1个 HCSR04超声波传感器1个OLED串口屏1个