鸿蒙OS IoT设备开发之基础 —— 外设驱动

鸿蒙系统(HarmonyOS)介绍 鸿蒙系统(HarmonyOS)介绍 鸿蒙OS是一个基于微内核设计的操作系统,旨在为不同类型的智能设备提供统一的平台支持。 鸿蒙OS是一个基于微内核设计的操作系统,旨在为不同类型的智能设备提供统一的平台支持。 阅读详情

        历尽挫折,总算将鸿蒙OS设备开发环境 DevEco device tools 安装完成。因事耽搁了一段时间,如今重新上手,开始尝试 MCU 编程的最基础部分:硬件驱动。

        之前买过一本《HarmonyOS IoT设备开发实战》:

        本想对照书的内容逐步实施,但发现书的内容和我安装的环境(Harmony OS 3.0.3LTS)并非一一对应,而且书上的代码还要自己敲入,思考再三,决定尝试用 AI 辅助,实现硬件驱动程序的编写。书只是作为参考。

1、GPIO口

        单片机的硬件编程,首先是驱动 IO 口,系统示例中已包含了一个 LED example 例程,GPIO控制比较简单,阅读程序后基本能理解,便直接编译后下载到板子上,功能正常:

        通过上述过程实际感受了一下所安装的鸿蒙设备开发环境的使用细节,初步知道了集成环境(IDE)如何操作。

        示例程序编写的有点复杂,但让我了解了鸿蒙 OS 中的线程概念,还算有价值,代码如下:

#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "app_demo_sysinfo.h"       // 20260722

#define LED_INTERVAL_TIME_US 2000000
#define LED_TASK_STACK_SIZE 512
#define LED_TASK_PRIO 25
#define LED_TEST_GPIO 9 // for hispark_pegasus
enum LedState {
    LED_ON = 0,
    LED_OFF,
    LED_SPARK,
};

enum LedState g_ledState = LED_SPARK;

static void *LedTask(const char *arg)
{
    (void)arg;
    printf("Hello, OpenHarmony!\n");
    
    while (1) {
        switch (g_ledState) {
            case LED_ON:
                IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
                usleep(LED_INTERVAL_TIME_US);
                break;
            case LED_OFF:
                IoTGpioSetOutputVal(LED_TEST_GPIO, 0);
                usleep(LED_INTERVAL_TIME_US);
                break;
            case LED_SPARK:
                IoTGpioSetOutputVal(LED_TEST_GPIO, 0);
                usleep(LED_INTERVAL_TIME_US);
                IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
                usleep(LED_INTERVAL_TIME_US);
                break;
            default:
                usleep(LED_INTERVAL_TIME_US);
                break;
        }
    }
    return NULL;
}

static void LedExampleEntry(void)
{
    osThreadAttr_t attr;

    IoTGpioInit(LED_TEST_GPIO);
    IoTGpioSetDir(LED_TEST_GPIO, IOT_GPIO_DIR_OUT);

    attr.name = "LedTask";
    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)LedTask, NULL, &attr) == NULL) {
        printf("[LedExample] Falied to create LedTask!\n");
    }
    //app_demo_heap_task();   // 20260722
}

SYS_RUN(LedExampleEntry);

2、UART

        Uart 是单片机最常用的硬件之一,所以第二步就着手驱动 uart 接口。

        uart0 被系统的日志输出所占用,故准备启用 uart1。

        系统例程中没有关于 uart 的示例程序,便尝试用 AI 辅助,让豆包帮我编写一段 uart1 的demo 程序。

        按照提示,豆包帮我完成了一段 uart1 的demo程序。因为想保留 LED 闪烁功能,故将 AI 编写的 demo 程序嵌入到原有的 LED example 中。

        开始编译出错。对照头文件 iot _uart.h,发现豆包所写的函数格式有点小错误,修正后编译正确,下载后运行,日志输出提示栈溢出,估计是启用串口后,系统会开相应的收发缓冲区,增加了内存开销。

        将原来 LED 任务的栈尺寸从 512 改为 1024后,运行正常。程序如下:

include <stdio.h>
#include "iot_errno.h"
#include "iot_uart.h"
#include "unistd.h"
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"

#define LED_INTERVAL_TIME_US 1000000
#define LED_TASK_STACK_SIZE 1024
#define LED_TASK_PRIO 25
#define LED_TEST_GPIO 9 // for hispark_pegasus

// UART1 初始化
static void Uart1Test(void)
{
    IotUartAttribute uart_cfg = {
        .baudRate = 115200,
        .dataBits = IOT_UART_DATA_BIT_8,
        .stopBits = IOT_UART_STOP_BIT_1,
        .parity = IOT_UART_PARITY_NONE
    };
    // 初始化UART1
    unsigned int ret = IoTUartInit(1, &uart_cfg);

    if(ret != 0  ) {
        printf("Failed to initialize UART1: %d\n", ret);
    }
    else
    {
        char buf[] = "Hello UART1!\r\n";
        printf("UART1 write result: %d\n", IoTUartWrite(1, (unsigned char *)buf, sizeof(buf)-1));
    }
}

static void *LedTask(const char *arg)
{
    (void)arg;

    printf("Hello, OpenHarmony!\n");
    
    while (1) {
                IoTGpioSetOutputVal(LED_TEST_GPIO, 0);
                usleep(LED_INTERVAL_TIME_US);
                IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
                usleep(LED_INTERVAL_TIME_US);
                IoTUartWrite(1, "s ", 2);
    }

    return NULL;
}

static void LedExampleEntry(void)
{
    osThreadAttr_t attr;

    Uart1Test();

    IoTGpioInit(LED_TEST_GPIO);
    IoTGpioSetDir(LED_TEST_GPIO, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(LED_TEST_GPIO, 1);

    attr.name = "LedTask";
    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)LedTask, NULL, &attr) == NULL) {
        printf("[LedExample] Falied to create LedTask!\n");
    }
    else
    {
        printf("[LedExample] LedTask created successfully!\n");
    }
}

SYS_RUN(LedExampleEntry);

3、I2C

        因为手头有一块 SSD1306 小屏,故选择 I2C 作为第三个驱动的外设。

        还是让豆包帮我编写,豆包也确实尽责,编写了一段让我可以直接拷贝到 IDE 环境中编译运行的程序,包括:ssd1306_i2c.c、ssd1306_i2c.h 以及调用测试函数的主程序,还有 DevEco 中编译必须的 BUILD.gn。

        我习惯将新的功能添加到已经实现的程序中,故仍以前面的程序为基础,略微修改了 BUILD.gn:

import("//build/lite/config/component/lite_component.gni")


static_library("uart1demo") {
    sources = [
        "uart1hello.c",
        "ssd1306_i2c.c",
        "ssd1306_i2c.h"
    ]
    include_dirs = [
        "//applications/sample/wifi_iot/app/iothardware",
        "//utils/native/lite/include",
        "//kernel/liteos_m/kal/cmsis",
        "//base/iot_hardware/peripheral/interfaces/kits",
        # 海思底层SDK路径
        "//device/hisilicon/hispark_pegasus/sdk_liteos/include"
    ]
    # Hi3861 Pegasus 正确UART依赖
    # deps = [ "//vendor/hisi/hi3861/hi3861_peripheral:iot_uart"]

    deps = []
}

        可这段程序编译不太顺利,对 I2C 引脚的复用功能设置函数在 iot 的头文件中未找到定义,和豆包交流了并尝试了数次,总算用海思的底层完成了 I2C 驱动。

        豆包还算不错,在 iot 中(BASE目录下)受阻后,先是换 Wifi_iot 的头文件,在我装的系统中也找不到,最后选择了海思提供的库才算搞定。

        经历这些挫折,让我更进一步了解了所安装的鸿蒙系统,还是有收获的。海思的库在 Device 目录下,完整目录为:

/OpenHarmony303/OpenHarmony/device/hisilicon/hispark_pegasus/sdk_liteos/include

        这里面的硬件相关头文件比较全:

        豆包的程序基本正确,除了个别细节(如符号化常数定义)不对外,无大错,估计是系统版本更新所致。

        程序运行结果如下:

        仔细阅读代码,发现豆包所编写的代码基本和网上以及我买的那本书上一致,看来它是学习了这些内容。

         不过按我多年从事硬件编程的经验,这段程序还有优化的空间,主要是显示数据的刷新,豆包写的是一次 i2c 写一个字节数据,对于点阵显示屏而言,效率太低,因为写一字节数据,i2c 实际输出 2 个字节(一字节命令、一字节数据),按豆包的程序刷新整屏(128*64),分 8 页数据,共要写 1024 字节数据,如果一次一字节,实际 i2c 输出了2048 字节,在实际产品中,这将会大大降低程序效率,对于实时系统,甚至有可能降低可靠性,因为会影响程序的实时性。

        正确的操作,应该是一个页面128字节一次写入,i2c 总共输出129字节。程序如下:

ssd1306_i2c.h(注意:头文件用了 hi_io.h、hi_i2c.h):

#ifndef SSD1306_I2C_H
#define SSD1306_I2C_H

#include <stdint.h>
#include "hi_io.h"
#include "hi_i2c.h"

#define SSD1306_WIDTH    128
#define SSD1306_HEIGHT   64
#define SSD1306_ADDR     0x78  // 屏幕不亮改为0x3D
#define I2C_IDX          HI_I2C_IDX_0
#define I2C_BAUDRATE     100000

//8x8 ASCII字模,ASCII 32(' ') ~ 126('~')
static const uint8_t font8x8[95][8] =
{
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},// 32 空格
{0x00,0x00,0x5F,0x00,0x00,0x00,0x00,0x00},// 33 !
{0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00},// 34 "
{0x14,0x7F,0x14,0x7F,0x14,0x00,0x00,0x00},// 35 #
{0x24,0x2A,0x7F,0x2A,0x12,0x00,0x00,0x00},// 36 $
{0x23,0x13,0x08,0x64,0x62,0x00,0x00,0x00},// 37 %
{0x36,0x49,0x55,0x22,0x50,0x00,0x00,0x00},// 38 &
{0x00,0x05,0x03,0x00,0x00,0x00,0x00,0x00},// 39 '
{0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00},// 40 (
{0x00,0x41,0x22,0x1C,0x00,0x00,0x00,0x00},// 41 )
{0x14,0x08,0x3E,0x08,0x14,0x00,0x00,0x00},// 42 *
{0x08,0x08,0x3E,0x08,0x08,0x00,0x00,0x00},// 43 +
{0x00,0x80,0x70,0x30,0x00,0x00,0x00,0x00},// 44 ,
{0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00},// 45 -
{0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00},// 46 .
{0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00},// 47 /
{0x3E,0x51,0x49,0x45,0x3E,0x00,0x00,0x00},// 48 0
{0x00,0x42,0x7F,0x40,0x00,0x00,0x00,0x00},// 49 1
{0x42,0x61,0x51,0x49,0x46,0x00,0x00,0x00},// 50 2
{0x21,0x41,0x45,0x4B,0x31,0x00,0x00,0x00},// 51 3
{0x18,0x14,0x12,0x7F,0x10,0x00,0x00,0x00},// 52 4
{0x27,0x45,0x45,0x45,0x39,0x00,0x00,0x00},// 53 5
{0x3C,0x4A,0x49,0x49,0x30,0x00,0x00,0x00},// 54 6
{0x01,0x71,0x09,0x05,0x03,0x00,0x00,0x00},// 55 7
{0x36,0x49,0x49,0x49,0x36,0x00,0x00,0x00},// 56 8
{0x06,0x49,0x49,0x29,0x1E,0x00,0x00,0x00},// 57 9
{0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00},// 58 :
{0x00,0x56,0x36,0x00,0x00,0x00,0x00,0x00},// 59 ;
{0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00},// 60 <
{0x14,0x14,0x14,0x14,0x14,0x00,0x00,0x00},// 61 =
{0x00,0x41,0x22,0x14,0x08,0x00,0x00,0x00},// 62 >
{0x02,0x01,0x51,0x09,0x06,0x00,0x00,0x00},// 63 ?
{0x32,0x49,0x79,0x41,0x3E,0x00,0x00,0x00},// 64 @
{0x7E,0x11,0x11,0x11,0x7E,0x00,0x00,0x00},// 65 A
{0x7F,0x49,0x49,0x49,0x36,0x00,0x00,0x00},// 66 B
{0x3E,0x41,0x41,0x41,0x22,0x00,0x00,0x00},// 67 C
{0x7F,0x41,0x41,0x22,0x1C,0x00,0x00,0x00},// 68 D
{0x7F,0x49,0x49,0x49,0x41,0x00,0x00,0x00},// 69 E
{0x7F,0x09,0x09,0x09,0x01,0x00,0x00,0x00},// 70 F
{0x3E,0x41,0x49,0x49,0x7A,0x00,0x00,0x00},// 71 G
{0x7F,0x08,0x08,0x08,0x7F,0x00,0x00,0x00},// 72 H
{0x00,0x41,0x7F,0x41,0x00,0x00,0x00,0x00},// 73 I
{0x20,0x40,0x41,0x3F,0x01,0x00,0x00,0x00},// 74 J
{0x7F,0x08,0x14,0x22,0x41,0x00,0x00,0x00},// 75 K
{0x7F,0x40,0x40,0x40,0x40,0x00,0x00,0x00},// 76 L
{0x7F,0x02,0x0C,0x02,0x7F,0x00,0x00,0x00},// 77 M
{0x7F,0x04,0x08,0x10,0x7F,0x00,0x00,0x00},// 78 N
{0x3E,0x41,0x41,0x41,0x3E,0x00,0x00,0x00},// 79 O
{0x7F,0x09,0x09,0x09,0x06,0x00,0x00,0x00},// 80 P
{0x3E,0x41,0x51,0x21,0x5E,0x00,0x00,0x00},// 81 Q
{0x7F,0x09,0x19,0x29,0x46,0x00,0x00,0x00},// 82 R
{0x46,0x49,0x49,0x49,0x31,0x00,0x00,0x00},// 83 S
{0x01,0x01,0x7F,0x01,0x01,0x00,0x00,0x00},// 84 T
{0x3F,0x40,0x40,0x40,0x3F,0x00,0x00,0x00},// 85 U
{0x1F,0x20,0x40,0x20,0x1F,0x00,0x00,0x00},// 86 V
{0x3F,0x40,0x38,0x40,0x3F,0x00,0x00,0x00},// 87 W
{0x63,0x14,0x08,0x14,0x63,0x00,0x00,0x00},// 88 X
{0x07,0x08,0x70,0x08,0x07,0x00,0x00,0x00},// 89 Y
{0x61,0x51,0x49,0x45,0x43,0x00,0x00,0x00},// 90 Z
{0x00,0x7F,0x41,0x41,0x00,0x00,0x00,0x00},// 91 [
{0x02,0x04,0x08,0x10,0x20,0x00,0x00,0x00},// 92 '\'
{0x00,0x41,0x41,0x7F,0x00,0x00,0x00,0x00},// 93 ]
{0x04,0x02,0x01,0x02,0x04,0x00,0x00,0x00},// 94 ^
{0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00},// 95 _
{0x00,0x01,0x02,0x04,0x00,0x00,0x00,0x00},// 96 `
{0x20,0x54,0x54,0x54,0x78,0x00,0x00,0x00},// 97 a
{0x7F,0x48,0x48,0x48,0x30,0x00,0x00,0x00},// 98 b
{0x38,0x44,0x44,0x44,0x28,0x00,0x00,0x00},// 99 c
{0x30,0x48,0x48,0x48,0x7F,0x00,0x00,0x00},//100 d
{0x38,0x54,0x54,0x54,0x18,0x00,0x00,0x00},//101 e
{0x08,0x7E,0x09,0x01,0x02,0x00,0x00,0x00},//102 f
{0x18,0xA4,0xA4,0xA4,0x7C,0x00,0x00,0x00},//103 g
{0x7F,0x08,0x08,0x08,0x70,0x00,0x00,0x00},//104 h
{0x00,0x00,0x7A,0x40,0x00,0x00,0x00,0x00},//105 i
{0x40,0x80,0x84,0x7A,0x00,0x00,0x00,0x00},//106 j
{0x7F,0x10,0x28,0x44,0x00,0x00,0x00,0x00},//107 k
{0x00,0x41,0x7F,0x40,0x00,0x00,0x00,0x00},//108 l
{0x78,0x04,0x18,0x04,0x78,0x00,0x00,0x00},//109 m
{0x78,0x08,0x08,0x08,0x70,0x00,0x00,0x00},//110 n
{0x38,0x44,0x44,0x44,0x38,0x00,0x00,0x00},//111 o
{0xFC,0x24,0x24,0x24,0x18,0x00,0x00,0x00},//112 p
{0x18,0x24,0x24,0x24,0xFC,0x00,0x00,0x00},//113 q
{0x78,0x08,0x08,0x08,0x08,0x00,0x00,0x00},//114 r
{0x48,0x54,0x54,0x54,0x24,0x00,0x00,0x00},//115 s
{0x04,0x3F,0x44,0x40,0x20,0x00,0x00,0x00},//116 t
{0x3C,0x40,0x40,0x20,0x7C,0x00,0x00,0x00},//117 u
{0x1C,0x20,0x40,0x20,0x1C,0x00,0x00,0x00},//118 v
{0x3C,0x40,0x30,0x40,0x3C,0x00,0x00,0x00},//119 w
{0x44,0x28,0x10,0x28,0x44,0x00,0x00,0x00},//120 x
{0x0C,0x50,0x50,0x50,0x3C,0x00,0x00,0x00},//121 y
{0x44,0x64,0x54,0x4C,0x44,0x00,0x00,0x00},//122 z
{0x00,0x08,0x36,0x41,0x00,0x00,0x00,0x00},//123 {
{0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00},//124 |
{0x00,0x41,0x36,0x08,0x00,0x00,0x00,0x00},//125 }
{0x08,0x08,0x2A,0x1C,0x08,0x00,0x00,0x00},//126 ~
};

// SSD1306 初始化命令表,128×64 I2C OLED
static const uint8_t ssd1306_init_cmds[] =
{
    0xAE,         // Display OFF
    0xD5, 0x80,   // Set clock divide
    0xA8, 0x3F,   // Multiplex ratio 64
    0xD3, 0x00,   // Display offset
    0x40,         // Display start line 0
    0x8D, 0x14,   // 开启内部电荷泵(I2C OLED必须)
    0x20, 0x02,   // Page寻址模式
    0xA1,         // Segment remap
    0xC8,         // COM扫描方向
    0xDA, 0x12,   // COM硬件配置,128‑64屏
    0x81, 0xCF,   // 对比度
    0xD9, 0xF1,   // Pre‑charge周期
    0xDB, 0x30,   // VCOMH
    0xA4,         // RAM输出
    0xA6,         // 正常显示(非反色)
    0xAF          // Display ON
};

static uint8_t g_oled_buf[SSD1306_WIDTH * SSD1306_HEIGHT / 8];

void Ssd1306_Init(void);
void Ssd1306_Clear(void);
void Ssd1306_Refresh(void);
void Ssd1306_DisplayString(uint8_t x, uint8_t y, const char *str);

#endif

ssd1306_i2c.c(注意 Ssd1306_Senddata函数)

#include "ssd1306_i2c.h"
#include <string.h>
#include <stdio.h>

// 发送单条命令
static hi_u32 Ssd1306_SendCmd(uint8_t cmd)
{
    uint8_t buf[2] = {0x00, cmd};
    hi_i2c_data i2c_data = {
        .send_buf = buf,
        .send_len = 2,
        .receive_buf = NULL,
        .receive_len = 0
    };
    return hi_i2c_write(I2C_IDX, SSD1306_ADDR, &i2c_data);
}

// 批量发送初始化命令
static hi_u32 Ssd1306_SendCmdArray(const uint8_t *cmds, uint16_t len)
{
    hi_u32 ret;
    for (uint16_t i = 0; i < len; i++)
    {
        ret = Ssd1306_SendCmd(cmds[i]);
        if (ret != HI_ERR_SUCCESS)
            return ret;
    }
    return HI_ERR_SUCCESS;
}

// 发送显示数据
static hi_u32 Ssd1306_SendData(uint8_t *dataptr, uint16_t len)
{
    uint8_t buf[SSD1306_WIDTH+1];
    uint16_t i;
    buf[0] = 0x40; // 数据标识符
    for (i = 0; i < len; i++)
    {
        buf[i + 1] = *dataptr;
        dataptr++;
    }
    hi_i2c_data i2c_data = {
        .send_buf = buf,
        .send_len = len + 1,
        .receive_buf = NULL,
        .receive_len = 0
    };
    return hi_i2c_write(I2C_IDX, SSD1306_ADDR, &i2c_data);
}

void Ssd1306_Init(void)
{
    // 1. GPIO复用配置:GPIO13=I2C0_SDA,GPIO14=I2C0_SCL
    hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA);
    hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL);

    // 2. 初始化I2C0,400K波特率
    hi_u32 ret = hi_i2c_init(I2C_IDX, I2C_BAUDRATE);
    if (ret != HI_ERR_SUCCESS)
    {
        printf("I2C init fail, ret=%#X\r\n", ret);
        return;
    }
    else
    {
        printf("I2C init success\r\n");
    }

    // 3. 下发SSD1306初始化序列
    ret = Ssd1306_SendCmdArray(ssd1306_init_cmds, sizeof(ssd1306_init_cmds));
    if (ret != HI_ERR_SUCCESS)
    {
        printf("SSD1306 cmd send fail, ret=%#X\r\n", ret);
        return;
    }
    else
    {
        printf("SSD1306 cmd send success\r\n");
    }   

    Ssd1306_Clear();
    // 测试点亮左上角像素
    g_oled_buf[0] = 0xFF;
    Ssd1306_Refresh();
}

void Ssd1306_Clear(void)
{
    memset(g_oled_buf, 0x00, sizeof(g_oled_buf));
}

void Ssd1306_Refresh(void)
{
    for (uint8_t page = 0; page < 8; page++)
    {
        Ssd1306_SendCmd(0xB0 + page);
        Ssd1306_SendCmd(0x00);
        Ssd1306_SendCmd(0x10);
        
        Ssd1306_SendData(&g_oled_buf[page * SSD1306_WIDTH], SSD1306_WIDTH);
    }
}



void Ssd1306_DisplayString(uint8_t x, uint8_t y, const char *str)
{
    while (*str != '\0')
    {
        if (x > SSD1306_WIDTH - 8)
        {
            x = 0;
            y += 1;
        }
        //过滤超出可打印范围字符
        if((*str <32)||(*str>126))
        {
            str++;
            continue;
        }
        uint8_t idx = *str - 32;
        for (uint8_t i = 0; i < 8; i++)
        {
            g_oled_buf[y * SSD1306_WIDTH + x + i] = font8x8[idx][i];
        }
        x += 8;
        str++;
    }
    Ssd1306_Refresh();
}

        在原来的主程序上增加了几句 i2c 测试函数:

#include <stdio.h>
#include "iot_errno.h"
#include "iot_uart.h"
#include "unistd.h"
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"

#include "ssd1306_i2c.h"

#define LED_INTERVAL_TIME_US 1000000
#define LED_TASK_STACK_SIZE 1024
#define LED_TASK_PRIO 25
#define LED_TEST_GPIO 9 // for hispark_pegasus

// UART1 初始化
static void Uart1Test(void)
{
    IotUartAttribute uart_cfg = {
        .baudRate = 115200,
        .dataBits = IOT_UART_DATA_BIT_8,
        .stopBits = IOT_UART_STOP_BIT_1,
        .parity = IOT_UART_PARITY_NONE
    };
    // 初始化UART1
    unsigned int ret = IoTUartInit(1, &uart_cfg);

    if(ret != 0  ) {
        printf("Failed to initialize UART1: %d\n", ret);
    }
    else
    {
        char buf[] = "Hello UART1!\r\n";
        printf("UART1 write result: %d\n", IoTUartWrite(1, (unsigned char *)buf, sizeof(buf)-1));
    }
}

static void *LedTask(const char *arg)
{
    (void)arg;

    printf("Hello, OpenHarmony!\n");
    
    while (1) {
                IoTGpioSetOutputVal(LED_TEST_GPIO, 0);
                usleep(LED_INTERVAL_TIME_US);
                IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
                usleep(LED_INTERVAL_TIME_US);
                IoTUartWrite(1, "s ", 2);
    }

    return NULL;
}

static void LedExampleEntry(void)
{
    osThreadAttr_t attr;

    Uart1Test();

    Ssd1306_Init();
    Ssd1306_DisplayString(3, 3, "Hello Hi3861!");
   
    IoTGpioInit(LED_TEST_GPIO);
    IoTGpioSetDir(LED_TEST_GPIO, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(LED_TEST_GPIO, 1);

    attr.name = "LedTask";
    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)LedTask, NULL, &attr) == NULL) {
        printf("[LedExample] Falied to create LedTask!\n");
    }
    else
    {
        printf("[LedExample] LedTask created successfully!\n");
    }
}

SYS_RUN(LedExampleEntry);

        由此可以看出,虽然 AI 可以帮你减少很多编程的工作量,但要做一个真正可靠的产品,必须能读懂 AI 帮你编写的程序, 以它为基础优化后使用,而非不加处理的照搬。尤其是硬件产品,有诸多软件实现的显性功能之外的隐性约束,如:实时性、可靠性、低功耗等。

4、开发环境使用遇到的一个问题

        在上述实施过程中,经常会遇到做着做着就连不上远程(虚拟机)了,观察发现,虚拟机已经死机,只好重启。

        在做调试程序时精力没放在这方面,重启就重启吧。

        完成之后才想起来问一下豆包,在它的提示下确定是虚拟机内存耗尽所致。

        原因是打开鸿蒙工程后,VScode 会自动扫描系统目录下的所有内容,并做相应处理,从而开了很多线程,逐渐占满了内存。我虚拟机分配了8G 都不够。总共就 16G 内存,不能再增加了!

        在豆包的指导下,做了多次尝试,都没有明显效果,只好按它所建议,只打开自己的工作目录,编程完成后,用命令行编辑、烧录。或者启动工程,快速编译、烧录后退出。

        因为编程时需要参考库函数的头文件,故我自己创建了一个Worksapce,打开工作目录和库的 include 目录,这样编写时比较方便。

        这是不得而已的对策,不知道这个现象是否正常?有无更好的解决方法?毕竟这样等于丧失了 IDE 环境的优势。

        顺带提出一个疑问:鸿蒙 OS 的设备开发环境到底需要什么样资源的 PC 才能胜任?还望高手指点!

——————————————————

 

IOT项目之网卡驱动 本文主要介绍了网卡底层驱动和TCP/IP协议的理论和应用。互联网协议族(Internet Protocol Suite)是一个网络通信模型,以及一整个网络传输协议家族,为互联网的基础通信架构。它常被通称为TCP/IP协议族(TCP/IP Protocol Suite,或TCP/IP Protocols),简称TCP/IP。TCP/IP提供点对点的连接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。 阅读详情

相关推荐

华为鸿蒙系统HarmonyOS学习之二:鸿蒙HarmonyOS系统架构

华为鸿蒙系统HarmonyOS学习之二:系统架构

jyl_sh的专栏 2万+

物联网实战--驱动篇之(九)NB-IOT(BC260)

讲解NBIOT模块 BC260的驱动程序和使用方法

ypp240124016的博客 3485

鸿蒙系统-初见

初见鸿蒙Os~

小码哥的博客 1493

IoT DC3 概念解读:驱动——协议接入的统一抽象

在开源IoT DC3物联网系统中驱动(Driver)扮演着至关重要的角色,它充当了软件系统与物理设备之间的桥梁。驱动的主要功能是依据特定的通信协议连接到设备,并根据设备模板中配置的位号信息进行数据采集和指令控制。不同的设备可能使用不同的通信协议,因此需要匹配相应类型的驱动来实现有效的通信。这类驱动能够与多种不同品牌和型号的PLC进行通信,如西门子、施耐德等,它们通常支持多种协议,包括但不限于Modbus、Profibus等。驱动是一种特殊的软件组件或程序,用于实现上层应用软件与硬件设备之间的交互。

Pnoker 1139

一、华为鸿蒙系统介绍

本节重点介绍了鸿蒙系统的发展背景和概念,从鸿蒙系统的技术特性、技术架构和系统安全性等方面对鸿蒙系统作了详细的解读。

fengguu的博客 1377

2021最新HarmonyOS鸿蒙系统应用开发之基础入门教程到实战—持续更新(第二节:鸿蒙OS系统分布式操作)

第二节:鸿蒙OS系统分布式操作 2.1、鸿蒙OS系统定位 HarmonyOS是一款“面向未来”、面向全场景(移动办公、运动健康、社交通信、媒体娱乐等)的分布式操作系统。在传统的单设备系统能力的基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备。 对消费者而言,HarmonyOS能够将生活场景中的各类终端进行能力整合,可以实现不同的终端设备之间的快速连接、能力互助、资源共享,匹配合适的设备、提供流畅的全场景体验。

m0_60512599的博客 1405

IOTOS物联中台NB-IoT驱动开发实例

本文章为原创,转载请注明出处! 登录平台:IOTOS®爱投斯物联中台 账号:iotos_test 密码:iotos123 代码地址:IOTOSDK-Python: IOTOS Python版本SDK,自带原生接口和采集引擎 (gitee.com) 目录 1、驱动目的 2、开发文档要求 3、代码示例 4、驱动解析 4.1、导入指定依赖包 4.2、从中台中获取数据 4.3、根据中台获取的数据及开发文档进行获取数据再将其上传的操作 4.4、执行效果如下 1、驱动目的 与指定平...

IOTOS的博客 1185

记一次在JAVA中客户端使用axis调用webservice服务端出现的异常:Unmarshalling Error: For input string: ""

在使axis调用webservice服务端,参照网上给的demo: Call call = (Call) service.createCall(); call.setTargetEndpointAddress(endpoint);//设置服务请求路径 QName qn = new QName(name); call.setOperationName(qn); call.addParamet

kry1201的专栏 8080

嵌入式驱动开发实战:从零开始掌握六大外设驱动

本文介绍了嵌入式驱动开发的核心概念与六大外设驱动开发方法。主要内容包括: 驱动开发本质:作为硬件与软件的桥梁,涉及寄存器映射、时序控制和中断响应三大核心技术 六大外设驱动全景: GPIO:基础输入输出控制 I2C:两线制总线通信 SPI:四线全双工传输 UART:异步串口通信 PWM:脉冲宽度调制 ADC:模数转换 GPIO驱动详解: 通过寄存器配置实现输入/输出模式 提供裸机操作代码示例 介绍中断处理方式 展示Linux内核驱动框架 I2C驱动开发: 解析标准通信时序 提供GPIO模拟实现方案

lza_csdn2019的博客 792

电赛综合测评题练习(一)-(与2013年电赛综合测评要求类似)

电赛综合测评题练习 文章目录电赛综合测评题练习前言1. 波形发生器1.1 题目说明1.1.1 可用器件1.1.2 设计要求1.1.3 设计方案论证1.2 仿真电路设计1.2.1 脉冲波发生器电路1.2.1.1 方案介绍1.2.1.2 理论分析与计算1.2.1.3 电路系统设计1.2.1.4 仿真方案与仿真测试结果1.2.2 锯齿波电路1.2.2.1 理论分析与计算1.2.2.2 电路系统设计1.2.2.3 仿真方案与仿真测试结果1.2.3 正弦波I电路1.2.3.1 理论分析与计算1.2.3.2 电路系

daydayup!的博客 3万+

从零到千兆:KSZ9031 PHY芯片在Zynq PS端的驱动移植心路历程

本文详细记录了在Xilinx Zynq-7000平台(基于XC7Z020芯片)上,为KSZ9031千兆以太网PHY芯片移植LwIP协议栈驱动的完整过程。从硬件连接配置、Vivado工程设置到LwIP库的深度修改与调试,分享了解决PHY识别、自协商及性能优化等关键问题的实战经验,助力开发者实现稳定的千兆网络连接。

honey的博客 1104

华为鸿蒙系统学习笔记1-介绍

华为鸿蒙系统(HarmonyOS)是基于微内核的全场景分布式OS,可按需扩展,实现更广泛的系统安全,主要用于智能物联网,特点是低时延,甚至可到毫秒级乃至亚毫秒级,由华为技术有限公司开发。 华为自研操作系统鸿蒙OS打通了手机、电脑、平板、电视、汽车、智能穿戴等产品,并兼容全部的安卓应用和Web应用的操作系统。 鸿蒙OS发布现场,余承东在现场发布了它的英文名——Harmony OS:鸿蒙用中文的意...

鹿鸣天涯 1万+

clock-gating整理

文章目录clock gating 理解1、latch双稳态器件常见锁存器结构SR锁存器D锁存器2、clock gating(clock low-active) latch + AND gating 电路(clock high-active)latch + OR gating 电路 clock gating 理解 1、latch 参考:https://www.cnblogs.com/IClearner/p/6443539.html 双稳态器件 稳定状态为0或1两种 举例:交叉耦合反相器 假设初始Q为1,则可

d_b_的博客 1万+

华为鸿蒙OS能取代安卓吗?

先回答问题,不能,起码几年之内不存在这种可能。8月9日华为的开发者大会上,余承东说:鸿蒙是一款基于微内核的全场景分布式OS。鸿蒙OS的设计初衷是为满足全场景智慧体验的高标准的连接要求,为此华为提出了4大特性的系统解决方案。1、分布式架构首次用于终端OS,实现跨终端无缝协同体验。2、 确定时延引擎和高性能IPC技术实现系统天生流畅。3、基于微内核架构重塑终端设备可信安全。4、通过统一IDE...

weixin_30689307的博客 5007

Ubuntu升级遇到grub-efi-amd64-signed安装失败?3步搞定这个烦人错误

本文深度解析Ubuntu系统升级时grub-efi-amd64-signed安装失败并提示“cannot find EFI directory”错误的根本原因。该错误通常由EFI系统分区挂载异常、BIOS/UEFI引导模式不匹配或dpkg包状态死锁导致。文章提供了三步精准修复流程:首先检查并修复ESP分区挂载,其次处理dpkg依赖问题,最后针对传统BIOS系统提供适配方案,帮助用户安全彻底地解决这一常见升级难题。

r7s8t的博客 398

SolidWorks软件安装管理程序在创建该注册表项时遇到错误: UNKNOWN\Components的解决方案

SolidWorks软件安装管理程序在创建该注册表项时遇到错误: UNKNOWN\Components的解决方案

Q82556499的博客 4166

鸿蒙系统概述(HarmonyOS)

系统定义、技术特征、系统安全。目录鸿蒙系统概述(HarmonyOS)系统定义系统定位技术架构内核层系统服务层框架层应用层技术特性硬件互助,资源共享一次开发,多端部署统一OS,弹性部署系统安全正确的人正确的设备正确地使用数据系统定位HarmonyOS是一款面向万物互联时代的、全新的分布式操作系统。

2302_80826162的博客 2799

AutoSAR_BSW高阶 7. Signal Group 信号组

Autosar BSW的高级配置是实现复杂汽车电子系统的关键步骤之一。通过合理配置信号组和使用适当的参数,您可以提高系统性能,确保数据的可靠传输。在本博客中,我们深入探讨了信号组的概念和高级配置参数,并提供了示例代码,希望这些信息能够帮助您更好地理解和应用Autosar BSW的高级配置。如果您在配置过程中遇到任何问题,不妨寻求专业支持,以确保您的汽车电子系统能够顺利运行。Autosar COM 模块是一个广泛应用于汽车行业的关键技术,它使不同的电子控制单元能够有效地通信和协作。

一直在水些技术小文 662

鸿蒙OS与IoT设备的集成!

物联网(IoT)技术正在以前所未有的速度改变我们的生活和工作方式。从智能家居到工业自动化,从健康监测到智慧城市,IoT设备在各个领域发挥着至关重要的作用。与之相辅相成的,是操作系统的不断进化,而鸿蒙操作系统(HarmonyOS)在这一进程中发挥了巨大的潜力。鸿蒙OS的设计使其能够无缝集成各种IoT设备,实现设备间的协作和资源共享。本文将深入探讨鸿蒙操作系统与IoT设备的集成架构,数据采集与传输、远程控制与管理、安全性问题,以及与其他操作系统的对比,最后展望IoT与鸿蒙OS的未来发展。

小白酷爱学编程,欢迎大家一块儿学习~~ 614

Transformer实战(5)——Hugging Face环境配置与应用详解

本文详细介绍 Transformer 模型的实践应用全流程。首先讲解基于 Anaconda 的环境配置,包括 transformers 库安装及 hf-mirror 镜像加速方案。然后以 BERT 为例,演示分词器使用、文本编码及 fill-mask 等任务实现,对比 PyTorch/TensorFlow 框架差异。接着展示 Hugging Face 社区模型应用,包括 GPT-2 文本生成和零样本分类。最后扩展至多模态领域,使用 CLIP 模型实现零样本图像分类。

盼小辉丶的博客 1万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

华为鸿蒙OS VS 小米澎湃OS(HyperOS)

是由苹果开发的移动操作系统。小米基于开源实时操作系统NuttX打造的物联网嵌入式软件平台,Vela在各种物联网硬件平台上提供统一的软件服务,支持丰富的组件和易用的框架,打通碎片化的物联网应。小米澎湃OS系统仍旧是基于安卓底层开发的,加入了自研的vela系统,重写了底层架构。小米澎湃系统基于安卓,完美继承了安卓丰富的生态,华为鸿蒙系统则通过兼容安卓应用以及自身的开源社区,逐步完善自己的生态体系。这并不意味着鸿蒙系统完全是套壳安卓,技术上还是有点区别的,鸿蒙系统的微内核架构使其具有更高的灵活性和可扩展性。

木头分享 - 分享有价值的、实用的干货 3176

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

HarmonyOS鸿蒙开发入门 :鸿蒙系统介绍

系统定位 HarmonyOS是一款面向万物互联时代的、全新的分布式操作系统。 在传统的单设备系统能力基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备,提供全场景(移动办公、运动健康、社交通信、媒体娱乐等)业务能力。 Play Video 816 HarmonyOS有三大特征: 搭载该操作系统的设备在系统层面融为一体、形成超级终端,让

月梦工作室 3693

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

华为鸿蒙系统能用安卓软件吗,华为鸿蒙2.0可以替代安卓吗,华为鸿蒙2.0优势在哪...

在华为开发者大会上,华为消费业务CEO 余承东,正式发布鸿蒙OS2.0,并宣布华为鸿蒙OS将全面启用全场景生态,并将于2020年12月发布手机版。余承东还表示,明年,华为的智能手机将全面升级,以支持鸿蒙操作系统2.0。从9月10日起,EMUI11正式开通BETA,Magic UI4.0将于9月中旬开启内部测试招聘活动。荣耀30系列和荣耀V30系列将首当其冲。Magic UI 4.0也将支持升级到鸿...

weixin_42438750的博客 1853

鸿蒙OS在物联网(IoT)中的应用!

鸿蒙OS作为一款跨设备、跨平台的操作系统,其在物联网领域的应用前景广阔。通过分布式架构微内核设计和设备互联能力,鸿蒙OS不仅能够推动智能家居工业物联网等领域的发展,还能在全球物联网生态系统中占据重要地位。然而,要实现这一目标,鸿蒙OS还需克服市场竞争、生态建设等挑战,逐步完善应用生态和开发者支持,才能在物联网领域取得更大的成功。❤️ 如果本文帮到了你…如果你在学习过程中遇到bug,请留言,我帮你踩坑!

小白酷爱学编程,欢迎大家一块儿学习~~ 1472

鸿蒙不是安卓,不是 iOS,那它到底是谁?——从0开始全面认识鸿蒙系统(HarmonyOS)

兄弟姐妹们,科技圈这么多年,大家是不是都已经默默接受一个“事实”:手机操作系统只有两种——安卓和 iOS?你要么用 Google 家的开放安卓,要么用苹果家的封闭果子;你想跑应用?两家说了算;你想搞开发?也得看它们给不给接口。这年头,连喝个奶茶都得看人脸支付权限,更别说整啥“自主系统”了。鸿蒙系统 HarmonyOS,它说:老子来,是要打破边界,不止手机,是全场景的统一!好家伙,这一下把圈里圈外都炸了锅。那么鸿蒙到底是谁?它图什么?到底靠不靠谱?咱今天就把这个话题掰开揉碎,说得明明白白。

小白酷爱学编程,欢迎大家一块儿学习~~ 1285

vela和鸿蒙,小米Vela系统发布,将对标华为鸿蒙OS

目前的智能手机销量排行榜上,前五里面中国厂商就占据其三,可以说是主导著智能手机行业。虽然销量高,但在最主要的技术方面却受制于别国的技术,例如芯片生产制造、操作系统等。其中操作系统大部分使用的是 Android 的定制版本。随着物联网的发展,硬件联网、智能化成为主流,为了避免再重新中美贸易站的劣势情况出现,中国厂商迫切需要筹备自己的物联网操作系统。目前有阿里 AliOS、华为 LiteOS 及 鸿蒙...

weixin_39974958的博客 2297
上一篇: 鸿蒙设备开发环境 DevEco Device Tool 安装记
下一篇: 鸿蒙OS IoT 设备开发之基础 —— Wifi 连接
嵌入之梦
博客等级 码龄21年 134粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入之梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值