【FFH】OpenHarmony API 原创
API
API(application programming interface)是用来构建应用程序软件的一组子程序定义,协议和工具。一般来说,这是一套在各种软件组件之间明确定义的通信方法。
它是一些预先定义的函数,目的是提供应用程序与开发人员基于某种软件或硬件得以访问一组例程的能力,并且不足要访问源码或者理解内部工作机制的具体实现。
更加详细的介绍请戳此处
常用头文件
#include <stdio.h>
#include <unistd.h>//C 和 C++ 程序设计语言中提供对 POSIX 操作系统 API 的访问功能的 头文件 的名称
#include "cmsis_os2.h"//典型的 CMSIS-RTOS2 API 实现与现有的实时内核接口。
#include "ohos_init.h"//提供用于初始化和启动服务和功能的条目
#include "iot_gpio.h" //声明 GPIO 接口函数。这些函数用于 GPIO 初始化、输入/输出设置和电平设置。
注意:#include<>——直接从编译器自带的函数库中寻找文件
#include" "——是先从自定义的文件中找 ,如果找不到在从函数库中寻找文件。
具体参考此处
Thread API
先介绍一下线程API 的名称和用法
osThreadNew//创建一个新线程并将这个加入活跃线程组.func:任务函数;argument:作为启动参数传递给任务函数的指针;attr:任务入口函数的参数列表
osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
osThreadGetName//返回指定线程的名字
osThreadGetId//返回当前线程ID
osThreadGetState//线程状态
osThreadSetPriority//设置线程优先级
osThreadGetPriority//获取线程优先级
osThreadYield//将运行控制转交给下一个处于Ready状态的线程
osThreadSuspend//挂起指定线程运行(任务挂起)。thread_id:任务ID
osStatus_t osThreadSuspend (osThreadId_t thread_id)
osThreadResume//恢复线程运行(任务恢复).thread_id:任务ID
osStatus_t osThreadResume (osThreadId_t thread_id)
osThreadDetach//分离线程
osThreadJoin//等待线程终止运行
osThreadExit//终止当前线程运行
osThreadTerminate//终止指定线程的运行(删除某个任务)。thread_id:任务ID。
osStatus_t osThreadTerminate (osThreadId_t thread_id)
osThreadGetStackSize//获取指定线程的栈空间大小
osThreadGetStackSpace//获取指定线程未使用的栈空间大小
osThreadGetCount//获取活跃线程数
osThreadEnumerate//获取线程组中活跃线程数
比较重要:
线程代码具体实现
#include <stdio.h>
#include <unistd.h>//C 和 C++ 程序设计语言中提供对 POSIX 操作系统 API 的访问功能的 头文件 的名称
#include "cmsis_os2.h"//典型的 CMSIS-RTOS2 API 实现与现有的实时内核接口。
#include "ohos_init.h"
//创建线程
osThreadId_t newThread(char *name, osThreadFunc_t func, void *arg) {
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024*2, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, arg, &attr);
if (tid == NULL) {
printf("[Thread Test] osThreadNew(%s) failed.\r\n", name);
} else {
printf("[Thread Test] osThreadNew(%s) success, thread id: %d.\r\n", name, tid);//如果成功就打印线程名字和ID。
}
return tid;
}
//传递给任务函数的指针
void threadTest(void *arg) {
static int count = 0;
printf("%s\r\n",(char *)arg);//打印出自己的参数
osThreadId_t tid = osThreadGetId();
printf("[Thread Test] threadTest osThreadGetId, thread id:%p\r\n", tid);
while (1) {//循环并且输出count的值
count++;
printf("[Thread Test] threadTest, count: %d.\r\n", count);
osDelay(20);
}
}
//编写线程函数内容,使用上述API进行相关操作
void rtosv2_thread_main(void *arg)// void 指针可以指向任意类型的数据,就是说可以用任意类型的指针对 void 指针对 void 指针赋值。
{
(void)arg;//将本指针值(即地址本身)转换为无类型数据,起作用等同于p_arg=p_arg; , 目的是不让编译器在编译时报警告信息。
osThreadId_t tid=newThread("test_thread", threadTest, "This is a test thread.");
//下面就是一些API函数的用法,优先级设置,获取线程ID等等。
const char *t_name = osThreadGetName(tid);
printf("[Thread Test] osThreadGetName, thread name: %s.\r\n", t_name);
osThreadState_t state = osThreadGetState(tid);
printf("[Thread Test] osThreadGetState, state :%d.\r\n", state);
osStatus_t status = osThreadSetPriority(tid, osPriorityNormal4);
printf("[Thread Test] osThreadSetPriority, status: %d.\r\n", status);
osPriority_t pri = osThreadGetPriority (tid);
printf("[Thread Test] osThreadGetPriority, priority: %d.\r\n", pri);
status = osThreadSuspend(tid);
printf("[Thread Test] osThreadSuspend, status: %d.\r\n", status);
status = osThreadResume(tid);
printf("[Thread Test] osThreadResume, status: %d.\r\n", status);
uint32_t stacksize = osThreadGetStackSize(tid);
printf("[Thread Test] osThreadGetStackSize, stacksize: %d.\r\n", stacksize);
uint32_t stackspace = osThreadGetStackSpace(tid);
printf("[Thread Test] osThreadGetStackSpace, stackspace: %d.\r\n", stackspace);
uint32_t t_count = osThreadGetCount();
printf("[Thread Test] osThreadGetCount, count: %d.\r\n", t_count);
osDelay(100);
status = osThreadTerminate(tid);//终止所创建线程
printf("[Thread Test] osThreadTerminate, status: %d.\r\n", status);
}
//创建一个线程(任务)
static void ThreadTestTask(void)
{
osThreadAttr_t attr;
attr.name = "rtosv2_thread_main";//任务名称
attr.attr_bits = 0U;//属性位,用于设置osStatus_t osThreadJoin (osThreadId_t thread_id);函数能否使用,默认为0.
attr.cb_mem = NULL;//控制块的指针,不操作设置为NULL。
attr.cb_size = 0U;//控制块的指针大小默认0.
attr.stack_mem = NULL;//任务栈指针,不操作设置为NULL。
attr.stack_size = 1024;//任务栈大小
attr.priority = osPriorityNormal;//任务的优先级设置
if (osThreadNew((osThreadFunc_t)rtosv2_thread_main, NULL, &attr) == NULL) {
printf("[ThreadTestTask] Falied to create rtosv2_thread_main!\n");//通过osThreadNew函数传递参数设置任务函数,创建任务--后面编写线程函数rtosv2_thread_main。
}
}
APP_FEATURE_INIT(ThreadTestTask);
Timer API
软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设定的Tick时钟计数值后会触发用户定义的回调函数。
定时器的运作机制:软件定时器(操作系统提供的,一类系统接口,构建在硬件定时器基础之上,可以提供不受硬件定时器资源限制的定时器服务)的触发遵循队列规则–先进先出。当用户创建并且启动了一个软件定时器的时候,LiteOS根据当前系统的Tick时间以及用户设置的时间间隔确定定时器结束Tick时间,并且将该定时器控制结构挂入即使全局链表。
注意:1.我们在创建软件计时器的时候,要指定时间到达后要调用的函数(回调函数),在回调函数中处理信息,两次触发回调函数的时间间隔Tick叫做定时器的定时周期。
2.在回调函数中应快进快出。绝对不允许使用任何可能引起软件定时器任务挂起或阻塞API接口,也不允许在回调函数中出现死循环。
osTimerNew//创建和初始化定时器
osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr)//func:函数指针指向回调函数;type:定时器类型,osTimerOnce表示单次定时器,ostimer周期表示周期性定时器;argument:定时器回调函数的参数;attr:计时器属性;返回定时器ID。
osTimerGetName//获取指定的定时器的名字。
osTimerStart//启动或重启指定的定时器
osStatus_t osTimerStart (osTimerId_t timer_id,uint32_t ticks)//timer_id:定时器ID;ticks:计时器的值
osTimerStop//停止指定的定时器
osStatus_t osTimerStop (osTimerId_t timer_id)//timer_id:定时器ID
osTimerlsRunning//检查一个定时器是否在运行
osTimerDelete//删除定时器
osStatus_t osTimerDelete (osTimerId_t timer_id)//timer_id:定时器ID
代码分析
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
static int times = 0;
//定时器的回调函数
void cb_timeout_periodic(void *arg) {
(void)arg;
times++;
}
//使用osTimerNew创建一个100个时钟周期调用一次回调函数cb_timeout_periodic定时器,每隔100个时钟周期检查一下全局变量times是否小于3,若不小于3则停止时钟周期
void timer_periodic(void) {
osTimerId_t periodic_tid = osTimerNew(cb_timeout_periodic, osTimerPeriodic, NULL, NULL);//创建定时器
if (periodic_tid == NULL) {
printf("[Timer Test] osTimerNew(periodic timer) failed.\r\n");
return;
} else {
printf("[Timer Test] osTimerNew(periodic timer) success, tid: %p.\r\n",periodic_tid);
}
osStatus_t status = osTimerStart(periodic_tid, 100);//启动定时器,并且设置滴答计时器的值为100。
if (status != osOK) {
printf("[Timer Test] osTimerStart(periodic timer) failed.\r\n");
return;
} else {
printf("[Timer Test] osTimerStart(periodic timer) success, wait a while and stop.\r\n");
}
while(times < 3) {
printf("[Timer Test] times:%d.\r\n",times);
osDelay(100);
}
//停止并删除定时器
status = osTimerStop(periodic_tid);
printf("[Timer Test] stop periodic timer, status :%d.\r\n", status);
status = osTimerDelete(periodic_tid);
printf("[Timer Test] kill periodic timer, status :%d.\r\n", status);
}
//创建一个线程
static void TimerTestTask(void)
{
osThreadAttr_t attr;
attr.name = "timer_periodic";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024;
attr.priority = osPriorityNormal;
if (osThreadNew((osThreadFunc_t)timer_periodic, NULL, &attr) == NULL) {
printf("[TimerTestTask] Falied to create timer_periodic!\n");
}
}
APP_FEATURE_INIT(TimerTestTask);
BUILD.gn文件
static_library("timer_demo") {
sources = [
"timer.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
]
}
Delay API
>
osDelay //等待指定的ticks
osDElayUntil//等待到指定的时钟周期
代码分析
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
void rtosv2_delay_main(void *arg) {
(void)arg;
printf("[Delay Test] Current system tick: %d.\r\n", osKernelGetTickCount());
osStatus_t status = osDelay(100);//使用osDelay,让线程等100个时钟周期
printf("[Delay Test] osDelay, status: %d.\r\n", status);
printf("[Delay Test] Current system tick: %d.\r\n", osKernelGetTickCount());//获取当前的时钟周期tick, 在此基础上增加100个时钟周期
uint32_t tick = osKernelGetTickCount();
tick += 100;
status = osDelayUntil(tick);//让线程等待tick + 100个时钟周期后恢复运行
printf("[Delay Test] osDelayUntil, status: %d.\r\n", status);
printf("[Delay Test] Current system tick: %d.\r\n", osKernelGetTickCount());
}
//创建一个线程
static void DelayTestTask(void)
{
osThreadAttr_t attr;
attr.name = "rtosv2_delay_main";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024;
attr.priority = osPriorityNormal;
if (osThreadNew((osThreadFunc_t)rtosv2_delay_main, NULL, &attr) == NULL) {
printf("[DelayTestTask] Falied to create rtosv2_delay_main!\n");
}
}
APP_FEATURE_INIT(DelayTestTask);
BUILD.gn文件
static_library("delay_demo") {
sources = [
"delay.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
]
}
Mutex API
当有任务持有的时候,互斥锁处于闭锁状态,这个任务获得该互斥锁的所有权,一个任务持有互斥锁的时候,其他任务不可以再对该互斥锁开锁或者持有。
osMutexNew//创建并且初始化一个互斥锁
osMutexId_t osMutexNew (const osMutexAttr_t *attr)//attr:互斥对象的属性
osMutexGetName//获得指定互斥锁的名字
osMutexAcquire//获得指定的互斥锁的访问权限,若已经被锁定,则返回超时如果没有其他线程获得互斥锁,该函数立即返回并阻塞互斥锁对象.
osStatus_t osMutexAcquire (osMutexId_t mutex_id,uint32_t timeout)//mutex_id:互斥锁ID,timeout:超时值
osMutexRelease//释放指定的互斥锁
osStatus_t osMutexRelease (osMutexId_t mutex_id)//mutex_id:互斥锁ID
osMutexGetOwner//获得指定互斥锁的所有者线程
osMutexDelete//删除指定的互斥锁
osStatus_t osMutexDelete (osMutexId_t mutex_id)//mutex_id:互斥锁ID
代码分析
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
static int g_test_value = 0;
void number_thread(void *arg) {
osMutexId_t *mid = (osMutexId_t *)arg;
while(1) {
if (osMutexAcquire(*mid, 100) == osOK) {
g_test_value++;
if (g_test_value % 2 == 0) {
printf("[Mutex Test]%s gets an even value %d.\r\n", osThreadGetName(osThreadGetId()), g_test_value);
} else {
printf("[Mutex Test]%s gets an odd value %d.\r\n", osThreadGetName(osThreadGetId()), g_test_value);
}
osMutexRelease(*mid);
osDelay(5);
}
}
}
osThreadId_t newThread(char *name, osThreadFunc_t func, void *arg) {
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024*2, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, arg, &attr);
if (tid == NULL) {
printf("[Mutex Test]osThreadNew(%s) failed.\r\n", name);
} else {
printf("[Mutex Test]osThreadNew(%s) success, thread id: %d.\r\n", name, tid);
}
return tid;
}
void rtosv2_mutex_main(void *arg) {
(void)arg;
osMutexAttr_t attr = {0};
osMutexId_t mid = osMutexNew(&attr);
if (mid == NULL) {
printf("[Mutex Test]osMutexNew, create mutex failed.\r\n");
} else {
printf("[Mutex Test]osMutexNew, create mutex success.\r\n");
}
osThreadId_t tid1 = newThread("Thread_1", number_thread, &mid);
osThreadId_t tid2 = newThread("Thread_2", number_thread, &mid);
osThreadId_t tid3 = newThread("Thread_3", number_thread, &mid);
osDelay(13);
osThreadId_t tid = osMutexGetOwner(mid);
printf("[Mutex Test]osMutexGetOwner, thread id: %p, thread name: %s.\r\n", tid, osThreadGetName(tid));
osDelay(17);
osThreadTerminate(tid1);
osThreadTerminate(tid2);
osThreadTerminate(tid3);
osMutexDelete(mid);
}
static void MutexTestTask(void)
{
osThreadAttr_t attr;
attr.name = "rtosv2_mutex_main";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024;
attr.priority = osPriorityNormal;
if (osThreadNew((osThreadFunc_t)rtosv2_mutex_main, NULL, &attr) == NULL) {
printf("[MutexTestTask] Falied to create rtosv2_mutex_main!\n");
}
}
APP_FEATURE_INIT(MutexTestTask);
BUILD.gn文件
static_library("mutex_demo") {
sources = [
"mutex.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
]
}
Semaphore API
信号量(Semaphore)是一种实现任务间通信的机制,实现任务之间同步或临界资源的互斥访问。信号量功能可以在多任务的操作系统中实现不同任务间的同步运行。
使用场景
-
互斥锁:作用互斥的时候,信号量创建后计数是满的,在需要使临界资源时,先申请信号量,让其变空,其他任务需要使用临界资源的时候会因为无法申请到信号量而阻塞,从而保证了临界资源的安全。
-
任务间同步:信号量在创建后被置空,任务1申请信号量而阻塞,任务2在某种条件发生后释放信号量,于是任务1进入ready或running态,从而实现两个任务间的同步。
-
资源计数:信号量作为一个特殊的计数器,可以递增或递减,但是不能为负值。
-
中断与任务的同步:在中断未触发时将信号量的值置为0,从而堵塞服务处理任务,一旦中断被触发,则唤醒堵塞的中断服务处理任务进行中断处理。
osSemaphoreNew//创建并初始化一个信号量
osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr)//max_count:信号量计数值的最大值;initial_count:信号量计数值的初始值;attr:信号量属性。 返回信号量ID。
osSemaphoreGetName//获取一个信号量的名字
osSemaphoreAcquire//获取一个信号量令牌,若获取不到返回超时
osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout)//semaphore_id:信号量ID;timeout:超时值(若这个值=0,就可以从中断服务例程中调用)
osSemaphoreRelease//释放一个信号量的令牌,但是令牌的数量不超过初始定义的
osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id);//semaphore_id:信号量ID
osSemaphoreGetCount//获取当前信号令牌数
osSemaphoreDelete//删除一个信号量
osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id);//semaphore_id:信号量ID
代码分析
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#define BUFFER_SIZE 5U
static int product_number = 0;
osSemaphoreId_t empty_id;
osSemaphoreId_t filled_id;
//用经典的消费者,生产这问题,这里时生产者线程
void producer_thread(void *arg) {
(void)arg;
empty_id = osSemaphoreNew(BUFFER_SIZE, BUFFER_SIZE, NULL);
filled_id = osSemaphoreNew(BUFFER_SIZE, 0U, NULL);
while(1) {
osSemaphoreAcquire(empty_id, osWaitForever);
product_number++;
printf("[Semp Test]%s produces a product, now product number: %d.\r\n", osThreadGetName(osThreadGetId()), product_number);
osDelay(4);
osSemaphoreRelease(filled_id);
}
}
//消费者线程
void consumer_thread(void *arg) {
(void)arg;
while(1){
osSemaphoreAcquire(filled_id, osWaitForever);
product_number--;
printf("[Semp Test]%s consumes a product, now product number: %d.\r\n", osThreadGetName(osThreadGetId()), product_number);
osDelay(3);
osSemaphoreRelease(empty_id);
}
}
osThreadId_t newThread(char *name, osThreadFunc_t func, void *arg) {
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024*2, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, arg, &attr);
if (tid == NULL) {
printf("[Semp Test]osThreadNew(%s) failed.\r\n", name);
} else {
printf("[Semp Test]osThreadNew(%s) success, thread id: %d.\r\n", name, tid);
}
return tid;
}
void rtosv2_semp_main(void *arg) {
(void)arg;
empty_id = osSemaphoreNew(BUFFER_SIZE, BUFFER_SIZE, NULL);
filled_id = osSemaphoreNew(BUFFER_SIZE, 0U, NULL);
//消费者的速度比生产者快,故设置消费者个数少于生产者(2个消费者)
osThreadId_t ptid1 = newThread("producer1", producer_thread, NULL);
osThreadId_t ptid2 = newThread("producer2", producer_thread, NULL);
osThreadId_t ptid3 = newThread("producer3", producer_thread, NULL);
osThreadId_t ctid1 = newThread("consumer1", consumer_thread, NULL);
osThreadId_t ctid2 = newThread("consumer2", consumer_thread, NULL);
osDelay(50);
//终止指定线程的运行
osThreadTerminate(ptid1);
osThreadTerminate(ptid2);
osThreadTerminate(ptid3);
osThreadTerminate(ctid1);
osThreadTerminate(ctid2);
osSemaphoreDelete(empty_id);
osSemaphoreDelete(filled_id);
}
//创建一个线程
static void SempTestTask(void)
{
osThreadAttr_t attr;
attr.name = "rtosv2_semp_main";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024;
attr.priority = osPriorityNormal;
if (osThreadNew((osThreadFunc_t)rtosv2_semp_main, NULL, &attr) == NULL) {
printf("[SempTestTask] Falied to create rtosv2_semp_main!\n");
}
}
APP_FEATURE_INIT(SempTestTask);
BUILD.gn文件
static_library("semp_demo") {
sources = [
"semp.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
]
}
MessageQueue API
消息队列,常用于任务之间通信,接收任务或中断的不固定长度的消息。还可以起到缓冲消息的作用。
osMessageQueueNew//创建和初始化一个消息队列
osMessageQueueId_t osMessageQueueNew (uint32_t msg_count,uint32_t msg_size,const osMessageQueueAttr_t *attr)//msg_count:队列中的最大消息数;msg_size:最大消息大小(以字节为单位);attr:消息队列属性;空:默认值
osMessageQueueGetName//返回指定的消息队列的名字
osMessageQueuePut//向指定消息队列存放一条消息,若满了返回超时
osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id,const void *msg_ptr,uint8_t msg_prio,uint32_t timeout);//mq_id:由osMessageQueueNew获得的消息队列ID
msg_ptr:要发送的消息;msg_prio:指优先级;timeout:超时值
osMessageQueueGet//从指定的消息队列中取得一条消息,若消息队列为空,返回超时
osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id,void *msg_ptr,uint8_t *msg_prio,uint32_t timeout);//msg_ptr:指针指向队列中获取消息的缓冲区指针
osMessageQueueGetCapacity//获得指定的消息队列的消息容量
osMessageQueueGetMsgSize//获得指定的消息队列中可以存放的最大消息的大小
osMessageQueueGetCount//获得指定的消息队列中的消息数
osMessageQueueGetSpace//获得指定的消息队列中还可以存放的消息数
osMessageQueueQueueReset//将指定的消息队列重置为初始状态
osMessageQueueDelete//删除指定的消息队列
osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id);//mq_id:消息队列ID;
##代码分析##
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#define QUEUE_SIZE 3
typedef struct {
osThreadId_t tid;
int count;
} message_entry;
osMessageQueueId_t qid;
//发送者发送count和线程ID,并打印出来。
void sender_thread(void *arg) {
static int count=0;
message_entry sentry;
(void)arg;
while(1) {
sentry.tid = osThreadGetId();
sentry.count = count;
printf("[Message Test] %s send %d to message queue.\r\n", osThreadGetName(osThreadGetId()), count);
osMessageQueuePut(qid, (const void *)&sentry, 0, osWaitForever);
count++;
osDelay(5);
}
}
//接收者从消息列队里面获取一条信息,并且打印输出。
void receiver_thread(void *arg) {
(void)arg;
message_entry rentry;
while(1) {
osMessageQueueGet(qid, (void *)&rentry, NULL, osWaitForever);
printf("[Message Test] %s get %d from %s by message queue.\r\n", osThreadGetName(osThreadGetId()), rentry.count, osThreadGetName(rentry.tid));
osDelay(3);
}
}
//创建一个新线程
osThreadId_t newThread(char *name, osThreadFunc_t func, void *arg) {
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024*2, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, arg, &attr);
if (tid == NULL) {
printf("[Message Test] osThreadNew(%s) failed.\r\n", name);
} else {
printf("[Message Test] osThreadNew(%s) success, thread id: %d.\r\n", name, tid);
}
return tid;
}
//主程序创建了三个消息发送者和两个消息接收者
void rtosv2_msgq_main(void *arg) {
(void)arg;
qid = osMessageQueueNew(QUEUE_SIZE, sizeof(message_entry), NULL);
//调用新线程
osThreadId_t ctid1 = newThread("recevier1", receiver_thread, NULL);
osThreadId_t ctid2 = newThread("recevier2", receiver_thread, NULL);
osThreadId_t ptid1 = newThread("sender1", sender_thread, NULL);
osThreadId_t ptid2 = newThread("sender2", sender_thread, NULL);
osThreadId_t ptid3 = newThread("sender3", sender_thread, NULL);
osDelay(20);
uint32_t cap = osMessageQueueGetCapacity(qid);
printf("[Message Test] osMessageQueueGetCapacity, capacity: %d.\r\n",cap);
uint32_t msg_size = osMessageQueueGetMsgSize(qid);
printf("[Message Test] osMessageQueueGetMsgSize, size: %d.\r\n",msg_size);
uint32_t count = osMessageQueueGetCount(qid);
printf("[Message Test] osMessageQueueGetCount, count: %d.\r\n",count);
uint32_t space = osMessageQueueGetSpace(qid);
printf("[Message Test] osMessageQueueGetSpace, space: %d.\r\n",space);
osDelay(80);
osThreadTerminate(ctid1);
osThreadTerminate(ctid2);
osThreadTerminate(ptid1);
osThreadTerminate(ptid2);
osThreadTerminate(ptid3);
osMessageQueueDelete(qid);
}
//创建了一个线程
static void MessageTestTask(void)
{
osThreadAttr_t attr;
attr.name = "rtosv2_msgq_main";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024;
attr.priority = osPriorityNormal;
if (osThreadNew((osThreadFunc_t)rtosv2_msgq_main, NULL, &attr) == NULL) {
printf("[MessageTestTask] Falied to create rtosv2_msgq_main!\n");
}
}
APP_FEATURE_INIT(MessageTestTask);
BUILD.gn文件
static_library("message_demo") {
sources = [
"message.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/kal",
]
}
GPIO API
先介绍一下GPIO API 的名称和用法
//GPIO模块的初始化
unsigned int GpioInit(void);
//设置GPIO的引脚方向。id:设定引脚,dir:指定输入输出。
unsigned int GpioSetDir(WifilotGpioldx id,WifilotGpioDir dir);
//设置GPIO引脚的输出状态。id:设定引脚,val:指定高电平或低电平。
unsigned int GpioSetOutputVal(WifilotGpioldx id,WifilotGpioValue val);
//设置引脚功能。id:设定引脚,val:指定引脚功能。
unsigned int loSetFunc(WifilotloName id,unsigned char val);
//解除GPIO模块初始化
unsigned int GpioDeinit(void);
应用:电灯样例代码分析。
#include <stdio.h>
#include <unistd.h>//C 和 C++ 程序设计语言中提供对 POSIX 操作系统 API 的访问功能的 头文件 的名称
#include "cmsis_os2.h"//典型的 CMSIS-RTOS2 API 实现与现有的实时内核接口。
#include "ohos_init.h"//提供用于初始化和启动服务和功能的条目
#include "iot_gpio.h" //声明 GPIO 接口函数。这些函数用于 GPIO 初始化、输入/输出设置和电平设置。
//宏定义(方便该值,增加代码可读性)
#define LED_TASK_GPIO 9
#define LED_TASK_STACK_SIZE 1024
#define LED_TASK_PRIO 25
static void* GpioTask(const char* arg)
{
(void)arg;
//用来初始化GPIO
IoTGpioInit(LED_TASK_GPIO);
//设置刚刚初始好的GPIO引脚的输出状态 IoTGpioSetDir(LED_TASK_GPIO,IOT_GPIO_DIR_OUT);
//进行死循环操作小灯的亮灭
while (1) {
printf(" LED_SPARK! \n");
//设置引脚功能 IoTGpioSetOutputVal(LED_TASK_GPIO,0);
osDelay(50);
IoTGpioSetOutputVal(LED_TASK_GPIO,1);
osDelay(50);
}
return NULL;
}
//创建一个线程
static void GpioExampleEntry(void)
{
osThreadAttr_t attr;
attr.name = "GpioTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = LED_TASK_STACK_SIZE;
attr.priority = LED_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)GpioTask, NULL, &attr) == NULL) {
printf("[GpioExample] Falied to create GpioTask!\n");
}
}
SYS_RUN(GpioExampleEntry); //注意和线程的名称保持一致。
想对cmsis_os2.h了解得更多可戳此处
然后配置相应的BUILD.gn文件
static_library("led_example") {
//查看参与编译的模块
sources = [
"led_example.c",
]
//.C文件里面的头文件所包含的路径
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/kal",
"//base/iot_hardware/peripheral/interfaces/kits",
]
}
PWM API
先介绍一下PWM API 的名称和用法
//PWM模块初始化。 port :PWM端口号
unsighed int PwmInit(WifiIotPwmPort port);
//开始输出PWM信号。duty:占空比(高电平占周期的时间);freq:分频倍数
unsigned int PwmStart(WifiIotPwmPort port,unsigned short duty,unsigned short freq);
//停止输出PWM信号。
unsigned int PwmStop(WifiIotPwmPort port);
//解除PWM初始化。
unsigned int PwmDeinit(WifiIotPwmPort port);
//设置PWM模块时钟源
unsigned int PwmSetClock(WifiIotPwmPortClkSource clkScouce);
应用:用于调光系统的脉宽调制
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"
//上面的头文件同上个例子
#include "iot_pwm.h"//PWM初始化
#include "iot_errno.h"//定义了通过错误码来回报错误信息的宏
#include "hi_io.h"//这里用#include <io.h> 而不是#include "io.h" 说明io.h在编译器的默认搜索路径,而不在使用这个#include的文件的工程路径
#define RED_LED_PIN_NAME 10
#define RED_LED_PIN_FUNCTION WIFI_IOT_IO_FUNC_GPIO_10_GPIO
#define RESOLUTION 4096
#define PWM_FREQ_DIVITION 64000
//定义的线程
static void PWMLedDemoTask(void *arg)
{
(void)arg;
//炫彩灯板的红灯
hi_io_set_func(10, 5);
IoTPwmInit(1);
while (1) {
// use PWM control RED LED brightness
for (int i = 1; i <= RESOLUTION; i *= 2) {
IoTPwmStart(1, i, PWM_FREQ_DIVITION);
usleep(250000);
IoTPwmStop(1);
}
}
}
static void PWMLedDemo(void)
{
osThreadAttr_t attr;
// set Red LED pin to GPIO function
IoTGpioInit(10);
attr.name = "PWMLedDemoTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 4096;
attr.priority = osPriorityNormal;
if (osThreadNew(PWMLedDemoTask, NULL, &attr) == NULL) {
printf("[ColorfulLightDemo] Falied to create PWMLedDemoTask!\n");
}
}
APP_FEATURE_INIT(PWMLedDemo);
配置相关的BUILD.gn文件
static_library("pwm_led_demo") {
sources = [
"pwm_led_demo.c",
]
//头文件的路径与上个例子一样
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/kal",
"//base/iot_hardware/peripheral/interfaces/kits",
]
}
主要参考
上面的代码样例均来自智能家居套件完整例程里面的,我只是对部分代码进行了注释分析。
智能家居套件完整例程