文章目录
-
- [Hi3861 OpenHarmony](#Hi3861 OpenHarmony)
-
-
- [1. 学习内容](#1. 学习内容)
- [2. Hi3861 芯片概述](#2. Hi3861 芯片概述)
- [3. OpenHarmony 概述](#3. OpenHarmony 概述)
- [4. 开发环境概述](#4. 开发环境概述)
- [4. OpenHarmony 第一行代码](#4. OpenHarmony 第一行代码)
-
- [4.1 代码实现](#4.1 代码实现)
- [4.2 编译烧录过程](#4.2 编译烧录过程)
- [6. 多线程操作【重点】](#6. 多线程操作【重点】)
-
- [6.1 OHOS 多线程操作](#6.1 OHOS 多线程操作)
- [6.2 多个线程创建和调度](#6.2 多个线程创建和调度)
- [6.3 Mutex 互斥锁机制](#6.3 Mutex 互斥锁机制)
- [6.4 Semaphore 信号量机制](#6.4 Semaphore 信号量机制)
-
Hi3861 OpenHarmony
1. 学习内容
- GPIO 输入输出,高低电平
- 系统编程多线程控制,锁机制
- 单总线数据传感器,设备控制。
- 联网操作 + MQTT + 云平台初步使用
2. Hi3861 芯片概述
官方海思提供的手册内容

3. OpenHarmony 概述
OpenHarmony 是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的一款面向全场景的开源分布式操作系统。以下为你从其诞生背景、特点、应用场景、技术架构
主要用于智能家居,工业物联网,穿戴系统使用,是一个【完整的实时操作系统】。可以提供系统支持,并且兼容多平台硬件。
4. 开发环境概述
基于 Ubuntu 22.04 搭建的 OpenHarmony 3.0 开发环境,利用 Ubuntu 环境进行程序编程,通过**【交叉编译工具】**将程序编译为 hi3861 支持的可执行系统文件,烧录到开发版中,进行后续的程序开发。

代码根据开发要求,对应的路径为
~/Desktop/OpenHarmony/code-v3.0-LTS/OpenHarmony/applications/sample/wifi-iot/app

4. OpenHarmony 第一行代码
4.1 代码实现
OpenHarmony 代码都是给予【多线程模式实现】,完成的每一个模块都是一个【线程模块】

【程序模块】
c
/*
C 语言标准库三剑客
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
以下是需要导入的 OpenHarmony 相关头文件
ohos_init.h OpenHarmony OS 系统初始化相关头文件
cmsis_os2.h 实时操作系统头文件
hi_timer.h 海思提供的 timer 定时器头文件
*/
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_timer.h"
/*
【第三步】
在 OHOS 每一个组件都是一个线程模块,需要提供对应的线程任务代码
线程任务代码要求
1. 返回值为 void
2. 参数为 void *
*/
/**
* @brief 测试使用 Hello 线程任务函数
*
* @param arg 用户提供的 void * 参数。
*/
void hello_thread(void * arg);
/*
【第一步】
注册组件函数,
函数要求 static 修饰,同时返回值和参数都是 void
函数名称根据当前模块名称决定。
*/
static void helloTask(void)
{
/*
osThreadId_t osThreadNew (osThreadFunc_t func,
void *argument,
const osThreadAttr_t *attr);
osThreadId_t OHOS 中对应线程号类型。 真实类型是 void *。
details Thread ID identifies the thread.
typedef void *osThreadId_t;
osThreadFunc_t 函数指针变量名,要求提供的函数必须是返回值 为 void
参数为 void * 类型。
typedef void (*osThreadFunc_t) (void *argument);
void *argument 当前线程任务函数所需参数
const osThreadAttr_t *attr OHOS 提供的线程属性结构体类型。
其中【重点】内容
1. 线程名称
2. 线程占用的【stack】 栈区内存大小
3. 线程优先级
当前程序创建线程任务,需要提供
1. 线程目标任务函数
2. 线程任务函数所需参数
3. 线程任务相关属性结构体
返回结果是当前 osThreadId_t,对应线程【地址】
*/
/*
【第五步】
创建线程
*/
// 5.1 创建 osThreadAttr_t 线程属性结构体变量
osThreadAttr_t thread_attr;
memset(&thread_attr, 0, sizeof(osThreadAttr_t));
thread_attr.name = "hello_DD"; // 线程名称
thread_attr.attr_bits = 1024; // 当前线程占用的栈区大小,1024 ==> 1KB
thread_attr.priority = osPriorityNormal; // 默认优先级
// 5.2 利用 osThreadNew 创建线程,线程完毕,立即执行。
osThreadId_t thread_id = osThreadNew(hello_thread,
HI_NULL, // HI_NULL <==> NULL 海思公司自行定义的 NULL 类型。
&thread_attr);
if (HI_NULL == thread_id)
{
perror("[osThreadNew] create thread [hello_thread] failed!");
exit(EXIT_FAILURE);
}
}
/*
【第二步】
对当前组件进行注册,利用 OHOS 提供的有参数宏进行注册操作
APP_FEATURE_INIT 是 OHOS 提供的用于注册组件的有参数宏,要求提供的
函数返回值必须是 void 类型,参数也是 void 类型。利用函数指针
对当前组件功能进行注册操作。
*/
APP_FEATURE_INIT(helloTask);
/*
【第四步】
线程任务函数实现
*/
void hello_thread(void * arg)
{
while (1)
{
printf("Hello OHOS Thread\n");
/*
osStatus_t osDelay (uint32_t ticks);
ticks 嘀嗒,当前系统执行一次任务的时间。
Hi3861 基于 OHOS tick 时间为 【10 ms】,可以认为当前开发板一秒钟执行 100 次任务。
100 ticks == 100 * 10ms == 1 s
*/
osDelay(100);
}
}
BUILD.gn 文件内容
python
static_library("demo01_hello") {
sources = [
"demo_hello.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/kal/cmsis"
]
}

APP 目录下的 BUILD.gn 文件内容
python
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
"demo01_hello",
]
}

4.2 编译烧录过程
安装 CH340 驱动。
编译程序
切换路径到 OpenHarmony 原码根目录下
shqf@qf:~/Desktop/OpenHarmony/code-v3.0-LTS/OpenHarmony
使用编译命令
hb build
对项目进行编译操作

使用 HiBurn 烧录程序
端口确定

需要烧录到开发版中的程序在 Linux 虚拟机中,利用共享文件夹通过 IP 地址找到对应文件,文件路径如下, 需要根据自行的 IP 地址进行修改,目标文件为
Hi3861_wifiiot_app_allinone.bin
\\192.168.25.129\qf\Desktop\OpenHarmony\code-v3.0-LTS\OpenHarmony\out\hispark_pegasus\wifiiot_hispark_pegasus

进行烧录操作

Connect 之后,开发板按下 RESET 键,进入烧录过程

烧录完成

HiBurn 断开连接,XCOM 连接当前开发板,打开串口,开发板按键 RESET ,启动程序运行

6. 多线程操作【重点】
6.1 OHOS 多线程操作
学习 OHOS 多线程操作是为后续的 RTT 准备
- 多线程操作
- 锁机制【Mutex Sem】
- 消息队列【MessageQueue】
6.2 多个线程创建和调度
多线程案例
c
/*
C 语言标准库三剑客
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
以下是需要导入的 OpenHarmony 相关头文件
ohos_init.h OpenHarmony OS 系统初始化相关头文件
cmsis_os2.h 实时操作系统头文件
hi_timer.h 海思提供的 timer 定时器头文件
*/
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_timer.h"
/*
多个线程任务执行和调度
*/
void test_thread1(void *arg);
void test_thread2(void *arg);
void test_thread3(void *arg);
static void threadTestTask(void)
{
osThreadAttr_t thread_attr;
memset(&thread_attr, 0, sizeof(osThreadAttr_t));
thread_attr.name = "thread1";
thread_attr.stack_size = 1024;
thread_attr.priority = osPriorityNormal;
osThreadId_t thread_id1 = osThreadNew(test_thread1, HI_NULL, &thread_attr);
if (HI_NULL == thread_id1)
{
perror("[osThreadNew] create thread [thread_id1] failed!");
exit(EXIT_FAILURE);
}
thread_attr.name = "thread2";
osThreadId_t thread_id2 = osThreadNew(test_thread2, HI_NULL, &thread_attr);
if (HI_NULL == thread_id2)
{
perror("[osThreadNew] create thread [thread_id2] failed!");
exit(EXIT_FAILURE);
}
thread_attr.name = "thread3";
osThreadId_t thread_id3 = osThreadNew(test_thread3, HI_NULL, &thread_attr);
if (HI_NULL == thread_id3)
{
perror("[osThreadNew] create thread [thread_id3] failed!");
exit(EXIT_FAILURE);
}
}
APP_FEATURE_INIT(threadTestTask);
void test_thread1(void *arg)
{
while (1)
{
printf("Thread Test1 Running!\n");
osDelay(200);
}
}
void test_thread2(void *arg)
{
while (1)
{
printf("Thread Test2 Running!\n");
osDelay(500);
}
}
void test_thread3(void *arg)
{
while (1)
{
printf("Thread Test3 Running!\n");
osDelay(1000);
}
}
组件内部 BUILD.gn
python
static_library("demo02_thread") {
sources = [
"demo_thread.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/kal/cmsis"
]
}
App 目录下 BUILD.gn
python
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
# "demo01_hello",
"demo02_thread",
]
}
6.3 Mutex 互斥锁机制
Linux 系统编程中互斥锁使用方式
- 定义 Mutex 互斥锁变量
- 对 Mutex 进行 init 初始化操作
- 利用 lock 和 unlock 限制同步资源内容
- 使用完毕利用 destroy 对锁变量进行销毁
OpenHarmony 中的操作流程和 Linux 系统编程一致,只是函数方式略有不同。互斥锁案例代码
c
/*
C 语言标准库三剑客
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
以下是需要导入的 OpenHarmony 相关头文件
ohos_init.h OpenHarmony OS 系统初始化相关头文件
cmsis_os2.h 实时操作系统头文件
hi_timer.h 海思提供的 timer 定时器头文件
*/
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_timer.h"
/**
* @brief 自定义字符串数据处理函数
*
* @param str 所需参数是字符串数据
*/
void print_string(const char *str);
/*
线程任务函数
*/
void test_thread1(void *arg);
void test_thread2(void *arg);
/// \details Mutex ID identifies the mutex.
// typedef void *osMutexId_t; 互斥锁类型
osMutexId_t mutex;
static void mutexTestTask(void)
{
/*
osMutexId_t osMutexNew (const osMutexAttr_t *attr);
互斥锁初始化操作,所需参数是 osMutexAttr_t 类型,互斥锁属性类型。
/// Create and Initialize a Mutex object.
/// \param[in] attr mutex attributes; NULL: default values.
/// \return mutex ID for reference by other functions or NULL in case of error.
osMutexId_t osMutexNew (const osMutexAttr_t *attr);
osMutexAttr_t 互斥属性结构体,默认情况下 osMutexNew 所需参数为 NULL
*/
mutex = osMutexNew(HI_NULL);
if (HI_NULL == mutex)
{
perror("[osMutexNew] create and Initialize Mutex object Failed!");
exit(EXIT_FAILURE);
}
osThreadAttr_t thread_attr;
memset(&thread_attr, 0, sizeof(osThreadAttr_t));
thread_attr.name = "thread1";
thread_attr.stack_size = 1024;
thread_attr.priority = osPriorityNormal;
osThreadId_t tid1 = osThreadNew(test_thread1, "Hello_XX", &thread_attr);
if (HI_NULL == tid1)
{
perror("[osThreadNew] create thread [thread1] failed!");
exit(EXIT_FAILURE);
}
thread_attr.name = "thread2";
osThreadId_t tid2 = osThreadNew(test_thread2, "Hello_ZZ", &thread_attr);
if (HI_NULL == tid2)
{
perror("[osThreadNew] create thread [thread2] failed!");
exit(EXIT_FAILURE);
}
}
APP_FEATURE_INIT(mutexTestTask);
void print_string(const char *str)
{
while (*str)
{
printf("%c", *str);
str++;
osDelay(100);
}
}
void test_thread1(void *arg)
{
/*
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout);
去指针化操作 osMutexId_t mutex_id 实际类型是一个 void *
获取当前 Mutex 互斥锁执行权限,
osMutexId_t mutex_id mutex 互斥锁 ID
uint32_t timeout 指定获取的时间。
返回值 osStatus_t OHOS 中错误类型,枚举类型
typedef enum {
osOK = 0, ///< Operation completed successfully.
osError = -1, ///< Unspecified RTOS error: run-time error but no other error message fits.
osErrorTimeout = -2, ///< Operation not completed within the timeout period.
osErrorResource = -3, ///< Resource not available.
osErrorParameter = -4, ///< Parameter error.
osErrorNoMemory = -5, ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
osErrorISR = -6, ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
osStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
} osStatus_t;
*/
osStatus_t status = osMutexAcquire(mutex, osWaitForever);
if (status)
{
perror("[osMutexAcquire] Acquire a Mutex Failed!\n");
exit(EXIT_FAILURE);
}
print_string((const char *)arg);
status = osMutexRelease(mutex);
if (status)
{
perror("[osMutexRelease] Release a Mutex Failed!\n");
exit(EXIT_FAILURE);
}
}
void test_thread2(void *arg)
{
osStatus_t status = osMutexAcquire(mutex, osWaitForever);
if (status)
{
perror("[osMutexAcquire] Acquire a Mutex Failed!\n");
exit(EXIT_FAILURE);
}
print_string((const char *)arg);
status = osMutexRelease(mutex);
if (status)
{
perror("[osMutexRelease] Release a Mutex Failed!\n");
exit(EXIT_FAILURE);
}
}
组件内部 BUILD.gn
python
static_library("demo03_mutex") {
sources = [
"demo_mutex.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/kal/cmsis"
]
}
App 目录下 BUILD.gn
python
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
# "demo01_hello",
# "demo02_thread",
"demo03_mutex",
]
}
6.4 Semaphore 信号量机制
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ohos_init.h" // HarmonyOS 初始化头文件
#include "cmsis_os2.h" // CMSIS-RTOS2 API 头文件
#include "hi_timer.h" // 定时器头文件
// 线程函数声明
void hello_thread1(void *arg);
void hello_thread2(void *arg);
void hello_thread3(void *arg);
osSemaphoreId_t sem; // 信号量句柄
static void helloTask(void)
{
// 创建一个信号量
// 参数说明:
// 2 - 信号量的最大计数值(关键修改:从3改为2)
// 2 - 信号量的初始计数值(确保一开始就有两个可用)
// HI_NULL - 无额外属性
sem = osSemaphoreNew(2, 2, HI_NULL); // 关键修改:最大计数值改为2
if(HI_NULL == sem)
{
perror("osSemaphoreNew failed!\n");
exit(EXIT_FAILURE);
}
// 定义线程属性结构体
osThreadAttr_t thread_attr;
memset(&thread_attr, 0, sizeof(osThreadAttr_t));
// 设置线程1属性
thread_attr.name = "hello_D1"; // 线程名称
thread_attr.attr_bits = 1024; // 栈大小(字节)
thread_attr.priority = osPriorityNormal; // 线程优先级
// 创建线程1
osThreadId_t thread_id1 = osThreadNew(hello_thread1, HI_NULL, &thread_attr);
if (thread_id1 == HI_NULL)
{
perror("osThreadNew failed!");
exit(EXIT_FAILURE);
}
// 设置线程2属性
thread_attr.name = "hello_D2";
osThreadId_t thread_id2 = osThreadNew(hello_thread2, HI_NULL, &thread_attr);
if (thread_id2 == HI_NULL)
{
perror("osThreadNew failed!");
exit(EXIT_FAILURE);
}
// 设置线程3属性
thread_attr.name = "hello_D3";
osThreadId_t thread_id3 = osThreadNew(hello_thread3, HI_NULL, &thread_attr);
if (thread_id3 == HI_NULL)
{
perror("osThreadNew failed!");
exit(EXIT_FAILURE);
}
}
// HarmonyOS 应用特性初始化宏,指定 helloTask 为入口函数
APP_FEATURE_INIT(helloTask);
// 线程1的执行函数
void hello_thread1(void *arg)
{
int count = 0;
while (1)
{
// 获取信号量(等待直到获取成功)
osSemaphoreAcquire(sem, osWaitForever);
printf("[T1] hello ohos thread1 - count: %d\n", ++count);
osDelay(1000); // 延迟1000毫秒(1秒)
// 释放信号量
osSemaphoreRelease(sem);
osDelay(10); // 小延迟,避免立即重新获取信号量
}
}
// 线程2的执行函数
void hello_thread2(void *arg)
{
int count = 0;
while (1)
{
// 获取信号量(等待直到获取成功)
osSemaphoreAcquire(sem, osWaitForever);
printf("[T2] hello ohos thread2 - count: %d\n", ++count);
osDelay(1000); // 延迟1000毫秒(1秒)
// 释放信号量
osSemaphoreRelease(sem);
osDelay(10); // 小延迟,避免立即重新获取信号量
}
}
// 线程3的执行函数
void hello_thread3(void *arg)
{
int count = 0;
while (1)
{
// 获取信号量(等待直到获取成功)
osSemaphoreAcquire(sem, osWaitForever);
printf("[T3] hello ohos thread3 - count: %d\n", ++count);
osDelay(1000); // 关键修改:统一延迟时间为1000毫秒
// 释放信号量
osSemaphoreRelease(sem);
osDelay(10); // 小延迟,避免立即重新获取信号量
}
}
运行结果为
[T1] hello ohos thread1 - count: 1
[T2] hello ohos thread2 - count: 1
(等待约1秒)
[T3] hello ohos thread3 - count: 1
[T1] hello ohos thread2 - count: 2
(等待约1秒)
[T2] hello ohos thread2 - count: 2
[T3] hello ohos thread3 - count: 2