按照board和soc分离要求整改代码

Signed-off-by: Laowang-BearPi <wangcheng@holdiot.com>
This commit is contained in:
Laowang-BearPi
2022-01-11 13:21:56 +08:00
parent 6e213078ba
commit 64b507c059
702 changed files with 74396 additions and 56 deletions
Regular → Executable
+6 -29
View File
@@ -1,36 +1,13 @@
# device_board_bearpi
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Introduce
#### Software Architecture
Software architecture description
It is used to place bearpi development boards. For details, see readme of each development board
#### Installation
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
For installation tutorials, see readme on each development board.
#### Instructions
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
See readme on each development board.
Regular → Executable
+3 -27
View File
@@ -1,39 +1,15 @@
# device_board_bearpi
#### 介绍
{**以下是 Gitee 平台说明,您可以替换此简介**
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
#### 软件架构
软件架构说明
本仓用于放置BearPi开发板板相关内容,详情请参见各开发板readme。
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
安装教程请参见各开发板readme。
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
请参见各开发板readme。
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+26
View File
@@ -0,0 +1,26 @@
# Copyright (c) 2021 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/lite/config/component/lite_component.gni")
build_ext_component("run_bearpi_hm_nano_scons") {
exec_path = rebase_path(".", root_build_dir)
outdir = rebase_path(root_out_dir)
if (host_os == "win") {
command = "sh bearpi_hm_nano_build.sh $outdir win"
} else {
command = "sh bearpi_hm_nano_build.sh $outdir linux"
}
}
+127
View File
@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (C) 2021 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Notes:
This is project config file for OpenHarmony OSS Audit Tool, if you have any questions or concerns, please email chenyaxun.
-->
<!-- OAT(OSS Audit Tool) configuration guide:
basedir: Root dir, the basedir + project path is the real source file location.
licensefile:
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
tasklist(only for batch mode):
1. task: Define oat check thread, each task will start a new thread.
2. task name: Only an name, no practical effect.
3. task policy: Default policy for projects under this task, this field is required and the specified policy must defined in policylist.
4. task filter: Default filefilter for projects under this task, this field is required and the specified filefilter must defined in filefilterlist.
5. task project: Projects to be checked, the path field define the source root dir of the project.
policyList:
1. policy: All policyitems will be merged to default OAT.xml rules, the name of policy doesn't affect OAT check process.
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
3. policyitem type:
"compatibility" is used to check license compatibility in the specified path;
"license" is used to check source license header in the specified path;
"copyright" is used to check source copyright header in the specified path;
"import" is used to check source dependency in the specified path, such as import ... ,include ...
"filetype" is used to check file type in the specified path, supported file types: archive, binary
"filename" is used to check whether the specified file exists in the specified path(support projectroot in default OAT.xml), supported file names: LICENSE, README, README.OpenSource
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
7. policyitem filefilter: Used to bind filefilter which define filter rules.
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
Note:If the text contains special characters, please escape them according to the following rules:
" == &gt;
& == &gt;
' == &gt;
< == &gt;
> == &gt;
-->
<configuration>
<oatconfig>
<licensefile>sdk_liteos/license/LICENSE</licensefile>
<policylist>
<policy name="projectPolicy" desc="">
<policyitem type="copyright" name="Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED." path=".*" desc="HiSilicon copyright"/>
<policyitem type="copyright" name="Copyright (c) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED." path=".*" desc="HiSilicon copyright"/>
<policyitem type="copyright" name="Copyright (C) 2020 Hisilicon (Shanghai) Technologies Co., Ltd. All rights reserved." path=".*" desc="HiSilicon copyright"/>
<policyitem type="license" name="BSD-3-Clause" path=".*" desc="HiSilicon copyright"/>
<policyitem type="license" name="EndUserLicenseAgreement" path=".*" desc="HiSilicon copyright"/>
</policy>
</policylist>
<filefilterlist>
<filefilter name="defaultFilter" desc="Files not to check">
<!--filteritem type="filename" name="*.lds|*.pod"/-->
<!--filteritem type="filepath" name="dir name underproject/.*" desc="Describe the reason for filtering scan results"/-->
</filefilter>
<filefilter name="defaultPolicyFilter" desc="Filters for compatibilitylicense header policies">
<!--filteritem type="filepath" name="dir name underproject/.*" desc="Describe the reason for filtering scan results"/-->
<filteritem type="filepath" name="sdk_liteos/platform/os/.*" desc="liteos"/>
<filteritem type="filepath" name="sdk_liteos/third_party/.*" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="hi3861_adapter/.*" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/components/iperf2/include/iperf.h" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.mk" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.sh" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.gni" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.xml" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.cfg" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.csv" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.S|*.gn" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.txt" desc="Temp files"/>
</filefilter>
<filefilter name="copyrightPolicyFilter" desc="Filters for copyright header policies" >
<filteritem type="filepath" name="sdk_liteos/platform/os/.*" desc="liteos"/>
<filteritem type="filepath" name="sdk_liteos/third_party/.*" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="hi3861_adapter/.*" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/components/iperf2/include/iperf.h" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.mk" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.sh" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.gni" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.xml" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.cfg" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.png" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.csv" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.S|*.gn" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.txt" desc="Temp files"/>
</filefilter>
<filefilter name="licenseFileNamePolicyFilter" desc="Filters for LICENSE file policies" >
<!--filteritem type="filepath" name="dir name underproject/.*" desc="Describe the reason for filtering scan results"/-->
</filefilter>
<filefilter name="readmeFileNamePolicyFilter" desc="Filters for README file policies" >
</filefilter>
<filefilter name="readmeOpenSourcefileNamePolicyFilter" desc="Filters for README.OpenSource file policies" >
<!--filteritem type="filepath" name="dir name underproject/.*" desc="Describe the reason for filtering scan results"/-->
</filefilter>
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies" >
<filteritem type="filepath" name="sdk_liteos/build/libs/.*.a" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/build/libs/.*.o" desc="Describe the reason for filtering scan results"/>
<filteritem type="filename" name="*.exe|*.bin|*.png" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/tools/nvtool/tools/nv/cdbm" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/tools/lzma_tool/lzma_tool" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/build/scripts/ota_builder" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/tools/sign_tool/sign_tool" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/tools/nvtool/nv_builder" desc="Describe the reason for filtering scan results"/>
<filteritem type="filepath" name="sdk_liteos/third_party/u-boot-v2019.07/u-boot-v2019.07.tar.gz" desc="Describe the reason for filtering scan results"/>
</filefilter>
</filefilterlist>
</oatconfig>
</configuration>
+103
View File
@@ -0,0 +1,103 @@
# BearPi-HM Nano<a name="ZH-CN_TOPIC_0000001130176841"></a>
- [Get source code](#section11660541590)
- [Construction of development environment](#section11660541591)
- [Source code compilation](#section11660541592)
- [Firmware burning](#section11660541593)
- [Introduction to development board](#section11660541593)
- [Development board details](#section12212842173518)
- [Application](#section1464106163819)
## Get source code<a name="section11660541590"></a>
```
repo init -u git@gitee.com:openharmony/manifest.git -b master --no-repo-verify
repo sync -c
repo forall -c 'git lfs pull'
```
## Construction of development environment<a name="section11660541591"></a>
Please refer to [Hi3861 development environment construction](https://gitee.com/openharmony/docs/blob/master/en/device-dev/quick-start/quickstart-lite-steps-hi3861-setting.md)
## Source code compilation<a name="section11660541592"></a>
```
hb set
bearpi
>bearpi_hm_nano
选择bearpi_hm_nano
hb build -f
```
## Firmware burning<a name="section11660541593"></a>
1. Open hiburn tool in windows, click 'Refresh', and select com number in 'com', as shown in the following figure。
![](docs/quick-start/figures/HiBurn_Main_interface.png)
Then click 'Setting' and select 'Com settings'.
2. Set 'Baud' to '921600' in com settings, and click OK, as shown in the figure below.
![](docs/quick-start/figures/HiBurn_Comsettings.png)
3. Click the 'select file' button in hiburn tool, and in the pop-up file box, select the './out/bearpi_hm_nano/bearpi_hm_nano/' file under the 'Hi3861_wifiiot_app_allinone.bin' path of the project file, as shown in the following figure.
![](docs/quick-start/figures/HiBurn_Open_file.png)
4. Click the 'Auto burn' check box, and then click 'Connect', as shown in the following figure.
![](docs/quick-start/figures/HiBurn_Ready_to_download.png)
The 'Connect' button changes to 'Disconnect' and waits for the download.
5. Reset the 'RESET' button on the development board to start downloading the program, as shown in the figure below.
![](docs/quick-start/figures/Reset_development_board.png)
![](docs/quick-start/figures/Hiburn_Downloading.png)
6. Until the word "Execution Successful" appears, the program download is completed.
7. After downloading, click the 'Disconnect' button to facilitate later debugging.
## Introduction to development board<a name="section11660541593"></a>
### Development board overview
BearPi[BearPi-HM Nano](https://item.taobao.com/item.htm?id=633296694816)is a development board specially built by BearPi school for openharmony system. It carries a highly integrated 2.4GHz WiFi SoC chip hi3861, and carries NFC circuit and standard E53 interface. The standard E53 interface can expand cases such as intelligent humidifier, intelligent desk lamp, intelligent security, intelligent smoke detector, etc.
### Development board function
BearPi-HM Nano development board, for developers, is used for openharmony development and learning. At the same time, it provides rich cases and tutorials to realize full scene application design.
1. E53 interface: it is a standard interface with rich resources and easy to expand. It realizes multi application case expansion, making case development more flexible and convenient.
2. NFC: the on-board NFC RF circuit, combined with the key capabilities of openharmony, can perfectly realize the "touch and touch" networking mechanism and service pull-up function of openharmony system, reduce the complexity of user operation, and improve the user experience.
3. User keys: open function keys. The key functions are fully defined by the developer, which increases user operability.
## Development board details<a name="section12212842173518"></a>
The detailed functions of the development board are shown in the figure below:
![](figures/BearPi-HM_NanoBoardDetail.png)
## Application<a name="section1464106163819"></a>
### Development board application scenario
Bearpi_HM_Nano can be used in intelligent humidifier, intelligent desk lamp, intelligent security, intelligent smoke detector and other cases, such as the following cases.
1. Intelligent humidifier: it can monitor the current indoor temperature and humidity in real time, and can open and close the humidifier remotely and in real time.
2. Intelligent desk lamp: it can monitor the current indoor light intensity in real time. When it is lower than the predetermined threshold, the desk lamp will be turned on automatically, and the independent control of the desk lamp can be realized.
3. Intelligent security: it can monitor the movement of human body within the range in real time and report to the cloud display to realize the monitoring and alarm of intelligent security.
4. Intelligent smoke sensing: it can monitor the smoke concentration in the current room in real time and report to the cloud display. When the smoke concentration exceeds the set threshold, the alarm will trigger the alarm immediately.
## Repositories Involved<a name="section1371113476307"></a>
**device/board/bearpi/bearpi_hm_nano**
vendor/bearpi
+110
View File
@@ -0,0 +1,110 @@
# BearPi-HM Nano<a name="ZH-CN_TOPIC_0000001130176841"></a>
- [获取源码](#section11660541590)
- [开发环境搭建](#section11660541591)
- [源码编译](#section11660541592)
- [固件烧录](#section11660541593)
- [开发板介绍](#section11660541594)
- [开发板详情](#section12212842173518)
- [应用案例场景](#section1464106163819)
## 获取源码<a name="section11660541590"></a>
```
repo init -u git@gitee.com:openharmony/manifest.git -b master --no-repo-verify
repo sync -c
repo forall -c 'git lfs pull'
```
## 开发环境搭建<a name="section11660541591"></a>
请参考[Hi3861开发环境搭建](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-steps-hi3861-setting.md)
## 源码编译<a name="section11660541592"></a>
```
hb set
bearpi
>bearpi_hm_nano
选择bearpi_hm_nano
hb build -f
```
## 固件烧录<a name="section11660541593"></a>
1. 在Windows打开Hiburn工具,并点击`Refresh`,在`COM`中选择COM号,如下图所示。
- Hiburn工具下载地址(百度云):https://pan.baidu.com/s/1i6P_LuUzclS6hlQ3XHOobQ&amp;t=downloads 提取码:1234
![](docs/quick-start/figures/HiBurn主界面.png)
然后点击`Setting`,并选择 `Com settings`
2. 在Com settings中设置`Baud`为:`921600`,点击确定 ,如下图所示。
![](docs/quick-start/figures/HiBurn_Comsettings.png)
3. 点击 Hiburn工具中的`Select file`按钮,在弹出的文件框中,选择工程文件`./out/bearpi_hm_nano/bearpi_hm_nano/` 路径下的`Hi3861_wifiiot_app_allinone.bin` 文件,如下图所示。
![](docs/quick-start/figures/HiBurn_打开文件.png)
4. 点击`Auto burn`复选框,然后点击`Connect`,如下图所示。
![](docs/quick-start/figures/HiBurn准备下载.png)
此时`Connect`按钮变成`Disconnect`,等待下载。
5. 复位开发板`RESET`按键,开始下载程序,如下图所示。
![](docs/quick-start/figures/复位开发板.png)
![](docs/quick-start/figures/Hiburn_下载程序中.png)
6. 直到出现`Execution Successful`字样,程序下载完成。
7. 下载完后,点击`Disconnect`按钮,便于后面调测使用。
## 开发板介绍<a name="section11660541594"></a>
### 开发板概述
小熊派[BearPi-HM Nano](https://item.taobao.com/item.htm?id=633296694816)是一款由小熊派专为OpenHarmony系统打造的开发板,板载高度集成的2.4GHz WiFi SoC芯片Hi3861,并板载NFC电路及标准的E53接口,标准的E53接口可扩展智能加湿器、智能台灯、智能安防、智能烟感等案例。
### 开发板功能
BearPi-HM Nano开发板,面向开发者,用于OpenHarmony开发学习,同时提供丰富案例和教程,实现全场景应用设计。
1. E53 Interface:是一种资源丰富,易于扩展的标准接口,实现多应用案例扩展,使得案例开发变得更加灵活和方便。
2. NFC:板载的NFC射频电路,配合OpenHarmony开放的关键能力,可以完美实现OpenHarmony系统的“碰一碰”联网机制和服务拉起功能,降低用户操作复杂度,从而提高用户体验。
3. 用户按键:开放式功能按键,按键功能全权由开发者定义,增加了用户可操作性。
## 开发板详情<a name="section12212842173518"></a>
开发板详细功能如下图所示:
![](figures/BearPi-HM_NanoBoardDetail.png)
## 应用案例场景<a name="section1464106163819"></a>
### 开发板应用场景
BearPi-HM Nano可用于智能加湿器、智能台灯、智能安防、智能烟感等案例,如以下案例。
1. 智能加湿器:可实时监测室内当前的温湿度,可实现远程实时开启和关闭加湿器。
2. 智能台灯:可实时监测当前的室内光照强度,低于预定的阈值时,自动开启台灯,并可实现对台灯的单独控制。
3. 智能安防:可实时监测范围内人体的移动,并上报云端显示,实现智能安防的监测和警报。
4. 智能烟感:可实时监测当前房间中的烟雾浓度,并上报云端显示,当烟雾浓度超过设定的阈值时,报警器立即触发警报。
## 相关仓<a name="section1371113476307"></a>
**device/board/bearpi/bearpi_hm_nano**
vendor/bearpi
+19
View File
@@ -0,0 +1,19 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("thread_example") {
sources = [
"thread_example.c"
]
}
+118
View File
@@ -0,0 +1,118 @@
# BearPi-HM_Nano开发板OpnenHarmony内核编程开发——Thread多线程
本示例将演示如何在BearPi-HM_Nano开发板上使用cmsis 2.0 接口进行多线程开发。
## Thread API分析
### osThreadNew()
```c
osThreadId_t osThreadNew(osThreadFunc_t func, void *argument,const osThreadAttr_t *attr )
```
**描述:**
函数osThreadNew通过将线程添加到活动线程列表并将其设置为就绪状态来启动线程函数。线程函数的参数使用参数指针*argument传递。当创建的thread函数的优先级高于当前运行的线程时,创建的thread函数立即启动并成为新的运行线程。线程属性是用参数指针attr定义的。属性包括线程优先级、堆栈大小或内存分配的设置。可以在RTOS启动(调用 osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| func | 线程函数。 |
| argument |作为启动参数传递给线程函数的指针。|
| attr |线程属性。|
## 软件设计
**主要代码分析**
在ThreadExample函数中,通过osThreadNew()函数创建了Thread1和Thread2两个进程,Thread1和Thread2启动后会输出打印日志。
```c
/**
* @brief Thread1 entry
*
*/
void Thread1(void)
{
int sum = 0;
while (1) {
printf("This is BearPi-HM_Nano Thread1----%d\n", sum++);
usleep(1000000);
}
}
/**
* @brief Thread2 entry
*
*/
void Thread2(void)
{
int sum = 0;
while (1) {
printf("This is BearPi-HM_Nano Thread2----%d\n", sum++);
usleep(500000);
}
}
/**
* @brief Main Entry of the Thread Example
*
*/
static void ThreadExample(void)
{
osThreadAttr_t attr;
attr.name = "Thread1";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 25;
// Create the Thread1 task
if (osThreadNew((osThreadFunc_t)Thread1, NULL, &attr) == NULL) {
printf("Failed to create Thread1!\n");
}
// Create the Thread2 task
attr.name = "Thread2";
if (osThreadNew((osThreadFunc_t)Thread2, NULL, &attr) == NULL) {
printf("Failed to create Thread2!\n");
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `thread_example` 参与编译。
```r
"A1_kernal_thread:thread_example",
#"A2_kernel_timer:timer_example",
#"A3_kernel_event:event_example",
#"A4_kernel_mutex:mutex_example",
#"A5_kernel_semaphore:semaphore_example",
#"A6_kernel_message:message_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,Thread1和Thread2会交替打印信息。
```c
This is BearPi-HM_Nano Thread1----2
This is BearPi-HM_Nano Thread2----4
This is BearPi-HM_Nano Thread2----5
This is BearPi-HM_Nano Thread1----3
This is BearPi-HM_Nano Thread2----6
This is BearPi-HM_Nano Thread2----7
```
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
/**
* @brief Thread1 entry
*
*/
void Thread1(void)
{
int sum = 0;
while (1) {
printf("This is BearPi-HM_Nano Thread1----%d\n", sum++);
usleep(1000000);
}
}
/**
* @brief Thread2 entry
*
*/
void Thread2(void)
{
int sum = 0;
while (1) {
printf("This is BearPi-HM_Nano Thread2----%d\n", sum++);
usleep(500000);
}
}
/**
* @brief Main Entry of the Thread Example
*
*/
static void ThreadExample(void)
{
osThreadAttr_t attr;
attr.name = "Thread1";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 25;
// Create the Thread1 task
if (osThreadNew((osThreadFunc_t)Thread1, NULL, &attr) == NULL) {
printf("Failed to create Thread1!\n");
}
// Create the Thread2 task
attr.name = "Thread2";
if (osThreadNew((osThreadFunc_t)Thread2, NULL, &attr) == NULL) {
printf("Failed to create Thread2!\n");
}
}
APP_FEATURE_INIT(ThreadExample);
+18
View File
@@ -0,0 +1,18 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("timer_example") {
sources = [
"timer_example.c"
]
}
+121
View File
@@ -0,0 +1,121 @@
# BearPi-HM_Nano开发板OpnenHarmony内核编程开发——定时器
本示例将演示如何在BearPi-HM_Nano开发板上使用cmsis 2.0 接口进行定时器开发。
## Timer API分析
### osTimerNew()
```c
osTimerId_t osTimerNew (osTimerFunc_t func,osTimerType_t type,void *argument,const osTimerAttr_t *attr)
```
**描述:**
函数osTimerNew创建一个一次性或周期性计时器,并将其与一个带参数的回调函数相关联。计时器在osTimerStart启动之前一直处于停止状态。可以在RTOS启动(调用 osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| func | 函数指针指向回调函数。 |
| type | 定时器类型,osTimerOnce表示单次定时器,ostimer周期表示周期性定时器。 |
| argument |定时器回调函数的参数。|
| attr |计时器属性。|
### osTimerStart()
```c
osStatus_t osTimerStart (osTimerId_t timer_id,uint32_t ticks)
```
**描述:**
函数osTimerStart启动或重新启动指定参数timer_id的计时器。参数ticks指定计时器的计数值。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| timer_id | 由osTimerNew获得的计时器ID。 |
| ticks | 时间滴答计时器的值。 |
## 软件设计
**主要代码分析**
在TimerExample函数中,通过osTimerNew()函数创建了回调函数为Timer1Callback的定时器1,并通过osTimerStart()函数将该定时器设置为100个tick,因为hi3861默认10ms为一个tick,所以100个tick正好为1S钟,1S计时到后会触发Timer1Callback()函数并打印日志。定时器2也同理为3S触发Timer2Callback()函数并打印日志。
```c
/**
* @brief Main Entry of the Timer Example
*
*/
static void TimerExample(void)
{
osTimerId_t id1, id2;
uint32_t timerDelay;
osStatus_t status;
id1 = osTimerNew(Timer1Callback, osTimerPeriodic, NULL, NULL);
if (id1 != NULL)
{
// Hi3861 1U=10ms,100U=1S
timerDelay = 100U;
status = osTimerStart(id1, timerDelay);
if (status != osOK) {
printf("Failed to start Timer1!\n");
}
}
id2 = osTimerNew(Timer2Callback, osTimerPeriodic, NULL, NULL);
if (id2 != NULL) {
// Hi3861 1U=10ms,300U=3S
timerDelay = 300U;
status = osTimerStart(id2, timerDelay);
if (status != osOK) {
printf("Failed to start Timer2!\n");
}
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `timer_example` 参与编译。
```r
#"A1_kernal_thread:thread_example",
"A2_kernel_timer:timer_example",
#"A3_kernel_event:event_example",
#"A4_kernel_mutex:mutex_example",
#"A5_kernel_semaphore:semaphore_example",
#"A6_kernel_message:message_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,Timer1Callback会1S打印一次数据,Timer2Callback会3S打印一次数据。
```
This is BearPi Harmony Timer1_Callback!
This is BearPi Harmony Timer1_Callback!
This is BearPi Harmony Timer1_Callback!
This is BearPi Harmony Timer2_Callback!
This is BearPi Harmony Timer1_Callback!
This is BearPi Harmony Timer1_Callback!
This is BearPi Harmony Timer1_Callback!
This is BearPi Harmony Timer2_Callback!
```
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
/**
* @brief Callback for Timer1 triggering
*
*/
void Timer1Callback(void* arg)
{
(void)arg;
printf("This is BearPi HarmonyOS Timer1Callback!\n");
}
/**
* @brief Callback for Timer2 triggering
*
*/
void Timer2Callback(void* arg)
{
(void)arg;
printf("This is BearPi HarmonyOS Timer2Callback!\n");
}
/**
* @brief Main Entry of the Timer Example
*
*/
static void TimerExample(void)
{
osTimerId_t id1, id2;
uint32_t timerDelay;
osStatus_t status;
id1 = osTimerNew(Timer1Callback, osTimerPeriodic, NULL, NULL);
if (id1 != NULL) {
// Hi3861 1U=10ms,100U=1S
timerDelay = 100U;
status = osTimerStart(id1, timerDelay);
if (status != osOK) {
printf("Failed to start Timer1!\n");
}
}
id2 = osTimerNew(Timer2Callback, osTimerPeriodic, NULL, NULL);
if (id2 != NULL) {
// Hi3861 1U=10ms,300U=3S
timerDelay = 300U;
status = osTimerStart(id2, timerDelay);
if (status != osOK) {
printf("Failed to start Timer2!\n");
}
}
}
APP_FEATURE_INIT(TimerExample);
+18
View File
@@ -0,0 +1,18 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("event_example") {
sources = [
"event_example.c"
]
}
+162
View File
@@ -0,0 +1,162 @@
# BearPi-HM_Nano开发板OpnenHarmony内核编程开发——事件标志
本示例将演示如何在BearPi-HM_Nano开发板上使用cmsis 2.0 接口使用事件标志同步线程。
## EventFlags API分析
### osEventFlagsNew()
```c
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
```
**描述:**
osEventFlagsNew函数创建了一个新的事件标志对象,用于跨线程发送事件,并返回事件标志对象标识符的指针,或者在出现错误时返回NULL。可以在RTOS启动(调用 osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| attr |事件标志属性;空:默认值. |
### osEventFlagsSet()
```c
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id,uint32_t flags)
```
**描述:**
osEventFlagsSet函数在一个由参数ef_id指定的事件标记对象中设置由参数flags指定的事件标记。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| ef_id | 事件标志由osEventFlagsNew获得的ID 。 |
| flags | 指定设置的标志。 |
### osEventFlagsWait()
```c
uint32_t osEventFlagsWait(osEventFlagsId_t ef_id,uint32_t flags,uint32_t options,uint32_t timeout)
```
**描述:**
osEventFlagsWait函数挂起当前运行线程,直到设置了由参数ef_id指定的事件对象中的任何或所有由参数flags指定的事件标志。当这些事件标志被设置,函数立即返回。否则,线程将被置于阻塞状态。
> **注意** :如果参数timeout设置为0,可以从中断服务例程调用。
**参数:**
|参数名|描述|
|:--|:------|
| ef_id | 事件标志由osEventFlagsNew获得的ID。 |
| flags | 指定要等待的标志。 |
| options | 指定标记选项。 |
| timeout | 超时时间,0表示不超时。 |
## 软件设计
**主要代码分析**
在EventExample函数中,通过osEventFlagsNew()函数创建了事件标记IDEventReceiverThread()函数中通过osEventFlagsWait()函数一直将线程置于阻塞状态,等待事件标记。在EventSenderThread()函数中通过osEventFlagsSet()函数每隔1S设置的标志,实现任务间的同步。
```c
/**
* @brief Event sender thread used to set event flag
*
*/
void EventSenderThread(void *argument)
{
(void)argument;
while (1) {
osEventFlagsSet(g_eventFlagsId, FLAGS_MSK1);
//suspend thread
osThreadYield();
osDelay(100);
}
}
/**
* @brief Event receiver thread blocking wait event flag
*
*/
void EventReceiverThread(void *argument)
{
uint32_t flags;
(void)argument;
while (1) {
flags = osEventFlagsWait(g_eventFlagsId, FLAGS_MSK1, osFlagsWaitAny, osWaitForever);
printf("Receive Flags is %d\n", flags);
}
}
/**
* @brief Main Entry of the Event Example
*
*/
static void EventExample(void)
{
g_eventFlagsId = osEventFlagsNew(NULL);
if (g_eventFlagsId == NULL) {
printf("Failed to create EventFlags!\n");
}
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 25;
attr.name = "EventSenderThread";
if (osThreadNew(EventSenderThread, NULL, &attr) == NULL) {
printf("Failed to create EventSenderThread!\n");
}
attr.name = "EventReceiverThread";
if (osThreadNew(EventReceiverThread, NULL, &attr) == NULL) {
printf("Failed to create EventReceiverThread!\n");
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改 `applications\sample\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `event_example` 参与编译。
```r
#"A1_kernal_thread:thread_example",
#"A2_kernel_timer:timer_example",
"A3_kernel_event:event_example",
#"A4_kernel_mutex:mutex_example",
#"A5_kernel_semaphore:semaphore_example",
#"A6_kernel_message:message_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会每隔1S输出一次日志。
```
Receive Flags is 1
Receive Flags is 1
Receive Flags is 1
Receive Flags is 1
Receive Flags is 1
```
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
#define FLAGS_MSK1 0x00000001U
osEventFlagsId_t g_eventFlagsId; // event flags id
/**
* @brief Event sender thread used to set event flag
*
*/
void EventSenderThread(void* argument)
{
(void)argument;
while (1) {
osEventFlagsSet(g_eventFlagsId, FLAGS_MSK1);
// suspend thread
osThreadYield();
osDelay(100);
}
}
/**
* @brief Event receiver thread blocking wait event flag
*
*/
void EventReceiverThread(void* argument)
{
uint32_t flags;
(void)argument;
while (1) {
flags = osEventFlagsWait(g_eventFlagsId, FLAGS_MSK1, osFlagsWaitAny, osWaitForever);
printf("Receive Flags is %d\n", flags);
}
}
/**
* @brief Main Entry of the Event Example
*
*/
static void EventExample(void)
{
g_eventFlagsId = osEventFlagsNew(NULL);
if (g_eventFlagsId == NULL) {
printf("Failed to create EventFlags!\n");
}
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 25;
attr.name = "EventSenderThread";
if (osThreadNew(EventSenderThread, NULL, &attr) == NULL) {
printf("Failed to create EventSenderThread!\n");
}
attr.name = "EventReceiverThread";
if (osThreadNew(EventReceiverThread, NULL, &attr) == NULL) {
printf("Failed to create EventReceiverThread!\n");
}
}
APP_FEATURE_INIT(EventExample);
+18
View File
@@ -0,0 +1,18 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("mutex_example") {
sources = [
"mutex_example.c"
]
}
+182
View File
@@ -0,0 +1,182 @@
# BearPi-HM_Nano开发板OpnenHarmony内核编程开发——互斥锁
本示例将演示如何在BearPi-HM_Nano开发板上使用cmsis 2.0 接口使用互斥来同步任务。
## Mutex API分析
### osMutexNew()
```c
osMutexId_t osMutexNew(const osMutexAttr_t *attr)
```
**描述:**
函数osMutexNew创建并初始化一个新的互斥锁对象,并返回指向互斥锁对象标识符的指针,如果出现错误则返回NULL可以在RTOS启动(调用 osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| attr |互斥对象的属性。 |
### osMutexAcquire()
```c
osStatus_t osMutexAcquire(osMutexId_t mutex_id,uint32_t timeout)
```
**描述:**
函数osMutexAcquire一直等待,直到参数mutex_id指定的互斥对象可用为止。如果没有其余线程获得互斥锁,该函数立即返回并阻塞互斥锁对象。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| mutex_id | 通过osMutexNew获得互斥锁ID。 |
| timeout | 超时值。 |
### osMutexRelease()
```c
osStatus_t osMutexRelease(osMutexId_t mutex_id)
```
**描述:**
函数osMutexRelease释放一个由参数mutex_id指定的互斥量。当前等待这个互斥锁的其余线程将被置于就绪状态。
> **注意** :不能从中断服务例程调用此函数。
**参数:**
|参数名|描述|
|:--|:------|
| mutex_id | 通过osMutexNew获得互斥锁ID。 |
## 软件设计
**主要代码分析**
在MutexExample函数中,通过osMutexNew()函数创建了互斥锁ID,并创建的三个不同优先级的任务,在第一秒,高优先级和中优先级线程被延迟。因此,低优先级线程可以启动自己的工作,获得互斥锁并在持有它时延迟。在第一秒之后,高优先级和中优先级线程就准备好了。因此高优先级线程获得优先级并尝试获取互斥锁。因为互斥锁已经被低优先级线程所拥有,所以高优先级线程被阻塞,中间优先级线程被执行,并开始执行许多非阻塞的工作,3S后低优先级释放互斥锁,高优先级线程准备就绪并立即被调度。
```c
void HighPrioThread(void)
{
// wait 1s until start actual work
osDelay(100);
while (1) {
// try to acquire mutex
osMutexAcquire(g_mutexId, osWaitForever);
printf("HighPrioThread is running.\n");
osDelay(300);
osMutexRelease(g_mutexId);
}
}
void MidPrioThread(void)
{
// wait 1s until start actual work
osDelay(100);
while (1) {
printf("MidPrioThread is running.\n");
osDelay(100);
}
}
void LowPrioThread(void)
{
while (1) {
osMutexAcquire(g_mutexId, osWaitForever);
printf("LowPrioThread is running.\n");
// block mutex for 3s
osDelay(300);
osMutexRelease(g_mutexId);
}
}
/**
* @brief Main Entry of the Mutex Example
*
*/
void MutexExample(void)
{
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.name = "HighPrioThread";
attr.priority = 24;
if (osThreadNew((osThreadFunc_t)HighPrioThread, NULL, &attr) == NULL) {
printf("Failed to create HighPrioThread!\n");
}
attr.name = "MidPrioThread";
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)MidPrioThread, NULL, &attr) == NULL) {
printf("Failed to create MidPrioThread!\n");
}
attr.name = "LowPrioThread";
attr.priority = 26;
if (osThreadNew((osThreadFunc_t)LowPrioThread, NULL, &attr) == NULL) {
printf("Failed to create LowPrioThread!\n");
}
g_mutexId = osMutexNew(NULL);
if (g_mutexId == NULL) {
printf("Failed to create Mutex!\n");
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `mutex_example` 参与编译。
```r
#"A1_kernal_thread:thread_example",
#"A2_kernel_timer:timer_example",
#"A3_kernel_event:event_example",
"A4_kernel_mutex:mutex_example",
#"A5_kernel_semaphore:semaphore_example",
#"A6_kernel_message:message_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,中优先级任务一直正常运行,而高优先级和低优先级的任务因为互相抢占互斥锁,交替运行。
```c
LowPrioThread is runing.
MidPrioThread is runing.
MidPrioThread is runing.
MidPrioThread is runing.
HighPrioThread is runing.
MidPrioThread is runing.
MidPrioThread is runing.
MidPrioThread is runing.
LowPrioThread is runing.
MidPrioThread is runing.
MidPrioThread is runing.
MidPrioThread is runing.
HighPrioThread is runing.
MidPrioThread is runing.
MidPrioThread is runing.
MidPrioThread is runing
```
+100
View File
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
osMutexId_t g_mutexId;
void HighPrioThread(void)
{
// wait 1s until start actual work
osDelay(100);
while (1) {
// try to acquire mutex
osMutexAcquire(g_mutexId, osWaitForever);
printf("HighPrioThread is running.\n");
osDelay(300);
osMutexRelease(g_mutexId);
}
}
void MidPrioThread(void)
{
// wait 1s until start actual work
osDelay(100);
while (1) {
printf("MidPrioThread is running.\n");
osDelay(100);
}
}
void LowPrioThread(void)
{
while (1) {
osMutexAcquire(g_mutexId, osWaitForever);
printf("LowPrioThread is running.\n");
// block mutex for 3s
osDelay(300);
osMutexRelease(g_mutexId);
}
}
/**
* @brief Main Entry of the Mutex Example
*
*/
void MutexExample(void)
{
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.name = "HighPrioThread";
attr.priority = 24;
if (osThreadNew((osThreadFunc_t)HighPrioThread, NULL, &attr) == NULL) {
printf("Failed to create HighPrioThread!\n");
}
attr.name = "MidPrioThread";
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)MidPrioThread, NULL, &attr) == NULL) {
printf("Failed to create MidPrioThread!\n");
}
attr.name = "LowPrioThread";
attr.priority = 26;
if (osThreadNew((osThreadFunc_t)LowPrioThread, NULL, &attr) == NULL) {
printf("Failed to create LowPrioThread!\n");
}
g_mutexId = osMutexNew(NULL);
if (g_mutexId == NULL) {
printf("Failed to create Mutex!\n");
}
}
APP_FEATURE_INIT(MutexExample);
+18
View File
@@ -0,0 +1,18 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("semaphore_example") {
sources = [
"semaphore_example.c"
]
}
+171
View File
@@ -0,0 +1,171 @@
# BearPi-HM_Nano开发板OpnenHarmony内核编程开发——信号量
本示例将演示如何在BearPi-HM_Nano开发板上使用cmsis 2.0 接口通过信号量同时从不同的线程访问共享资源。
## Semaphore API分析
### osSemaphoreNew()
```c
osSemaphoreId_t osSemaphoreNew(uint32_t max_count,uint32_t initial_count,const osSemaphoreAttr_t *attr)
```
**描述:**
osSemaphoreNew 函数创建并初始化一个信号量对象,该对象用于管理对共享资源的访问,并返回指向信号量对象标识符的指针或在发生错误时返回 NULL 。它可以在 RTOS 启动之前(调用 osKernelStart)安全地调用,但不能在它初始化之前(调用 osKernelInitialize)调用。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| max_count |可用令牌的最大数量。 |
| initial_count |可用令牌的初始数量。 |
| attr |信号量的属性;空:默认值。 |
### osSemaphoreRelease()
```c
osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id)
```
**描述:**
函数osSemaphoreRelease释放由参数semaphore_id指定的信号量对象的标记。
> **注意** :该函数可以在中断服务例程调用。
**参数:**
|参数名|描述|
|:--|:------|
| semaphore_id | 由osSemaphoreNew获得的信号量ID。 |
### osSemaphoreAcquire()
```c
osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id,uint32_t timeout)
```
**描述:**
阻塞函数osSemaphoreAcquire一直等待,直到由参数semaphore_id指定的信号量对象的标记可用为止。如果一个令牌可用,该函数立即返回并递减令牌计数。
> **注意** :如果参数timeout设置为0,可以从中断服务例程调用。
**参数:**
|参数名|描述|
|:--|:------|
| semaphore_id | 由osSemaphoreNew获得的信号量ID。 |
| timeout | 超时值。 |
## 软件设计
**主要代码分析**
在Semaphore_example函数中,通过osSemaphoreNew()函数创建了g_semaphoreId信号量,Semaphore1Thread()函数中通过osSemaphoreAcquire()函数获取两个信号量,Semaphore2Thread()和Semaphore3Thread()函数中,先开始阻塞等待g_semaphoreId信号量。只有当Semaphore1Thread()函数中增加两次信号量,Semaphore2Thread()和Semaphore3Thread()才能继续同步运行。若Semaphore1Thread()函数中只增加一次信号量,那Semaphore2Thread()和Semaphore3Thread()只能轮流执行。
```c
void Semaphore1Thread(void)
{
while (1) {
//release Semaphores twice so that Semaphore2Thread and Semaphore3Thread can execute synchronously
osSemaphoreRelease(g_semaphoreId);
//if the Semaphore is released only once, Semaphore2Thread and Semaphore3Thread will run alternately.
osSemaphoreRelease(g_semaphoreId);
printf("Semaphore1Thread Release Semap \n");
osDelay(100);
}
}
void Semaphore2Thread(void)
{
while (1) {
//wait Semaphore
osSemaphoreAcquire(g_semaphoreId, osWaitForever);
printf("Semaphore2Thread get Semap \n");
osDelay(1);
}
}
void Semaphore3Thread(void)
{
while (1) {
//wait Semaphore
osSemaphoreAcquire(g_semaphoreId, osWaitForever);
printf("Semaphore3Thread get Semap \n");
osDelay(1);
}
}
/**
* @brief Main Entry of the Semaphore Example
*
*/
void SemaphoreExample(void)
{
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 24;
attr.name = "Semaphore1Thread";
if (osThreadNew((osThreadFunc_t)Semaphore1Thread, NULL, &attr) == NULL) {
printf("Failed to create Semaphore1Thread!\n");
}
attr.name = "Semaphore2Thread";
if (osThreadNew((osThreadFunc_t)Semaphore2Thread, NULL, &attr) == NULL) {
printf("Failed to create Semaphore2Thread!\n");
}
attr.name = "Semaphore3Thread";
if (osThreadNew((osThreadFunc_t)Semaphore3Thread, NULL, &attr) == NULL) {
printf("Failed to create Semaphore3Thread!\n");
}
g_semaphoreId = osSemaphoreNew(4, 0, NULL);
if (g_semaphoreId == NULL) {
printf("Failed to create Semaphore!\n");
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `semaphore_example` 参与编译。
```r
#"A1_kernal_thread:thread_example",
#"A2_kernel_timer:timer_example",
#"A3_kernel_event:event_example",
#"A4_kernel_mutex:mutex_example",
"A5_kernel_semaphore:semaphore_example",
#"A6_kernel_message:message_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,Semaphore1Thread一次释放两个信号量,Semaphore2Thread和Semaphore3Thread同步执行。
```
Semaphore1Thread Release Semap
Semaphore2Thread get Semap
Semaphore3Thread get Semap
Semaphore1Thread Release Semap
Semaphore2Thread get Semap
Semaphore3Thread get Semap
Semaphore1Thread Release Semap
Semaphore2Thread get Semap
Semaphore3Thread get Semap
```
+95
View File
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
osSemaphoreId_t g_semaphoreId;
void Semaphore1Thread(void)
{
while (1) {
// release Semaphores twice so that Semaphore2Thread and Semaphore3Thread can execute synchronously
osSemaphoreRelease(g_semaphoreId);
// if the Semaphore is released only once, Semaphore2Thread and Semaphore3Thread will run alternately.
osSemaphoreRelease(g_semaphoreId);
printf("Semaphore1Thread Release Semap \n");
osDelay(100);
}
}
void Semaphore2Thread(void)
{
while (1) {
// wait Semaphore
osSemaphoreAcquire(g_semaphoreId, osWaitForever);
printf("Semaphore2Thread get Semap \n");
osDelay(1);
}
}
void Semaphore3Thread(void)
{
while (1) {
// wait Semaphore
osSemaphoreAcquire(g_semaphoreId, osWaitForever);
printf("Semaphore3Thread get Semap \n");
osDelay(1);
}
}
/**
* @brief Main Entry of the Semaphore Example
*
*/
void SemaphoreExample(void)
{
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 24;
attr.name = "Semaphore1Thread";
if (osThreadNew((osThreadFunc_t)Semaphore1Thread, NULL, &attr) == NULL) {
printf("Failed to create Semaphore1Thread!\n");
}
attr.name = "Semaphore2Thread";
if (osThreadNew((osThreadFunc_t)Semaphore2Thread, NULL, &attr) == NULL) {
printf("Failed to create Semaphore2Thread!\n");
}
attr.name = "Semaphore3Thread";
if (osThreadNew((osThreadFunc_t)Semaphore3Thread, NULL, &attr) == NULL) {
printf("Failed to create Semaphore3Thread!\n");
}
g_semaphoreId = osSemaphoreNew(4, 0, NULL);
if (g_semaphoreId == NULL) {
printf("Failed to create Semaphore!\n");
}
}
APP_FEATURE_INIT(SemaphoreExample);
+18
View File
@@ -0,0 +1,18 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("message_example") {
sources = [
"message_example.c"
]
}
+164
View File
@@ -0,0 +1,164 @@
# BearPi-HM_Nano开发板OpnenHarmony内核编程开发——消息队列
本示例将演示如何在BearPi-HM_Nano开发板上使用cmsis 2.0 接口通过消息队列进行线程之间交换消息。
## MessageQueue API分析
### osMessageQueueNew()
```c
osMessageQueueId_t osMessageQueueNew(uint32_t msg_count,uint32_t msg_size,const osMessageQueueAttr_t *attr)
```
**描述:**
函数osMessageQueueNew创建并初始化一个消息队列对象。该函数返回消息队列对象标识符,如果出现错误则返回NULL,可以在RTOS启动(调用 osKernelStart)之前安全地调用该函数,也可以在内核初始化 (调用 osKernelInitialize)之前调用该函数。
> **注意** :不能在中断服务调用该函数。
**参数:**
|参数名|描述|
|:--|:------|
| msg_count |队列中的最大消息数。 |
| msg_size |最大消息大小(以字节为单位)。 |
| attr |消息队列属性;空:默认值。 |
### osMessageQueuePut()
```c
osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id,const void *msg_ptr,uint8_t msg_prio,uint32_t timeout)
```
**描述:**
函数osMessageQueuePut将msg_ptr指向的消息放入参数mq_id指定的消息队列中。
> **注意** :如果参数timeout设置为0,可以从中断服务例程调用。
**参数:**
|参数名|描述|
|:--|:------|
| mq_id | 由osMessageQueueNew获得的消息队列ID。 |
| msg_ptr | 要发送的消息。 |
| msg_prio | 指优先级。 |
| timeout | 超时值。 |
### osMessageQueueGet()
```c
osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id,void *msg_ptr,uint8_t *msg_prio,uint32_t timeout)
```
**描述:**
函数osMessageQueueGet从参数mq_id指定的消息队列中检索消息,并将其保存到参数msg_ptr所指向的缓冲区中。
> **注意** :如果参数timeout设置为0,可以从中断服务例程调用。
**参数:**
|参数名|描述|
|:--|:------|
| mq_id | 由osMessageQueueNew获得的消息队列ID。 |
| msg_ptr | 指针指向队列中获取消息的缓冲区指针。 |
| msg_prio | 指优先级。 |
| timeout | 超时值。 |
## 软件设计
**主要代码分析**
在MessageExample函数中,通过osMessageQueueNew()函数创建了消息队列IDMsgQueue1Thread()函数中通过osMessageQueuePut()函数向消息队列中发送消息。在MsgQueue2Thread()函数中通过osMessageQueueGet()函数读取消息队列中的消息比打印出来。
```c
void MsgQueue1Thread(void *argument)
{
(void)argument;
//do some work...
msg.buf = "Hello BearPi-HM_Nano!";
msg.idx = 0U;
while (1) {
osMessageQueuePut(g_msgQueueId, &msg, 0U, 0U);
//suspend thread
osThreadYield();
osDelay(100);
}
}
void MsgQueue2Thread(void *argument)
{
osStatus_t status;
(void)argument;
while (1) {
//wait for message
status = osMessageQueueGet(g_msgQueueId, &msg, NULL, osWaitForever);
if (status == osOK) {
printf("Message Queue Get msg:%s\n", msg.buf);
}
}
}
/**
* @brief Main Entry of the Message Example
*
*/
static void MessageExample(void)
{
g_msgQueueId = osMessageQueueNew(MSGQUEUE_OBJECTS, 100, NULL);
if (g_msgQueueId == NULL) {
printf("Failed to create Message Queue!\n");
}
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 10;
attr.priority = 25;
attr.name = "MsgQueue1Thread";
if (osThreadNew(MsgQueue1Thread, NULL, &attr) == NULL) {
printf("Failed to create MsgQueue1Thread!\n");
}
attr.name = "MsgQueue2Thread";
if (osThreadNew(MsgQueue2Thread, NULL, &attr) == NULL) {
printf("Failed to create MsgQueue2Thread!\n");
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `message_example` 参与编译。
```r
#"A1_kernal_thread:thread_example",
#"A2_kernel_timer:timer_example",
#"A3_kernel_event:event_example",
#"A4_kernel_mutex:mutex_example",
#"A5_kernel_semaphore:semaphore_example",
"A6_kernel_message:message_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印从消息队列中获取的消息。
```c
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
```
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
// number of Message Queue Objects
#define MSGQUEUE_OBJECTS 16
typedef struct {
// object data type
char* buf;
uint8_t idx;
} MSGQUEUE_OBJ_t;
MSGQUEUE_OBJ_t msg;
// message queue id
osMessageQueueId_t g_msgQueueId;
void MsgQueue1Thread(void* argument)
{
(void)argument;
// do some work...
msg.buf = "Hello BearPi-HM_Nano!";
msg.idx = 0U;
while (1) {
osMessageQueuePut(g_msgQueueId, &msg, 0U, 0U);
// suspend thread
osThreadYield();
osDelay(100);
}
}
void MsgQueue2Thread(void* argument)
{
osStatus_t status;
(void)argument;
while (1) {
// wait for message
status = osMessageQueueGet(g_msgQueueId, &msg, NULL, osWaitForever);
if (status == osOK) {
printf("Message Queue Get msg:%s\n", msg.buf);
}
}
}
/**
* @brief Main Entry of the Message Example
*
*/
static void MessageExample(void)
{
g_msgQueueId = osMessageQueueNew(MSGQUEUE_OBJECTS, 100, NULL);
if (g_msgQueueId == NULL) {
printf("Failed to create Message Queue!\n");
}
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 10;
attr.priority = 25;
attr.name = "MsgQueue1Thread";
if (osThreadNew(MsgQueue1Thread, NULL, &attr) == NULL) {
printf("Failed to create MsgQueue1Thread!\n");
}
attr.name = "MsgQueue2Thread";
if (osThreadNew(MsgQueue2Thread, NULL, &attr) == NULL) {
printf("Failed to create MsgQueue2Thread!\n");
}
}
APP_FEATURE_INIT(MessageExample);
+24
View File
@@ -0,0 +1,24 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("led_example") {
sources = [
"led_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
]
}
+104
View File
@@ -0,0 +1,104 @@
# BearPi-HM_Nano开发板基础外设开发——GPIO输出
本示例将演示如何在BearPi-HM_Nano开发板上使用GPIO输出功能去点亮LED灯。
## GPIO API分析
本案例主要使用了以下几个API完成GPIO输出功能。
### IoTGpioInit()
```c
unsigned int IoTGpioInit(unsigned int id);
```
**描述:**
初始化GPIO外设。
### IoTGpioSetFunc()
```c
unsigned int IoTGpioSetFunc(unsigned int id, unsigned char val);
```
**描述:**
设置GPIO引脚复用功能。
**参数:**
|参数名|描述|
|:--|:------|
| id | 表示GPIO引脚号。 |
| val | 表示GPIO复用功能。 |
### IoTGpioSetDir()
```c
unsigned int IoTGpioSetDir(unsigned int id, IotGpioDir dir);
```
**描述:**
设置GPIO输出方向。
**参数:**
|参数名|描述|
|:--|:------|
| id | 表示GPIO引脚号。 |
| dir | 表示GPIO输出方向。 |
## 硬件设计
本案例将使用板载的LED来验证GPIO的输出功能,在BearPi-HM_Nano开发板上LED的连接电路图如下图所示,LED的控制引脚与主控芯片的GPIO_2连接,所以需要编写软件去控制GPIO_2输出高低电平实现LED灯的亮灭。
![LED灯电路](../../docs/figures/B1_basic_led_blink/LED灯电路.png )
## 软件设计
**主要代码分析**
LedTask()为LED灯测试主任务,该任务先调用 IoTGpioInit()初始化GPIO,因为LED灯的控制引脚接在GPIO_2上,所以通过IoTGpioSetDir()将GPIO_2设置为普通GPIO的输出模式。最后在死循环里面间隔 1s 输出GPIO_2的高低电平,实现LED灯闪烁的现象。
```c
/**
* @brief led task output high and low levels to turn on and off LED
*
*/
static void LedTask(void)
{
//init gpio of LED
IoTGpioInit(LED_GPIO);
//set GPIO_2 is output mode
IoTGpioSetDir(LED_GPIO, IOT_GPIO_DIR_OUT);
while (1) {
//set GPIO_2 output high levels to turn on LED
IoTGpioSetOutputVal(LED_GPIO, 1);
//delay 1s
sleep(1);
//set GPIO_2 output low levels to turn off LED
IoTGpioSetOutputVal(LED_GPIO, 0);
//delay 1s
sleep(1);
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app` 路径下 BUILD.gn 文件,指定 `led_example` 参与编译。
```r
"B1_basic_led_blink:led_example",
#"B2_basic_button:button_example",
#"B3_basic_pwm_led:pwm_example",
#"B4_basic_adc:adc_example",
#"B5_basic_i2c_nfc:i2c_example",
#"B6_basic_uart:uart_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,开发板的LED灯开始闪烁。
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "ohos_init.h"
#define LED_GPIO 2
/**
* @brief led task output high and low levels to turn on and off LED
*
*/
static void LedTask(void)
{
// init gpio of LED
IoTGpioInit(LED_GPIO);
// set GPIO_2 is output mode
IoTGpioSetDir(LED_GPIO, IOT_GPIO_DIR_OUT);
while (1) {
// set GPIO_2 output high levels to turn on LED
IoTGpioSetOutputVal(LED_GPIO, 1);
// delay 1s
sleep(1);
// set GPIO_2 output low levels to turn off LED
IoTGpioSetOutputVal(LED_GPIO, 0);
// delay 1s
sleep(1);
}
}
/**
* @brief Main Entry of the Led Example
*
*/
static void LedExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "LedTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL) {
printf("Failed to create LedTask!\n");
}
}
APP_FEATURE_INIT(LedExampleEntry);
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("button_example") {
sources = [
"button_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
]
}
+158
View File
@@ -0,0 +1,158 @@
# BearPi-HM_Nano开发板基础外设开发——GPIO输入
本示例将演示如何在BearPi-HM_Nano开发板上使用GPIO输入功能去读取按键状态。
## GPIO API分析
本案例主要使用了以下几个API完成GPIO输出功能。
### IoTGpioInit()
```c
unsigned int IoTGpioInit(unsigned int id);
```
**描述:**
初始化GPIO外设。
### IoTGpioSetFunc()
```c
unsigned int IoTGpioSetFunc(unsigned int id, unsigned char val);
```
**描述:**
设置GPIO引脚复用功能。
**参数:**
|参数名|描述|
|:--|:------|
| id | 表示GPIO引脚号。 |
| val | 表示GPIO复用功能。 |
### IoTGpioSetDir()
```c
unsigned int IoTGpioSetDir(unsigned int id, IotGpioDir dir);
```
**描述:**
设置GPIO输出方向。
**参数:**
|参数名|描述|
|:--|:------|
| id | 表示GPIO引脚号。 |
| dir | 表示GPIO输出方向。 |
### IoSetPull()
```c
unsigned int IoTGpioSetPull(unsigned int id, IotGpioPull val);
```
**描述:**
设备GPIO的上下拉方式。
**参数:**
|参数名|描述|
|:--|:------|
| id | 表示GPIO引脚号。 |
| val | 表示要设置的上拉或下拉。 |
### IoTGpioRegisterIsrFunc()
```c
unsigned int IoTGpioRegisterIsrFunc(unsigned int id, IotGpioIntType intType, IotGpioIntPolarity intPolarity,
GpioIsrCallbackFunc func, char *arg);
```
**描述:**
启用GPIO引脚的中断功能。这个函数可以用来为GPIO pin设置中断类型、中断极性和中断回调。
**参数:**
|参数名|描述|
|:--|:------|
| id | 表示GPIO引脚号。 |
| intType| 表示中断类型。 |
| intPolarity| 表示中断极性。 |
| func| 表示中断回调函数.。 |
| arg| 表示中断回调函数中使用的参数的指针。 |
## 硬件设计
本案例将使用板载的两个用户按键来验证GPIO的输入功能,在BearPi-HM_Nano开发板上用户按键的连接电路图如下图所示,按键F1的检测引脚与主控芯片的GPIO_11连接,按键F2的检测引脚与主控芯片的GPIO_12连接,所以需要编写软件去读取GPIO_11和GPIO_12的电平值,判断按键是否被按下。
![按键电路](../../docs/figures/B2_basic_button/按键电路.png "按键电路")
## 软件设计
**主要代码分析**
这部分代码主要分析按键触发中断的功能代码,这里以按键F1为例,按键F1的检测引脚与主控芯片的GPIO_11连接,首先通过调用IoTGpioSetFunc()和IoTGpioSetDir()将GPIO_11设置为普通GPIO的输入模式。从前面原理图可知,当按键按下时,GPIO_11会被下拉到地,所以这里要使用IoTGpioSetPull()将GPIO_11引脚设置为上拉,这样才能产生电平的跳变。最后通过IoTGpioRegisterIsrFunc()将中断类型设置为边沿触发,且为下降沿触发,当按键被按下时,GPIO_11会从高电平转为低电平,产生一个下降,这个时候就会触发中断并回调F1_Pressed函数。在F1_Pressed函数中实现点亮LED灯操作。
```c
/**
* @brief Callback for F1 key
*
*/
static void F1Pressed(char *arg)
{
(void)arg;
IoTGpioSetOutputVal(LED_GPIO, 1);
}
/**
* @brief Callback for F2 key
*
*/
static void F2Pressed(char *arg)
{
(void)arg;
IoTGpioSetOutputVal(LED_GPIO, 0);
}
/**
* @brief Main Entry of the Button Example
*
*/
static void ButtonExampleEntry(void)
{
//init gpio of LED
IoTGpioInit(LED_GPIO);
IoTGpioSetDir(LED_GPIO, IOT_GPIO_DIR_OUT);
//init gpio of F1 key and set it as the falling edge to trigger interrupt
IoTGpioInit(BUTTON_F1_GPIO);
IoTGpioSetDir(BUTTON_F1_GPIO, IOT_GPIO_DIR_IN);
IoTGpioSetPull(BUTTON_F1_GPIO, IOT_GPIO_PULL_UP);
IoTGpioRegisterIsrFunc(BUTTON_F1_GPIO, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1Pressed, NULL);
//init gpio of F2 key and set it as the falling edge to trigger interrupt
IoTGpioInit(BUTTON_F2_GPIO);
IoTGpioSetDir(BUTTON_F2_GPIO, IOT_GPIO_DIR_IN);
IoTGpioSetPull(BUTTON_F2_GPIO, IOT_GPIO_PULL_UP);
IoTGpioRegisterIsrFunc(BUTTON_F2_GPIO, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, F2Pressed, NULL);
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app` 路径下 BUILD.gn 文件,指定 `button_example` 参与编译。
```r
#"B1_basic_led_blink:led_example",
"B2_basic_button:button_example",
#"B3_basic_pwm_led:pwm_example",
#"B4_basic_adc:adc_example",
#"B5_basic_i2c_nfc:i2c_example",
#"B6_basic_uart:uart_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,开发板开始正常工作,按下F1按键LED会点亮,按下F2按键LED会熄灭。
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "ohos_init.h"
#define LED_GPIO 2
#define BUTTON_F1_GPIO 11
#define BUTTON_F2_GPIO 12
/**
* @brief Callback for F1 key
*
*/
static void F1Pressed(char* arg)
{
(void)arg;
IoTGpioSetOutputVal(LED_GPIO, 1);
}
/**
* @brief Callback for F2 key
*
*/
static void F2Pressed(char* arg)
{
(void)arg;
IoTGpioSetOutputVal(LED_GPIO, 0);
}
/**
* @brief Main Entry of the Button Example
*
*/
static void ButtonExampleEntry(void)
{
// init gpio of LED
IoTGpioInit(LED_GPIO);
IoTGpioSetDir(LED_GPIO, IOT_GPIO_DIR_OUT);
// init gpio of F1 key and set it as the falling edge to trigger interrupt
IoTGpioInit(BUTTON_F1_GPIO);
IoTGpioSetFunc(BUTTON_F1_GPIO, IOT_GPIO_FUNC_GPIO_11_GPIO);
IoTGpioSetDir(BUTTON_F1_GPIO, IOT_GPIO_DIR_IN);
IoTGpioSetPull(BUTTON_F1_GPIO, IOT_GPIO_PULL_UP);
IoTGpioRegisterIsrFunc(BUTTON_F1_GPIO, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1Pressed, NULL);
// init gpio of F2 key and set it as the falling edge to trigger interrupt
IoTGpioInit(BUTTON_F2_GPIO);
IoTGpioSetFunc(BUTTON_F2_GPIO, IOT_GPIO_FUNC_GPIO_12_GPIO);
IoTGpioSetDir(BUTTON_F2_GPIO, IOT_GPIO_DIR_IN);
IoTGpioSetPull(BUTTON_F2_GPIO, IOT_GPIO_PULL_UP);
IoTGpioRegisterIsrFunc(BUTTON_F2_GPIO, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_FALL_LEVEL_LOW, F2Pressed, NULL);
}
APP_FEATURE_INIT(ButtonExampleEntry);
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("pwm_example") {
sources = [
"pwm_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
]
}
+140
View File
@@ -0,0 +1,140 @@
# BearPi-HM_Nano开发板基础外设开发——PWM输出
本示例将演示如何在BearPi-HM_Nano开发板上使用GPIO的PWM功能实现呼吸灯的效果。
## PWM API分析
本案例主要使用了以下几个API完成PWM功能实现呼吸灯功能。
### IoTGpioInit()
```c
unsigned int IoTGpioInit(unsigned int id);
```
**描述:**
初始化GPIO外设。
### IoTGpioSetFunc()
```c
unsigned int IoTGpioSetFunc(unsigned int id, unsigned char val);
```
**描述:**
设置GPIO引脚复用功能。
**参数:**
|参数名|描述|
|:--|:------|
| id | 表示GPIO引脚号。 |
| val | 表示GPIO复用功能。 |
### IoTGpioSetDir()
```c
unsigned int IoTGpioSetDir(unsigned int id, IotGpioDir dir);
```
**描述:**
设置GPIO输出方向。
**参数:**
|参数名|描述|
|:--|:------|
| id | 表示GPIO引脚号。 |
| dir | 表示GPIO输出方向。 |
### IoTPwmInit()
```c
unsigned int IoTPwmInit(unsigned int port);
```
**描述:**
初始化PWM功能。
**参数:**
|参数名|描述|
|:--|:------|
| port | 表示PWM设备端口号。 |
## IoTPwmStart()
```c
unsigned int IoTPwmStart(unsigned int port, unsigned short duty, unsigned int freq);
```
**描述:**
根据输入参数输出PWM信号。
**参数:**
|参数名|描述|
|:--|:------|
| port | PWM端口号。 |
| duty| 占空比。 |
| freq| 分频倍数。 |
## 硬件设计
本案例将使用板载的LED来验证GPIO的PWM功能,在BearPi-HM_Nano开发板上LED的连接电路图如下图所示,LED的控制引脚与主控芯片的GPIO_2连接,所以需要编写软件去控制GPIO_2输出PWM波实现呼吸灯的效果。
![](../../docs/figures/B3_basic_pwm_led/LED灯电路.png "LED灯电路")
## 软件设计
**主要代码分析**
PWMTask()为PWM测试主任务,该任务先调用 IoTGpioInit()初始化GPIO,因为LED灯的控制引脚接在GPIO_2上,所以通过调用IoTGpioSetFunc()将GPIO_2复用为PWM功能,并通过IoTPwmInit()初始化PWM2端口,最后在死循环里面间隔10us输出不同占空比的PWM波,实现呼吸灯的效果。
```c
/**
* @brief pwm task output PWM with different duty cycle
*
*/
static void PwmTask(void)
{
unsigned int i;
//init gpio of LED
IoTGpioInit(LED_GPIO);
//set the GPIO_2 multiplexing function to PWM
IoTGpioSetFunc(LED_GPIO, IOT_GPIO_FUNC_GPIO_2_PWM2_OUT);
//set GPIO_2 is output mode
IoTGpioSetDir(LED_GPIO, IOT_GPIO_DIR_OUT);
//init PWM2
IoTPwmInit(LED_GPIO);
while (1) {
for (i = 0; i < 100; i ++)
{
//output PWM with different duty cycle
IoTPwmStart(LED_GPIO, i, 40000);
usleep(10);
}
i = 0;
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app` 路径下 BUILD.gn 文件,指定 `pwm_example` 参与编译。
```r
#"B1_basic_led_blink:led_example",
#"B2_basic_button:button_example",
"B3_basic_pwm_led:pwm_example",
#"B4_basic_adc:adc_example",
#"B5_basic_i2c_nfc:i2c_example",
#"B6_basic_uart:uart_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,开发板开始正常工作,LED开始不断变化亮度,实现呼吸灯的效果。
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_pwm.h"
#include "ohos_init.h"
#define LED_GPIO 2
/**
* @brief pwm task output PWM with different duty cycle
*
*/
static void PwmTask(void)
{
unsigned int i;
// init gpio of LED
IoTGpioInit(LED_GPIO);
// set the GPIO_2 multiplexing function to PWM
IoTGpioSetFunc(LED_GPIO, IOT_GPIO_FUNC_GPIO_2_PWM2_OUT);
// set GPIO_2 is output mode
IoTGpioSetDir(LED_GPIO, IOT_GPIO_DIR_OUT);
// init PWM2
IoTPwmInit(LED_GPIO);
while (1) {
for (i = 0; i < 100; i++) {
// output PWM with different duty cycle
IoTPwmStart(LED_GPIO, i, 40000);
usleep(10);
}
i = 0;
}
}
/**
* @brief Main Entry of the Pwm Example
*
*/
static void PwmExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "PwmTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)PwmTask, NULL, &attr) == NULL) {
printf("Failed to create PwmTask!\n");
}
}
APP_FEATURE_INIT(PwmExampleEntry);
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("adc_example") {
sources = [
"adc_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
]
}
+103
View File
@@ -0,0 +1,103 @@
# BearPi-HM_Nano开发板基础外设开发——ADC采样
本示例将演示如何在BearPi-HM_Nano开发板上通过按下按键改变GPIO口的电压,并使用ADC读取GPIO的电压值。
## ADC API分析
本案例主要使用了以下API完成ADC采样的功能。
### IoTAdcRead()
```c
unsigned int IoTAdcRead(unsigned int channel, unsigned short *data, IotAdcEquModelSel equModel,
IotAdcCurBais curBais, unsigned short rstCnt);
```
**描述:**
根据输入参数从指定的ADC通道读取一段采样数据。
**参数:**
|参数名|描述|
|:--|:------|
| channel | 表示ADC通道。 |
| data |表示指向存储读取数据的地址的指针。 |
| equModel | 表示平均算法的次数。 |
| curBais | 表示模拟功率控制模式。 |
| rstCnt | 指示从重置到转换开始的时间计数。一次计数等于334纳秒。值的范围必须从0到0xFF。|
## 硬件设计
本案例将使用板载用户按键F1来模拟GPIO口电压的变化。通过查看芯片手册可知GPIO_11对应的是 ADC Channel 5 ,所以需要编写软件去读取ADC Channel 5的电压,程序设计时先将GPIO_11上拉,使GPIO_11的电压一直处于高电平,当按键按下时GPIO_11接地,此时GPIO_11的电压变为 0 V。
![按键电路](../../docs/figures/B4_basic_adc/按键电路.png "按键电路")
## 软件设计
**主要代码分析**
该函数通过使用AdcRead()函数来读取 `ADC_CHANNEL_5` 的数值存储在data中, `IOT_ADC_EQU_MODEL_8` 表示8次平均算法模式,`IOT_ADC_CUR_BAIS_DEFAULT` 表示默认的自动识别模式,最后通过 `data * 1.8 * 4 / 4096.0` 计算出实际的电压值。
```c
/**
* @brief get ADC sampling value and convert it to voltage
*
*/
static float GetVoltage(void)
{
unsigned int ret;
unsigned short data;
ret = IoTAdcRead(5, &data, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 0xff);
if (ret != IOT_SUCCESS) {
printf("ADC Read Fail\n");
}
return (float)data * 1.8 * 4 / 4096.0;
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app` 路径下 BUILD.gn 文件,指定 `adc_example` 参与编译。
```r
#"B1_basic_led_blink:led_example",
#"B2_basic_button:button_example",
# "B3_basic_pwm_led:pwm_example",
"B4_basic_adc:adc_example",
#"B5_basic_i2c_nfc:i2c_example",
# "B6_basic_uart:uart_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,当F1按键未按下时采集到的电压为3.3V左右,当按键按下时,电压变为0.2V左右。
```c
=======================================
*************ADC_example***********
=======================================
vlt:3.371V
=======================================
*************ADC_example***********
=======================================
vlt:3.371V
=======================================
*************ADC_example***********
=======================================
vlt:3.373V
=======================================
*************ADC_example***********
=======================================
vlt:0.248V
=======================================
*************ADC_example***********
=======================================
vlt:0.244V
```
+92
View File
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "iot_adc.h"
#include "iot_errno.h"
#include "iot_gpio_ex.h"
#include "ohos_init.h"
#define ADC_TASK_STACK_SIZE 1024 * 8
#define ADC_TASK_PRIO 24
/**
* @brief get ADC sampling value and convert it to voltage
*
*/
static float GetVoltage(void)
{
unsigned int ret;
unsigned short data;
ret = IoTAdcRead(5, &data, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 0xff);
if (ret != IOT_SUCCESS) {
printf("ADC Read Fail\n");
}
return (float)data * 1.8 * 4 / 4096.0;
}
/**
* @brief Adc task get adc sampling voltage
*
*/
static void AdcTask(void)
{
float voltage;
// set GPIO_11 to pull-up mode
IoTGpioSetPull(11, IOT_GPIO_PULL_UP);
while (1) {
printf("=======================================\r\n");
printf("***************ADC_example*************\r\n");
printf("=======================================\r\n");
// get adc sampling voltage
voltage = GetVoltage();
printf("vlt:%.3fV\n", voltage);
// delay 1s
usleep(1000000);
}
}
/**
* @brief Main Entry of the Adc Example
*
*/
static void AdcExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "AdcTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = ADC_TASK_STACK_SIZE;
attr.priority = ADC_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)AdcTask, NULL, &attr) == NULL) {
printf("Failed to create AdcTask!\n");
}
}
APP_FEATURE_INIT(AdcExampleEntry);
+34
View File
@@ -0,0 +1,34 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("i2c_example") {
sources = [
"nfc/NT3H.c",
"nfc/nfc.c",
"nfc/ndef/rtd/nfcForum.c",
"nfc/ndef/rtd/rtdText.c",
"nfc/ndef/rtd/rtdUri.c",
"nfc/ndef/ndef.c",
"i2c_example.c"
]
cflags = [ "-Wno-unused-variable" ]
cflags += [ "-Wno-unused-but-set-variable" ]
cflags += [ "-Wno-unused-parameter" ]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"nfc/ndef",
"nfc/ndef/rtd/",
"nfc"
]
}
+152
View File
@@ -0,0 +1,152 @@
# BearPi-HM_Nano开发板基础外设开发——I2C控制NFC芯片
本示例将演示如何在BearPi-HM_Nano开发板上使用I2C协议向NFC芯片写入数据。
## I2C API分析
本示例主要使用了以下API完成I2C采样的功能。
### IoTI2cInit()
```c
unsigned int IoTI2cInit(unsigned int id, unsigned int baudrate);
```
**描述:**
用指定的频率初始化I2C设备。
**参数:**
|参数名|描述|
|:--|:------|
| id | I2C设备ID。 |
| baudrate |I2C频率。|
## IoTI2cSetBaudrate()
```c
unsigned int IoTI2cSetBaudrate(unsigned int id, unsigned int baudrate);
```
**描述:**
为I2C设备设置频率。
**参数:**
|参数名|描述|
|:--|:------|
| id | I2C设备ID。 |
| baudrate |I2C频率。|
## IoTI2cWrite()
```c
unsigned int IoTI2cWrite(unsigned int id, unsigned short deviceAddr, const unsigned char *data, unsigned int dataLen);
```
**描述:**
将数据写入I2C设备。
**参数:**
|参数名|描述|
|:--|:------|
| id | I2C设备ID。 |
| deviceAddr |I2C设备地址。|
| data |表示写入的数据。|
| dataLen |表示要写入的数据长度。|
## IoTI2cRead()
```c
unsigned int IoTI2cRead(unsigned int id, unsigned short deviceAddr, unsigned char *data, unsigned int dataLen);
```
**描述:**
从I2C设备读取数据。读取的数据将保存到i2cData指定的地址。
**参数:**
|参数名|描述|
|:--|:------|
| id | I2C设备ID。 |
| deviceAddr |I2C设备地址。|
| data |表示要读取的数据指向的指针。|
| dataLen |表示要读取的数据长度。|
## 硬件设计
如下图所示,NFC芯片使用的是I2C协议,I2C_SCL与GPIO_0相连接,I2C_SDA与GPIO_1相连接,所以需要编写软件使用GPIO_0和GPIO_1产生I2C信号去控制NFC芯片。
![E53接口电路](../../docs/figures/B5_basic_i2c_nfc/NFC电路.png "E53接口电路")
## 软件设计
**主要代码分析**
这部分代码为I2C初始化的代码,首先用 `IoTGpioSetFunc()` 函数将GPIO_0复用为I2C1_SDAGPIO_1复用为I2C1_SCL。然后调用IoTI2cInit()函数初始化I2C1端口,最后使用 `I2cSetBaudrate()` 函数设置I2C1的频率为400kbps。
```c
//GPIO_0 multiplexed to I2C1_SDA
IoTGpioInit(0);
IoTGpioSetFunc(0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA);
//GPIO_1 multiplexed to I2C1_SCL
IoTGpioInit(1);
IoTGpioSetFunc(1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL);
//baudrate: 400kbps
IoTI2cInit(WIFI_IOT_I2C_IDX_1, 400000);
```
这部分的代码是向NFC芯片写入数据,但需要写入2个记录时,第2个记录的位置需要用`NDEFLastPos`来定义;当需要写入3个记录时,第2个和第3个记录的位置分别需要用`NDEFMiddlePos``NDEFLastPos`来定义。
```c
ret=storeText(NDEFFirstPos, (uint8_t *)TEXT);
if(ret != 1)
{
printf("NFC Write Data Falied :%d ",ret);
}
ret=storeUrihttp(NDEFLastPos, (uint8_t *)WEB);
if(ret != 1)
{
printf("NFC Write Data Falied :%d ",ret);
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app` 路径下 BUILD.gn 文件,指定 `i2c_example` 参与编译。
```r
#"B1_basic_led_blink:led_example",
#"B2_basic_button:button_example",
#"B3_basic_pwm_led:pwm_example",
#"B4_basic_adc:adc_example",
"B5_basic_i2c_nfc:i2c_example",
#"B6_basic_uart:uart_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,并请使用带有NFC功能的手机靠近开发板,能读取数据。
```c
=======================================
***********I2C_NFC_example**********
=======================================
Please use the mobile phone with NFC function close to the development board!
=======================================
***********I2C_NFC_example**********
=======================================
Please use the mobile phone with NFC function close to the development board!
```
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_i2c.h"
#include "nfc.h"
#include "ohos_init.h"
#define I2C_TASK_STACK_SIZE 1024 * 8
#define I2C_TASK_PRIO 25
#define TEXT "Welcome to BearPi-HM_Nano!"
#define WEB "harmonyos.com"
#define WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA 6
#define WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL 6
#define WIFI_IOT_I2C_IDX_1 1
/**
* @brief i2c task writes data to NFC tag
*
*/
static void I2cTask(void)
{
uint8_t ret;
// GPIO_0 multiplexed to I2C1_SDA
IoTGpioInit(0);
IoTGpioSetFunc(0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA);
// GPIO_1 multiplexed to I2C1_SCL
IoTGpioInit(1);
IoTGpioSetFunc(1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL);
// baudrate: 400kbps
IoTI2cInit(WIFI_IOT_I2C_IDX_1, 400000);
printf("I2C Test Start\n");
ret = storeText(NDEFFirstPos, (uint8_t*)TEXT);
if (ret != 1) {
printf("NFC Write Data Falied :%d \n", ret);
}
ret = storeUrihttp(NDEFLastPos, (uint8_t*)WEB);
if (ret != 1) {
printf("NFC Write Data Falied :%d \n", ret);
}
while (1) {
printf("=======================================\n");
printf("***********I2C_NFC_example**********\n");
printf("=======================================\n");
printf("Please use the mobile phone with NFC function close to the development board!\n");
usleep(1000000);
}
}
/**
* @brief Main Entry of the I2c Example
*
*/
static void I2cExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "I2cTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = I2C_TASK_STACK_SIZE;
attr.priority = I2C_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)I2cTask, NULL, &attr) == NULL) {
printf("Falied to create I2cTask!\n");
}
}
APP_FEATURE_INIT(I2cExampleEntry);
+202
View File
@@ -0,0 +1,202 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "iot_i2c.h"
#include "iot_i2c_ex.h"
#include "NT3H.h"
#include "ndef.h"
#include "nfc.h"
#include "nfcForum.h"
/**
* @brief Defines I2C data transmission attributes.
*/
typedef struct {
/** Pointer to the buffer storing data to send */
unsigned char *sendBuf;
/** Length of data to send */
unsigned int sendLen;
/** Pointer to the buffer for storing data to receive */
unsigned char *receiveBuf;
/** Length of data received */
unsigned int receiveLen;
} WifiIotI2cData;
uint8_t nfcPageBuffer[NFC_PAGE_SIZE];
NT3HerrNo errNo;
// due to the nature of the NT3H a timeout is required to
// protectd 2 consecutive I2C access
inline const uint8_t* get_last_ncf_page(void) {
return nfcPageBuffer;
}
static bool writeTimeout( uint8_t *data, uint8_t dataSend) {
uint32_t status = 0;
status = IoTI2cWrite(1, (NT3H1X_SLAVE_ADDRESS<<1)|0x00, data,dataSend);
if (status != 0)
{
printf("===== Error: I2C write status1 = 0x%x! =====\r\n", status);
return 0;
}
usleep(300000);
return 1;
}
static bool readTimeout(uint8_t address, uint8_t *block_data) {
uint32_t status = 0;
IotI2cData nt3h1101_i2c_data = {0};
uint8_t buffer[1] = {address};
nt3h1101_i2c_data.sendBuf = buffer;
nt3h1101_i2c_data.sendLen = 1;
nt3h1101_i2c_data.receiveBuf = block_data;
nt3h1101_i2c_data.receiveLen = NFC_PAGE_SIZE;
status = IoTI2cWriteread(1, (NT3H1X_SLAVE_ADDRESS<<1)|0x00, &nt3h1101_i2c_data);
if (status != 0)
{
printf("===== Error: I2C write status = 0x%x! =====\r\n", status);
return 0;
}
return 1;
}
bool NT3HReadHeaderNfc(uint8_t *endRecordsPtr, uint8_t *ndefHeader) {
*endRecordsPtr=0;
bool ret = NT3HReadUserData(0);
// read the first page to see where is the end of the Records.
if (ret == true) {
// if the first byte is equals to NDEF_START_BYTE there are some records
// store theend of that
if ((NDEF_START_BYTE == nfcPageBuffer[0]) && (NTAG_ERASED != nfcPageBuffer[2])) {
*endRecordsPtr = nfcPageBuffer[1];
*ndefHeader = nfcPageBuffer[2];
}
return true;
} else {
errNo = NT3HERROR_READ_HEADER;
}
return ret;
}
bool NT3HWriteHeaderNfc(uint8_t endRecordsPtr, uint8_t ndefHeader) {
// read the first page to see where is the end of the Records.
bool ret = NT3HReadUserData(0);
if (ret == true) {
nfcPageBuffer[1] = endRecordsPtr;
nfcPageBuffer[2] = ndefHeader;
ret = NT3HWriteUserData(0, nfcPageBuffer);
if (ret == false) {
errNo = NT3HERROR_WRITE_HEADER;
}
} else {
errNo = NT3HERROR_READ_HEADER;
}
return ret;
}
bool NT3HEraseAllTag(void) {
bool ret = true;
uint8_t erase[NFC_PAGE_SIZE+1] = {USER_START_REG, 0x03, 0x03, 0xD0, 0x00, 0x00, 0xFE};
ret = writeTimeout(erase, sizeof(erase));
if (ret == false) {
errNo = NT3HERROR_ERASE_USER_MEMORY_PAGE;
}
return ret;
}
bool NT3HReaddManufactoringData(uint8_t *manuf) {
return readTimeout(MANUFACTORING_DATA_REG, manuf);
}
bool NT3HReadConfiguration(uint8_t *configuration){
return readTimeout(CONFIG_REG, configuration);
}
bool getSessionReg(void) {
return readTimeout(SESSION_REG, nfcPageBuffer);
}
bool NT3HReadUserData(uint8_t page) {
uint8_t reg = USER_START_REG+page;
// if the requested page is out of the register exit with error
if (reg > USER_END_REG) {
errNo = NT3HERROR_INVALID_USER_MEMORY_PAGE;
return false;
}
bool ret = readTimeout(reg, nfcPageBuffer);
if (ret == false) {
errNo = NT3HERROR_READ_USER_MEMORY_PAGE;
}
return ret;
}
bool NT3HWriteUserData(uint8_t page, const uint8_t* data) {
bool ret = true;
uint8_t dataSend[NFC_PAGE_SIZE +1]; // data plus register
uint8_t reg = USER_START_REG+page;
// if the requested page is out of the register exit with error
if (reg > USER_END_REG) {
errNo = NT3HERROR_INVALID_USER_MEMORY_PAGE;
ret = false;
goto end;
}
dataSend[0] = reg; // store the register
memcpy(&dataSend[1], data, NFC_PAGE_SIZE);
ret = writeTimeout(dataSend, sizeof(dataSend));
if (ret == false) {
errNo = NT3HERROR_WRITE_USER_MEMORY_PAGE;
goto end;
}
end:
return ret;
}
bool NT3HReadSram(void){
bool ret=false;
for (int i = SRAM_START_REG, j=0; i<=SRAM_END_REG; i++,j++) {
ret = readTimeout(i, nfcPageBuffer);
if (ret==false) {
return ret;
}
//memcpy(&userData[offset], pageBuffer, sizeof(pageBuffer));
}
return ret;
}
void NT3HGetNxpSerialNumber(char* buffer) {
uint8_t manuf[16];
if (NT3HReaddManufactoringData(manuf)) {
for(int i=0; i<6; i++) {
buffer[i] = manuf[i];
}
}
}
+122
View File
@@ -0,0 +1,122 @@
#ifndef NT3H_H_
#define NT3H_H_
#include "stdbool.h"
#include <stdint.h>
#define NT3H1X_SLAVE_ADDRESS 0x55
#define MANUFACTORING_DATA_REG 0x0
#define USER_START_REG 0x1
// NT3H1201 // for th 2K
#define USER_END_REG 0x77
#define CONFIG_REG 0x7A
// NT3H1101 // for th 1K
// #define USER_END_REG 0x38 // just the first 8 bytes for th 1K
// #define CONFIG_REG 0x3A
#define SRAM_START_REG 0xF8
#define SRAM_END_REG 0xFB // just the first 8 bytes
#define SESSION_REG 0xFE
#define NFC_PAGE_SIZE 16
typedef enum {
NT3HERROR_NO_ERROR,
NT3HERROR_READ_HEADER,
NT3HERROR_WRITE_HEADER,
NT3HERROR_INVALID_USER_MEMORY_PAGE,
NT3HERROR_READ_USER_MEMORY_PAGE,
NT3HERROR_WRITE_USER_MEMORY_PAGE,
NT3HERROR_ERASE_USER_MEMORY_PAGE,
NT3HERROR_READ_NDEF_TEXT,
NT3HERROR_WRITE_NDEF_TEXT,
NT3HERROR_TYPE_NOT_SUPPORTED
}NT3HerrNo;
extern uint8_t nfcPageBuffer[NFC_PAGE_SIZE];
extern NT3HerrNo errNo;
typedef enum {
NDEFFirstPos,
NDEFMiddlePos,
NDEFLastPos
} RecordPosEnu;
/*
* This strucure is used in the ADD record functionality
* to store the last nfc page information, in order to continue from that point.
*/
typedef struct {
uint8_t page;
uint8_t usedBytes;
} UncompletePageStr;
typedef struct {
RecordPosEnu ndefPosition;
uint8_t rtdType;
uint8_t *rtdPayload;
uint8_t rtdPayloadlength;
void *specificRtdData;
}NDEFDataStr;
void NT3HGetNxpSerialNumber(char* buffer);
/*
* read the user data from the requested page
* first page is 0
*
* the NT3H1201 has 119 PAges
* the NT3H1101 has 56 PAges (but the 56th page has only 8 Bytes)
*/
bool NT3HReadUserData(uint8_t page);
/*
* Write data information from the starting requested page.
* If the dataLen is bigger of NFC_PAGE_SIZE, the consecuiteve needed
* pages will be automatically used.
*
* The functions stops to the latest available page.
*
first page is 0
* the NT3H1201 has 119 PAges
* the NT3H1101 has 56 PAges (but the 56th page has only 8 Bytes)
*/
bool NT3HWriteUserData(uint8_t page, const uint8_t* data);
/*
* The function read the first page of user data where is stored the NFC Header.
* It is important because it contains the total size of all the stored records.
*
* param endRecordsPtr return the value of the total size excluding the NDEF_END_BYTE
* param ndefHeader Store the NDEF Header of the first record
*/
bool NT3HReadHeaderNfc(uint8_t *endRecordsPtr, uint8_t *ndefHeader);
/*
* The function write the first page of user data where is stored the NFC Header.
* update the bytes that contains the payload Length and the first NDEF Header
*
* param endRecordsPtr The value of the total size excluding the NDEF_END_BYTE
* param ndefHeader The NDEF Header of the first record
*/
bool NT3HWriteHeaderNfc(uint8_t endRecordsPtr, uint8_t ndefHeader);
bool getSessionReg(void);
bool getNxpUserData(char* buffer);
bool NT3HReadSram(void);
bool NT3HReadSession(void);
bool NT3HReadConfiguration(uint8_t *configuration);
bool NT3HEraseAllTag(void);
bool NT3HReaddManufactoringData(uint8_t *manuf) ;
bool NT3HResetUserData(void);
#endif /* NFC_H_ */
+227
View File
@@ -0,0 +1,227 @@
#include "ndef.h"
#include <string.h>
#include "nfcForum.h"
#include "rtdTypes.h"
#include "NT3H.h"
typedef uint8_t (*composeRtdPtr)(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg);
static composeRtdPtr composeRtd[] = {composeRtdText,composeRtdUri};
int16_t firstRecord(UncompletePageStr *page, const NDEFDataStr *data, RecordPosEnu rtdPosition) {
NDEFRecordStr record;
NDEFHeaderStr header;
uint8_t typeFunct=0;
switch (data->rtdType){
case RTD_TEXT:
typeFunct =0;
break;
case RTD_URI:
typeFunct = 1;
break;
default:
return -1;
break;
}
// clear all buffers
memset(&record,0,sizeof(NDEFRecordStr));
memset(nfcPageBuffer, 0, NFC_PAGE_SIZE);
// this is the first record
header.startByte = NDEF_START_BYTE;
composeNDEFMBME(true, true, &record);
// prepare the NDEF Header and payload
uint8_t recordLength = composeRtd[typeFunct](data, &record, &nfcPageBuffer[sizeof(NDEFHeaderStr)]);
header.payloadLength = data->rtdPayloadlength + recordLength;
// write first record
memcpy(nfcPageBuffer, &header, sizeof(NDEFHeaderStr));
return sizeof(NDEFHeaderStr)+recordLength;
}
int16_t addRecord(UncompletePageStr *pageToUse, const NDEFDataStr *data, RecordPosEnu rtdPosition) {
NDEFRecordStr record;
NDEFHeaderStr header={0};
uint8_t newRecordPtr, mbMe;
bool ret = true;
uint8_t tmpBuffer[NFC_PAGE_SIZE];
uint8_t typeFunct=0;
switch (data->rtdType){
case RTD_TEXT:
typeFunct =0;
break;
case RTD_URI:
typeFunct = 1;
break;
default:
return -1;
break;
}
// first Change the Header of the first Record
NT3HReadHeaderNfc(&newRecordPtr, &mbMe);
record.header = mbMe;
composeNDEFMBME(true, false, &record); // this is the first record
mbMe = record.header;
memset(&record,0,sizeof(NDEFRecordStr));
memset(tmpBuffer,0,NFC_PAGE_SIZE);
// prepare second record
uint8_t recordLength = composeRtd[typeFunct](data, &record, tmpBuffer);
if (rtdPosition == NDEFMiddlePos) {
// this is a record in the middle adjust it on the buffet
composeNDEFMBME(false, false, &record);
} else if (rtdPosition == NDEFLastPos){
// this is the last record adjust it on the buffet
composeNDEFMBME(false, true, &record);
}
tmpBuffer[0] = record.header;
header.payloadLength += data->rtdPayloadlength + recordLength;
// save the new value of length on the first page
NT3HWriteHeaderNfc((newRecordPtr+header.payloadLength), mbMe);
// use the last valid page and start to add the new record
NT3HReadUserData(pageToUse->page);
if (pageToUse->usedBytes+recordLength< NFC_PAGE_SIZE) {
memcpy(&nfcPageBuffer[pageToUse->usedBytes], tmpBuffer, recordLength);
return recordLength+pageToUse->usedBytes;
} else {
uint8_t byteToCopy = NFC_PAGE_SIZE-pageToUse->usedBytes;
memcpy(&nfcPageBuffer[pageToUse->usedBytes], tmpBuffer, byteToCopy);
NT3HWriteUserData(pageToUse->page, nfcPageBuffer);
// update the info with the new page
pageToUse->page++;
pageToUse->usedBytes=recordLength-byteToCopy;
//copy the remain part in the pageBuffer because this is what the caller expect
memcpy(nfcPageBuffer, &tmpBuffer[byteToCopy], pageToUse->usedBytes);
return pageToUse->usedBytes;
}
}
static bool writeUserPayload(int16_t payloadPtr, const NDEFDataStr *data, UncompletePageStr *addPage){
uint8_t addedPayload;
bool ret=false;
uint8_t finish=payloadPtr+data->rtdPayloadlength;
bool endRecord = false;
uint8_t copyByte=0;
// if the header is less then the NFC_PAGE_SIZE, fill it with the payload
if (NFC_PAGE_SIZE>payloadPtr) {
if (data->rtdPayloadlength > NFC_PAGE_SIZE-payloadPtr)
copyByte = NFC_PAGE_SIZE-payloadPtr;
else
copyByte = data->rtdPayloadlength;
}
// Copy the payload
memcpy(&nfcPageBuffer[payloadPtr], data->rtdPayload, copyByte);
addedPayload = copyByte;
//if it is sufficient one send add the NDEF_END_BYTE
if ((addedPayload >= data->rtdPayloadlength)&&((payloadPtr+copyByte) < NFC_PAGE_SIZE)) {
nfcPageBuffer[(payloadPtr+copyByte)] = NDEF_END_BYTE;
endRecord = true;
}
ret = NT3HWriteUserData(addPage->page, nfcPageBuffer);
while (!endRecord) {
addPage->page++; // move to a new register
memset(nfcPageBuffer,0,NFC_PAGE_SIZE);
//special case just the NDEF_END_BYTE remain out
if (addedPayload == data->rtdPayloadlength) {
nfcPageBuffer[0] = NDEF_END_BYTE;
ret = NT3HWriteUserData(addPage->page, nfcPageBuffer);
endRecord = true;
if (ret == false) {
errNo = NT3HERROR_WRITE_NDEF_TEXT;
}
goto end;
}
if (addedPayload < data->rtdPayloadlength) {
// add the NDEF_END_BYTE if there is enough space
if ((data->rtdPayloadlength-addedPayload) < NFC_PAGE_SIZE){
memcpy(nfcPageBuffer, &data->rtdPayload[addedPayload], (data->rtdPayloadlength-addedPayload));
nfcPageBuffer[(data->rtdPayloadlength-addedPayload)] = NDEF_END_BYTE;
} else {
memcpy(nfcPageBuffer, &data->rtdPayload[addedPayload], NFC_PAGE_SIZE);
}
addedPayload += NFC_PAGE_SIZE;
ret = NT3HWriteUserData(addPage->page, nfcPageBuffer);
if (ret == false) {
errNo = NT3HERROR_WRITE_NDEF_TEXT;
goto end;
}
} else {
endRecord = true;
}
}
end:
return ret;
}
typedef int16_t (*addFunct_T) (UncompletePageStr *page, const NDEFDataStr *data, RecordPosEnu rtdPosition);
static addFunct_T addFunct[] = {firstRecord, addRecord, addRecord};
bool NT3HwriteRecord(const NDEFDataStr *data) {
uint8_t recordLength=0, mbMe;
UncompletePageStr addPage;
addPage.page = 0;
// calculate the last used page
if (data->ndefPosition != NDEFFirstPos ) {
NT3HReadHeaderNfc(&recordLength, &mbMe);
addPage.page = (recordLength+sizeof(NDEFHeaderStr)+1)/NFC_PAGE_SIZE;
//remove the NDEF_END_BYTE byte because it will overwrite by the new Record
addPage.usedBytes = (recordLength+sizeof(NDEFHeaderStr)+1)%NFC_PAGE_SIZE - 1;
}
// call the appropriate function and consider the pointer
// within the NFC_PAGE_SIZE that need to be used
int16_t payloadPtr = addFunct[data->ndefPosition](&addPage, data, data->ndefPosition);
if (payloadPtr == -1) {
errNo = NT3HERROR_TYPE_NOT_SUPPORTED;
return false;
}
return writeUserPayload(payloadPtr, data, &addPage);
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef NDEF_H_
#define NDEF_H_
#include "NT3H.h"
bool NT3HwriteRecord(const NDEFDataStr *data);
#endif /* NDEF_H_ */
@@ -0,0 +1,69 @@
#include "nfcForum.h"
#include <string.h>
static void rtdHeader(uint8_t type, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg) {
ndefRecord->header |= 1;
ndefRecord->header |= BIT_SR;
I2CMsg[0] = ndefRecord->header;
ndefRecord->typeLength = 1;
I2CMsg[1] = ndefRecord->typeLength;
ndefRecord->type.typeCode=type;
I2CMsg[3] = ndefRecord->type.typeCode;
}
uint8_t composeRtdText(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg) {
uint8_t retLen;
rtdHeader(RTD_TEXT, ndefRecord, I2CMsg);
uint8_t payLoadLen = addRtdText(&ndefRecord->type.typePayload.text);
memcpy(&I2CMsg[4], &ndefRecord->type.typePayload.text, payLoadLen);
ndefRecord->payloadLength = ndef->rtdPayloadlength+payLoadLen; // added the typePayload
I2CMsg[2]=ndefRecord->payloadLength;
retLen = 3 + /*sizeof(ndefRecord->header) +
sizeof(ndefRecord->typeLength) +
sizeof(ndefRecord->payloadLength) +*/
3 + //sizeof(RTDTextTypeStr)-sizeof(TextExtraDataStr)
1 /*sizeof(ndefRecord->type.typeCode)*/;
return retLen;
}
uint8_t composeRtdUri(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg) {
rtdHeader(RTD_URI, ndefRecord, I2CMsg);
uint8_t payLoadLen = addRtdUriRecord(ndef, &ndefRecord->type.typePayload.uri);
memcpy(&I2CMsg[4], &ndefRecord->type.typePayload.uri, payLoadLen);
ndefRecord->payloadLength = ndef->rtdPayloadlength+payLoadLen; // added the typePayload
I2CMsg[2]=ndefRecord->payloadLength;
return 5;
/* retLen = sizeof(ndefRecord->header) +
sizeof(ndefRecord->typeLength) +
sizeof(ndefRecord->payloadLength) +
sizeof(1) + //ndefRecord->type.typePayload.uri.type
sizeof(ndefRecord->type.typeCode);
*/
}
void composeNDEFMBME(bool isFirstRecord, bool isLastRecord, NDEFRecordStr *ndefRecord) {
if (isFirstRecord)
ndefRecord->header |= BIT_MB;
else
ndefRecord->header &= ~MASK_MB;
if (isLastRecord)
ndefRecord->header |= BIT_ME;
else
ndefRecord->header &= ~MASK_ME;
}
@@ -0,0 +1,46 @@
#ifndef NFCFORUM_H_
#define NFCFORUM_H_
#include <stdbool.h>
#include "rtdTypes.h"
#include "NT3H.h"
#define NDEF_START_BYTE 0x03
#define NDEF_END_BYTE 0xFE
#define NTAG_ERASED 0xD0
typedef struct {
uint8_t startByte;
uint8_t payloadLength;
}NDEFHeaderStr;
#define BIT_MB (1<<7)
#define BIT_ME (1<<6)
#define BIT_CF (1<<5)
#define BIT_SR (1<<4)
#define BIT_IL (1<<3)
#define BIT_TNF (1<<0)
#define MASK_MB 0x80
#define MASK_ME 0x40
#define MASK_CF 0x20
#define MASK_SR 0x10
#define MASK_IL 0x08
#define MASK_TNF 0x07
typedef struct {
uint8_t header;
uint8_t typeLength;
uint8_t payloadLength;
RTDTypeStr type;
}NDEFRecordStr;
uint8_t composeRtdText(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg);
uint8_t composeRtdUri(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg);
void composeNDEFMBME(bool isFirstRecord, bool isLastRecord, NDEFRecordStr *ndefRecord);
#endif /* NFCFORUM.H_H_ */
+22
View File
@@ -0,0 +1,22 @@
#include "rtdText.h"
#include "rtdTypes.h"
#include <string.h>
uint8_t addRtdText(RtdTextTypeStr *typeStr) {
// return addNDEFTextPayload(bodyLength, ndefRecord);
typeStr->status=0x2;
typeStr->language[0]='e';
typeStr->language[1]='n';
return 3;
}
void prepareText(NDEFDataStr *data, RecordPosEnu position, uint8_t *text) {
data->ndefPosition = position;
data->rtdType = RTD_TEXT;
data->rtdPayload = text;
data->rtdPayloadlength = strlen((const char *)text);
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef RTDTEXT_H_
#define RTDTEXT_H_
#include "NT3H.h"
#define BIT_STATUS (1<<7)
#define BIT_RFU (1<<6)
#define MASK_STATUS 0x80
#define MASK_RFU 0x40
#define MASK_IANA 0b00111111
typedef struct {
char *body;
uint8_t bodyLength;
}RtdTextUserPayload;
typedef struct {
uint8_t status;
uint8_t language[2];
RtdTextUserPayload rtdPayload;
}RtdTextTypeStr;
uint8_t addRtdText(RtdTextTypeStr *typeStr);
void prepareText(NDEFDataStr *data, RecordPosEnu position, uint8_t *text);
#endif /* NDEFTEXT_H_ */
@@ -0,0 +1,21 @@
#ifndef RTDTYPES_H_
#define RTDTYPES_H_
#include "rtdText.h"
#include "rtdUri.h"
#define RTD_TEXT 'T'
#define RTD_URI 'U'
typedef union {
RtdTextTypeStr text;
RTDUriTypeStr uri;
} RTDTypeUnion;
typedef struct {
uint8_t typeCode;
RTDTypeUnion typePayload;
}RTDTypeStr;
#endif /* RTDTYPES_H_ */
+24
View File
@@ -0,0 +1,24 @@
#include "rtdUri.h"
#include <string.h>
#include "rtdTypes.h"
RTDUriTypeStr uri;
uint8_t addRtdUriRecord(const NDEFDataStr *ndef, RTDUriTypeStr *uriType) {
uriType->type=((RTDUriTypeStr*) ndef->specificRtdData)->type;
return 1;
}
void prepareUrihttp(NDEFDataStr *data, RecordPosEnu position, uint8_t *text) {
data->ndefPosition = position;
data->rtdType = RTD_URI;
data->rtdPayload = text;
data->rtdPayloadlength = strlen((const char *)text);;
uri.type = httpWWW;
data->specificRtdData = &uri;
}
+62
View File
@@ -0,0 +1,62 @@
#include "NT3H.h"
#ifndef RTDURI_H_
#define RTDURI_H_
typedef enum {
freeForm, //0x00 No prepending is done ... the entire URI is contained in the URI Field
httpWWW, //0x01 http://www.
httpsWWW, //0x02 https://www.
http, //0x03 http://
https, //0x04 https://
tel, //0x05 tel:
mailto, //0x06 mailto:
ftpAnonymous,//0x07 ftp://anonymous:anonymous@
ftpFtp, //0x08 ftp://ftp.
ftps, //0x09 ftps://
sftp, //0x0A sftp://
smb, //0x0B smb://
nfs, //0x0C nfs://
ftp, //0x0D ftp://
dav, //0x0E dav://
news, //0x0F news:
telnet, //0x10 telnet://
imap, //0x11 imap:
rtps, //0x12 rtsp://
urn, //0x13 urn:
/*
0x14 pop:
0x15 sip:
0x16 sips:
0x17 tftp:
0x18 btspp://
0x19 btl2cap://
0x1A btgoep://
0x1B tcpobex://
0x1C irdaobex://
0x1D file://
0x1E urn:epc:id:
0x1F urn:epc:tag:
0x20 urn:epc:pat:
0x21 urn:epc:raw:
0x22 urn:epc:
0x23 urn:nfc:
*/
}UriTypeE;
typedef struct {
char *body;
uint8_t bodyLength;
void *extraData; // herre should be stored specific URI msgs
}RtdUriUserPayload;
typedef struct {
UriTypeE type;
RtdUriUserPayload userPayload; // here should be stored specific URI msgs
}RTDUriTypeStr;
uint8_t addRtdUriRecord(const NDEFDataStr *ndef, RTDUriTypeStr *typeStr);
void prepareUrihttp(NDEFDataStr *data, RecordPosEnu position, uint8_t *text);
#endif /* RTDURI_H_ */
+24
View File
@@ -0,0 +1,24 @@
#include <stdbool.h>
#include "rtdText.h"
#include "rtdUri.h"
#include "ndef.h"
#include "nfc.h"
bool storeUrihttp(RecordPosEnu position, uint8_t *http){
NDEFDataStr data;
prepareUrihttp(&data, position, http);
return NT3HwriteRecord( &data );
}
bool storeText(RecordPosEnu position, uint8_t *text){
NDEFDataStr data;
prepareText(&data, position, text);
return NT3HwriteRecord( &data );
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef _NFC_H_
#define _NFC_H_
#include "NT3H.h"
/*
* The function write in the NT3H a new URI Rtd on the required position
*
* param:
* position: where add the record
* http: the address to write
*
*/
bool storeUrihttp(RecordPosEnu position, uint8_t *http);
/*
* The function write in the NT3H a new Text Rtd on the required position
*
* param:
* position: where add the record
* text: the text to write
*
*/
bool storeText(RecordPosEnu position, uint8_t *text);
#endif /* NFC_H_ */
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("uart_example") {
sources = [
"uart_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
]
}
+130
View File
@@ -0,0 +1,130 @@
# BearPi-HM_Nano开发板基础外设开发——UART数据读写
本示例将演示如何在BearPi-HM_Nano开发板上使用UART进行数据的收发。
## UART API分析
本示例主要使用了以下API完成UART数据读写。
### IoTUartInit()
```c
unsigned int IoTUartInit(unsigned int id, const IotUartAttribute *param);
```
**描述:**
配置一个UART设备。
**参数:**
|参数名|描述|
|:--|:------|
| id | UART端口号。 |
| param |表示基本UART属性。|
### IoTUartWrite()
```c
int IoTUartWrite(unsigned int id, const unsigned char *data, unsigned int dataLen);
```
**描述:**
将数据写入UART设备。
**参数:**
|参数名|描述|
|:--|:------|
| id | UART端口号。 |
| data |表示指向要写入数据的起始地址的指针。|
| dataLen |表示读取数据的长度。|
### IoTUartRead()
```c
int IoTUartRead(unsigned int id, unsigned char *data, unsigned int dataLen);
```
**描述:**
从UART设备读取数据。
**参数:**
|参数名|描述|
|:--|:------|
| id | UART端口号。 |
| data |表示指向要读取数据的起始地址的指针。|
| dataLen |表示读取数据的长度。|
## 硬件设计
本案例将用 BearPi-HM_Nano 开发板 E53 接口的 UART 作为测试,如原理图所示第 18 和 19 脚分别为 TXD 和 RXD ,连接了主控芯片的 GPIO_6 和 GPIO_5 ,所以在编写软件的时候需要将 GPIO_6 和 GPIO_5 分别复用为 TXD 和 RXD 。
![](../../docs/figures/B6_basic_uart/E53接口电路.png "E53接口电路")
## 软件设计
**主要代码分析**
这部分代码为UART初始化的代码,首先要在 `uart_attr` 结构体这配置波特率、数据位、停止位、奇偶检验位,然后通过 `IoTUartInit()` 函数对串口1进行配置。
```c
IotUartAttribute uart_attr = {
//baud_rate: 9600
.baudRate = 9600,
//data_bits: 8bits
.dataBits = 8,
.stopBits = 1,
.parity = 0,
};
//Initialize uart driver
ret = IoTUartInit(WIFI_IOT_UART_IDX_1, &uart_attr);
if (ret != IOT_SUCCESS) {
printf("Failed to init uart! Err code = %d\n", ret);
return;
}
```
这部分的代码主要实现通过 `IoTUartWrite()` 函数在串口1发送一串数据,然后通过 `IoTUartRead()` 函数将数据都回来,并通过 `debug` 串口打印出来。
```c
//send data through uart1
IoTUartWrite(WIFI_IOT_UART_IDX_1, (unsigned char *)data, strlen(data));
//receive data through uart1
IoTUartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE);
printf("Uart1 read data:%s\n", uart_buff_ptr);
```
## 编译调试
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app` 路径下 BUILD.gn 文件,指定 `uart_example` 参与编译。
```r
#"B1_basic_led_blink:led_example",
#"B2_basic_button:button_example",
#"B3_basic_pwm_led:pwm_example",
#"B4_basic_adc:adc_example",
#"B5_basic_i2c_nfc:i2c_example",
"B6_basic_uart:uart_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键, `将开发板上E53接口的UART_TX和UART_RX用杜邦线短接` 通过串口助手查看日志,串口1实现自发自收。
```c
=======================================
*************UART_example**************
=======================================
Uart1 read data:Hello, BearPi!
=======================================
*************UART_example**************
=======================================
Uart1 read data:Hello, BearPi!
```
+98
View File
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_uart.h"
#include "ohos_init.h"
#define UART_TASK_STACK_SIZE 1024 * 8
#define UART_TASK_PRIO 25
#define UART_BUFF_SIZE 1000
#define WIFI_IOT_UART_IDX_1 1
static const char* data = "Hello, BearPi!\r\n";
/**
* @brief uart task send data through uart1 and receive data through uart1
*
*/
static void UartTask(void)
{
uint8_t uart_buff[UART_BUFF_SIZE] = {0};
uint8_t* uart_buff_ptr = uart_buff;
uint32_t ret;
IotUartAttribute uart_attr = {
// baud_rate: 9600
.baudRate = 9600,
// data_bits: 8bits
.dataBits = 8,
.stopBits = 1,
.parity = 0,
};
// Initialize uart driver
ret = IoTUartInit(WIFI_IOT_UART_IDX_1, &uart_attr);
if (ret != IOT_SUCCESS) {
printf("Failed to init uart! Err code = %d\n", ret);
return;
}
while (1) {
printf("=======================================\r\n");
printf("*************UART_example**************\r\n");
printf("=======================================\r\n");
// send data through uart1
IoTUartWrite(WIFI_IOT_UART_IDX_1, (unsigned char*)data, strlen(data));
// receive data through uart1
IoTUartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE);
printf("Uart1 read data:%s\n", uart_buff_ptr);
usleep(1000000);
}
}
/**
* @brief Main Entry of the UART Example
*
*/
static void UartExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "UartTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = UART_TASK_STACK_SIZE;
attr.priority = UART_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)UartTask, NULL, &attr) == NULL) {
printf("Failed to create UartTask!\n");
}
}
APP_FEATURE_INIT(UartExampleEntry);
+53
View File
@@ -0,0 +1,53 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
# "A1_kernal_thread:thread_example",
# "A2_kernel_timer:timer_example",
# "A3_kernel_event:event_example",
# "A4_kernel_mutex:mutex_example",
# "A5_kernel_semaphore:semaphore_example",
# "A6_kernel_message:message_example",
"B1_basic_led_blink:led_example",
# "B2_basic_button:button_example",
# "B3_basic_pwm_led:pwm_example",
# "B4_basic_adc:adc_example",
# "B5_basic_i2c_nfc:i2c_example",
# "B6_basic_uart:uart_example",
# "C1_e53_sf1_mq2:e53_sf1_example",
# "C2_e53_ia1_temp_humi_pls:e53_ia1_example",
# "C3_e53_sc1_pls:e53_sc1_example",
# "C4_e53_sc2_axis:e53_sc2_example",
# "C5_e53_is1_infrared:e53_is1_example",
# "D1_iot_wifi_ap:wifi_ap",
# "D2_iot_wifi_sta_connect:wifi_sta_connect",
# "D3_iot_udp_client:udp_client",
# "D4_iot_tcp_server:tcp_server",
# "D5_iot_mqtt:iot_mqtt",
# "D6_iot_cloud_oc:oc_mqtt",
# "D7_iot_cloud_oc_smoke:cloud_oc_smoke",
# "D8_iot_cloud_oc_light:cloud_oc_light",
# "D9_iot_cloud_oc_manhole_cover:cloud_oc_manhole_cover",
# "D10_iot_cloud_oc_infrared:cloud_oc_infrared",
# "D11_iot_cloud_oc_agriculture:cloud_oc_agriculture",
# "D12_iot_cloud_oc_gps:cloud_oc_gps",
]
}
+25
View File
@@ -0,0 +1,25 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("e53_sf1_example") {
sources = [
"src/E53_SF1.c",
"e53_sf1_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"include"
]
}
+111
View File
@@ -0,0 +1,111 @@
# BearPi-HM_Nano开发板传感器驱动开发——MQ2读取烟雾浓度
本示例将演示如何在BearPi-HM_Nano开发板上使用E53_SF1读取烟雾浓度,当烟雾浓度超标时蜂鸣器发出警报,设备安装如下图所示。
![E53_SF1安装](../../docs/figures/C1_e53_sf1_mq2/E53_SF1安装.png "E53_SF1安装")
## E53_SF1 API分析
本案例主要使用了以下API完成烟雾浓度读取。
### E53SF1Init()
```C
void E53SF1Init(void)
```
**描述:**
初始化E53_SF1。
### MQ2PPMCalibration()
```C
void MQ2PPMCalibration(void)
```
**描述:**
MQ2传感器校准。
### GetMQ2PPM()
```C
float GetMQ2PPM(void)
```
**描述:**
获取烟雾浓度ppm。
## 硬件设计
本案例将用到 E53_SF1 智慧烟感扩展板与 BearPi-HM_Nano 开发板,其中E53_SF1扩展板原理图如下,ADC输出引脚为第五脚,将E53_SF1扩展板插在 BearPi-HM_Nano 开发板上后,该ADC输出引脚与GPIO_13相连接,通过查看芯片手册可知GPIO_13对应的是 ADC Channel 6 ,所以需要编写软件去读取ADC Channel 6的电压实现对烟雾浓度的读取。
![E53_SF1接口](../../docs/figures/C1_e53_sf1_mq2/E53_SF1接口.png "E53_SF1接口")
![E53接口电路](../../docs/figures/C1_e53_sf1_mq2/E53接口电路.png "E53接口电路")
E53_SF1 智慧烟感扩展板与 BearPi-HM_Nano 开发板安装如下图所示。
![E53_SF1安装](../../docs/figures/C1_e53_sf1_mq2/E53_SF1安装.png "E53_SF1安装")
## 软件设计
**主要代码分析**
首先调用 `E53SF1Init()` 函数初始化E53_SF1所接的引脚的功能,再等待1s后进行校准,获取正常环境下传感器的参数,然后循环调用 `GetMQ2PPM()` 函数读取ppm值并通过串口打印出来,当ppm大于100时触发蜂鸣器报警,小于100时关闭报警。
```C
static void ExampleTask(void)
{
int ret;
float ppm;
E53SF1Init();
//Sensor calibration
usleep(1000000);
MQ2PPMCalibration();
while (1) {
printf("=======================================\r\n");
printf("*************E53_SF1_example***********\r\n");
printf("=======================================\r\n");
//get mq2 ppm
ret = GetMQ2PPM(&ppm);
if (ret != 0) {
printf("ADC Read Fail\n");
return ;
}
printf("ppm:%.3f \n", ppm);
if (ppm > 15) {
BeepStatusSet(ON);
} else {
BeepStatusSet(OFF);
}
usleep(1000000);
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `e53_sf1_example` 参与编译。
```r
"C1_e53_sf1_mq2:e53_sf1_example",
#"C2_e53_ia1_temp_humi_pls:e53_ia1_example",
#"C3_e53_sc1_pls:e53_sc1_example",
#"C4_e53_sc2_axis:e53_sc2_example",
#"C5_e53_is1_infrared:e53_is1_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印以下信息,对着烟雾探头制作烟雾,ppm会升高蜂鸣器发出报警。
```c
=======================================
*************E53_SF1_example***********
=======================================
ppm:19.094
=======================================
*************E53_SF1_example***********
=======================================
ppm:18.797
```
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "E53_SF1.h"
#define TASK_STACK_SIZE 1024*8
#define TASK_PRIO 25
static void ExampleTask(void)
{
int ret;
float ppm;
E53SF1Init();
//Sensor calibration
usleep(1000000);
MQ2PPMCalibration();
while (1) {
printf("=======================================\r\n");
printf("*************E53_SF1_example***********\r\n");
printf("=======================================\r\n");
//get mq2 ppm
ret = GetMQ2PPM(&ppm);
if (ret != 0) {
printf("ADC Read Fail\n");
return ;
}
printf("ppm:%.3f \n", ppm);
if (ppm > 15) {
BeepStatusSet(ON);
} else {
BeepStatusSet(OFF);
}
usleep(1000000);
}
}
/**
* @brief Main Entry of the E53_SF1 Example
*
*/
static void ExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "ExampleTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = TASK_STACK_SIZE;
attr.priority = TASK_PRIO;
if (osThreadNew((osThreadFunc_t)ExampleTask, NULL, &attr) == NULL) {
printf("Failed to create ExampleTask!\n");
}
}
APP_FEATURE_INIT(ExampleEntry);
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __E53_SF1_H__
#define __E53_SF1_H__
typedef enum
{
OFF = 0,
ON
} E53SF1Status;
void E53SF1Init(void);
void MQ2PPMCalibration(void);
int GetMQ2PPM(float *ppm);
void BeepStatusSet(E53SF1Status status);
#endif /* __E53_SF1_H__ */
+121
View File
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "E53_SF1.h"
#include "iot_adc.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_pwm.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define CAL_PPM 20 //校准环境中PPM值
#define RL 1 // RL阻值
#define WIFI_IOT_IO_NAME_GPIO_8 8
#define WIFI_IOT_PWM_PORT_PWM1 1
#define WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT 5
#define WIFI_IOT_ADC_6 6
static float R0; //元件在洁净空气中的阻值
/***************************************************************
* 函数名称: E53SF1Init
* 说 明: 初始化E53_SF1扩展板
* 参 数: 无
* 返 回 值: 无
***************************************************************/
void E53SF1Init(void)
{
IoTGpioInit(WIFI_IOT_IO_NAME_GPIO_8); //初始化GPIO_8
IoTGpioSetFunc(WIFI_IOT_IO_NAME_GPIO_8, WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT); //设置GPIO_8引脚复用功能为PWM
IoTGpioSetDir(WIFI_IOT_IO_NAME_GPIO_8, IOT_GPIO_DIR_OUT); //设置GPIO_8引脚为输出模式
IoTPwmInit(WIFI_IOT_PWM_PORT_PWM1); //初始化PWM1端口
}
/***************************************************************
* 函数名称: GetVoltage
* 说 明: 获取电压值函数
* 参 数: 无
*
* 返 回 值: 无
***************************************************************/
static float GetVoltage(void)
{
unsigned int ret;
unsigned short data;
ret = IoTAdcRead(WIFI_IOT_ADC_6, &data, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 0xff);
if (ret != IOT_SUCCESS)
{
printf("ADC Read Fail\n");
}
return (float)data * 1.8 * 4 / 4096.0;
}
/***************************************************************
* 函数名称: GetMQ2PPM
* 说 明: 获取PPM函数
* 参 数: ppm 烟雾浓度
* 返 回 值: 0 成功; -1 失败
***************************************************************/
int GetMQ2PPM(float* ppm)
{
unsigned int ret;
unsigned short data;
float voltage, RS;
ret = IoTAdcRead(WIFI_IOT_ADC_6, &data, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 0xff);
if (ret != 0) {
printf("ADC Read Fail\n");
return -1;
}
voltage = (float)data * 1.8 * 4 / 4096.0;
RS = (5 - voltage) / voltage * RL; //计算RS
*ppm = 613.9f * pow(RS / R0, -2.074f); //计算ppm
return 0;
}
/***************************************************************
* 函数名称: MQ2PPMCalibration
* 说 明: 传感器校准函数
* 参 数: 无
* 返 回 值: 无
***************************************************************/
void MQ2PPMCalibration(void)
{
float voltage = GetVoltage();
float RS = (5 - voltage) / voltage * RL;
R0 = RS / pow(CAL_PPM / 613.9f, 1 / -2.074f);
}
/***************************************************************
* 函数名称: BeepStatusSet
* 说 明: 蜂鸣器报警与否
* 参 数: status,ENUM枚举的数据
* OFF,蜂鸣器
* ON,开蜂鸣器
* 返 回 值: 无
***************************************************************/
void BeepStatusSet(E53SF1Status status)
{
if (status == ON) {
IoTPwmStart(WIFI_IOT_PWM_PORT_PWM1, 50, 4000); //输出PWM波
}
if (status == OFF) {
IoTPwmStop(WIFI_IOT_PWM_PORT_PWM1);
}
}
+25
View File
@@ -0,0 +1,25 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("e53_ia1_example") {
sources = [
"src/E53_IA1.c",
"e53_ia1_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"include"
]
}
+155
View File
@@ -0,0 +1,155 @@
# BearPi-HM_Nano开发板传感器驱动开发——E53_IA1读取温度 、湿度、光照强度
本示例将演示如何在BearPi-HM_Nano开发板上使用E53_IA1读取温度 、湿度、光照强度,当温度 、湿度超标时开启电机通风,当光照强度过低时,开启补光灯补光,设备安装如下图所示。
![E53_IA1安装](../../docs/figures/C2_e53_ia1_temp_humi_pls/E53_IA1安装.png "E53_IA1安装")
## E53_IA1 API分析
本案例主要使用了以下API完成温度 、湿度、光照强度读取。
### E53IA1Init()
```C
void E53IA1Init(void)
```
**描述:**
初始化E53_IA1
### E53IA1ReadData()
```C
void E53IA1ReadData(E53IA1Data *ReadData)
```
**描述:**
读取温度 、湿度、光照强度。
### Light_StatusSet()
```C
void LightStatusSet(E53IA1Status status)
```
**描述:**
控制补光灯开关。
**参数:**
|参数名|描述|
|:--|:------|
| status | ON开,OFF关闭。 |
### Motor_StatusSet()
```C
void MotorStatusSet(E53IA1Status status)
```
**描述:**
控制电机开关。
**参数:**
|参数名|描述|
|:--|:------|
| status | ON开,OFF关闭。 |
## 硬件设计
本案例将用到 E53_IA1 智慧农业扩展板与 BearPi-HM_Nano 开发板,其中E53_IA1扩展板接口原理图如下,温湿度传感器sht30和光照强度传感器BH1750都是通过I2C来驱动,电机和补光灯分别通过GPIO_8和GPIO_14来控制。
![E53_IA1接口](../../docs/figures/C2_e53_ia1_temp_humi_pls/E53_IA1接口.png "E53_IA1接口")
![E53接口电路](../../docs/figures/C2_e53_ia1_temp_humi_pls/E53接口电路.png "E53接口电路")
E53_IA1 智慧农业扩展板与 BearPi-HM_Nano 开发板安装如下图所示。
![E53_IA1安装](../../docs/figures/C2_e53_ia1_temp_humi_pls/E53_IA1安装.png "E53_IA1安装")
## 软件设计
**主要代码分析**
首先调用 `E53IA1Init()` 函数初始化E53_IA1所接的引脚的功能,然后循环调用 `E53IA1ReadData(E53IA1Data *ReadData)` 函数读取温度 、湿度、光照强度并通过串口打印出来,当光照强度过低时,开启补光灯补光,当温度 、湿度超标时开启电机通风。
```C
static void ExampleTask(void)
{
int ret;
E53IA1Data data;
ret = E53IA1Init();
if (ret != 0) {
printf("E53_IA1 Init failed!\r\n");
return;
}
while (1) {
printf("\r\n=======================================\r\n");
printf("\r\n*************E53_IA1_example***********\r\n");
printf("\r\n=======================================\r\n");
ret = E53IA1ReadData(&data);
if (ret != 0) {
printf("E53_IA1 Read Data failed!\r\n");
return;
}
printf("\r\n******************************Lux Value is %.2f\r\n", data.Lux);
printf("\r\n******************************Humidity is %.2f\r\n", data.Humidity);
printf("\r\n******************************Temperature is %.2f\r\n", data.Temperature);
if ((int)data.Lux < 20) {
LightStatusSet(ON);
} else {
LightStatusSet(OFF);
}
if (((int)data.Humidity > 70) | ((int)data.Temperature > 35)) {
MotorStatusSet(ON);
} else {
MotorStatusSet(OFF);
}
usleep(1000000);
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `e53_ia1_example` 参与编译。
```r
#"C1_e53_sf1_mq2:e53_sf1_example",
"C2_e53_ia1_temp_humi_pls:e53_ia1_example",
#"C3_e53_sc1_pls:e53_sc1_example",
#"C4_e53_sc2_axis:e53_sc2_example",
#"C5_e53_is1_infrared:e53_is1_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印温湿度及光照强度信息。用手遮住扩展板,补光灯会自动开启,控制温度或者湿度超标,电机会自动开启。
```c
=======================================
*************E53_IA1_example***********
=======================================
******************************Lux Value is 53.33
******************************Humidity is 44.10
******************************Temperature is 28.13
=======================================
*************E53_IA1_example***********
=======================================
******************************Lux Value is 53.33
******************************Humidity is 44.10
******************************Temperature is 28.13
```
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "E53_IA1.h"
#define TASK_STACK_SIZE 1024 * 8
#define TASK_PRIO 25
static void ExampleTask(void)
{
int ret;
E53IA1Data data;
ret = E53IA1Init();
if (ret != 0) {
printf("E53_IA1 Init failed!\r\n");
return;
}
while (1) {
printf("\r\n=======================================\r\n");
printf("\r\n*************E53_IA1_example***********\r\n");
printf("\r\n=======================================\r\n");
ret = E53IA1ReadData(&data);
if (ret != 0) {
printf("E53_IA1 Read Data failed!\r\n");
return;
}
printf("\r\n******************************Lux Value is %.2f\r\n", data.Lux);
printf("\r\n******************************Humidity is %.2f\r\n", data.Humidity);
printf("\r\n******************************Temperature is %.2f\r\n", data.Temperature);
if ((int)data.Lux < 20) {
LightStatusSet(ON);
} else {
LightStatusSet(OFF);
}
if (((int)data.Humidity > 70) | ((int)data.Temperature > 35)) {
MotorStatusSet(ON);
} else {
MotorStatusSet(OFF);
}
usleep(1000000);
}
}
static void ExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "ExampleTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = TASK_STACK_SIZE;
attr.priority = TASK_PRIO;
if (osThreadNew((osThreadFunc_t)ExampleTask, NULL, &attr) == NULL) {
printf("Failed to create ExampleTask!\n");
}
}
APP_FEATURE_INIT(ExampleEntry);
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __E53_IA1_H__
#define __E53_IA1_H__
/* 寄存器宏定义 --------------------------------------------------------------------*/
#define SHT30_ADDR 0x44
#define BH1750_ADDR 0x23
typedef enum
{
OFF = 0,
ON
} E53IA1Status;
/* E53_IA1传感器数据类型定义 ------------------------------------------------------------*/
typedef struct
{
float Lux; //光照强度
float Humidity; //湿度
float Temperature; //温度
} E53IA1Data;
int E53IA1Init(void);
int E53IA1ReadData(E53IA1Data *ReadData);
void LightStatusSet(E53IA1Status status);
void MotorStatusSet(E53IA1Status status);
#endif /* __E53_IA1_H__ */
+309
View File
@@ -0,0 +1,309 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "E53_IA1.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_i2c.h"
#include "iot_i2c_ex.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA 6
#define WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL 6
#define WIFI_IOT_IO_FUNC_GPIO_8_GPIO 0
#define WIFI_IOT_IO_FUNC_GPIO_14_GPIO 4
#define WIFI_IOT_I2C_IDX_1 1
/***************************************************************
* 函数名称: E53IA1IoInit
* 说 明: E53_IA1 GPIO初始化
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static void E53IA1IoInit(void)
{
IoTGpioInit(8);
IoTGpioSetFunc(8, WIFI_IOT_IO_FUNC_GPIO_8_GPIO);
IoTGpioSetDir(8, IOT_GPIO_DIR_OUT); //设置GPIO_8为输出模式
IoTGpioInit(14);
IoTGpioSetFunc(14, WIFI_IOT_IO_FUNC_GPIO_14_GPIO);
IoTGpioSetDir(14, IOT_GPIO_DIR_OUT); //设置GPIO_14为输出模式
IoTGpioInit(0);
IoTGpioSetFunc(0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA); // GPIO_0复用为I2C1_SDA
IoTGpioInit(1);
IoTGpioSetFunc(1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL); // GPIO_1复用为I2C1_SCL
IoTI2cInit(WIFI_IOT_I2C_IDX_1, 400000);
}
/***************************************************************
* 函数名称: Init_BH1750
* 说 明: 写命令初始化BH1750
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
static int InitBH1750(void)
{
int ret;
uint8_t send_data[1] = {0x01};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x00, send_data, 1);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: StartBH1750
* 说 明: 启动BH1750
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
static int StartBH1750(void)
{
int ret;
uint8_t send_data[1] = {0x10};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x00, send_data, 1);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: SHT30Reset
* 说 明: SHT30复位
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
static int SHT30Reset(void)
{
int ret;
uint8_t send_data[2] = {0x30, 0xA2};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (SHT30_ADDR << 1) | 0x00, send_data, 2);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: InitSHT30
* 说 明: 初始化SHT30,设置测量周期
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static int InitSHT30(void)
{
int ret;
uint8_t send_data[2] = {0x22, 0x36};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (SHT30_ADDR << 1) | 0x00, send_data, 2);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: SHT3xCheckCrc
* 说 明: 检查数据正确性
* 参 数: data:读取到的数据
nbrOfBytes:需要校验的数量
checksum:读取到的校对比验值
* 返 回 值: 校验结果,0-成功 1-失败
***************************************************************/
static uint8_t SHT3xCheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)
{
uint8_t crc = 0xFF;
uint8_t bit = 0;
uint8_t byteCtr;
const int16_t POLYNOMIAL = 0x131;
// calculates 8-Bit checksum with given polynomial
for (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr) {
crc ^= (data[byteCtr]);
for (bit = 8; bit > 0; --bit) {
if (crc & 0x80)
crc = (crc << 1) ^ POLYNOMIAL;
else
crc = (crc << 1);
}
}
if (crc != checksum)
return 1;
else
return 0;
}
/***************************************************************
* 函数名称: SHT3xCalcTemperatureC
* 说 明: 温度计算
* 参 数: u16sT:读取到的温度原始数据
* 返 回 值: 计算后的温度数据
***************************************************************/
static float SHT3xCalcTemperatureC(uint16_t u16sT)
{
float temperatureC = 0; // variable for result
u16sT &= ~0x0003; // clear bits [1..0] (status bits)
//-- calculate temperature [℃] --
temperatureC = (175 * (float)u16sT / 65535 - 45); // T = -45 + 175 * rawValue / (2^16-1)
return temperatureC;
}
/***************************************************************
* 函数名称: SHT3xCalcRH
* 说 明: 湿度计算
* 参 数: u16sRH:读取到的湿度原始数据
* 返 回 值: 计算后的湿度数据
***************************************************************/
static float SHT3xCalcRH(uint16_t u16sRH)
{
float humidityRH = 0; // variable for result
u16sRH &= ~0x0003; // clear bits [1..0] (status bits)
//-- calculate relative humidity [%RH] --
humidityRH = (100 * (float)u16sRH / 65535); // RH = rawValue / (2^16-1) * 10
return humidityRH;
}
/***************************************************************
* 函数名称: E53IA1Init
* 说 明: 初始化E53_IA1
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
int E53IA1Init(void)
{
int ret;
E53IA1IoInit();
ret = InitBH1750();
if (ret != 0) {
printf("Init BH1750 failed!\r\n");
return -1;
}
ret = InitSHT30();
if (ret != 0) {
printf("Init SHT30 failed!\r\n");
return -1;
}
}
/***************************************************************
* 函数名称: E53IA1ReadData
* 说 明: 测量光照强度、温度、湿度
* 参 数: ReadData,光照强度、温度、湿度数据
* 返 回 值: 0 成功; -1 失败
***************************************************************/
int E53IA1ReadData(E53IA1Data* ReadData)
{
int ret;
ret = StartBH1750(); // 启动传感器采集数据
if (ret != 0) {
printf("Start BH1750 failed!\r\n");
return -1;
}
usleep(180000);
uint8_t recv_data[2] = {0};
ret = IoTI2cRead(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x01, recv_data, 2); // 读取传感器数据
if (ret != 0) {
return -1;
}
ReadData->Lux = (float)(((recv_data[0] << 8) + recv_data[1]) / 1.2);
uint8_t data[3]; // data array for checksum verification
uint16_t dat, tmp;
uint8_t SHT3X_Data_Buffer[6]; // byte 0,1 is temperature byte 4,5 is humidity
IotI2cData sht30_i2c_data = {0};
uint8_t send_data[2] = {0xE0, 0x00};
sht30_i2c_data.sendBuf = send_data;
sht30_i2c_data.sendLen = 2;
sht30_i2c_data.receiveBuf = SHT3X_Data_Buffer;
sht30_i2c_data.receiveLen = 6;
ret = IoTI2cWriteread(WIFI_IOT_I2C_IDX_1, (SHT30_ADDR << 1) | 0x00, &sht30_i2c_data); // Read bh1750 sensor data
if (ret != 0) {
return -1;
}
/* check tem */
data[0] = SHT3X_Data_Buffer[0];
data[1] = SHT3X_Data_Buffer[1];
data[2] = SHT3X_Data_Buffer[2];
tmp = SHT3xCheckCrc(data, 2, data[2]);
/* value is ture */
if (!tmp) {
dat = ((uint16_t)data[0] << 8) | data[1];
ReadData->Temperature = SHT3xCalcTemperatureC(dat);
}
/* check humidity */
data[0] = SHT3X_Data_Buffer[3];
data[1] = SHT3X_Data_Buffer[4];
data[2] = SHT3X_Data_Buffer[5];
/* value is ture */
tmp = SHT3xCheckCrc(data, 2, data[2]);
if (!tmp) {
dat = ((uint16_t)data[0] << 8) | data[1];
ReadData->Humidity = SHT3xCalcRH(dat);
}
return 0;
}
/***************************************************************
* 函数名称: LightStatusSet
* 说 明: 灯状态设置
* 参 数: status,ENUM枚举的数据
* OFF,关
* ON,开
* 返 回 值: 无
***************************************************************/
void LightStatusSet(E53IA1Status status)
{
if (status == ON) {
IoTGpioSetOutputVal(14, 1); //设置GPIO_14输出高电平点亮灯
}
if (status == OFF) {
IoTGpioSetOutputVal(14, 0); //设置GPIO_14输出低电平关闭灯
}
}
/***************************************************************
* 函数名称: MotorStatusSet
* 说 明: 电机状态设置
* 参 数: status,ENUM枚举的数据
* OFF,关
* ON,开
* 返 回 值: 无
***************************************************************/
void MotorStatusSet(E53IA1Status status)
{
if (status == ON) {
IoTGpioSetOutputVal(8, 1); //设置GPIO_8输出高电平打开电机
}
if (status == OFF) {
IoTGpioSetOutputVal(8, 0); //设置GPIO_8输出低电平关闭电机
}
}
+25
View File
@@ -0,0 +1,25 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("e53_sc1_example") {
sources = [
"src/E53_SC1.c",
"e53_sc1_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"include"
]
}
+124
View File
@@ -0,0 +1,124 @@
# BearPi-HM_Nano开发板传感器驱动开发——E53_SC1读取光照强度
本示例将演示如何在BearPi-HM_Nano开发板上使用E53_SC1读取温度 、湿度、光照强度,当光照强度过低时,开启补光灯补光,设备安装如下图所示。
![E53_SC1安装](../../docs/figures/C3_e53_sc1_pls/E53_SC1安装.png "E53_SC1安装")
## E53_SC1 API分析
本案例主要使用了以下API完成温度 、湿度、光照强度读取。
### E53SC1Init()
```C
int E53SC1Init(void);
```
**描述:**
初始化E53_SC1。
### E53SC1ReadData()
```C
int E53SC1ReadData(float *data);
```
**描述:**
读取光照强度。
**参数:**
|参数名|描述|
|:--|:------|
| data | data,光照强度数据指针。 |
### LightStatusSet()
```C
void LightStatusSet(E53SC1Status status);
```
**描述:**
控制补光灯开关
**参数:**
|参数名|描述|
|:--|:------|
| status | ON开,OFF关闭。 |
## 硬件设计
本案例将用到 E53_SC1 智慧路灯扩展板与 BearPi-HM_Nano 开发板,其中E53_SC1扩展板原理图如下,光照强度传感器BH1750是通过I2C来驱动,灯是通过GPIO_7来控制。
![E53_SC1接口](../../docs/figures/C3_e53_sc1_pls/E53_SC1接口.png "E53_SC1接口")
![E53接口电路](../../docs/figures/C3_e53_sc1_pls/E53接口电路.png "E53接口电路")
E53_SC1 智慧路灯扩展板与 BearPi-HM_Nano 开发板安装如下图所示。
![E53_SC1安装](../../docs/figures/C3_e53_sc1_pls/E53_SC1安装.png "E53_SC1安装")
## 软件设计
**主要代码分析**
首先调用 `E53SC1Init()` 函数初始化E53_SC1所接的引脚的功能,然后循环调用 `E53SC1ReadData()` 函数读取光照强度并通过串口打印出来,当光照强度过低时,开启灯。
```C
static void ExampleTask(void)
{
int ret;
float Lux;
ret = E53SC1Init();
if (ret != 0) {
printf("E53_SC1 Init failed!\r\n");
return;
}
while (1) {
printf("=======================================\r\n");
printf("*************E53_SC1_example***********\r\n");
printf("=======================================\r\n");
ret = E53SC1ReadData(&Lux);
if (ret != 0) {
printf("E53_SC1 Read Data failed!\r\n");
return;
}
printf("Lux data:%.2f\r\n", Lux);
if (Lux < 20) {
LightStatusSet(ON);
} else {
LightStatusSet(OFF);
}
usleep(1000000);
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `e53_sc1_example` 参与编译。
```r
#"C1_e53_sf1_mq2:e53_sf1_example",
#"C2_e53_ia1_temp_humi_pls:e53_ia1_example",
"C3_e53_sc1_pls:e53_sc1_example",
#"C4_e53_sc2_axis:e53_sc2_example",
#"C5_e53_is1_infrared:e53_is1_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印光照强度信息。用手遮住扩展板,补光灯会自动开启。
```c
=======================================
*************E53_SC1_example***********
=======================================
Lux data:53.33
=======================================
*************E53_SC1_example***********
=======================================
Lux data:53.33
```
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "E53_SC1.h"
#include "cmsis_os2.h"
#include "ohos_init.h"
#define TASK_STACK_SIZE 1024 * 8
#define TASK_PRIO 25
static void ExampleTask(void)
{
int ret;
float Lux;
ret = E53SC1Init();
if (ret != 0) {
printf("E53_SC1 Init failed!\r\n");
return;
}
while (1) {
printf("=======================================\r\n");
printf("*************E53_SC1_example***********\r\n");
printf("=======================================\r\n");
ret = E53SC1ReadData(&Lux);
if (ret != 0) {
printf("E53_SC1 Read Data failed!\r\n");
return;
}
printf("Lux data:%.2f\r\n", Lux);
if (Lux < 20) {
LightStatusSet(ON);
} else {
LightStatusSet(OFF);
}
usleep(1000000);
}
}
static void ExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "ExampleTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = TASK_STACK_SIZE;
attr.priority = TASK_PRIO;
if (osThreadNew((osThreadFunc_t)ExampleTask, NULL, &attr) == NULL) {
printf("Failed to create ExampleTask!\n");
}
}
APP_FEATURE_INIT(ExampleEntry);
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __E53_SC1_H__
#define __E53_SC1_H__
#define BH1750_ADDR 0x23
typedef enum
{
OFF = 0,
ON
} E53SC1Status;
int E53SC1Init(void);
int E53SC1ReadData(float *data);
void LightStatusSet(E53SC1Status status);
#endif /* __E53_SC1_H__ */
+142
View File
@@ -0,0 +1,142 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "E53_SC1.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_i2c.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA 6
#define WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL 6
#define WIFI_IOT_IO_FUNC_GPIO_7_GPIO 0
#define WIFI_IOT_I2C_IDX_1 1
/***************************************************************
* 函数名称: E53SC1IoInit
* 说 明: E53_SC1 GPIO初始化
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static void E53SC1IoInit(void)
{
IoTGpioInit(7);
IoTGpioSetFunc(7, WIFI_IOT_IO_FUNC_GPIO_7_GPIO);
IoTGpioSetDir(7, IOT_GPIO_DIR_OUT); //设置GPIO_7为输出模式
IoTGpioInit(0);
IoTGpioSetFunc(0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA); // GPIO_0复用为I2C1_SDA
IoTGpioInit(1);
IoTGpioSetFunc(1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL); // GPIO_1复用为I2C1_SCL
IoTI2cInit(WIFI_IOT_I2C_IDX_1, 400000); /* baudrate: 400kbps */
}
/***************************************************************
* 函数名称: Init_BH1750
* 说 明: 写命令初始化BH1750
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
static int InitBH1750(void)
{
int ret;
uint8_t send_data[1] = {0x01};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x00, send_data, 1);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: Start_BH1750
* 说 明: 启动BH1750
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
static int StartBH1750(void)
{
int ret;
uint8_t send_data[1] = {0x10};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x00, send_data, 1);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: E53SC1Init
* 说 明: 初始化E53_SC1
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
int E53SC1Init(void)
{
int ret;
E53SC1IoInit();
ret = InitBH1750();
if (ret != 0) {
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: E53_SC1_Read_Data
* 说 明: 测量光照强度
* 参 数: data,光照强度数据指针
* 返 回 值: 0 成功; -1 失败
***************************************************************/
int E53SC1ReadData(float* data)
{
int ret;
int result;
ret = StartBH1750(); // 启动传感器采集数据
if (ret != 0) {
printf("Start BH1750 failed!\r\n");
return -1;
}
usleep(180000);
uint8_t recv_data[2] = {0};
ret = IoTI2cRead(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x01, recv_data, 2); // 读取传感器数据
if (ret != 0) {
return -1;
}
*data = (float)(((recv_data[0] << 8) + recv_data[1]) / 1.2); //合成数据,即光照数据
return 0;
}
/***************************************************************
* 函数名称: LightStatusSet
* 说 明: 灯状态设置
* 参 数: status,ENUM枚举的数据
* OFF,光灯
* ON,开灯
* 返 回 值: 无
***************************************************************/
void LightStatusSet(E53SC1Status status)
{
if (status == ON) {
IoTGpioSetOutputVal(7, 1); //设置GPIO_7输出高电平点亮LED灯
}
if (status == OFF) {
IoTGpioSetOutputVal(7, 0); //设置GPIO_7输出低电平点亮LED灯
}
}
+25
View File
@@ -0,0 +1,25 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("e53_sc2_example") {
sources = [
"src/E53_SC2.c",
"e53_sc2_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"include"
]
}
+132
View File
@@ -0,0 +1,132 @@
# BearPi-HM_Nano开发板传感器驱动开发——E53_SC2读取三轴加速度
本示例将演示如何在BearPi-HM_Nano开发板上使用E53_SC2读取三轴加速度,设备安装如下图所示。
![](../../docs/figures/C4_e53_sc2_axis/E53_SC2安装.png "E53_SC2安装")
## E53_SC2 API分析
本案例主要使用了以下API完成三轴加速度读取。
### E53SC2Init()
```C
int E53SC2Init(void);
```
**描述:**
初始化E53_SC2。
### E53SC2ReadData()
```C
int E53SC2ReadData(E53SC2Data *ReadData);
```
**描述:**
读取三轴加速度及温度。
## 硬件设计
本案例将用到 E53_SC2 智慧井盖扩展板与 BearPi-HM_Nano 开发板,其中E53_SC2扩展板原理图如下,三轴加速度传感器MPU6050是通过I2C来驱动。
![](../../docs/figures/C4_e53_sc2_axis/E53_SC2接口.png "E53_SC2接口")
![](../../docs/figures/C4_e53_sc2_axis/E53接口电路.png "E53接口电路")
E53_SC2 智慧井盖扩展板与 BearPi-HM_Nano 开发板安装如下图所示。
![](../../docs/figures/C4_e53_sc2_axis/E53_SC2安装.png "E53_SC2安装")
## 软件设计
**主要代码分析**
首先调用 `E53SC2Init()` 函数初始化E53_SC2所接的引脚的功能,然后循环调用 `E53SC2ReadData()` 函数读取三轴加速度并通过串口打印出来,设置第一次读出的三轴加速度为水平状态,当倾斜开发板后会点亮扩展板上倾斜倾斜状态的灯。
```C
static void ExampleTask(void)
{
uint8_t ret;
E53SC2Data data;
int X = 0, Y = 0, Z = 0;
ret = E53SC2Init();
if (ret != 0) {
printf("E53_SC2 Init failed!\r\n");
return;
}
while (1) {
printf("=======================================\r\n");
printf("*************E53_SC2_example***********\r\n");
printf("=======================================\r\n");
ret = E53SC2ReadData(&data);
if (ret != 0) {
printf("E53_SC2 Read Data!\r\n");
return;
}
printf("\r\n**************Temperature is %d\r\n", (int)data.Temperature);
printf("\r\n**************Accel[0] is %d\r\n", (int)data.Accel[0]);
printf("\r\n**************Accel[1] is %d\r\n", (int)data.Accel[1]);
printf("\r\n**************Accel[2] is %d\r\n", (int)data.Accel[2]);
if (X == 0 && Y == 0 && Z == 0) {
X = (int)data.Accel[0];
Y = (int)data.Accel[1];
Z = (int)data.Accel[2];
} else {
if (X + 100 < data.Accel[0] || X - 100 > data.Accel[0] || Y + 100 < data.Accel[1]
|| Y - 100 > data.Accel[1] || Z + 100 < data.Accel[2] || Z - 100 > data.Accel[2]) {
LedD1StatusSet(OFF);
LedD2StatusSet(ON);
} else {
LedD1StatusSet(ON);
LedD2StatusSet(OFF);
}
}
usleep(1000000);
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `e53_sc2_example` 参与编译。
```r
#"C1_e53_sf1_mq2:e53_sf1_example",
#"C2_e53_ia1_temp_humi_pls:e53_ia1_example",
#"C3_e53_sc1_pls:e53_sc1_example",
"C4_e53_sc2_axis:e53_sc2_example",
#"C5_e53_is1_infrared:e53_is1_example",
```
### 运行结果<a name="section18115713118"></a>
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印温度和三轴加速度信息。当倾斜开发板后会点亮扩展板上倾斜倾斜状态的灯。
```c
=======================================
*************E53_SC2_example***********
=======================================
******************************Temperature is 25
******************************Accel[0] is 45
******************************Accel[1] is 3
******************************Accel[2] is 2089
=======================================
*************E53_SC2_example***********
=======================================
******************************Temperature is 25
******************************Accel[0] is 49
******************************Accel[1] is 5
******************************Accel[2] is 2087
```
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "E53_SC2.h"
#include "cmsis_os2.h"
#include "ohos_init.h"
#define TASK_STACK_SIZE 1024 * 8
#define TASK_PRIO 25
static void ExampleTask(void)
{
uint8_t ret;
E53SC2Data data;
int X = 0, Y = 0, Z = 0;
ret = E53SC2Init();
if (ret != 0) {
printf("E53_SC2 Init failed!\r\n");
return;
}
while (1) {
printf("=======================================\r\n");
printf("*************E53_SC2_example***********\r\n");
printf("=======================================\r\n");
ret = E53SC2ReadData(&data);
if (ret != 0) {
printf("E53_SC2 Read Data!\r\n");
return;
}
printf("\r\n**************Temperature is %d\r\n", (int)data.Temperature);
printf("\r\n**************Accel[0] is %d\r\n", (int)data.Accel[0]);
printf("\r\n**************Accel[1] is %d\r\n", (int)data.Accel[1]);
printf("\r\n**************Accel[2] is %d\r\n", (int)data.Accel[2]);
if (X == 0 && Y == 0 && Z == 0) {
X = (int)data.Accel[0];
Y = (int)data.Accel[1];
Z = (int)data.Accel[2];
} else {
if (X + 100 < data.Accel[0] || X - 100 > data.Accel[0] || Y + 100 < data.Accel[1] ||
Y - 100 > data.Accel[1] || Z + 100 < data.Accel[2] || Z - 100 > data.Accel[2]) {
LedD1StatusSet(OFF);
LedD2StatusSet(ON);
} else {
LedD1StatusSet(ON);
LedD2StatusSet(OFF);
}
}
usleep(1000000);
}
}
static void ExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "ExampleTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = TASK_STACK_SIZE;
attr.priority = TASK_PRIO;
if (osThreadNew((osThreadFunc_t)ExampleTask, NULL, &attr) == NULL) {
printf("Failed to create ExampleTask!\n");
}
}
APP_FEATURE_INIT(ExampleEntry);
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __E53_SC2_H__
#define __E53_SC2_H__
/* 宏定义 --------------------------------------------------------------------*/
#define MPU6050_GYRO_OUT 0x43 //MPU6050陀螺仪数据寄存器地址
#define MPU6050_ACC_OUT 0x3B //MPU6050加速度数据寄存器地址
#define MPU6050_SLAVE_ADDRESS 0x68 //MPU6050器件读地址
#define MPU6050_ADDRESS_AD0_LOW 0x68 // address pin low (GND), default for InvenSense evaluation board
#define MPU6050_RA_CONFIG 0x1A
#define MPU6050_RA_ACCEL_CONFIG 0x1C
#define MPU6050_RA_FF_THR 0x1D
#define MPU6050_RA_FF_DUR 0x1E
#define MPU6050_RA_MOT_THR 0x1F //运动检测阀值设置寄存器
#define MPU6050_RA_MOT_DUR 0x20 //运动检测时间阀值
#define MPU6050_RA_ZRMOT_THR 0x21
#define MPU6050_RA_ZRMOT_DUR 0x22
#define MPU6050_RA_FIFO_EN 0x23
#define MPU6050_RA_INT_PIN_CFG 0x37 //中断/旁路设置寄存器
#define MPU6050_RA_INT_ENABLE 0x38 //中断使能寄存器
#define MPU6050_RA_TEMP_OUT_H 0x41
#define MPU6050_RA_USER_CTRL 0x6A
#define MPU6050_RA_PWR_MGMT_1 0x6B
#define MPU6050_RA_WHO_AM_I 0x75
#define SENSOR_DATA_WIDTH_8_BIT 8 // 8 bit
#define ACCEL_DATA_LEN 6
#define TEMP_DATA_LEN 2
typedef enum
{
OFF = 0,
ON
} E53SC2Status;
enum AccelAxisNum {
ACCEL_X_AXIS = 0,
ACCEL_Y_AXIS = 1,
ACCEL_Z_AXIS = 2,
ACCEL_AXIS_NUM = 3,
};
enum AccelAxisPart {
ACCEL_X_AXIS_LSB = 0,
ACCEL_X_AXIS_MSB = 1,
ACCEL_Y_AXIS_LSB = 2,
ACCEL_Y_AXIS_MSB = 3,
ACCEL_Z_AXIS_LSB = 4,
ACCEL_Z_AXIS_MSB = 5,
ACCEL_AXIS_BUTT,
};
enum TempPart {
TEMP_LSB = 0,
TEMP_MSB = 1,
};
/* E53_SC2传感器数据类型定义 ------------------------------------------------------------*/
typedef struct
{
short Temperature;
short Accel[3];
} E53SC2Data;
int E53SC2Init(void);
int E53SC2ReadData(E53SC2Data *ReadData);
void LedD1StatusSet(E53SC2Status status);
void LedD2StatusSet(E53SC2Status status);
#endif
+381
View File
@@ -0,0 +1,381 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "E53_SC2.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_i2c.h"
#include "iot_i2c_ex.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA 6
#define WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL 6
#define WIFI_IOT_IO_FUNC_GPIO_8_GPIO 0
#define WIFI_IOT_IO_FUNC_GPIO_7_GPIO 0
#define WIFI_IOT_I2C_IDX_1 1
#define WIFI_IOT_IO_NAME_GPIO_7 7
#define WIFI_IOT_IO_NAME_GPIO_8 8
#define WIFI_IOT_IO_NAME_GPIO_0 0
#define WIFI_IOT_IO_NAME_GPIO_1 1
#define RESET_DELAY_US 20000
#define READ_DATA_DELAY_US 50000
/***************************************************************
* 函数名称: E53SC2IoInit
* 说 明: E53_SC2 GPIO初始化
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static void E53SC2IoInit(void)
{
IoTGpioInit(WIFI_IOT_IO_NAME_GPIO_8);
IoTGpioSetFunc(WIFI_IOT_IO_NAME_GPIO_8, WIFI_IOT_IO_FUNC_GPIO_8_GPIO);
IoTGpioSetDir(WIFI_IOT_IO_NAME_GPIO_8, IOT_GPIO_DIR_OUT); // 设置GPIO_8为输出模式
IoTGpioInit(WIFI_IOT_IO_NAME_GPIO_7);
IoTGpioSetFunc(WIFI_IOT_IO_NAME_GPIO_7, WIFI_IOT_IO_FUNC_GPIO_7_GPIO);
IoTGpioSetDir(WIFI_IOT_IO_NAME_GPIO_7, IOT_GPIO_DIR_OUT); // 设置GPIO_7为输出模式
IoTGpioInit(WIFI_IOT_IO_NAME_GPIO_0);
IoTGpioSetFunc(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA); // GPIO_0复用为I2C1_SDA
IoTGpioInit(WIFI_IOT_IO_NAME_GPIO_1);
IoTGpioSetFunc(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL); // GPIO_1复用为I2C1_SCL
IoTI2cInit(WIFI_IOT_I2C_IDX_1, 400000); /* baudrate: 400kbps */
}
/***************************************************************
* 函数功能: 通过I2C写入一个值到指定寄存器内
* 输入参数: AddrI2C设备地址
* Reg:目标寄存器
* Value:值
* 返 回 值: 无
* 说 明: 无
**************************************************************/
static int MPU6050WriteData(uint8_t Reg, uint8_t Value)
{
uint32_t ret;
uint8_t send_data[2] = {Reg, Value};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (MPU6050_SLAVE_ADDRESS << 1) | 0x00, send_data, 2);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数功能: 通过I2C写入一段数据到指定寄存器内
* 输入参数: AddrI2C设备地址
* Reg:目标寄存器
* RegSize:寄存器尺寸(8位或者16位)
* pBuffer:缓冲区指针
* Length:缓冲区长度
* 返 回 值: HAL_StatusTypeDef:操作结果
* 说 明: 在循环调用是需加一定延时时间
**************************************************************/
static int MPU6050WriteBuffer(uint8_t Reg, uint8_t* pBuffer, uint16_t Length)
{
uint32_t ret = 0;
uint8_t send_data[256] = {0};
send_data[0] = Reg;
for (int j = 0; j < Length; j++) {
send_data[j + 1] = pBuffer[j];
}
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (MPU6050_SLAVE_ADDRESS << 1) | 0x00, send_data, Length + 1);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数功能: 通过I2C读取一段寄存器内容存放到指定的缓冲区内
* 输入参数: AddrI2C设备地址
* Reg:目标寄存器
* RegSize:寄存器尺寸(8位或者16位)
* pBuffer:缓冲区指针
* Length:缓冲区长度
* 返 回 值: HAL_StatusTypeDef:操作结果
* 说 明: 无
**************************************************************/
static int MPU6050ReadBuffer(uint8_t Reg, uint8_t* pBuffer, uint16_t Length)
{
uint32_t ret = 0;
IotI2cData mpu6050_i2c_data = {0};
uint8_t buffer[1] = {Reg};
mpu6050_i2c_data.sendBuf = buffer;
mpu6050_i2c_data.sendLen = 1;
mpu6050_i2c_data.receiveBuf = pBuffer;
mpu6050_i2c_data.receiveLen = Length;
ret = IoTI2cWriteread(WIFI_IOT_I2C_IDX_1, (MPU6050_SLAVE_ADDRESS << 1) | 0x00, &mpu6050_i2c_data);
if (ret != 0) {
printf("===== Error: I2C writeread ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数功能: 写数据到MPU6050寄存器
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
***************************************************************/
static void MPU6050WriteReg(uint8_t reg_add, uint8_t reg_dat)
{
MPU6050WriteData(reg_add, reg_dat);
}
/***************************************************************
* 函数功能: 从MPU6050寄存器读取数据
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
***************************************************************/
static int MPU6050ReadData(uint8_t reg_add, unsigned char* read, uint8_t num)
{
return MPU6050ReadBuffer(reg_add, read, num);
}
/***************************************************************
* 函数功能: 读取MPU6050的加速度数据
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
***************************************************************/
static int MPU6050ReadAcc(short* accData)
{
int ret;
uint8_t buf[ACCEL_DATA_LEN];
ret = MPU6050ReadData(MPU6050_ACC_OUT, buf, ACCEL_DATA_LEN);
if (ret != 0) {
return -1;
}
accData[ACCEL_X_AXIS] = (buf[ACCEL_X_AXIS_LSB] << SENSOR_DATA_WIDTH_8_BIT) | buf[ACCEL_X_AXIS_MSB];
accData[ACCEL_Y_AXIS] = (buf[ACCEL_Y_AXIS_LSB] << SENSOR_DATA_WIDTH_8_BIT) | buf[ACCEL_Y_AXIS_MSB];
accData[ACCEL_Z_AXIS] = (buf[ACCEL_Z_AXIS_LSB] << SENSOR_DATA_WIDTH_8_BIT) | buf[ACCEL_Z_AXIS_MSB];
return 0;
}
/***************************************************************
* 函数功能: 读取MPU6050的角速度数据
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
***************************************************************/
static int MPU6050ReadGyro(short* gyroData)
{
int ret;
uint8_t buf[ACCEL_DATA_LEN];
ret = MPU6050ReadData(MPU6050_GYRO_OUT, buf, ACCEL_DATA_LEN);
if (ret != 0) {
return -1;
}
gyroData[ACCEL_X_AXIS] = (buf[ACCEL_X_AXIS_LSB] << SENSOR_DATA_WIDTH_8_BIT) | buf[ACCEL_X_AXIS_MSB];
gyroData[ACCEL_Y_AXIS] = (buf[ACCEL_Y_AXIS_LSB] << SENSOR_DATA_WIDTH_8_BIT) | buf[ACCEL_Y_AXIS_MSB];
gyroData[ACCEL_Z_AXIS] = (buf[ACCEL_Z_AXIS_LSB] << SENSOR_DATA_WIDTH_8_BIT) | buf[ACCEL_Z_AXIS_MSB];
return 0;
}
/***************************************************************
* 函数功能: 读取MPU6050的原始温度数据
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
***************************************************************/
static int MPU6050ReadTemp(short* tempData)
{
int ret;
uint8_t buf[TEMP_DATA_LEN];
ret = MPU6050ReadData(MPU6050_RA_TEMP_OUT_H, buf, TEMP_DATA_LEN); // 读取温度值
if (ret != 0) {
return -1;
}
*tempData = (buf[TEMP_LSB] << SENSOR_DATA_WIDTH_8_BIT) | buf[TEMP_MSB];
return 0;
}
/***************************************************************
* 函数功能: 读取MPU6050的温度数据,转化成摄氏度
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
**************************************************************/
static int MPU6050ReturnTemp(short* Temperature)
{
int ret;
short temp3;
uint8_t buf[TEMP_DATA_LEN];
ret = MPU6050ReadData(MPU6050_RA_TEMP_OUT_H, buf, TEMP_DATA_LEN); // 读取温度值
if (ret != 0) {
return -1;
}
temp3 = (buf[TEMP_LSB] << SENSOR_DATA_WIDTH_8_BIT) | buf[TEMP_MSB];
*Temperature = (((double)(temp3 + 13200)) / 280) - 13;
return 0;
}
/***************************************************************
* 函数功能: 自由落体中断
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
**************************************************************/
void FreeFallInterrupt(void) // 自由落体中断
{
MPU6050WriteReg(MPU6050_RA_FF_THR, 0x01); // 自由落体阈值
MPU6050WriteReg(MPU6050_RA_FF_DUR, 0x01); // 自由落体检测时间20ms 单位1ms 寄存器0X20
}
void MotionInterrupt(void) // 运动中断
{
MPU6050WriteReg(MPU6050_RA_MOT_THR, 0x03); // 运动阈值
MPU6050WriteReg(MPU6050_RA_MOT_DUR, 0x14); // 检测时间20ms 单位1ms 寄存器0X20
}
void ZeroMotionInterrupt(void) // 静止中断
{
MPU6050WriteReg(MPU6050_RA_ZRMOT_THR, 0x20); // 静止阈值
MPU6050WriteReg(MPU6050_RA_ZRMOT_DUR, 0x20); // 静止检测时间20ms 单位1ms 寄存器0X20
}
/***************************************************************
* 函数功能: 初始化MPU6050芯片
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
***************************************************************/
void MPU6050Init(void)
{
MPU6050WriteReg(MPU6050_RA_PWR_MGMT_1, 0X80); // 复位MPU6050
usleep(RESET_DELAY_US);
MPU6050WriteReg(MPU6050_RA_PWR_MGMT_1, 0X00); // 唤醒MPU6050
MPU6050WriteReg(MPU6050_RA_INT_ENABLE, 0X00); // 关闭所有中断
MPU6050WriteReg(MPU6050_RA_USER_CTRL, 0X00); // I2C主模式关闭
MPU6050WriteReg(MPU6050_RA_FIFO_EN, 0X00); // 关闭FIFO
MPU6050WriteReg(MPU6050_RA_INT_PIN_CFG,
0X80); // 中断的逻辑电平模式,设置为0,中断信号为高电;设置为1,中断信号为低电平时。
MotionInterrupt(); // 运动中断
MPU6050WriteReg(MPU6050_RA_CONFIG, 0x04); // 配置外部引脚采样和DLPF数字低通滤波器
MPU6050WriteReg(MPU6050_RA_ACCEL_CONFIG, 0x1C); // 加速度传感器量程和高通滤波器配置
MPU6050WriteReg(MPU6050_RA_INT_PIN_CFG, 0X1C); // INT引脚低电平平时
MPU6050WriteReg(MPU6050_RA_INT_ENABLE, 0x40); // 中断使能寄存器
}
/***************************************************************
* 函数功能: 读取MPU6050的ID
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
***************************************************************/
int MPU6050ReadID(void)
{
unsigned char Re = 0;
MPU6050ReadData(MPU6050_RA_WHO_AM_I, &Re, 1); // 读器件地址
if (Re != 0x68) {
printf("MPU6050 dectected error!\r\n");
return -1;
} else {
return 0;
}
}
/***************************************************************
* 函数名称: E53SC2Init
* 说 明: 初始化E53_SC2
* 参 数: 无
* 返 回 值: 无
***************************************************************/
int E53SC2Init(void)
{
uint32_t ret = 0;
E53SC2IoInit();
MPU6050Init();
ret = MPU6050ReadID();
if (ret != 0) {
return -1;
}
osDelay(100);
return 0;
}
/***************************************************************
* 函数名称: E53SC2ReadData
* 说 明: 读取数据
* 参 数: 无
* 返 回 值: 无
***************************************************************/
int E53SC2ReadData(E53SC2Data* ReadData)
{
int ret;
short Accel[3];
short Temp;
if (MPU6050ReadID() != 0) {
return -1;
}
ret = MPU6050ReadAcc(Accel);
if (ret != 0) {
return -1;
}
ret = MPU6050ReturnTemp(&Temp);
if (ret != 0) {
return -1;
}
ReadData->Temperature = Temp;
ReadData->Accel[ACCEL_X_AXIS] = Accel[ACCEL_X_AXIS];
ReadData->Accel[ACCEL_Y_AXIS] = Accel[ACCEL_Y_AXIS];
ReadData->Accel[ACCEL_Z_AXIS] = Accel[ACCEL_Z_AXIS];
usleep(READ_DATA_DELAY_US);
return 0;
}
/***************************************************************
* 函数名称: LedD1StatusSet
* 说 明: LED_D1状态设置
* 参 数: status,ENUM枚举的数据
* OFF,关
* ON,开
* 返 回 值: 无
***************************************************************/
void LedD1StatusSet(E53SC2Status status)
{
if (status == ON) {
IoTGpioSetOutputVal(7, 1); // 设置GPIO_7输出高电平点亮灯
}
if (status == OFF) {
IoTGpioSetOutputVal(7, 0); // 设置GPIO_7输出低电平关闭灯
}
}
/***************************************************************
* 函数名称: LedD2StatusSet
* 说 明: LED_D2状态设置
* 参 数: status,ENUM枚举的数据
* OFF,关
* ON,开
* 返 回 值: 无
***************************************************************/
void LedD2StatusSet(E53SC2Status status)
{
if (status == ON) {
IoTGpioSetOutputVal(8, 1); // 设置GPIO_8输出高电平点亮灯
}
if (status == OFF) {
IoTGpioSetOutputVal(8, 0); // 设置GPIO_8输出低电平关闭灯
}
}
+25
View File
@@ -0,0 +1,25 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("e53_is1_example") {
sources = [
"src/E53_IS1.c",
"e53_is1_example.c"
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"include"
]
}
+88
View File
@@ -0,0 +1,88 @@
# BearPi-HM_Nano开发板传感器驱动开发——E53_IS1人体红外感应
本示例将演示如何在BearPi-HM_Nano开发板上使用E53_IS1实现人体红外感应,当检测到有人走动时,蜂鸣器发出报警,设备安装如下图所示。
![](../../docs/figures/C5_e53_is1_infrared/E53_IS1安装.png "E53_IS1安装")
## E53_IS1 API分析
本案例主要使用了以下API完成人体红外感应。
### E53IS1Init()
```C
void E53IS1Init(void);
```
**描述:**
初始化E53_IS1。
### E53IS1ReadData()
```C
void E53IS1ReadData(E53IS1CallbackFunc func);
```
**描述:**
设置人体感应触发的回调函数。
## 硬件设计
本案例将用到 E53_IS1 红外感应扩展板与 BearPi-HM_Nano 开发板,其中E53_IS1扩展板原理图如下,当检测到人时,传感器会输出高电平,通过对GPIO_7的监测就能判断是否有人走动。
![](../../docs/figures/C5_e53_is1_infrared/E53_IS1接口.png "E53_IS1接口")
![](../../docs/figures/C5_e53_is1_infrared/E53接口电路.png "E53接口电路")
E53_IS1 红外感应扩展板与 BearPi-HM_Nano 开发板安装如下图所示
![](../../docs/figures/C5_e53_is1_infrared/E53_IS1安装.png "E53_IS1安装")
## 软件设计
**主要代码分析**
首先调用 `E53IS1Init()` 函数初始化E53_SC1所接的引脚的功能,然后调用 `E53IS1ReadData()` BeepAlarm(),系统启动后会通过osEventFlagsWait()函数让ExampleTask任务一直等待事件标志位FLAGS_MSK1,当检测到人后,BeepAlarm()函数会发送事件标志位,ExampleTask任务继续运行开启蜂鸣器报警3秒钟 然后关闭蜂鸣器继续等待下一次触发事件。
```C
static void BeepAlarm(char *arg)
{
(void)arg;
osEventFlagsSet(g_eventFlagsId, FLAGS_MSK1);
}
static void ExampleTask(void)
{
int ret;
E53IS1Init();
ret = E53IS1ReadData(BeepAlarm);
if (ret != 0) {
printf("E53_IS1 Read Data failed!\r\n");
return ;
}
while (1) {
osEventFlagsWait(g_eventFlagsId, FLAGS_MSK1, osFlagsWaitAny, osWaitForever);
BeepStatusSet(ON);
osDelay(300);
BeepStatusSet(OFF);
}
}
```
## 编译调试
### 修改 BUILD.gn 文件
修改`device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `e53_is1_example` 参与编译。
```r
#"C1_e53_sf1_mq2:e53_sf1_example",
#"C2_e53_ia1_temp_humi_pls:e53_ia1_example",
#"C3_e53_sc1_pls:e53_sc1_example",
#"C4_e53_sc2_axis:e53_sc2_example",
"C5_e53_is1_infrared:e53_is1_example",
```
### 运行结果
示例代码编译烧录代码后,按下开发板的RESET按键,人员靠近开发板,蜂鸣器开始报警。
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "E53_IS1.h"
#include "cmsis_os2.h"
#include "ohos_init.h"
#define TASK_STACK_SIZE 1024 * 8
#define TASK_PRIO 25
#define FLAGS_MSK1 0x00000001U
osEventFlagsId_t g_eventFlagsId;
static void BeepAlarm(char* arg)
{
(void)arg;
osEventFlagsSet(g_eventFlagsId, FLAGS_MSK1);
}
static void ExampleTask(void)
{
int ret;
E53IS1Init();
ret = E53IS1ReadData(BeepAlarm);
if (ret != 0) {
printf("E53_IS1 Read Data failed!\r\n");
return;
}
while (1) {
osEventFlagsWait(g_eventFlagsId, FLAGS_MSK1, osFlagsWaitAny, osWaitForever);
BeepStatusSet(ON);
osDelay(300);
BeepStatusSet(OFF);
}
}
static void ExampleEntry(void)
{
g_eventFlagsId = osEventFlagsNew(NULL);
if (g_eventFlagsId == NULL) {
printf("Failed to create EventFlags!\n");
}
osThreadAttr_t attr;
attr.name = "ExampleTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = TASK_STACK_SIZE;
attr.priority = TASK_PRIO;
if (osThreadNew((osThreadFunc_t)ExampleTask, NULL, &attr) == NULL) {
printf("Failed to create Example_Task!\n");
}
}
APP_FEATURE_INIT(ExampleEntry);
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __E53_IS1_H__
#define __E53_IS1_H__
typedef void (*E53IS1CallbackFunc) (char *arg);
typedef enum
{
OFF = 0,
ON
} E53IS1Status;
void E53IS1Init(void);
int E53IS1ReadData(E53IS1CallbackFunc func);
void BeepStatusSet(E53IS1Status status);
#endif
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "E53_IS1.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_pwm.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define WIFI_IOT_PWM_PORT_PWM1 1
#define WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT 5
#define WIFI_IOT_IO_FUNC_GPIO_7_GPIO 0
/***************************************************************
* 函数名称: E53IS1IoInit
* 说 明: E53_SC2 GPIO初始化
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static void E53IS1IoInit(void)
{
IoTGpioInit(8); //初始化GPIO
IoTGpioSetFunc(8, WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT); //设置GPIO_8引脚复用功能为PWM
IoTGpioSetDir(8, IOT_GPIO_DIR_OUT); //设置GPIO_8引脚为输出模式
IoTPwmInit(WIFI_IOT_PWM_PORT_PWM1); //初始化PWM1端口
IoTGpioInit(7);
IoTGpioSetFunc(7, WIFI_IOT_IO_FUNC_GPIO_7_GPIO);
IoTGpioSetDir(7, IOT_GPIO_DIR_IN); //设置GPIO_7为输入模式
IoTGpioSetPull(7, IOT_GPIO_PULL_UP);
}
/***************************************************************
* 函数名称: E53IS1Init
* 说 明: 初始化E53_IS1
* 参 数: 无
* 返 回 值: 无
***************************************************************/
void E53IS1Init(void)
{
E53IS1IoInit();
}
/***************************************************************
* 函数名称: E53IS1ReadData
* 说 明: 读取数据
* 参 数: func 人体感应传感器回调函数
* 返 回 值: 无
***************************************************************/
int E53IS1ReadData(E53IS1CallbackFunc func)
{
uint32_t ret;
ret = IoTGpioRegisterIsrFunc(7, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_RISE_LEVEL_HIGH, func, NULL);
if (ret != 0) {
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: BeepStatusSet
* 说 明: 蜂鸣器报警与否
* 参 数: status,ENUM枚举的数据
* OFF,蜂鸣器
* ON,开蜂鸣器
* 返 回 值: 无
***************************************************************/
void BeepStatusSet(E53IS1Status status)
{
if (status == ON) {
IoTPwmStart(WIFI_IOT_PWM_PORT_PWM1, 50, 4000); //输出PWM波
}
if (status == OFF) {
IoTPwmStop(WIFI_IOT_PWM_PORT_PWM1);
}
}
+35
View File
@@ -0,0 +1,35 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("cloud_oc_infrared") {
sources = [
"iot_cloud_oc_sample.c",
"src/E53_IS1.c",
"src/wifi_connect.c",
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"//foundation/communication/wifi_lite/interfaces/wifiservice",
"//third_party/cJSON",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/oc_mqtt/oc_mqtt_al",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/oc_mqtt/oc_mqtt_profile_v5",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/inc",
"include",
]
deps = [
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link:iot_link",
]
}
+166
View File
@@ -0,0 +1,166 @@
# BearPi-HM_Nano开发板智慧安防案例开发
本示例将演示如何在BearPi-HM_Nano开发板上使用MQTT协议连接华为IoT平台,使用E53_IS1 智慧安防扩展板与 BearPi-HM_Nano 开发板实现智慧安防的案例,设备安装如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/E53_IS1安装.png "E53_IS1安装")
## 软件设计
### 连接平台
在连接平台前需要设置获取CONFIG_APP_DEVICEID、CONFIG_APP_DEVICEPWD、CONFIG_APP_SERVERIP、CONFIG_APP_SERVERPORT,通过oc_mqtt_profile_connect()函数连接平台。
```c
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = queue_create("queue_rcvmsg",10,1);
if(NULL == g_app_cb.app_msg){
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void) memset( &connect_para, 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
//连接平台
ret = oc_mqtt_profile_connect(&connect_para);
if((ret == (int)en_oc_mqtt_err_ok)){
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
}
else
{
printf("oc_mqtt_profile_connect faild!\r\n");
}
```
### 推送数据
当需要上传数据时,需要先拼装数据,让后通过oc_mqtt_profile_propertyreport上报数据。代码示例如下:
```c
static void deal_report_msg(void)
{
oc_mqtt_profile_service_t service;
oc_mqtt_profile_kv_t status;
if (g_app_cb.connected != 1) {
return;
}
service.event_time = NULL;
service.service_id = "Infrared";
service.service_property = &status;
service.nxt = NULL;
status.key = "Infrared_Status";
status.value = g_infraredStatus ? "Intrude" : "Safe";
status.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
status.nxt = NULL;
//发送数据
oc_mqtt_profile_propertyreport(NULL,&service);
return;
}
```
## 编译调试
### 登录
设备接入华为云平台之前,需要在平台注册用户账号,华为云地址:<https://www.huaweicloud.com/>
在华为云首页单击产品,找到IoT物联网,单击设备接入IoTDA 并单击立即使用,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/登录平台01.png "登录平台")
![](../../docs/figures/D10_iot_cloud_oc_infrared/登录平台02.png "登录平台")
### 创建产品
在设备接入页面可看到总览界面,展示了华为云平台接入的协议与域名信息,根据需要选取MQTT通讯必要的信息备用,如下图所示。
接入协议(端口号):MQTT 1883
域名:iot-mqtts.cn-north-4.myhuaweicloud.com
![](../../docs/figures/D10_iot_cloud_oc_infrared/查看平台信息.png "查看平台信息")
选中侧边栏产品页,单击右上角“创建产品”,在页面中选中所属资源空间,并且按要求填写产品名称,选中MQTT协议,数据格式为JSON,并填写厂商名称,在下方模型定义栏中选择所属行业以及添加设备类型,并单击右下角“确定”,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/创建产品01.png "创建产品")
创建完成后,在产品页会自动生成刚刚创建的产品,单击“查看”可查看创建的具体信息,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/创建产品02.png "创建产品")
单击产品详情页的自定义模型,在弹出页面中新增服务,如下图所示。
服务ID`Infrared`(必须一致)
服务类型:`Senser`(可自定义)
![](../../docs/figures/D10_iot_cloud_oc_infrared/创建产品03.png "创建产品")
在“Infrared”的下拉菜单下点击“添加属性”填写“Infrared_Status”相关信息,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/创建产品04.png "创建产品")
#### 注册设备
在侧边栏中单击“设备”,进入设备页面,单击右上角“注册设备”,勾选对应所属资源空间并选中刚刚创建的产品,注意设备认证类型选择“秘钥”,按要求填写秘钥,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/注册设备01.png "注册设备")
记录下设备ID和设备密钥,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/注册设备02.png "注册设备")
注册完成后,在设备页面单击“所有设备”,即可看到新建的设备,同时设备处于未激活状态,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/注册设备03.png "注册设备")
### 修改代码中设备信息
修改`iot_cloud_oc_sample.c`中第31行附近的wifi的ssid和pwd,以及设备的DEVICEID和DEVICEPWD(这两个参数是在平台注册设备时产生的),如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/修改设备信息.png "修改设备信息")
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `cloud_oc_infrared` 参与编译。
```r
#"D7_iot_cloud_oc_smoke:cloud_oc_smoke",
#"D8_iot_cloud_oc_light:cloud_oc_light",
#"D9_iot_cloud_oc_manhole_cover:cloud_oc_manhole_cover",
"D10_iot_cloud_oc_infrared:cloud_oc_infrared",
#"D11_iot_cloud_oc_agriculture:cloud_oc_agriculture",
#"D12_iot_cloud_oc_gps:cloud_oc_gps",
```
### 测试
示例代码编译烧录代码后,按下开发板的RESET按键,平台上的设备显示为在线状态,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/设备在线.png "设备在线")
点击设备右侧的“查看”,进入设备详情页面,可看到上报的数据,如下图所示。
![](../../docs/figures/D10_iot_cloud_oc_infrared/查看设备信息.png "查看设备信息")
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __E53_IS1_H__
#define __E53_IS1_H__
typedef void (*E53IS1CallbackFunc) (char *arg);
typedef enum
{
OFF = 0,
ON
} E53IS1Status;
void E53IS1Init(void);
int E53IS1ReadData(E53IS1CallbackFunc func);
void BeepStatusSet(E53IS1Status status);
#endif
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __WIFI_CONNECT_H__
#define __WIFI_CONNECT_H__
int WifiConnect(const char *ssid,const char *psk);
#endif /* __WIFI_CONNECT_H__ */
@@ -0,0 +1,176 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
#include <dtls_al.h>
#include <mqtt_al.h>
#include <oc_mqtt_al.h>
#include <oc_mqtt_profile.h>
#include "E53_IS1.h"
#include "wifi_connect.h"
#define CONFIG_WIFI_SSID "BearPi" // 修改为自己的WiFi 热点账号
#define CONFIG_WIFI_PWD "BearPi" // 修改为自己的WiFi 热点密码
#define CONFIG_APP_SERVERIP "121.36.42.100"
#define CONFIG_APP_SERVERPORT "1883"
#define CONFIG_APP_DEVICEID "60154da604feea02d7f9ae8d_2354566786" // 替换为注册设备后生成的deviceid
#define CONFIG_APP_DEVICEPWD "123456789" // 替换为注册设备后生成的密钥
#define CONFIG_APP_LIFETIME 60 // seconds
#define CONFIG_QUEUE_TIMEOUT (5 * 1000)
#define MSGQUEUE_COUNT 16
#define MSGQUEUE_SIZE 10
#define CLOUD_TASK_STACK_SIZE (1024 * 10)
#define CLOUD_TASK_PRIO 24
#define BEEP_DELAY 5
typedef enum {
en_msg_cmd = 0,
en_msg_report,
} en_msg_type_t;
typedef struct {
char* request_id;
char* payload;
} cmd_t;
typedef struct {
osMessageQueueId_t app_msg;
int connected;
} app_cb_t;
static app_cb_t g_app_cb;
int g_infraredStatus = 0;
static void deal_report_msg(void)
{
oc_mqtt_profile_service_t service;
oc_mqtt_profile_kv_t status;
if (g_app_cb.connected != 1) {
return;
}
service.event_time = NULL;
service.service_id = "Infrared";
service.service_property = &status;
service.nxt = NULL;
status.key = "Infrared_Status";
status.value = g_infraredStatus ? "Intrude" : "Safe";
status.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
status.nxt = NULL;
oc_mqtt_profile_propertyreport(NULL, &service);
return;
}
#define FLAGS_MSK1 0x00000001U
osEventFlagsId_t g_eventFlagsId;
static void BeepAlarm(char* arg)
{
(void)arg;
osEventFlagsSet(g_eventFlagsId, FLAGS_MSK1);
}
static int CloudMainTaskEntry(void)
{
uint32_t ret;
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = osMessageQueueNew(MSGQUEUE_COUNT, MSGQUEUE_SIZE, NULL);
if (g_app_cb.app_msg == NULL) {
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void)memset_s(&connect_para, sizeof(connect_para), 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = NULL;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
ret = oc_mqtt_profile_connect(&connect_para);
if ((ret == (int)en_oc_mqtt_err_ok)) {
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
} else {
printf("oc_mqtt_profile_connect faild!\r\n");
}
E53IS1Init();
ret = E53IS1ReadData(BeepAlarm);
if (ret != 0) {
printf("E53_IS1 Read Data failed!\r\n");
return;
}
deal_report_msg();
while (1) {
osEventFlagsWait(g_eventFlagsId, FLAGS_MSK1, osFlagsWaitAny, osWaitForever);
BeepStatusSet(ON);
g_infraredStatus = 1;
deal_report_msg();
sleep(BEEP_DELAY);
BeepStatusSet(OFF);
g_infraredStatus = 0;
deal_report_msg();
}
return 0;
}
static void IotMainTaskEntry(void)
{
g_eventFlagsId = osEventFlagsNew(NULL);
if (g_eventFlagsId == NULL) {
printf("Failed to create EventFlags!\n");
}
osThreadAttr_t attr;
attr.name = "CloudMainTaskEntry";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = CLOUD_TASK_STACK_SIZE;
attr.priority = CLOUD_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)CloudMainTaskEntry, NULL, &attr) == NULL) {
printf("Failed to create CloudMainTaskEntry!\n");
}
}
APP_FEATURE_INIT(IotMainTaskEntry);
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "E53_IS1.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_pwm.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define WIFI_IOT_PWM_PORT_PWM1 1
#define WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT 5
#define WIFI_IOT_IO_FUNC_GPIO_7_GPIO 0
/***************************************************************
* 函数名称: E53IS1IoInit
* 说 明: E53_SC2 GPIO初始化
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static void E53IS1IoInit(void)
{
IoTGpioInit(8); //初始化GPIO
IoTGpioSetFunc(8, WIFI_IOT_IO_FUNC_GPIO_8_PWM1_OUT); //设置GPIO_8引脚复用功能为PWM
IoTGpioSetDir(8, IOT_GPIO_DIR_OUT); //设置GPIO_8引脚为输出模式
IoTPwmInit(WIFI_IOT_PWM_PORT_PWM1); //初始化PWM1端口
IoTGpioInit(7);
IoTGpioSetFunc(7, WIFI_IOT_IO_FUNC_GPIO_7_GPIO);
IoTGpioSetDir(7, IOT_GPIO_DIR_IN); //设置GPIO_7为输入模式
IoTGpioSetPull(7, IOT_GPIO_PULL_UP);
}
/***************************************************************
* 函数名称: E53IS1Init
* 说 明: 初始化E53_IS1
* 参 数: 无
* 返 回 值: 无
***************************************************************/
void E53IS1Init(void)
{
E53IS1IoInit();
}
/***************************************************************
* 函数名称: E53IS1ReadData
* 说 明: 读取数据
* 参 数: func 人体感应传感器回调函数
* 返 回 值: 无
***************************************************************/
int E53IS1ReadData(E53IS1CallbackFunc func)
{
uint32_t ret;
ret = IoTGpioRegisterIsrFunc(7, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_RISE_LEVEL_HIGH, func, NULL);
if (ret != 0) {
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: BeepStatusSet
* 说 明: 蜂鸣器报警与否
* 参 数: status,ENUM枚举的数据
* OFF,蜂鸣器
* ON,开蜂鸣器
* 返 回 值: 无
***************************************************************/
void BeepStatusSet(E53IS1Status status)
{
if (status == ON) {
IoTPwmStart(WIFI_IOT_PWM_PORT_PWM1, 50, 4000); //输出PWM波
}
if (status == OFF) {
IoTPwmStop(WIFI_IOT_PWM_PORT_PWM1);
}
}
@@ -0,0 +1,239 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "lwip/api_shell.h"
#include "lwip/ip4_addr.h"
#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "cmsis_os2.h"
#include "ohos_init.h"
#include "wifi_device.h"
#include "wifi_error_code.h"
#define DEF_TIMEOUT 15
#define ONE_SECOND 1
static void WiFiInit(void);
static void WaitSacnResult(void);
static int WaitConnectResult(void);
static void OnWifiScanStateChangedHandler(int state, int size);
static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo* info);
static void OnHotspotStaJoinHandler(StationInfo* info);
static void OnHotspotStateChangedHandler(int state);
static void OnHotspotStaLeaveHandler(StationInfo* info);
static int g_staScanSuccess = 0;
static int g_ConnectSuccess = 0;
static int g_ssid_count = 0;
static struct netif* g_lwip_netif = NULL;
static WifiEvent g_wifiEventHandler = {0};
WifiErrorCode error;
#define SELECT_WLAN_PORT "wlan0"
int WifiConnect(const char* ssid, const char* psk)
{
WifiScanInfo* info = NULL;
unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
//初始化WIFI
WiFiInit();
//使能WIFI
if (EnableWifi() != WIFI_SUCCESS) {
printf("EnableWifi failed, error = %d\r\n", error);
return -1;
}
//判断WIFI是否激活
if (IsWifiActive() == 0) {
printf("Wifi station is not actived.\r\n");
return -1;
}
//分配空间,保存WiFi信息
info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);
if (info == NULL) {
return -1;
}
//轮询查找WiFi列表
do {
//重置标志位
g_ssid_count = 0;
g_staScanSuccess = 0;
//开始扫描
Scan();
//等待扫描结果
WaitSacnResult();
//获取扫描列表
error = GetScanInfoList(info, &size);
} while (g_staScanSuccess != 1);
//打印WiFi列表
printf("********************\r\n");
for (uint8_t i = 0; i < g_ssid_count; i++) {
printf("no:%03d, ssid:%-30s, rssi:%5d\r\n", i + 1, info[i].ssid, info[i].rssi / 100);
}
printf("********************\r\n");
//连接指定的WiFi热点
for (uint8_t i = 0; i < g_ssid_count; i++) {
if (strcmp(ssid, info[i].ssid) == 0) {
int result;
printf("Select:%3d wireless, Waiting...\r\n", i + 1);
//拷贝要连接的热点信息
WifiDeviceConfig select_ap_config = {0};
strcpy(select_ap_config.ssid, info[i].ssid);
strcpy(select_ap_config.preSharedKey, psk);
select_ap_config.securityType = WIFI_SEC_TYPE_PSK;
if (AddDeviceConfig(&select_ap_config, &result) == WIFI_SUCCESS) {
if (ConnectTo(result) == WIFI_SUCCESS && WaitConnectResult() == 1) {
printf("WiFi connect succeed!\r\n");
g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);
break;
}
}
}
if (i == g_ssid_count - 1) {
printf("ERROR: No wifi as expected\r\n");
while (1)
osDelay(100);
}
}
//启动DHCP
if (g_lwip_netif) {
dhcp_start(g_lwip_netif);
printf("begain to dhcp\r\n");
}
//等待DHCP
for (;;) {
if (dhcp_is_bound(g_lwip_netif) == ERR_OK) {
printf("<-- DHCP state:OK -->\r\n");
//打印获取到的IP信息
netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);
break;
}
printf("<-- DHCP state:Inprogress -->\r\n");
osDelay(100);
}
osDelay(100);
return 0;
}
static void WiFiInit(void)
{
g_wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedHandler;
g_wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedHandler;
g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
error = RegisterWifiEvent(&g_wifiEventHandler);
if (error != WIFI_SUCCESS) {
printf("register wifi event fail!\r\n");
} else {
printf("register wifi event succeed!\r\n");
}
}
static void OnWifiScanStateChangedHandler(int state, int size)
{
if (size > 0) {
g_ssid_count = size;
g_staScanSuccess = 1;
}
printf("callback function for wifi scan:%d, %d\r\n", state, size);
return;
}
static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo* info)
{
if (info == NULL) {
printf("WifiConnectionChanged:info is null, stat is %d.\n", state);
} else {
if (state == WIFI_STATE_AVALIABLE) {
g_ConnectSuccess = 1;
} else {
g_ConnectSuccess = 0;
}
}
}
static void OnHotspotStaJoinHandler(StationInfo* info)
{
(void)info;
printf("STA join AP\n");
return;
}
static void OnHotspotStaLeaveHandler(StationInfo* info)
{
(void)info;
printf("HotspotStaLeave:info is null.\n");
return;
}
static void OnHotspotStateChangedHandler(int state)
{
printf("HotspotStateChanged:state is %d.\n", state);
return;
}
static void WaitSacnResult(void)
{
int scanTimeout = DEF_TIMEOUT;
while (scanTimeout > 0) {
sleep(ONE_SECOND);
scanTimeout--;
if (g_staScanSuccess == 1) {
printf("WaitSacnResult:wait success[%d]s\n", (DEF_TIMEOUT - scanTimeout));
break;
}
}
if (scanTimeout <= 0) {
printf("WaitSacnResult:timeout!\n");
}
}
static int WaitConnectResult(void)
{
int ConnectTimeout = DEF_TIMEOUT;
while (ConnectTimeout > 0) {
sleep(ONE_SECOND);
ConnectTimeout--;
if (g_ConnectSuccess == 1) {
printf("WaitConnectResult:wait success[%d]s\n", (DEF_TIMEOUT - ConnectTimeout));
break;
}
}
if (ConnectTimeout <= 0) {
printf("WaitConnectResult:timeout!\n");
return 0;
}
return 1;
}
+35
View File
@@ -0,0 +1,35 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("cloud_oc_agriculture") {
sources = [
"iot_cloud_oc_sample.c",
"src/E53_IA1.c",
"src/wifi_connect.c",
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"//foundation/communication/wifi_lite/interfaces/wifiservice",
"//third_party/cJSON",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/oc_mqtt/oc_mqtt_al",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/oc_mqtt/oc_mqtt_profile_v5",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/inc",
"include",
]
deps = [
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link:iot_link",
]
}
+346
View File
@@ -0,0 +1,346 @@
# BearPi-HM_Nano开发板智慧农业案例开发
本示例将演示如何在BearPi-HM_Nano开发板上使用MQTT协议连接华为IoT平台,使用的是E53_IA1 智慧农业扩展板与 BearPi-HM_Nano 开发板,设备安装如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/E53_IA1安装.png "E53_IA1安装")
## 软件设计
### 连接平台
在连接平台前需要设置获取CONFIG_APP_DEVICEID、CONFIG_APP_DEVICEPWD、CONFIG_APP_SERVERIP、CONFIG_APP_SERVERPORT,通过oc_mqtt_profile_connect()函数连接平台。
```c
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = queue_create("queue_rcvmsg",10,1);
if(NULL == g_app_cb.app_msg){
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void) memset( &connect_para, 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
//连接平台
ret = oc_mqtt_profile_connect(&connect_para);
if((ret == (int)en_oc_mqtt_err_ok)){
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
}
else
{
printf("oc_mqtt_profile_connect faild!\r\n");
}
```
### 推送数据
当需要上传数据时,需要先拼装数据,让后通过oc_mqtt_profile_propertyreport上报数据。代码示例如下:
```c
static void deal_report_msg(report_t *report)
{
oc_mqtt_profile_service_t service;
oc_mqtt_profile_kv_t temperature;
oc_mqtt_profile_kv_t humidity;
oc_mqtt_profile_kv_t luminance;
oc_mqtt_profile_kv_t led;
oc_mqtt_profile_kv_t motor;
if (g_app_cb.connected != 1) {
return;
}
service.event_time = NULL;
service.service_id = "Agriculture";
service.service_property = &temperature;
service.nxt = NULL;
temperature.key = "Temperature";
temperature.value = &report->temp;
temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
temperature.nxt = &humidity;
humidity.key = "Humidity";
humidity.value = &report->hum;
humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT;
humidity.nxt = &luminance;
luminance.key = "Luminance";
luminance.value = &report->lum;
luminance.type = EN_OC_MQTT_PROFILE_VALUE_INT;
luminance.nxt = &led;
led.key = "LightStatus";
led.value = g_app_cb.led?"ON":"OFF";
led.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
led.nxt = &motor;
motor.key = "MotorStatus";
motor.value = g_app_cb.motor?"ON":"OFF";
motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
motor.nxt = NULL;
//发送数据
oc_mqtt_profile_propertyreport(NULL,&service);
return;
}
```
### 命令接收
华为IoT平台支持下发命令,命令是用户自定义的。接收到命令后会将命令数据发送到队列中,task_main_entry函数中读取队列数据并调用deal_cmd_msg函数进行处理,代码示例如下:
```c
static int msg_rcv_callback(oc_mqtt_profile_msgrcv_t *msg)
{
int ret = 0;
char *buf;
int buf_len;
app_msg_t *app_msg;
if ((NULL == msg)|| (msg->request_id == NULL) || (msg->type != EN_OC_MQTT_PROFILE_MSG_TYPE_DOWN_COMMANDS)) {
return ret;
}
buf_len = sizeof(app_msg_t) + strlen(msg->request_id) + 1 + msg->msg_len + 1;
buf = malloc(buf_len);
if (NULL == buf) {
return ret;
}
app_msg = (app_msg_t *)buf;
buf += sizeof(app_msg_t);
app_msg->msg_type = en_msg_cmd;
app_msg->msg.cmd.request_id = buf;
buf_len = strlen(msg->request_id);
buf += buf_len + 1;
memcpy(app_msg->msg.cmd.request_id, msg->request_id, buf_len);
app_msg->msg.cmd.request_id[buf_len] = '\0';
buf_len = msg->msg_len;
app_msg->msg.cmd.payload = buf;
memcpy(app_msg->msg.cmd.payload, msg->msg, buf_len);
app_msg->msg.cmd.payload[buf_len] = '\0';
ret = queue_push(g_app_cb.app_msg,app_msg,10);
if (ret != 0) {
free(app_msg);
}
return ret;
}
///< COMMAND DEAL
#include <cJSON.h>
static void deal_cmd_msg(cmd_t *cmd)
{
cJSON *obj_root;
cJSON *obj_cmdname;
cJSON *obj_paras;
cJSON *obj_para;
int cmdret = 1;
oc_mqtt_profile_cmdresp_t cmdresp;
obj_root = cJSON_Parse(cmd->payload);
if (NULL == obj_root) {
goto EXIT_JSONPARSE;
}
obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
if (NULL == obj_cmdname) {
goto EXIT_CMDOBJ;
}
if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_light")) {
obj_paras = cJSON_GetObjectItem(obj_root, "paras");
if (NULL == obj_paras) {
goto EXIT_OBJPARAS;
}
obj_para = cJSON_GetObjectItem(obj_paras, "Light");
if (NULL == obj_para) {
goto EXIT_OBJPARA;
}
///< operate the LED here
if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON")) {
g_app_cb.led = 1;
Light_StatusSet(ON);
printf("Light On!\r\n");
} else {
g_app_cb.led = 0;
Light_StatusSet(OFF);
printf("Light Off!\r\n");
}
cmdret = 0;
} else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_Motor")) {
obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
if (NULL == obj_paras) {
goto EXIT_OBJPARAS;
}
obj_para = cJSON_GetObjectItem(obj_paras, "Motor");
if (NULL == obj_para) {
goto EXIT_OBJPARA;
}
///< operate the Motor here
if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON")) {
g_app_cb.motor = 1;
Motor_StatusSet(ON);
printf("Motor On!\r\n");
} else {
g_app_cb.motor = 0;
Motor_StatusSet(OFF);
printf("Motor Off!\r\n");
}
cmdret = 0;
}
EXIT_OBJPARA:
EXIT_OBJPARAS:
EXIT_CMDOBJ:
cJSON_Delete(obj_root);
EXIT_JSONPARSE:
///< do the response
cmdresp.paras = NULL;
cmdresp.request_id = cmd->request_id;
cmdresp.ret_code = cmdret;
cmdresp.ret_name = NULL;
(void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
return;
}
```
## 编译调试
### 登录
设备接入华为云平台之前,需要在平台注册用户账号,华为云地址:<https://www.huaweicloud.com/>
在华为云首页单击产品,找到IoT物联网,单击设备接入IoTDA 并单击立即使用,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/登录平台01.png "登录平台")
![](../../docs/figures/D11_iot_cloud_oc_agriculture/登录平台02.png "登录平台")
### 创建产品
在设备接入页面可看到总览界面,展示了华为云平台接入的协议与域名信息,根据需要选取MQTT通讯必要的信息备用,如下图所示。
接入协议(端口号):MQTT 1883
域名:iot-mqtts.cn-north-4.myhuaweicloud.com
![](../../docs/figures/D10_iot_cloud_oc_infrared/查看平台信息.png "查看平台信息")
选中侧边栏产品页,单击右上角“创建产品”,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品01.png "创建产品")
在页面中选中所属资源空间,并且按要求填写产品名称,选中MQTT协议,数据格式为JSON,并填写厂商名称,在下方模型定义栏中选择所属行业以及添加设备类型,并单击右下角“立即创建”,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品02.png "创建产品")
创建完成后,在产品页会自动生成刚刚创建的产品,单击“查看”可查看创建的具体信息,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品03.png "创建产品")
单击产品详情页的自定义模型,在弹出页面中新增服务,如下图所示。
服务ID`Agriculture`(必须一致)
服务类型:`Senser`(可自定义)
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品04.png "创建产品")
在“Agriculture”的下拉菜单下点击“添加属性”填写相关信息“Temperature”,
“Humidity”,“Luminance”,“LightStatus”,“MotorStatus”,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品05.png "创建产品")
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品06.png "创建产品")
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品07.png "创建产品")
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品08.png "创建产品")
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品09.png "创建产品")
在“Agriculture”的下拉菜单下点击“添加命令”填写相关信息。
命令名称:`Agriculture_Control_light`
参数名称:`Light`
数据类型:`string`
长度:`3`
枚举值:`ON,OFF`
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品10.png "创建产品")
命令名称:`Agriculture_Control_Motor`
参数名称:`Motor`
数据类型:`string`
长度:`3`
枚举值:`ON,OFF`
![](../../docs/figures/D11_iot_cloud_oc_agriculture/创建产品11.png "创建产品")
#### 注册设备
在侧边栏中单击“设备”,进入设备页面,单击右上角“注册设备”,勾选对应所属资源空间并选中刚刚创建的产品,注意设备认证类型选择“秘钥”,按要求填写秘钥,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/注册设备01.png "注册设备")
记录下设备ID和设备密钥,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/注册设备02.png "注册设备")
注册完成后,在设备页面单击“所有设备”,即可看到新建的设备,同时设备处于未激活状态,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/注册设备03.png "注册设备")
### 修改代码中设备信息
修改`iot_cloud_oc_sample.c`中第31行附近的wifi的ssid和pwd,以及设备的DEVICEID和DEVICEPWD(这两个参数是在平台注册设备时产生的),如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/修改设备信息.png "修改设备信息")
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `cloud_oc_agriculture` 参与编译。
```r
#"D7_iot_cloud_oc_smoke:cloud_oc_smoke",
#"D8_iot_cloud_oc_light:cloud_oc_light",
#"D9_iot_cloud_oc_manhole_cover:cloud_oc_manhole_cover",
#"D10_iot_cloud_oc_infrared:cloud_oc_infrared",
"D11_iot_cloud_oc_agriculture:cloud_oc_agriculture",
#"D12_iot_cloud_oc_gps:cloud_oc_gps",
```
### 测试
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印温湿度及光照强度信息,平台上的设备显示为在线状态,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/设备在线.png "设备在线")
点击设备右侧的“查看”,进入设备详情页面,可看到上报的数据,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/查看设备信息.png "查看设备信息")
在华为云平台设备详情页,单击“命令”,选择同步命令下发,选中创建的命令属性,单击“确定”,即可发送下发命令控制设备,如下图所示。
![](../../docs/figures/D11_iot_cloud_oc_agriculture/命令下发.png "命令下发")
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __E53_IA1_H__
#define __E53_IA1_H__
/* 寄存器宏定义 --------------------------------------------------------------------*/
#define SHT30_ADDR 0x44
#define BH1750_ADDR 0x23
typedef enum
{
OFF = 0,
ON
} E53IA1Status;
/* E53_IA1传感器数据类型定义 ------------------------------------------------------------*/
typedef struct
{
float Lux; //光照强度
float Humidity; //湿度
float Temperature; //温度
} E53IA1Data;
int E53IA1Init(void);
int E53IA1ReadData(E53IA1Data *ReadData);
void LightStatusSet(E53IA1Status status);
void MotorStatusSet(E53IA1Status status);
#endif /* __E53_IA1_H__ */
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __WIFI_CONNECT_H__
#define __WIFI_CONNECT_H__
int WifiConnect(const char *ssid,const char *psk);
#endif /* __WIFI_CONNECT_H__ */
@@ -0,0 +1,385 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
#include <dtls_al.h>
#include <mqtt_al.h>
#include <oc_mqtt_al.h>
#include <oc_mqtt_profile.h>
#include "E53_IA1.h"
#include "wifi_connect.h"
#define CONFIG_WIFI_SSID "Hold" // 修改为自己的WiFi 热点账号
#define CONFIG_WIFI_PWD "0987654321" // 修改为自己的WiFi 热点密码
#define CONFIG_APP_SERVERIP "121.36.42.100"
#define CONFIG_APP_SERVERPORT "1883"
#define CONFIG_APP_DEVICEID "6114182f2cce4f0286ff45f9_123456" // 替换为注册设备后生成的deviceid
#define CONFIG_APP_DEVICEPWD "123456789" // 替换为注册设备后生成的密钥
#define CONFIG_APP_LIFETIME 60 // seconds
#define CONFIG_QUEUE_TIMEOUT (5 * 1000)
#define MSGQUEUE_COUNT 16
#define MSGQUEUE_SIZE 10
#define CLOUD_TASK_STACK_SIZE (1024 * 10)
#define CLOUD_TASK_PRIO 24
#define SENSOR_TASK_STACK_SIZE (1024 * 4)
#define SENSOR_TASK_PRIO 25
#define TASK_DELAY 3
osMessageQueueId_t mid_MsgQueue; // message queue id
typedef enum {
en_msg_cmd = 0,
en_msg_report,
en_msg_conn,
en_msg_disconn,
} en_msg_type_t;
typedef struct {
char* request_id;
char* payload;
} cmd_t;
typedef struct {
int lum;
int temp;
int hum;
} report_t;
typedef struct {
en_msg_type_t msg_type;
union {
cmd_t cmd;
report_t report;
} msg;
} app_msg_t;
typedef struct {
osMessageQueueId_t app_msg;
int connected;
int led;
int motor;
} app_cb_t;
static app_cb_t g_app_cb;
static void deal_report_msg(report_t* report)
{
oc_mqtt_profile_service_t service;
oc_mqtt_profile_kv_t temperature;
oc_mqtt_profile_kv_t humidity;
oc_mqtt_profile_kv_t luminance;
oc_mqtt_profile_kv_t led;
oc_mqtt_profile_kv_t motor;
if (g_app_cb.connected != 1) {
return;
}
service.event_time = NULL;
service.service_id = "Agriculture";
service.service_property = &temperature;
service.nxt = NULL;
temperature.key = "Temperature";
temperature.value = &report->temp;
temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
temperature.nxt = &humidity;
humidity.key = "Humidity";
humidity.value = &report->hum;
humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT;
humidity.nxt = &luminance;
luminance.key = "Luminance";
luminance.value = &report->lum;
luminance.type = EN_OC_MQTT_PROFILE_VALUE_INT;
luminance.nxt = &led;
led.key = "LightStatus";
led.value = g_app_cb.led ? "ON" : "OFF";
led.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
led.nxt = &motor;
motor.key = "MotorStatus";
motor.value = g_app_cb.motor ? "ON" : "OFF";
motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
motor.nxt = NULL;
oc_mqtt_profile_propertyreport(NULL, &service);
return;
}
// use this function to push all the message to the buffer
static int msg_rcv_callback(oc_mqtt_profile_msgrcv_t* msg)
{
int ret = 0;
char* buf;
int buf_len;
app_msg_t* app_msg;
if ((msg == NULL) || (msg->request_id == NULL) || (msg->type != EN_OC_MQTT_PROFILE_MSG_TYPE_DOWN_COMMANDS)) {
return ret;
}
buf_len = sizeof(app_msg_t) + strlen(msg->request_id) + 1 + msg->msg_len + 1;
buf = malloc(buf_len);
if (buf == NULL) {
return ret;
}
app_msg = (app_msg_t*)buf;
buf += sizeof(app_msg_t);
app_msg->msg_type = en_msg_cmd;
app_msg->msg.cmd.request_id = buf;
buf_len = strlen(msg->request_id);
buf += buf_len + 1;
memcpy_s(app_msg->msg.cmd.request_id, buf_len, msg->request_id, buf_len);
app_msg->msg.cmd.request_id[buf_len] = '\0';
buf_len = msg->msg_len;
app_msg->msg.cmd.payload = buf;
memcpy_s(app_msg->msg.cmd.payload, buf_len, msg->msg, buf_len);
app_msg->msg.cmd.payload[buf_len] = '\0';
ret = osMessageQueuePut(g_app_cb.app_msg, &app_msg, 0U, CONFIG_QUEUE_TIMEOUT);
if (ret != 0) {
free(app_msg);
}
return ret;
}
static void oc_cmdresp(cmd_t* cmd, int cmdret)
{
oc_mqtt_profile_cmdresp_t cmdresp;
///< do the response
cmdresp.paras = NULL;
cmdresp.request_id = cmd->request_id;
cmdresp.ret_code = cmdret;
cmdresp.ret_name = NULL;
(void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
}
///< COMMAND DEAL
#include <cJSON.h>
static void deal_light_cmd(cmd_t* cmd, cJSON* obj_root)
{
cJSON* obj_paras;
cJSON* obj_para;
int cmdret;
obj_paras = cJSON_GetObjectItem(obj_root, "paras");
if (obj_paras == NULL) {
cJSON_Delete(obj_root);
}
obj_para = cJSON_GetObjectItem(obj_paras, "Light");
if (obj_paras == NULL) {
cJSON_Delete(obj_root);
}
///< operate the LED here
if (strcmp(cJSON_GetStringValue(obj_para), "ON") == 0) {
g_app_cb.led = 1;
LightStatusSet(ON);
printf("Light On!\r\n");
} else {
g_app_cb.led = 0;
LightStatusSet(OFF);
printf("Light Off!\r\n");
}
cmdret = 0;
oc_cmdresp(cmd, cmdret);
_ERR:
cJSON_Delete(obj_root);
return;
}
static void deal_motor_cmd(cmd_t* cmd, cJSON* obj_root)
{
cJSON* obj_paras;
cJSON* obj_para;
int cmdret;
obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
if (obj_paras == NULL) {
cJSON_Delete(obj_root);
}
obj_para = cJSON_GetObjectItem(obj_paras, "Motor");
if (obj_para == NULL) {
cJSON_Delete(obj_root);
}
///< operate the Motor here
if (strcmp(cJSON_GetStringValue(obj_para), "ON") == 0) {
g_app_cb.motor = 1;
MotorStatusSet(ON);
printf("Motor On!\r\n");
} else {
g_app_cb.motor = 0;
MotorStatusSet(OFF);
printf("Motor Off!\r\n");
}
cmdret = 0;
oc_cmdresp(cmd, cmdret);
_ERR:
cJSON_Delete(obj_root);
return;
}
static void deal_cmd_msg(cmd_t* cmd)
{
cJSON* obj_root;
cJSON* obj_cmdname;
int cmdret = 1;
obj_root = cJSON_Parse(cmd->payload);
if (obj_root == NULL) {
oc_cmdresp(cmd, cmdret);
}
obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
if (obj_cmdname == NULL) {
cJSON_Delete(obj_root);
}
if (strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_light") == 0) {
deal_light_cmd(cmd, obj_root);
} else if (strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_Motor") == 0) {
deal_motor_cmd(cmd, obj_root);
}
return;
}
static int CloudMainTaskEntry(void)
{
app_msg_t* app_msg;
uint32_t ret;
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = osMessageQueueNew(MSGQUEUE_COUNT, MSGQUEUE_SIZE, NULL);
if (g_app_cb.app_msg == NULL) {
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void)memset_s(&connect_para, sizeof(connect_para), 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
ret = oc_mqtt_profile_connect(&connect_para);
if ((ret == (int)en_oc_mqtt_err_ok)) {
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
} else {
printf("oc_mqtt_profile_connect faild!\r\n");
}
while (1) {
app_msg = NULL;
(void)osMessageQueueGet(g_app_cb.app_msg, (void**)&app_msg, NULL, 0xFFFFFFFF);
if (app_msg != NULL) {
switch (app_msg->msg_type) {
case en_msg_cmd:
deal_cmd_msg(&app_msg->msg.cmd);
break;
case en_msg_report:
deal_report_msg(&app_msg->msg.report);
break;
default:
break;
}
free(app_msg);
}
}
return 0;
}
static int SensorTaskEntry(void)
{
app_msg_t* app_msg;
int ret;
E53IA1Data data;
ret = E53IA1Init();
if (ret != 0) {
printf("E53_IA1 Init failed!\r\n");
return;
}
while (1) {
ret = E53IA1ReadData(&data);
if (ret != 0) {
printf("E53_IA1 Read Data failed!\r\n");
return;
}
app_msg = malloc(sizeof(app_msg_t));
printf("SENSOR:lum:%.2f temp:%.2f hum:%.2f\r\n", data.Lux, data.Temperature, data.Humidity);
if (app_msg != NULL) {
app_msg->msg_type = en_msg_report;
app_msg->msg.report.hum = (int)data.Humidity;
app_msg->msg.report.lum = (int)data.Lux;
app_msg->msg.report.temp = (int)data.Temperature;
if (osMessageQueuePut(g_app_cb.app_msg, &app_msg, 0U, CONFIG_QUEUE_TIMEOUT != 0)) {
free(app_msg);
}
}
sleep(TASK_DELAY);
}
return 0;
}
static void IotMainTaskEntry(void)
{
osThreadAttr_t attr;
attr.name = "CloudMainTaskEntry";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = CLOUD_TASK_STACK_SIZE;
attr.priority = CLOUD_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)CloudMainTaskEntry, NULL, &attr) == NULL) {
printf("Failed to create CloudMainTaskEntry!\n");
}
attr.stack_size = SENSOR_TASK_STACK_SIZE;
attr.priority = SENSOR_TASK_PRIO;
attr.name = "SensorTaskEntry";
if (osThreadNew((osThreadFunc_t)SensorTaskEntry, NULL, &attr) == NULL) {
printf("Failed to create SensorTaskEntry!\n");
}
}
APP_FEATURE_INIT(IotMainTaskEntry);
@@ -0,0 +1,309 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "E53_IA1.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_i2c.h"
#include "iot_i2c_ex.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA 6
#define WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL 6
#define WIFI_IOT_IO_FUNC_GPIO_8_GPIO 0
#define WIFI_IOT_IO_FUNC_GPIO_14_GPIO 4
#define WIFI_IOT_I2C_IDX_1 1
/***************************************************************
* 函数名称: E53IA1IoInit
* 说 明: E53_IA1 GPIO初始化
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static void E53IA1IoInit(void)
{
IoTGpioInit(8);
IoTGpioSetFunc(8, WIFI_IOT_IO_FUNC_GPIO_8_GPIO);
IoTGpioSetDir(8, IOT_GPIO_DIR_OUT); //设置GPIO_8为输出模式
IoTGpioInit(14);
IoTGpioSetFunc(14, WIFI_IOT_IO_FUNC_GPIO_14_GPIO);
IoTGpioSetDir(14, IOT_GPIO_DIR_OUT); //设置GPIO_14为输出模式
IoTGpioInit(0);
IoTGpioSetFunc(0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA); // GPIO_0复用为I2C1_SDA
IoTGpioInit(1);
IoTGpioSetFunc(1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL); // GPIO_1复用为I2C1_SCL
IoTI2cInit(WIFI_IOT_I2C_IDX_1, 400000);
}
/***************************************************************
* 函数名称: Init_BH1750
* 说 明: 写命令初始化BH1750
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
static int InitBH1750(void)
{
int ret;
uint8_t send_data[1] = {0x01};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x00, send_data, 1);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: StartBH1750
* 说 明: 启动BH1750
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
static int StartBH1750(void)
{
int ret;
uint8_t send_data[1] = {0x10};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x00, send_data, 1);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: SHT30Reset
* 说 明: SHT30复位
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
static int SHT30Reset(void)
{
int ret;
uint8_t send_data[2] = {0x30, 0xA2};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (SHT30_ADDR << 1) | 0x00, send_data, 2);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: InitSHT30
* 说 明: 初始化SHT30,设置测量周期
* 参 数: 无
* 返 回 值: 无
***************************************************************/
static int InitSHT30(void)
{
int ret;
uint8_t send_data[2] = {0x22, 0x36};
ret = IoTI2cWrite(WIFI_IOT_I2C_IDX_1, (SHT30_ADDR << 1) | 0x00, send_data, 2);
if (ret != 0) {
printf("===== Error: I2C write ret = 0x%x! =====\r\n", ret);
return -1;
}
return 0;
}
/***************************************************************
* 函数名称: SHT3xCheckCrc
* 说 明: 检查数据正确性
* 参 数: data:读取到的数据
nbrOfBytes:需要校验的数量
checksum:读取到的校对比验值
* 返 回 值: 校验结果,0-成功 1-失败
***************************************************************/
static uint8_t SHT3xCheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)
{
uint8_t crc = 0xFF;
uint8_t bit = 0;
uint8_t byteCtr;
const int16_t POLYNOMIAL = 0x131;
// calculates 8-Bit checksum with given polynomial
for (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr) {
crc ^= (data[byteCtr]);
for (bit = 8; bit > 0; --bit) {
if (crc & 0x80)
crc = (crc << 1) ^ POLYNOMIAL;
else
crc = (crc << 1);
}
}
if (crc != checksum)
return 1;
else
return 0;
}
/***************************************************************
* 函数名称: SHT3xCalcTemperatureC
* 说 明: 温度计算
* 参 数: u16sT:读取到的温度原始数据
* 返 回 值: 计算后的温度数据
***************************************************************/
static float SHT3xCalcTemperatureC(uint16_t u16sT)
{
float temperatureC = 0; // variable for result
u16sT &= ~0x0003; // clear bits [1..0] (status bits)
//-- calculate temperature [℃] --
temperatureC = (175 * (float)u16sT / 65535 - 45); // T = -45 + 175 * rawValue / (2^16-1)
return temperatureC;
}
/***************************************************************
* 函数名称: SHT3xCalcRH
* 说 明: 湿度计算
* 参 数: u16sRH:读取到的湿度原始数据
* 返 回 值: 计算后的湿度数据
***************************************************************/
static float SHT3xCalcRH(uint16_t u16sRH)
{
float humidityRH = 0; // variable for result
u16sRH &= ~0x0003; // clear bits [1..0] (status bits)
//-- calculate relative humidity [%RH] --
humidityRH = (100 * (float)u16sRH / 65535); // RH = rawValue / (2^16-1) * 10
return humidityRH;
}
/***************************************************************
* 函数名称: E53IA1Init
* 说 明: 初始化E53_IA1
* 参 数: 无
* 返 回 值: 0 成功; -1 失败
***************************************************************/
int E53IA1Init(void)
{
int ret;
E53IA1IoInit();
ret = InitBH1750();
if (ret != 0) {
printf("Init BH1750 failed!\r\n");
return -1;
}
ret = InitSHT30();
if (ret != 0) {
printf("Init SHT30 failed!\r\n");
return -1;
}
}
/***************************************************************
* 函数名称: E53IA1ReadData
* 说 明: 测量光照强度、温度、湿度
* 参 数: ReadData,光照强度、温度、湿度数据
* 返 回 值: 0 成功; -1 失败
***************************************************************/
int E53IA1ReadData(E53IA1Data* ReadData)
{
int ret;
ret = StartBH1750(); // 启动传感器采集数据
if (ret != 0) {
printf("Start BH1750 failed!\r\n");
return -1;
}
usleep(180000);
uint8_t recv_data[2] = {0};
ret = IoTI2cRead(WIFI_IOT_I2C_IDX_1, (BH1750_ADDR << 1) | 0x01, recv_data, 2); // 读取传感器数据
if (ret != 0) {
return -1;
}
ReadData->Lux = (float)(((recv_data[0] << 8) + recv_data[1]) / 1.2);
uint8_t data[3]; // data array for checksum verification
uint16_t dat, tmp;
uint8_t SHT3X_Data_Buffer[6]; // byte 0,1 is temperature byte 4,5 is humidity
IotI2cData sht30_i2c_data = {0};
uint8_t send_data[2] = {0xE0, 0x00};
sht30_i2c_data.sendBuf = send_data;
sht30_i2c_data.sendLen = 2;
sht30_i2c_data.receiveBuf = SHT3X_Data_Buffer;
sht30_i2c_data.receiveLen = 6;
ret = IoTI2cWriteread(WIFI_IOT_I2C_IDX_1, (SHT30_ADDR << 1) | 0x00, &sht30_i2c_data); // Read bh1750 sensor data
if (ret != 0) {
return -1;
}
/* check tem */
data[0] = SHT3X_Data_Buffer[0];
data[1] = SHT3X_Data_Buffer[1];
data[2] = SHT3X_Data_Buffer[2];
tmp = SHT3xCheckCrc(data, 2, data[2]);
/* value is ture */
if (!tmp) {
dat = ((uint16_t)data[0] << 8) | data[1];
ReadData->Temperature = SHT3xCalcTemperatureC(dat);
}
/* check humidity */
data[0] = SHT3X_Data_Buffer[3];
data[1] = SHT3X_Data_Buffer[4];
data[2] = SHT3X_Data_Buffer[5];
/* value is ture */
tmp = SHT3xCheckCrc(data, 2, data[2]);
if (!tmp) {
dat = ((uint16_t)data[0] << 8) | data[1];
ReadData->Humidity = SHT3xCalcRH(dat);
}
return 0;
}
/***************************************************************
* 函数名称: LightStatusSet
* 说 明: 灯状态设置
* 参 数: status,ENUM枚举的数据
* OFF,关
* ON,开
* 返 回 值: 无
***************************************************************/
void LightStatusSet(E53IA1Status status)
{
if (status == ON) {
IoTGpioSetOutputVal(14, 1); //设置GPIO_14输出高电平点亮灯
}
if (status == OFF) {
IoTGpioSetOutputVal(14, 0); //设置GPIO_14输出低电平关闭灯
}
}
/***************************************************************
* 函数名称: MotorStatusSet
* 说 明: 电机状态设置
* 参 数: status,ENUM枚举的数据
* OFF,关
* ON,开
* 返 回 值: 无
***************************************************************/
void MotorStatusSet(E53IA1Status status)
{
if (status == ON) {
IoTGpioSetOutputVal(8, 1); //设置GPIO_8输出高电平打开电机
}
if (status == OFF) {
IoTGpioSetOutputVal(8, 0); //设置GPIO_8输出低电平关闭电机
}
}
@@ -0,0 +1,239 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "lwip/api_shell.h"
#include "lwip/ip4_addr.h"
#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "cmsis_os2.h"
#include "ohos_init.h"
#include "wifi_device.h"
#include "wifi_error_code.h"
#define DEF_TIMEOUT 15
#define ONE_SECOND 1
static void WiFiInit(void);
static void WaitSacnResult(void);
static int WaitConnectResult(void);
static void OnWifiScanStateChangedHandler(int state, int size);
static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo* info);
static void OnHotspotStaJoinHandler(StationInfo* info);
static void OnHotspotStateChangedHandler(int state);
static void OnHotspotStaLeaveHandler(StationInfo* info);
static int g_staScanSuccess = 0;
static int g_ConnectSuccess = 0;
static int g_ssid_count = 0;
static struct netif* g_lwip_netif = NULL;
static WifiEvent g_wifiEventHandler = {0};
WifiErrorCode error;
#define SELECT_WLAN_PORT "wlan0"
int WifiConnect(const char* ssid, const char* psk)
{
WifiScanInfo* info = NULL;
unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
//初始化WIFI
WiFiInit();
//使能WIFI
if (EnableWifi() != WIFI_SUCCESS) {
printf("EnableWifi failed, error = %d\r\n", error);
return -1;
}
//判断WIFI是否激活
if (IsWifiActive() == 0) {
printf("Wifi station is not actived.\r\n");
return -1;
}
//分配空间,保存WiFi信息
info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);
if (info == NULL) {
return -1;
}
//轮询查找WiFi列表
do {
//重置标志位
g_ssid_count = 0;
g_staScanSuccess = 0;
//开始扫描
Scan();
//等待扫描结果
WaitSacnResult();
//获取扫描列表
error = GetScanInfoList(info, &size);
} while (g_staScanSuccess != 1);
//打印WiFi列表
printf("********************\r\n");
for (uint8_t i = 0; i < g_ssid_count; i++) {
printf("no:%03d, ssid:%-30s, rssi:%5d\r\n", i + 1, info[i].ssid, info[i].rssi / 100);
}
printf("********************\r\n");
//连接指定的WiFi热点
for (uint8_t i = 0; i < g_ssid_count; i++) {
if (strcmp(ssid, info[i].ssid) == 0) {
int result;
printf("Select:%3d wireless, Waiting...\r\n", i + 1);
//拷贝要连接的热点信息
WifiDeviceConfig select_ap_config = {0};
strcpy(select_ap_config.ssid, info[i].ssid);
strcpy(select_ap_config.preSharedKey, psk);
select_ap_config.securityType = WIFI_SEC_TYPE_PSK;
if (AddDeviceConfig(&select_ap_config, &result) == WIFI_SUCCESS) {
if (ConnectTo(result) == WIFI_SUCCESS && WaitConnectResult() == 1) {
printf("WiFi connect succeed!\r\n");
g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);
break;
}
}
}
if (i == g_ssid_count - 1) {
printf("ERROR: No wifi as expected\r\n");
while (1)
osDelay(100);
}
}
//启动DHCP
if (g_lwip_netif) {
dhcp_start(g_lwip_netif);
printf("begain to dhcp\r\n");
}
//等待DHCP
for (;;) {
if (dhcp_is_bound(g_lwip_netif) == ERR_OK) {
printf("<-- DHCP state:OK -->\r\n");
//打印获取到的IP信息
netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);
break;
}
printf("<-- DHCP state:Inprogress -->\r\n");
osDelay(100);
}
osDelay(100);
return 0;
}
static void WiFiInit(void)
{
g_wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedHandler;
g_wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedHandler;
g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
error = RegisterWifiEvent(&g_wifiEventHandler);
if (error != WIFI_SUCCESS) {
printf("register wifi event fail!\r\n");
} else {
printf("register wifi event succeed!\r\n");
}
}
static void OnWifiScanStateChangedHandler(int state, int size)
{
if (size > 0) {
g_ssid_count = size;
g_staScanSuccess = 1;
}
printf("callback function for wifi scan:%d, %d\r\n", state, size);
return;
}
static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo* info)
{
if (info == NULL) {
printf("WifiConnectionChanged:info is null, stat is %d.\n", state);
} else {
if (state == WIFI_STATE_AVALIABLE) {
g_ConnectSuccess = 1;
} else {
g_ConnectSuccess = 0;
}
}
}
static void OnHotspotStaJoinHandler(StationInfo* info)
{
(void)info;
printf("STA join AP\n");
return;
}
static void OnHotspotStaLeaveHandler(StationInfo* info)
{
(void)info;
printf("HotspotStaLeave:info is null.\n");
return;
}
static void OnHotspotStateChangedHandler(int state)
{
printf("HotspotStateChanged:state is %d.\n", state);
return;
}
static void WaitSacnResult(void)
{
int scanTimeout = DEF_TIMEOUT;
while (scanTimeout > 0) {
sleep(ONE_SECOND);
scanTimeout--;
if (g_staScanSuccess == 1) {
printf("WaitSacnResult:wait success[%d]s\n", (DEF_TIMEOUT - scanTimeout));
break;
}
}
if (scanTimeout <= 0) {
printf("WaitSacnResult:timeout!\n");
}
}
static int WaitConnectResult(void)
{
int ConnectTimeout = DEF_TIMEOUT;
while (ConnectTimeout > 0) {
sleep(ONE_SECOND);
ConnectTimeout--;
if (g_ConnectSuccess == 1) {
printf("WaitConnectResult:wait success[%d]s\n", (DEF_TIMEOUT - ConnectTimeout));
break;
}
}
if (ConnectTimeout <= 0) {
printf("WaitConnectResult:timeout!\n");
return 0;
}
return 1;
}
+35
View File
@@ -0,0 +1,35 @@
# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("cloud_oc_gps") {
sources = [
"iot_cloud_oc_sample.c",
"src/E53_ST1.c",
"src/wifi_connect.c",
]
include_dirs = [
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/board/bearpi/bearpi_hm_nano/iot_hardware_hals/include",
"//foundation/communication/wifi_lite/interfaces/wifiservice",
"//third_party/cJSON",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/oc_mqtt/oc_mqtt_al",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/oc_mqtt/oc_mqtt_profile_v5",
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link/inc",
"include",
]
deps = [
"//device/board/bearpi/bearpi_hm_nano/third_party/iot_link:iot_link",
]
}
+192
View File
@@ -0,0 +1,192 @@
# BearPi-HM_Nano开发板智慧物流案例开发
本示例将演示如何在BearPi-HM_Nano开发板上使用MQTT协议连接华为IoT平台,使用E53_ST1 智慧物流扩展板与 BearPi-HM_Nano 开发板实现智慧物流的案例,设备安装如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/E53_ST1安装.png "E53_ST1安装")
## 软件设计
### 连接平台
在连接平台前需要设置CONFIG_APP_DEVICEID、CONFIG_APP_DEVICEPWD、CONFIG_APP_SERVERIP、CONFIG_APP_SERVERPORT,通过oc_mqtt_profile_connect()函数连接平台。
```c
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = queue_create("queue_rcvmsg",10,1);
if(NULL == g_app_cb.app_msg){
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void) memset( &connect_para, 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
//连接平台
ret = oc_mqtt_profile_connect(&connect_para);
if((ret == (int)en_oc_mqtt_err_ok)){
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
}
else
{
printf("oc_mqtt_profile_connect faild!\r\n");
}
```
### 推送数据
当需要上传数据时,需要先拼装数据,让后通过oc_mqtt_profile_propertyreport上报数据。代码示例如下:
```c
static void deal_report_msg(report_t *report)
{
oc_mqtt_profile_service_t service;
oc_mqtt_profile_kv_t Longitude_value;
oc_mqtt_profile_kv_t Latitude_value;
oc_mqtt_profile_kv_t beep;
if (g_app_cb.connected != 1) {
return;
}
service.event_time = NULL;
service.service_id = "Track";
service.service_property = &Longitude_value;
service.nxt = NULL;
Longitude_value.key = "Longitude";
Longitude_value.value = &report->Longitude;
Longitude_value.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
Longitude_value.nxt = &Latitude_value;
Latitude_value.key = "Latitude";
Latitude_value.value = &report->Latitude;
Latitude_value.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
Latitude_value.nxt = &beep;
beep.key = "BeepStatus";
beep.value = g_app_cb.beep ? "ON" : "OFF";
beep.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
beep.nxt = NULL;
//发送数据
oc_mqtt_profile_propertyreport(NULL,&service);
return;
}
```
## 编译调试
### 登录
设备接入华为云平台之前,需要在平台注册用户账号,华为云地址:<https://www.huaweicloud.com/>
在华为云首页单击产品,找到IoT物联网,单击设备接入IoTDA 并单击立即使用,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/登录平台01.png "登录平台")
![](../../docs/figures/D12_iot_cloud_oc_gps/登录平台02.png "登录平台")
### 创建产品
在设备接入页面可看到总览界面,展示了华为云平台接入的协议与域名信息,根据需要选取MQTT通讯必要的信息备用,如下图所示。
接入协议(端口号):MQTT 1883
域名:iot-mqtts.cn-north-4.myhuaweicloud.com
![](../../docs/figures/D12_iot_cloud_oc_gps/查看平台信息.png "查看平台信息")
选中侧边栏产品页,单击右上角“创建产品”,在页面中选中所属资源空间,并且按要求填写产品名称,选中MQTT协议,数据格式为JSON,并填写厂商名称,在下方模型定义栏中选择所属行业以及添加设备类型,并单击右下角“确定”,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/新增产品.png "新增产品")
创建完成后,在产品页会自动生成刚刚创建的产品,单击“查看”可查看创建的具体信息,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/查看产品.png "查看产品")
单击产品详情页的自定义模型,在弹出页面中新增服务,如下图所示。
服务ID`Track`(必须一致)
服务类型:`Senser`(可自定义)
![](../../docs/figures/D12_iot_cloud_oc_gps/创建服务.png "创建服务")
在“Track”的下拉菜单下点击“添加属性”填写“Longitude、Latitude、BeepStatus”相关信息,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/新增属性1.png "新增属性1")
![](../../docs/figures/D12_iot_cloud_oc_gps/新增属性2.png "新增属性1")
![](../../docs/figures/D12_iot_cloud_oc_gps/新增属性3.png "新增属性1")
在“Track”的下拉菜单下点击“添加命令”填写相关信息,如下图所示。
命令名称:`Track_Control_Beep`
参数名称:`Beep`
数据类型:`string`
长度:`3`
枚举值:`ON,OFF`
![](../../docs/figures/D12_iot_cloud_oc_gps/新增命令.png "新增命令")
#### 注册设备
在侧边栏中单击“设备”,进入设备页面,单击右上角“注册设备”,勾选对应所属资源空间并选中刚刚创建的产品,注意设备认证类型选择“秘钥”,按要求填写秘钥,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/注册设备01.png "注册设备")
记录下设备ID和设备密钥,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/注册设备02.png "注册设备")
注册完成后,在设备页面单击“所有设备”,即可看到新建的设备,同时设备处于未激活状态,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/注册设备03.png "注册设备")
### 修改代码中设备信息
修改`iot_cloud_oc_sample.c`中第31行附近的wifi的ssid和pwd,以及设备的DEVICEID和DEVICEPWD(这两个参数是在平台注册设备时产生的),如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/修改设备信息.png "修改设备信息")
### 修改 BUILD.gn 文件
修改 `device\bearpi\bearpi_hm_nano\app`路径下 BUILD.gn 文件,指定 `cloud_oc_gps` 参与编译。
```r
#"D7_iot_cloud_oc_smoke:cloud_oc_smoke",
#"D8_iot_cloud_oc_light:cloud_oc_light",
#"D9_iot_cloud_oc_manhole_cover:cloud_oc_manhole_cover",
#"D10_iot_cloud_oc_infrared:cloud_oc_infrared",
#"D11_iot_cloud_oc_agriculture:cloud_oc_agriculture",
"D12_iot_cloud_oc_gps:cloud_oc_gps",
```
### 测试
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,平台上的设备显示为在线状态,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/设备在线.png "设备在线")
点击设备右侧的“查看”,进入设备详情页面,可看到上报的数据,如下图所示。
![](../../docs/figures/D12_iot_cloud_oc_gps/查看设备数据.png "查看设备数据")
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __E53_ST1_H__
#define __E53_ST1_H__
/***************************************************************
* 名 称: GasStatus_ENUM
* 说 明:枚举状态结构体
***************************************************************/
typedef enum
{
OFF = 0,
ON
} E53ST1Status;
/***************************************************\
*GPS NMEA-0183协议重要参数结构体定义
*卫星信息
\***************************************************/
typedef struct
{
uint32_t latitude_bd; //纬度 分扩大100000倍,实际要除以100000
uint8_t nshemi_bd; //北纬/南纬,N:北纬;S:南纬
uint32_t longitude_bd; //经度 分扩大100000倍,实际要除以100000
uint8_t ewhemi_bd; //东经/西经,E:东经;W:西经
}gps_msg;
/* E53_ST1传感器数据类型定义 ------------------------------------------------------------*/
typedef struct
{
float Longitude; //经度
float Latitude; //纬度
} E53ST1Data;
void E53ST1Init(void);
void E53ST1ReadData(E53ST1Data *ReadData);
void BeepStatusSet(E53ST1Status status);
#endif /* __E53_ST1_H__ */
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __WIFI_CONNECT_H__
#define __WIFI_CONNECT_H__
int WifiConnect(const char *ssid,const char *psk);
#endif /* __WIFI_CONNECT_H__ */
@@ -0,0 +1,314 @@
/*
* Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cmsis_os2.h"
#include "ohos_init.h"
#include <dtls_al.h>
#include <mqtt_al.h>
#include <oc_mqtt_al.h>
#include <oc_mqtt_profile.h>
#include "E53_ST1.h"
#include "wifi_connect.h"
#define CONFIG_WIFI_SSID "BearPi" // 修改为自己的WiFi 热点账号
#define CONFIG_WIFI_PWD "BearPi" // 修改为自己的WiFi 热点密码
#define CONFIG_APP_SERVERIP "121.36.42.100"
#define CONFIG_APP_SERVERPORT "1883"
#define CONFIG_APP_DEVICEID "60a8684306dc9602c03a98ef_213231231231" // 替换为注册设备后生成的deviceid
#define CONFIG_APP_DEVICEPWD "123456789" // 替换为注册设备后生成的密钥
#define CONFIG_APP_LIFETIME 60 // seconds
#define CONFIG_QUEUE_TIMEOUT (5 * 1000)
#define MSGQUEUE_COUNT 16
#define MSGQUEUE_SIZE 10
#define CLOUD_TASK_STACK_SIZE (1024 * 10)
#define CLOUD_TASK_PRIO 24
#define SENSOR_TASK_STACK_SIZE (1024 * 4)
#define SENSOR_TASK_PRIO 25
#define TASK_DELAY 3
typedef enum {
en_msg_cmd = 0,
en_msg_report,
} en_msg_type_t;
typedef struct {
char* request_id;
char* payload;
} cmd_t;
typedef struct {
char Longitude[10];
char Latitude[9];
} report_t;
typedef struct {
en_msg_type_t msg_type;
union {
cmd_t cmd;
report_t report;
} msg;
} app_msg_t;
typedef struct {
osMessageQueueId_t app_msg;
int connected;
int beep;
} app_cb_t;
static app_cb_t g_app_cb;
static void deal_report_msg(report_t* report)
{
oc_mqtt_profile_service_t service;
oc_mqtt_profile_kv_t Longitude_value;
oc_mqtt_profile_kv_t Latitude_value;
oc_mqtt_profile_kv_t beep;
if (g_app_cb.connected != 1) {
return;
}
service.event_time = NULL;
service.service_id = "Track";
service.service_property = &Longitude_value;
service.nxt = NULL;
Longitude_value.key = "Longitude";
Longitude_value.value = &report->Longitude;
Longitude_value.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
Longitude_value.nxt = &Latitude_value;
Latitude_value.key = "Latitude";
Latitude_value.value = &report->Latitude;
Latitude_value.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
Latitude_value.nxt = &beep;
beep.key = "BeepStatus";
beep.value = g_app_cb.beep ? "ON" : "OFF";
beep.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
beep.nxt = NULL;
oc_mqtt_profile_propertyreport(NULL, &service);
return;
}
// use this function to push all the message to the buffer
static int msg_rcv_callback(oc_mqtt_profile_msgrcv_t* msg)
{
int ret = 0;
char* buf;
int buf_len;
app_msg_t* app_msg;
if ((msg == NULL) || (msg->request_id == NULL) || (msg->type != EN_OC_MQTT_PROFILE_MSG_TYPE_DOWN_COMMANDS)) {
return ret;
}
buf_len = sizeof(app_msg_t) + strlen(msg->request_id) + 1 + msg->msg_len + 1;
buf = malloc(buf_len);
if (buf == NULL) {
return ret;
}
app_msg = (app_msg_t*)buf;
buf += sizeof(app_msg_t);
app_msg->msg_type = en_msg_cmd;
app_msg->msg.cmd.request_id = buf;
buf_len = strlen(msg->request_id);
buf += buf_len + 1;
memcpy_s(app_msg->msg.cmd.request_id, buf_len, msg->request_id, buf_len);
app_msg->msg.cmd.request_id[buf_len] = '\0';
buf_len = msg->msg_len;
app_msg->msg.cmd.payload = buf;
memcpy_s(app_msg->msg.cmd.payload, buf_len, msg->msg, buf_len);
app_msg->msg.cmd.payload[buf_len] = '\0';
ret = osMessageQueuePut(g_app_cb.app_msg, &app_msg, NULL, CONFIG_QUEUE_TIMEOUT);
if (ret != 0) {
free(app_msg);
}
return ret;
}
static void oc_cmdresp(cmd_t* cmd, int cmdret)
{
oc_mqtt_profile_cmdresp_t cmdresp;
///< do the response
cmdresp.paras = NULL;
cmdresp.request_id = cmd->request_id;
cmdresp.ret_code = cmdret;
cmdresp.ret_name = NULL;
(void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
}
///< COMMAND DEAL
#include <cJSON.h>
static void deal_cmd_msg(cmd_t* cmd)
{
cJSON* obj_root;
cJSON* obj_cmdname;
cJSON* obj_paras;
cJSON* obj_para;
int cmdret = 1;
obj_root = cJSON_Parse(cmd->payload);
if (obj_root == NULL) {
oc_cmdresp(cmd, cmdret);
}
obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
if (obj_cmdname == NULL) {
cJSON_Delete(obj_root);
}
if (strcmp(cJSON_GetStringValue(obj_cmdname), "Track_Control_Beep") == 0) {
obj_paras = cJSON_GetObjectItem(obj_root, "paras");
if (obj_paras == NULL) {
cJSON_Delete(obj_root);
}
obj_para = cJSON_GetObjectItem(obj_paras, "Beep");
if (obj_para == NULL) {
cJSON_Delete(obj_root);
}
///< operate the Beep here
if (strcmp(cJSON_GetStringValue(obj_para), "ON") == 0) {
g_app_cb.beep = 1;
BeepStatusSet(ON);
printf("Beep On!\r\n");
} else {
g_app_cb.beep = 0;
BeepStatusSet(OFF);
printf("Beep Off!\r\n");
}
cmdret = 0;
oc_cmdresp(cmd, cmdret);
}
return;
}
static int CloudMainTaskEntry(void)
{
app_msg_t* app_msg;
uint32_t ret;
WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
dtls_al_init();
mqtt_al_init();
oc_mqtt_init();
g_app_cb.app_msg = osMessageQueueNew(MSGQUEUE_COUNT, MSGQUEUE_SIZE, NULL);
if (g_app_cb.app_msg == NULL) {
printf("Create receive msg queue failed");
}
oc_mqtt_profile_connect_t connect_para;
(void)memset_s(&connect_para, sizeof(connect_para), 0, sizeof(connect_para));
connect_para.boostrap = 0;
connect_para.device_id = CONFIG_APP_DEVICEID;
connect_para.device_passwd = CONFIG_APP_DEVICEPWD;
connect_para.server_addr = CONFIG_APP_SERVERIP;
connect_para.server_port = CONFIG_APP_SERVERPORT;
connect_para.life_time = CONFIG_APP_LIFETIME;
connect_para.rcvfunc = msg_rcv_callback;
connect_para.security.type = EN_DTLS_AL_SECURITY_TYPE_NONE;
ret = oc_mqtt_profile_connect(&connect_para);
if ((ret == (int)en_oc_mqtt_err_ok)) {
g_app_cb.connected = 1;
printf("oc_mqtt_profile_connect succed!\r\n");
} else {
printf("oc_mqtt_profile_connect faild!\r\n");
}
while (1) {
app_msg = NULL;
(void)osMessageQueueGet(g_app_cb.app_msg, (void**)&app_msg, NULL, 0xFFFFFFFF);
if (app_msg != NULL) {
switch (app_msg->msg_type) {
case en_msg_cmd:
deal_cmd_msg(&app_msg->msg.cmd);
break;
case en_msg_report:
deal_report_msg(&app_msg->msg.report);
break;
default:
break;
}
free(app_msg);
}
}
return 0;
}
static int SensorTaskEntry(void)
{
E53ST1Data data;
app_msg_t* app_msg;
E53ST1Init();
while (1) {
E53ST1ReadData(&data);
printf("\r\n******************************Longitude Value is %.5f\r\n", data.Longitude);
printf("\r\n******************************Latitude Value is %.5f\r\n", data.Latitude);
app_msg = malloc(sizeof(app_msg_t));
if ((app_msg != NULL) & (data.Longitude != 0) & (data.Latitude != 0)) {
app_msg->msg_type = en_msg_report;
sprintf_s(app_msg->msg.report.Longitude, sizeof(app_msg->msg.report.Longitude), "%.5f\0", data.Longitude);
sprintf_s(app_msg->msg.report.Latitude, sizeof(app_msg->msg.report.Latitude), "%.5f\0", data.Latitude);
if (osMessageQueuePut(g_app_cb.app_msg, &app_msg, 0U, CONFIG_QUEUE_TIMEOUT) != 0) {
free(app_msg);
}
}
sleep(TASK_DELAY);
}
return 0;
}
static void IotMainTaskEntry(void)
{
osThreadAttr_t attr;
attr.name = "CloudMainTaskEntry";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = CLOUD_TASK_STACK_SIZE;
attr.priority = CLOUD_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)CloudMainTaskEntry, NULL, &attr) == NULL) {
printf("Failed to create CloudMainTaskEntry!\n");
}
attr.stack_size = SENSOR_TASK_STACK_SIZE;
attr.priority = SENSOR_TASK_PRIO;
attr.name = "SensorTaskEntry";
if (osThreadNew((osThreadFunc_t)SensorTaskEntry, NULL, &attr) == NULL) {
printf("Failed to create SensorTaskEntry!\n");
}
}
APP_FEATURE_INIT(IotMainTaskEntry);

Some files were not shown because too many files have changed in this diff Show More