1. Timer 定时器
1.1 定时器概述
定时器(Timer)是用于实现定时任务的组件,可在指定时间间隔后执行特定任务,支持一次性执行或周期性重复执行。其典型应用场景包括:
- 智能设备的定时控制(如智能鱼缸定时喂食、灯光定时开关);
- 周期性数据采集(如传感器定时上报数据);
- 定时提醒(如耗材更换提醒、系统维护提示)。
在 OpenHarmony 中,定时器的时间周期以 "系统嘀嗒(tick)" 为单位,1 个嘀嗒默认对应 10ms,因此定时参数需根据实际需求转换为嘀嗒数(如 500ms = 50 个嘀嗒)。
1.2 定时器代码实现
以下代码演示了在 OpenHarmony 中使用定时器实现周期性任务的完整流程,包括定时器创建、启动、任务执行及销毁。
1.2.1 完整代码
cpp
/* C语言标准库头文件 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* OpenHarmony相关头文件 */
#include "ohos_init.h" // 系统初始化头文件
#include "cmsis_os2.h" // 实时操作系统接口头文件
#include "hi_timer.h" // 海思定时器头文件
/* 全局变量:记录定时任务执行次数 */
int task_count = 0;
/* 定时器ID:用于标识和操作定时器 */
osTimerId_t timer_id;
/* 函数声明:定时器任务函数(定时执行的目标内容) */
void timer_target(void *arg);
/* 线程函数:创建并启动定时器 */
void thread_timer(void *arg) {
/*
创建定时器
函数原型:osTimerId_t osTimerNew(
osTimerFunc_t func, // 定时器任务函数(定时执行的函数)
osTimerType_t type, // 定时器类型(osTimerPeriodic:周期性;osTimerOnce:一次性)
void *argument, // 传递给任务函数的参数(NULL表示无参数)
const osTimerAttr_t *attr // 定时器属性(NULL表示默认属性)
)
此处创建周期性定时器,任务函数为timer_target
*/
timer_id = osTimerNew(timer_target, osTimerPeriodic, NULL, NULL);
if (timer_id == NULL) { // 检查定时器创建是否成功
perror("[osTimerNew] create Timer Failed!");
exit(1);
}
/*
启动定时器
函数原型:osStatus_t osTimerStart(
osTimerId_t timer_id, // 目标定时器ID
uint32_t ticks // 定时周期(单位:系统嘀嗒,1 tick = 10ms)
)
此处设置定时周期为500ms(500ms / 10ms = 50 ticks)
*/
osStatus_t status = osTimerStart(timer_id, 50);
if (status != osOK) { // 检查启动是否成功
perror("[osTimerStart] start Timer Failed!");
exit(status);
}
}
/* 初始化任务:创建定时器线程 */
static void TimerTestTask(void) {
/* 配置线程属性 */
osThreadAttr_t timer_thread_attr;
memset(&timer_thread_attr, 0, sizeof(osThreadAttr_t));
timer_thread_attr.name = "Timer_thread"; // 线程名称
timer_thread_attr.stack_size = 1024; // 栈大小(1024字节)
timer_thread_attr.priority = osPriorityNormal; // 优先级(正常)
/* 创建线程:用于执行定时器的创建和启动 */
osThreadId_t timer_thread_id = osThreadNew(thread_timer, NULL, &timer_thread_attr);
if (timer_thread_id == NULL) {
perror("[osThreadNew] create thread [Timer_thread] failed!");
exit(1);
}
}
/* 注册初始化任务:系统启动时自动执行TimerTestTask */
APP_FEATURE_INIT(TimerTestTask);
/* 定时器任务函数:定时执行的内容(每500ms执行一次) */
void timer_target(void *arg) {
// 打印当前任务执行次数
printf("task_count : %d\n", task_count);
task_count++; // 次数加1
// 当任务执行10次后,停止并销毁定时器
if (task_count == 10) {
/*
停止定时器
函数原型:osStatus_t osTimerStop(osTimerId_t timer_id)
*/
osStatus_t status = osTimerStop(timer_id);
if (status != osOK) {
perror("[osTimerStop] stop Timer Failed!");
exit(status);
}
/*
销毁定时器
函数原型:osStatus_t osTimerDelete(osTimerId_t timer_id)
*/
status = osTimerDelete(timer_id);
if (status != osOK) {
perror("[osTimerDelete] delete Timer Failed!");
exit(status);
}
printf("Timer stopped and deleted after 10 tasks.\n");
}
}
2. GPIO 和点灯大师
2.1 1 Hi3861****实物图和原理图


2.2 Hi3861 内置GPIO控制方式
GPIO (General Purpose Input/Output) 即通用输入输出接口,是嵌入式系统和微控制器中最基 本、最常用的外设接口之一。它允许微控制器 MCU 与外部设备进行简单的数字信号交互。
在 OpenHarmony 中将所有的 GPIO 进行编号,提供了一个标准的【枚举类型】从 0 开始到 15
结束
2.3 Hi3861芯片OHOS****对外所有引脚的名称枚举
对应所在头文件是 #include "hi_io.h"
cpp
/**
* @ingroup iot_io
*
* GPIO pin ID. CNcomment:IO硬件管脚编号。CNend
*/
typedef enum {
HI_IO_NAME_GPIO_0, /**< GPIO0 */
HI_IO_NAME_GPIO_1, /**< GPIO1 */
HI_IO_NAME_GPIO_2, /**< GPIO2 */
HI_IO_NAME_GPIO_3, /**< GPIO3 */
HI_IO_NAME_GPIO_4, /**< GPIO4 */
HI_IO_NAME_GPIO_5, /**< GPIO5 */
HI_IO_NAME_GPIO_6, /**< GPIO6 */
HI_IO_NAME_GPIO_7, /**< GPIO7 */
HI_IO_NAME_GPIO_8, /**< GPIO8 */
HI_IO_NAME_GPIO_9, /**< GPIO9 */
HI_IO_NAME_GPIO_10, /**< GPIO10 */
HI_IO_NAME_GPIO_11, /**< GPIO11 */
HI_IO_NAME_GPIO_12, /**< GPIO12 */
HI_IO_NAME_GPIO_13, /**< GPIO13 */
HI_IO_NAME_GPIO_14, /**< GPIO14 */
HI_IO_NAME_SFC_CSN, /**< SFC_CSN */
HI_IO_NAME_SFC_IO1, /**< SFC_IO1 */
HI_IO_NAME_SFC_IO2, /**< SFC_IO2 */
HI_IO_NAME_SFC_IO0, /**< SFC_IO0 */
HI_IO_NAME_SFC_CLK, /**< SFC_CLK */
HI_IO_NAME_SFC_IO3, /**< SFC_IO3 */
HI_IO_NAME_MAX,
} hi_io_name;
2.4 Hi3861芯片OHOS****针对于不同引脚功能控制枚举
对应所在头文件是 #include "hi_io.h"
以 GPIO7 引脚对应功能枚举为例
在 OHOS 中对所有引脚功能都有对应的枚举类型进行功能描述,后续代码中,只需要赋
值对应的枚举值,即可完成对应的切换功能。
cpp
/**
* @ingroup iot_io
*
* GPIO_7 pin function.CNcomment:GPIO_7管脚功能。CNend
*/
typedef enum {
HI_IO_FUNC_GPIO_7_GPIO,
HI_IO_FUNC_GPIO_7_UART1_CTS_N = 2,
HI_IO_FUNC_GPIO_7_SPI0_RXD,
HI_IO_FUNC_GPIO_7_PWM0_OUT = 5,
HI_IO_FUNC_GPIO_7_I2S0_BCLK,
HI_IO_FUNC_GPIO_7_BT_ACTIVE,
} hi_io_func_gpio_7;
2.5 标准GPIO输入输出控制枚举类型
对应所在头文件是 #include "hi_gpio.h"
dir ==> direction 方向
cpp
/**
* @ingroup iot_gpio
*
* I/O direction. CNcomment:GPIO方向。CNend
*/
typedef enum {
HI_GPIO_DIR_IN = 0, /**< Input.CNcomment:输入方向CNend*/
HI_GPIO_DIR_OUT /**< Output.CNcomment:输出方向CNend*/
} hi_gpio_dir;
2.6 IO****引脚对应的电平高低
对应所在头文件是 #include "hi_io.h"
HI_IO_PULL_UP 上拉 --> 高电平
HI_IO_PULL_DOWN 下拉 --> 低电平
cpp
/**
* @ingroup iot_io
*
* GPIO pull-up configuration.CNcomment:IO上下拉功能CNend
*/
typedef enum {
HI_IO_PULL_NONE, /**< Disabled.CNcomment:无拉CNend */
HI_IO_PULL_UP, /**< Pull-up enabled.CNcomment:上拉CNend */
HI_IO_PULL_DOWN, /**< Pull-down enabled.CNcomment:下拉CNend */
HI_IO_PULL_MAX, /**< Invalid.CNcomment:无效值CNend */
} hi_io_pull;
2.7 点灯 LED3 Warm

2.7.1 原理图分析

2.7.2 LED****初始化函数
LED 初始化函数用于配置 LED 对应的 GPIO 引脚工作模式,确保 LED 能够正常响应高低电平控制。以下是针对 LED3(连接到 IO2 引脚)的初始化实现:
cpp
/*
当前两个宏定义:
- LED_3_PIN:指定LED3对应的引脚为IO2
- LED_3_FUNC:指定IO2引脚的工作模式为GPIO模式
*/
#define LED_3_PIN HI_IO_NAME_GPIO_2
#define LED_3_FUNC HI_IO_FUNC_GPIO_2_GPIO
/**
* LED3 对应 GPIO 初始化函数
* 功能:配置IO2引脚为GPIO输出模式,为LED控制做准备
*/
void led_init(void)
{
/* 1. 初始化GPIO模块 */
/*
函数原型:hi_u32 hi_gpio_init(hi_void);
作用:初始化OpenHarmony的GPIO模块,使能GPIO功能
*/
hi_gpio_init();
/* 2. 设置LED3对应IO2的工作模式为GPIO */
/*
函数原型:hi_u32 hi_io_set_func(hi_io_name id, hi_u8 val);
参数说明:
- id:引脚编号(此处为LED_3_PIN,即IO2)
- val:引脚功能(此处为LED_3_FUNC,即GPIO模式)
作用:将IO2引脚从默认功能切换为GPIO功能,用于LED控制
*/
hi_io_set_func(LED_3_PIN, LED_3_FUNC);
/* 3. 设置IO2为GPIO输出模式 */
/*
函数原型:hi_u32 hi_gpio_set_dir(hi_gpio_idx id, hi_gpio_dir dir);
参数说明:
- id:GPIO引脚编号(与hi_io_name一致,即IO2)
- dir:方向模式(HI_GPIO_DIR_OUT表示输出模式)
作用:配置IO2为输出模式,允许通过软件控制其输出高低电平
*/
hi_gpio_set_dir(LED_3_PIN, HI_GPIO_DIR_OUT);
/* 4. 设置IO2引脚为上拉模式(默认高电平) */
/*
函数原型:hi_u32 hi_io_set_pull(hi_io_name id, hi_io_pull val);
参数说明:
- id:引脚编号(IO2)
- val:上下拉模式(HI_IO_PULL_UP表示上拉,默认输出高电平)
作用:确保引脚在未被主动控制时处于高电平状态,避免电平不确定
*/
hi_io_set_pull(LED_3_PIN, HI_IO_PULL_UP);
}
2.7.3 LED 线程任务代码
LED 线程任务通过周期性切换 GPIO 引脚的高低电平,实现 LED 的闪烁效果。具体实现如下:
cpp
/**
* LED 灯线程任务代码
* 功能:周期性切换LED3的亮灭状态(闪烁效果)
*/
void led_main(void *arg)
{
// 1. 初始化LED对应的GPIO(调用上面定义的led_init函数)
led_init();
int n = 0; // 计数变量,用于控制LED状态切换
while (1) // 无限循环,持续控制LED
{
if (n % 2) // 当n为奇数时
{
/*
函数原型:hi_u32 hi_gpio_set_ouput_val(hi_gpio_idx id, hi_gpio_value val);
参数说明:
- id:GPIO引脚编号(IO2)
- val:输出电平(HI_GPIO_VALUE0表示低电平)
作用:设置IO2输出低电平,假设LED为低电平点亮,则此时LED亮
*/
hi_gpio_set_ouput_val(LED_3_PIN, HI_GPIO_VALUE0);
}
else // 当n为偶数时
{
/*
设置IO2输出高电平,假设LED为低电平点亮,则此时LED灭
*/
hi_gpio_set_ouput_val(LED_3_PIN, HI_GPIO_VALUE1);
}
n += 1; // 计数加1
osDelay(100); // 延迟100个系统嘀嗒(1个嘀嗒=10ms,即延迟1000ms=1秒)
}
}
2.7.4 线程创建
通过创建线程来运行 LED 控制任务,确保 LED 闪烁功能在系统启动后自动执行:
cpp
/**
* 初始化任务:创建LED控制线程
*/
static void LedTestTask(void)
{
// 配置线程属性
osThreadAttr_t led_thread_attr;
memset(&led_thread_attr, 0, sizeof(osThreadAttr_t)); // 初始化属性结构体
led_thread_attr.name = "Led_thread"; // 线程名称(唯一标识)
led_thread_attr.stack_size = 1024; // 线程栈大小(1024字节)
led_thread_attr.priority = osPriorityNormal; // 线程优先级(正常优先级)
/*
创建LED控制线程
函数原型:osThreadId_t osThreadNew(osThreadFunc_t func, void *arg, const osThreadAttr_t *attr);
参数说明:
- func:线程入口函数(此处为led_main,即LED控制逻辑)
- arg:传递给线程的参数(NULL表示无参数)
- attr:线程属性(上面配置的led_thread_attr)
作用:创建并启动线程,执行LED闪烁任务
*/
osThreadId_t led_thread_id = osThreadNew(led_main, NULL, &led_thread_attr);
if (led_thread_id == NULL) // 检查线程创建是否成功
{
perror("[osThreadNew] create thread [Led_thread] failed!");
exit(1); // 创建失败则退出程序
}
}
// 注册初始化任务,系统启动时自动执行LedTestTask
APP_FEATURE_INIT(LedTestTask);