物联网开发操作系统

大题(代码解析)

PPT例子、实验代码看懂(理解)

其他题目

一共五章内容 绪论(比较少) 第二张比较多 3、4、6比重差不多一样多 ## 第一章 TinyOS的技术特点

  • 组件化编程(Componented-Based)
  • 事件驱动模式(Event-Driven)
  • 轻量级线程(lightweight thread)
  • 两级调度方式(Tasks And Events Concurrency Model)
  • 分阶段作业(Split-Phase Operations) 六个特点理解是什么意思

TinyOS的编程语言:nesC 组件分类:

  • Module组件(模块):实现某种逻辑功能;
  • Configuration组件(配件):将各个组件连接起来成为一个整体。不完成功能实现

HarmonyOS三大特性

  1. 硬件互助、资源共享
    • 分布式软总线 (最重要)
    • 分布式设备虚拟化
    • 分布式数据管理
    • 分布式任务调度
  2. 一次开发、多端部署
    • 提供了用户程序框架、Ability框架以及UI框架
    • 支持应用开发过程中多终端的业务逻辑和界面逻辑进行复用
    • 能够实现应用的一次开发、多端部署
    • 提升跨平台开发效率
  3. 统一OS、弹性部署
    • 通过组件化和小型化等设计方式,做到硬件资源可大可小
    • 支持多种终端设备按需弹性部署
    • 能够适配不同硬件资源和功能需求 分布式设计的基础:分布式软总线

第二章

(概念熟悉) 接口(interface):组件(Component)之间可以进行数据交换的唯一方式 接口的命令(command)函数和事件(event)函数

  • command 是命令,根据应用层的要求操作底层硬件实现相应功能,由组件本身实现
  • event 是事件,由中断触发,标志着系统状态的改变,由组件的使用者实现

useprovide接口

  • use使用接口
  • provide提供接口
  • 一个接口可以有多个实例

每个nesC有且只有一个顶层配件(top-level configuration)连接内部组件,顶层配件即为makefile文件的第一行指定的COMPONENT 事件是异步中断驱动的,是有优先级区别的 Task

  • 定义task和提交post的关键字
  • 返回类型为void的无参数函数
  • 没有优先级,表现为FIFO(先进先出)模式。事件是有优先级的
  • 后台执行(异步的)

应用程序开发步骤

  1. 在/opt/tinyos-2.x/apps下建立文件夹,以应用名字命名。文件夹下需包含4个文件:定制运行环境的makefile、头文件、顶层配件、核心处理模块
  2. 编写头文件(可选),里面定义了数据结构
  3. 编写顶层配件
    • 接口的提供和使用情况
    • 使用的组件列表
    • 组件间的接口连接关系
  4. 编写核心处理模块
    • 接口的提供、使用情况
    • 具体的实现代码 error_t为command操作的成功/失败结果
      1
      2
      3
      4
      5
      6
      typedef enum {
      SUCCESS = 0;
      FAIL = 1;
      ESIZE = 2; // 传递参数过大
      ...
      } error_t;
      SUCCESSFAIL为最常用的两种返回值 ### Blink例子(重要) Blink是一个基本的应用程序,它通过开启定时器来实现周期性地切换LED灯。 其文件位置为/opt/tinyos-2.1.x/apps/Blink。 编译下载到节点上,可以看到,该应用程序在节点的3个LED灯上显示了一个计数器。它只是简单的以4Hz的频率开关LED0,以2Hz开关LED1,以1HZ开关LED2。其效果就是:每两秒3个LED显示了二进制计数从0到7。 Blink程序由两个文件组成:模块文件(BlinkC.nc)和配件文件(BlinkAppC.nc)。注意:所有程序都需要一个顶层配件,通常是以应用程序的名字命名。BlinkAppC就是Blink程序的配件,也是nesC编译器产生可执行文件的源头。而BlinkC则提供Blink程序的逻辑实现。BlinkAppC是用来连接BlinkC模块和Blink所需的其他功能组件。

BlinkAppC.nc,这是一个顶层配件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
configuration BlinkAppC
{
// 这里一般由uses 和 provides 从句来说明使用到的和提供的接口,除了顶层
// 配件,模块和配件都可以使用和提供接口
}
Implementation //实现部分
{
components MainC, BlinkC, LedsC; //BlinkC是编写的模块
components new TimerMilliC() as Timer0; //as命名别名方便识别
components new TimerMilliC() as Timer1; //同一组件不同实例
components new TimerMilliC() as Timer2;
//components指定了这个配件用到的组件components
BlinkC -> MainC.Boot; // BlinkC.Boot -> MainC.Boot
BlinkC.Timer0 -> Timer0;//BlinkC.Timer0 -> Timer0.Timer0
BlinkC.Timer1 -> Timer1;// ->是连接的意思
BlinkC.Timer2 -> Timer2;// ->是一种包含两个内部规范元素的连接
BlinkC.Leds -> LedsC; //BlinkC.Leds -> LedsC.Leds
// 也就是把负责实现应用部分的模块BlinkC与系统的组件库连接起来
// 记住, BlinkAppC 和 BlinkC 组件是不一样的。更确切的说, BlinkAppC 是由
// Blinkc 组件连同 mainc ,ledsc 和3个 timer定时器一起组成的。
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module BlinkC ()
{
uses interface Timer<TMilli> as Timer0; //定义使用到的接口
//Timer1、Timer2的定义同上
uses interface Leds;
uses interface Boot;
//BlinkC 可以调用这些它使用的接口的任何命令,但必须实现这些接口的所有事件 event
}
implementation
{
event void Boot.booted()
{
call Timer0.startPeriodic( 250 ); //250ms周期性触发
call Timer1.startPeriodic( 500 );
call Timer2.startPeriodic( 1000 );
}
event void Timer0.fired()
{
dbg(“BlinkC”, “Timer 0 fired @ %s.\n”, sim_time_string());
call Leds.led0Toggle(); //led0灯切换灭-亮状态
}
//Timer1、Timer2的fired()事件函数同上
}

第三章(通信)

message_t:消息缓冲抽象

基本通信接口,以及接口下的方法(command)

  • Packet:提供了对message_t抽象数据类型的基本访问
    • void clear(message_t *msg) //清空消息内容
    • void setPayloadLength(message_t *msg, uint8_t len) //设定有效载荷区的长度
    • void *getPayload(message_t *msg, uint8_t len) //获得消息有效载荷区的指针
    • uint8_t payloadLength(message_t *msg) //获得消息的有效载荷区长度
    • uint8_t maxPayloadLength() //返回有效载荷区的最大长度
  • Send:提供基本的面向任意地址的消息发送接口
    • error_t send(message_t *msg, uint8_t len) //发送消息
    • error_t cancel(message_t *msg) //取消消息的发送
    • void sendDone(message_t *msg, error_t error) //指示消息发送结果的事件
    • void *getPayload(message_t *msg, uint8_t len) //返回消息有效载荷区的指针
    • uint8_t maxPayloadLength() //返回有效载荷区的最大长度
  • Receive:提供最基本的消息接收接口 提供了一个event函数receivemessage_t *receive(message_t *msg,void *payload)

主动消息接口 - AMSend - AMPacket

BlinkToRadio例子(3.1.4) ### 发送消息 BlinkToRadioC.nc 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include<Timer.h>
#include“BlinkToRadio.h“
module BlinkToRadioC{
uses interface Boot;
uses interface Leds;
uses interface Timer<TMilli> as Timer0;
// 消息发送
uses interface Packet;
uses interface AMPacket;
uses interface AMSend;
uses interface SplitControl as AMControl;
}
implementation{
uint16_t counter = 0;
// 声明一些作用域在模块内的变量,如:pkt,该变量用来存放
// 要发送的消息。还需要声明一个标识符,如:busy,用来跟踪
// 无线电信道是否处于发送忙的状态。
bool busy = FALSE;
message_t pkt;
// 无线模块的初始化工作。为了在系统启动时就可以使用无线模块,
// 必须在Boot.booted事件里调用AMControl.start命令。
event void Boot.booted(){
call AMControl.start();
}

event void Timer0.fired(){
counter++;
call Leds.set(counter);
}
// 因为TinyOS采用分阶段作业的方式,无线电功能启动和完成的
// 信号通过AMControl.startDone和AMControl.stopDone事件来传
// 递。还需要编写AMControl.startDone和AMControl.stopDone事
// 件处理函数。
event void AMControl.startDone(error_t err) {
if (err == SUCCESS) {
call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
}
else {
call AMControl.start();
}
}
event void AMControl.stopDone(error_t err) {
}

// 调用所需的接口,编写应用程序的逻辑实现过程。
event void Timer0.fired() {
...
if (!busy) {
BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)
(call Packet.getPayload(&pkt, NULL));
btrpkt->nodeid = TOS_NODE_ID;
btrpkt->counter = counter;
if (call AMSend.send(
AM_BROADCAST_ADDR,&pkt, sizeof(BlinkToRadioMsg)) == SUCCESS)
{
busy = TRUE;
}
}
}
// 实现所有使用到的接口的事件
event void AMSend.sendDone(message_t* msg, error_t error) {
if (&pkt == msg) {
busy = FALSE;
}
}
}
BlinkToRadio.h文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef BLINKTORADIO_H
#define BLINKTORADIO_H
enum{
TIMER_PERIOD_MILLI = 250
};
typedef nx_struct BlinkToRadioMsg {
nx_uint16_t nodeid;
nx_uint16_t counter;
} BlinkToRadioMsg;
/*
不能直接用数据读写message_t的有效载荷区,而
是使用一种结构体去操纵有效载荷区

在类型名字前的nx_前缀(如 nx_uint16_t)是针对nesC语
言的特定说明,表示struct和uint16_t 是外部类型。外部
类型在所有的节点平台上具有一样的表示。
*/
#endif
BlinkToRadioAppC.nc 配件(configuration)文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<Timer.h>
#include“BlinkToRadio.h“
configuration BlinkToRadioAppC{
}
implementation{
components MainC;
components LedsC;
components BlinkToRadioC as App;
components new TimerMilliC() as Timer0;
// 对配件BlinkToRadioAppC.nc里的实现部分进行
// 修改,增加相关组件的声明。
components ActiveMessageC;
components new AMSenderC(AM_BLINKTORADIO);
// BlinkToRadioC模块使用的通信接口由这两个模块提供。
// AM_BLINKTORADIO参数指明了AMSenderC组件
// 的AM标识号(AM Type),可在BlinkToRadio.h头文件
// 里用枚举来设定AM_BLINKTORADIO的值
// 如: enum{AM_BLINKTORADIO = 6;};

// 在配件里连接从使用者到提供者的所有接口。
App.Packet -> AMSenderC;
App.AMPacket -> AMSenderC;
App.AMSend -> AMSenderC;
App.AMControl -> ActiveMessageC;

App.Boot -> MainC;
App.Leds -> LedsC;
App.Timer0 -> Timer0;
}
编写makefile文件
1
2
3
4
# 告诉编译系统BlinkToRadioAppC是顶层配件
COMPONENT=BlinkToRadioAppC
# 载入TinyOS的编译系统
include $(MAKERULES)

接收消息

  1. 认识相关的组件与接口。

  2. 更新 BlinkToRadioC.nc里的 module区,增加所需接口的uses陈述。

    1
    2
    3
    4
    module BlinkToRadioC {
    ...
    uses interface Receive;
    }

  3. 声明新变量,增加所需初始化代码。

  4. 增加相关程序逻辑和命令。消息的接收是一个事件驱动的过程,故不需要调用命令。

  5. 实现相关的事件处理程序(非初始化)。

    1
    2
    3
    4
    5
    6
    7
    event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) {
    if (len == sizeof(BlinkToRadioMsg)) {
    BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)payload;
    call Leds.set(btrpkt->counter);
    }
    return msg;
    }
    首先,判断消息的长度是否符合;接着,将 BlinkToRadioMsg 类型的结构体指针btrpkt指向消息的有效载荷区;最后,通过指针读取消息中的计数值,并用它来设置3个LED灯的显示状态。

  6. 修改BlinkToRadioAppC 配件里的 implementation 区,增加相应的组件说明。

    1
    2
    3
    4
    5
    implementation {
    ...
    components new AMReceiverC(AM_BLINKTORADIO);
    ...
    }

  7. 连接接口,从使用者到提供者。

    1
    2
    3
    4
    implementation {
    ...
    App.Receive -> AMReceiverC;
    }

  8. 应用程序测试 这个应用程序可在mica或telosb的平台上运行。使用两个节点,任一节点都会显示另一个节点的计数值。 编译并下载 $ make micaz install.1 mib510,/dev/ttyS5

串口通信 1. 消息包格式 eg: 00 FF FF 00 04 04 00 06 00 04 00 01 - 00 表明此为AM类型信息包 - FF FF 目标地址 2 Byte - 00 04 链路层源地址 2 Byte - 04 消息包长度(单位:字节) 1 Byte - 00 网络组号 1 Byte - 06 AM类型 1 Byte - 00 04 Nodeid - 00 01 counter

目标地址 链路层源地址 消息长度 网络组号 AM类型 Nodeid counter
FF FF 00 04 04 00 06 00 04 00 01
  1. MIG 三个参数 eg:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    COMPONENT = TestSerialAppC
    # 在编译之前,要满足其他的依赖关系
    BUILD_EXTRA_DEPS += TestSerial.class
    # 当make clean时有额外文件(.class类型的文件和TestSerialMsg.java文件)需要清除
    CLEAN_EXTRA = *.class TestSerialMsg.java

    # 基于当前目录下所有java文件生成TestSerial.class,包括 TestSerialMsg.java
    TestSerial.class: $(wildcard *.java) TestSerialMsg.java
    javac *.java // 编译生成TestSerial.class

    TestSerialMsg.java:
    MIG java –target=null –java-classname=TestSerialMsg TestSerial.h TestSerialMsg –o $@

    include $(MAKERULES)
    用什么语言生成接口消息(java/python/C),在哪个文件可以找到消息结构的定义,消息结构的名字
参数/命令 含义
MIG 调用MIG工具
java 建立java类
–target=null 对象平台为null
–java-classname=TestSerialMsg Java类的取名
TestSerial.h 定义消息结构的头文件
TestSerialMsg 消息结构的定义名称
–o $@ 生成文件,指生成 TestSerialMsg.java

启动 MainC组件负责:系统平台初始化、软件平台初始化、调度器初始化

编译系统(重点考) make的用法(installreinstall)区别 Makefile解释->考大题 Makefile的最简形式

1
2
3
4
# 告诉编译系统BlinkToRadioAppC是顶层配件
COMPONENT=BlinkToRadioAppC
# 载入TinyOS的编译系统
include $(MAKERULES)


以下为鸿蒙部分

Java UI 用户界面设计(主要)

Java 基础(不考) JavaUI 分三层:

  • 页面
    • 容器组件(也叫做布局
      • 单体组件,最小单位

布局:

  • 定向布局(DirectionalLayout)重点考
  • 依赖布局(DependentLayout)重点考
  • 位置布局(PositionLayout)
  • 表格布局(TableLayout)
  • 自适应布局(AdaptiveBoxLayout)
  • 堆叠布局(StackLayout)

定向布局

将组件按照水平或者垂直方向排布,能够方便地对齐布局内的组件。 其支持的属性:

  • alignment 对齐方式

  • layout_alignment 对齐方式,此为定向布局DirectionalLayout所包含组件支持的属性,使得组件的对齐方式可以和父组件(DirectionalLayout)设定的alignment不同

  • orientation 子布局排列方向

  • weight 权重(所包含的组件的属性)

权重表示如图: 权重作用

alignment的取值:

取值 取值说明
left 表示左对齐
top 表示顶部对齐
right 表示右对齐
bottom 表示底部对齐
horizontal_center 表示水平居中对齐
vertical_center 表示垂直居中对齐
center 表示居中对齐
start 表示靠起始端对齐
end 表示靠结束端对齐

依赖布局

每个组件可以指定相对于其他同级组件的位置,或者指定相对于父组件的位置。 有一个属性:alignment(对齐方式)

取值 取值说明
left 表示左对齐
top 表示顶部对齐
right 表示右对齐
bottom 表示底部对齐
horizontal_center 表示水平居中对齐
vertical_center 表示垂直居中对齐
center 表示居中对齐
start 表示靠起始端对齐
end 表示靠结束端对齐

其他布局

  • 表格布局 能将组件按照行列的方式放在表格中,形成整洁有序的布局方式。
  • 堆叠布局(栈布局) 用来实现组件之间的层叠布局,添加到这个布局中的视图默认放到这块区域的左上角。第一个添加到布局中的视图显示在最底层,之后的组件会被添加到上层,依次堆叠。
  • 位置布局 用于为组件设定特殊的位置。指定组件的(x,y)坐标值在屏幕上显示。起始坐标(0,0)默认在左上角。
  • 自适应(盒子)布局 使得页面上的多个组件在不同屏幕尺寸设备上能够自适应调整列数。

单体组件

文本组件(Text

创建一个Text(xml版本)

1
2
3
4
5
6
7
8
9
10
11
12
<Text
ohos:id="$+id:text"
ohos:width="300vp" (设置宽度300vp)
ohos:height="150vp" (设置高度)
ohos:text="Text组件" (文本显示内容)
ohos:background_element="$graphic:background_text" (设置背景)
ohos:text_size="66fp" (设置字体大小)
ohos:text_color="white" (设置文字颜色)
ohos:italic="true" (设置斜体)
ohos:text_weight="700" (设置字重下面的是设置字体)
ohos:text_font="serif"
/>

最后,在MainAbilitySlice.java中,通过setUIContent()加载该xml布局。

1
2
3
4
5
6
7
8
9
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart (Intent intent){
Super.onStart(intent);

// 这一行是加载xml布局
Super.setUIContent(ResourceTable.Layout_text);
}
}

运行效果:

XML创建Text效果

Java版:打开MainAbilitySlice.java文件,找到onStart()方法,创建Text组件。

1
2
3
4
5
6
Text text = (Text) findComponentById(ResourceTable.Id_text); // 获取布局中组件
text.setText("text组件"); // 设置文本
text.setTextSize(66);// 设置文字大小
text.setTextColor(Color.WHITE);// 设置文字颜色
text.setWidth(300);
text.setHeight(150);

(和xml差不多) text

按钮组件(Button

Button无自有的XML属性,共有XML属性继承自Text。

普通按钮和其他按钮的区别在于不需要设置任何形状,只设置文本和背景颜色即可。

1
2
3
4
5
6
7
8
9
10
11
<Text
ohos:id="$+id:button"
ohos:width="200vp" (设置宽度200vp)
ohos:height="100vp" (设置高度)
ohos:text_size="30fp" (设置字体大小)
ohos:text="普通按钮" (按钮上文字显示的内容)
ohos:text_color="white" (设置文字颜色)
ohos:background_element="$graphic:background_button" (设置背景)
ohos:margin="25vp" (margin 为按钮外围和其他组件的间距padding为按钮外围和按钮内部内容的间距)
ohos:padding="10vp"
/>
其他形状的按钮: - 椭圆按钮:设置background_element实现,设置background_elementshape属性为oval(椭圆) - 胶囊按钮:指定background_element的背景文件为capsule_button.xml实现,在 capsule_button.xml文件中设置shape为矩形(rectangle),并且指定corners元素的 ohos:radius值。 - 圆形按钮:和椭圆按钮的区别在于组件本身的宽度和高度需要相同。

Toast对话框

1
2
ToastDialog toastDialog = new ToastDialog(this); // 创建toastDialog
toastDialog.setText("网络连接失败。").show(); // 显示toastDialog

Ability (不多)

Page Ability

  • 显示 Ability:需要调用父类Ability的onStart()方法,并使用super.setUIContent()方法加载之前创建的布局文件my_first_layout.xml。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import ohos.aafwk.ability.Ability;
    import ohos.aafwk.content.Intent;
    public class MyFirstAbility extends Ability {
    public void onStart(Intent intent)
    {
    // 调用父类onStart方法
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_my_first_layout);
    }
    }
    修改MyFirstAbility的配置信息的skills部分
    1
    2
    3
    4
    5
    6
    7
    8
    "skills": [{
    "entities": [
    "entity.system.home"
    ],
    "actions": [
    "action.system.home"
    ]
    }]
    一个应用只能有一个主Ability,HarmonyOS只会显示在config.json文件中遇到的第一个主Ability。

  • 销毁:terminateAbility()

生命周期

Service Ability(只考一个小点)

开启&停止 生命周期


物联网开发操作系统
https://piececao.github.io/2025/07/02/物联网开发操作系统/
Beitragsautor
Piececao
Veröffentlicht am
2. Juli 2025
Urheberrechtshinweis