首页
  • GM-3568JHF
  • M4-R1
  • M5-R1
  • SC-3568HA
  • M-K1HSE
  • CF-NRS1
  • CF-CRA2
  • 1684XB-32T
  • 1684X-416T
  • C-3568BQ
  • C-3588LQ
  • GC-3568JBAF
  • C-K1BA
商城
  • English
  • 简体中文
首页
  • GM-3568JHF
  • M4-R1
  • M5-R1
  • SC-3568HA
  • M-K1HSE
  • CF-NRS1
  • CF-CRA2
  • 1684XB-32T
  • 1684X-416T
  • C-3568BQ
  • C-3588LQ
  • GC-3568JBAF
  • C-K1BA
商城
  • English
  • 简体中文
  • M4-R1

    • 一、简介

      • M4-R1简介
    • 二、快速上手

      • 01 OpenHarmony概述
      • 02 镜像烧录
      • 03 应用开发快速上手
      • 04 设备开发快速上手
    • 三、应用开发

      • 01 ArkUI

        • 1 ArkTS语言简介
        • 2 UI 组件-Row 容器介绍
        • 3 UI 组件-Column 容器介绍
        • 4 UI 组件-Text 组件
        • 5 UI 组件-Toggle 组件
        • 6 UI 组件-Slider 组件
        • 7 UI 组件-Animation 组件&Transition 组件
      • 02 资料获取

        • 1 OpenHarmony 官方资料
      • 03 开发须知

        • 1 Full-SDK替换教程
        • 2 引入和使用三方库
        • 3 HDC调试
        • 4 命令行恢复出厂模式
        • 5 升级App为system权限
      • 04 构建第一个应用

        • 1 构建第一个ArkTs应用-HelloWorld
      • 05 案例

        • 01 串口调试助手应用案例
        • 02 手写板应用案例
        • 03 数字时钟应用案例
        • 04 WIFI 信息获取应用案例
    • 四、设备开发

      • 1 Ubuntu环境开发

        • 01 环境搭建
        • 02 下载源码
        • 03 编译源码
      • 2 使用DevEco Device Tool 工具

        • 01 工具简介
        • 02 开发环境的搭建
        • 03 导入SDK
        • 04 HUAWEI DevEco Tool 功能介绍
    • 五、内核外设与接口

      • 01 指南
      • 02 设备树介绍
      • 03 NAPI 入门
      • 04 ArkTS入门
      • 05 NAPI开发实战演示
      • 06 GPIO介绍
      • 07 I2C通讯
      • 08 SPI通信
      • 09 PWM 控制
      • 10 串口通讯
      • 11 TF卡
      • 12 屏幕
      • 13 触摸
      • 14 Ethernet(以太网)
      • 15 M.2 硬盘
      • 16 音频
      • 17 WIFI & BT
      • 18 摄像头
    • 六、资料下载

      • 资料下载
  • M5-R1

    • 一、简介

      • M5-R1简介
    • 二、快速上手

      • 镜像烧录
      • 环境搭建
      • 下载源码
    • 三、外设与接口

      • 树莓派接口
      • GPIO 接口
      • I2C 接口
      • SPI通信
      • PWM控制
      • 串口通讯
      • TF Card
      • 屏幕
      • 触摸
      • 音频
      • RTC
      • Ethernet
      • M.2
      • MINI-PCIE
      • Camera
      • WIFI&BT
    • 四、资料下载

      • 资料下载

10 串口通讯

1 UART介绍

关于UART通信的基本概念,请参考:https://zhuanlan.zhihu.com/p/657771076 . Rockchip UART (Universal Asynchronous Receiver/Transmitter) 基于16550A串⼝标准,完整模块⽀持以下功能:

  • 支持5、 6、 7、 8 bits数据位。
  • 支持1、 1.5、 2 bits停⽌位。
  • 支持奇校验和偶校验,不⽀持mark校验和space校验。
  • 支持接收FIFO和发送FIFO, ⼀般为32字节或者64字节。
  • 支持最⾼4M波特率,实际⽀持波特率需要芯⽚时钟分频策略配合。
  • 支持中断传输模式和DMA传输模式。
  • 支持硬件⾃动流控, RTS+CTS。

2 UART板卡接口

UART板卡接口

3 UART使用---命令行方式

3.1 设备树解析

提示

下文的文件路径:out/kernel/src_tmp/linux-5.10/arch/arm64/boot/dts/rockchip/需要先编译码源。

基础定义层(rk3568.dtsi):

uart3: serial@fe670000 {
    compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart";
    reg = <0x0 0xfe670000 0x0 0x100>;
    interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;
    clock-names = "baudclk", "apb_pclk";
    reg-shift = <2>;
    reg-io-width = <4>;
    dmas = <&dmac0 6>, <&dmac0 7>;
    pinctrl-names = "default";
    pinctrl-0 = <&uart3m0_xfer>;
    status = "disabled";
};

我们对一些基本属性进行解析:

  • compatible : 指定兼容性,支持RK3568 UART和标准DW APB UART
  • reg : 寄存器地址范围(0xfe670000-0xfe6700ff)
  • interrupts : 中断号119,高电平触发
  • clocks : 波特率时钟(SCLK_UART3)和APB时钟(PCLK_UART3)
  • dmas : DMA通道6(TX)和7(RX)
  • pinctrl-0 : 默认使用uart3m0_xfer引脚组
  • status : 默认禁用状态

引脚配置层(rk3568-pinctrl.dtsi),其中UART3提供2种引脚配置模式:

uart3m0_xfer: uart3m0-xfer {
    rockchip,pins =
        /* uart3_rxm0 */
        <1 RK_PA0 2 &pcfg_pull_up>,
        /* uart3_txm0 */
        <1 RK_PA1 2 &pcfg_pull_up>;
};

uart3m1_xfer: uart3m1-xfer {
    rockchip,pins =
        /* uart3_rxm1 */
        <3 RK_PC0 4 &pcfg_pull_up>,
        /* uart3_txm1 */
        <3 RK_PB7 4 &pcfg_pull_up>;
};
  • uart3m0_xfer : 引脚组1,使用PA0作为RX,PA1作为TX
  • uart3m1_xfer : 引脚组2,使用PC0作为RX,PB7作为TX

板级配置层( rk3568-toybrick-x0.dtsi )

&uart3 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&uart3m1_xfer>;
};
  • &uart3 : 引用基础定义中的uart3节点
  • status = "okay" : 使能UART3控制器
  • pinctrl-0 : 选择M1模式引脚(GPIO3_C0/GPIO3_B7)

3.2 应用层测试UART的方法

在过去进行单片机开发调试时,我们经常用到的是使用沁恒电子的CH340系列的USB 转串口模块,此外还有常见的FT232RL USB转串口芯片, 本次测试使用的是搭载FT232RL芯片的USB转串口模块,两者使用上没有任何区别,实际使用时,我们只需要把模块的TX RX 与 开发板的 RX TX 进行对接即可

USB转串口模块

在本实验中,我们依然选择此方式通过USB与板子进行UART通信。

和之前一样,驱动文件放置在 /dev 目录下 通过指令

ls /dev/tty*

即可查看到所有的终端设备如下: UART设备列表

其中tty前缀 为虚拟终端,ttyS 前缀为是本节需要研究的串口终端.

(ttyS3为UART3,ttyS8为UART8(该串口被蓝牙模块占用))

Busybox 是一个集成了上百个常用 Linux 命令的单一可执行文件,其中的stty是set tty 的缩写,是一个专门用于改变并打印终端行设置的命令。 常用指令如下:

查看端口

busybox stty -F /dev/ttySx     //ttyS为具体查看的端口

设置波特率

busybox stty -F /dev/ttyS3 baudrate

设置波特率为9600,8位数据为,一位停止位,无校验位

busybox stty -F /dev/ttyS3 9600 cs8 -cstopb -parenb

禁用硬件流控

busybox stty -F /dev/ttyS3 -crtscts

microcom 是 BusyBox 的一个组件,核心功能就是打开一个指定的串口设备,实现数据的接收

以波特率115200 运行串口

microcom -s 115200 /dev/ttyS3

3.2 具体功能演示

使用ssty工具查询开发板串口UART3参数

busybox stty -F /dev/ttyS3
UART参数查询

使用ssty工具修改串口波特率为115200,其中ispeed为输入速率,ospeed为输出速率

busybox stty -F /dev/ttyS3 ispeed 115200 ospeed 115200
UART波特率设置

(注意:每一次设备开机需要重新设置一遍波特率,重启默认会重置波特率为9600)

备注

串口工具下载地址和路径: https://pan.baidu.com/s/1ZUn2BNg-Sb6M-fWhDqAFMw?pwd=smcc 提取码:smcc ShimetaPi开源鸿蒙资料>02-软件工具>Rockchip>OpenHarmony>串口工具>sscom5.13.1.exe

按上述配置配置好串口调试助手后,在板卡端使用如下命令测试串口发送数据是否成功:

#在板卡上的终端执行如下指令
#使用echo命令向终端设备文件写入字符串"Hello!"、"OpenHarmony!"
echo Hello! > /dev/ttyS3
echo "OpenHarmony" > /dev/ttyS3
#PC上的串口调试助手会接收到内容
UART发送测试

PC段接收成功接收到数据如图所示,板卡发送数据正常。 下面对通过PC端发送数据,测试板卡的串口能否正常接收数据。 使用上文中提到的microcom工具, 在板卡上的终端执行如下指令,连接到串口设备 ttyS3 并进行双向通信,此时microcom命令会等待串口数据并把接收的数据显示在终端

microcom -s 115200 /dev/ttyS3
UART接收测试

板卡终端成功显示接收的数据。 PC端发送数据,板卡成功接收到数据,板卡接收数据正常。

4. UART使用---NAPI方式

资料路径

hap包: \05-开发资料\01-OpenHarmory 开发资料\外设测试APP\HAP\UART_TEST.hap

工程码源:\05-开发资料\01-OpenHarmory 开发资料\外设测试APP\SRC\UART_TEST

这里使用读写系统节点 /dev/ttyS3 的方式构建NAPI.

4-1 测试环境准备

首先对 /dev/ttyS3 节点进行权限设置:

chmod 777 /dev/ttyS3             //路径

4-2 测试程序使用介绍

以下是我们做的串口测试程序,实现的基本功能是串口的开关以及数据的收发,考虑到不好布局以及降低综合难度,并没有把参数配置功能加在程序界面中,而是用一行文字标注。提供的 C 码源中已经实现了这部分功能,请有能力的朋友自行添加到 ets 文件中!

我们将开发板通过USB转TTL模块连接到电脑,打开应用如下图所示,我们打开串口。

UART应用打开串口

打开串口后,点击开始接收,并使用PC端串口助手发送文本 "ShiMeta Pi ,Hello!" 应用程序成功接收到文本并显示在数据接收区。

再通过应用程序发送字符串 "open harmony!" ,串口终端也成功接收到数据,如下图所示:

UART数据收发1UART数据收发2

4-3 测试程序代码介绍

由于涉及的的知识点前面都有介绍,这里贴上测试程序napi_init.cpp代码,供有需要的朋友参考,也可以在资料中自行查看。

#include "napi/native_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "hilog/log.h"

const int GLOBAL_RESMGR = 0xFF00;
const char *UART_TAG = "[UART]";
const char *UART_DEVICE = "/dev/ttyS3";  // 固定使用ttyS3串口

// 全局变量
static int uart_fd = -1;        // 串口文件描述符
static struct termios old_cfg;  // 保存原始配置
static bool uart_opened = false;

// 配置串口参数
static int configure_uart(int fd, int baudrate, int databits, int stopbits, char parity)
{
    struct termios cfg;

    // 获取当前配置
    if (tcgetattr(fd, &cfg) != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, UART_TAG,
                   "Failed to get uart config: %{public}s", strerror(errno));
        return -1;
    }

    // 保存原始配置
    old_cfg = cfg;

    // 清除所有标志
    cfg.c_cflag &= ~CSIZE;
    cfg.c_cflag &= ~CSTOPB;
    cfg.c_cflag &= ~PARENB;
    cfg.c_cflag &= ~PARODD;

    // 设置数据位
    switch (databits) {
        case 5: cfg.c_cflag |= CS5; break;
        case 6: cfg.c_cflag |= CS6; break;
        case 7: cfg.c_cflag |= CS7; break;
        case 8: cfg.c_cflag |= CS8; break;
        default: cfg.c_cflag |= CS8; break;
    }

    // 设置停止位
    if (stopbits == 2) {
        cfg.c_cflag |= CSTOPB;
    }

    // 设置校验位
    switch (parity) {
        case 'O': case 'o': // 奇校验
            cfg.c_cflag |= PARENB;
            cfg.c_cflag |= PARODD;
            break;
        case 'E': case 'e': // 偶校验
            cfg.c_cflag |= PARENB;
            cfg.c_cflag &= ~PARODD;
            break;
        case 'N': case 'n': // 无校验
        default:
            cfg.c_cflag &= ~PARENB;
            break;
    }

    // 设置波特率
    speed_t speed;
    switch (baudrate) {
        case 4800: speed = B4800; break;
        case 9600: speed = B9600; break;
        case 19200: speed = B19200; break;
        case 38400: speed = B38400; break;
        case 57600: speed = B57600; break;
        case 115200: speed = B115200; break;
        case 230400: speed = B230400; break;
        case 460800: speed = B460800; break;
        case 921600: speed = B921600; break;
        case 1500000: speed = B1500000; break;
        default: speed = B115200; break;
    }

    cfsetispeed(&cfg, speed);
    cfsetospeed(&cfg, speed);

    // 设置控制模式
    cfg.c_cflag |= CLOCAL | CREAD;

    // 设置输入模式
    cfg.c_iflag &= ~(IXON | IXOFF | IXANY);
    cfg.c_iflag &= ~(INLCR | ICRNL | IGNCR);

    // 设置输出模式
    cfg.c_oflag &= ~OPOST;

    // 设置本地模式
    cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    // 设置读取参数
    cfg.c_cc[VTIME] = 0; // 非阻塞读取
    cfg.c_cc[VMIN] = 0;

    // 应用配置
    if (tcsetattr(fd, TCSANOW, &cfg) != 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, UART_TAG,
                   "Failed to set uart config: %{public}s", strerror(errno));
        return -1;
    }

    // 清空缓冲区
    tcflush(fd, TCIOFLUSH);

    return 0;
}

// 打开串口
static napi_value Open_UART(napi_env env, napi_callback_info info)
{
    napi_value result;

    // 检查串口是否已经打开
    if (uart_opened) {
        OH_LOG_Print(LOG_APP, LOG_WARN, GLOBAL_RESMGR, UART_TAG,
                   "UART is already opened");
        napi_create_string_utf8(env, "UART already opened", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    // 打开串口设备
    uart_fd = open(UART_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (uart_fd < 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, UART_TAG,
                   "Failed to open %{public}s: %{public}s", UART_DEVICE, strerror(errno));
        napi_create_string_utf8(env, "Failed to open UART device", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    // 配置串口参数 (115200, 8N1)
    if (configure_uart(uart_fd, 115200, 8, 1, 'N') != 0) {
        close(uart_fd);
        uart_fd = -1;
        napi_create_string_utf8(env, "Failed to configure UART", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    uart_opened = true;
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, UART_TAG,
               "UART opened successfully");

    napi_create_string_utf8(env, "UART opened successfully", NAPI_AUTO_LENGTH, &result);
    return result;
}

// 关闭串口
static napi_value Close_UART(napi_env env, napi_callback_info info)
{
    napi_value result;

    if (!uart_opened || uart_fd < 0) {
        OH_LOG_Print(LOG_APP, LOG_WARN, GLOBAL_RESMGR, UART_TAG,
                   "UART is not opened");
        napi_create_string_utf8(env, "UART is not opened", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    // 恢复原始配置
    tcsetattr(uart_fd, TCSANOW, &old_cfg);

    // 关闭串口
    close(uart_fd);
    uart_fd = -1;
    uart_opened = false;

    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, UART_TAG,
               "UART closed successfully");

    napi_create_string_utf8(env, "UART closed successfully", NAPI_AUTO_LENGTH, &result);
    return result;
}

// 设置串口配置
static napi_value Set_UART_Config(napi_env env, napi_callback_info info)
{
    napi_value result;
    size_t argc = 4;
    napi_value args[4];

    // 获取参数
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 4) {
        napi_create_string_utf8(env, "Invalid parameters", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    if (!uart_opened || uart_fd < 0) {
        napi_create_string_utf8(env, "UART is not opened", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    // 解析参数
    int32_t baudrate, databits, stopbits;
    char parity_char;
    size_t parity_len;
    char parity_str[10];

    napi_get_value_int32(env, args[0], &baudrate);
    napi_get_value_int32(env, args[1], &databits);
    napi_get_value_int32(env, args[2], &stopbits);
    napi_get_value_string_utf8(env, args[3], parity_str, sizeof(parity_str), &parity_len);

    parity_char = (parity_len > 0) ? parity_str[0] : 'N';

    // 重新配置串口
    if (configure_uart(uart_fd, baudrate, databits, stopbits, parity_char) != 0) {
        napi_create_string_utf8(env, "Failed to configure UART", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, UART_TAG,
               "UART configured: %{public}d-%{public}d-%{public}d-%{public}c",
               baudrate, databits, stopbits, parity_char);

    napi_create_string_utf8(env, "UART configured successfully", NAPI_AUTO_LENGTH, &result);
    return result;
}

// 发送数据
static napi_value Send_Data(napi_env env, napi_callback_info info)
{
    napi_value result;
    size_t argc = 1;
    napi_value args[1];

    // 获取参数
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    if (argc < 1) {
        napi_create_string_utf8(env, "Invalid parameters", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    if (!uart_opened || uart_fd < 0) {
        napi_create_string_utf8(env, "UART is not opened", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    // 获取要发送的字符串
    size_t str_len;
    napi_get_value_string_utf8(env, args[0], nullptr, 0, &str_len);

    char *send_data = (char*)malloc(str_len + 1);
    if (!send_data) {
        napi_create_string_utf8(env, "Memory allocation failed", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    napi_get_value_string_utf8(env, args[0], send_data, str_len + 1, &str_len);

    // 发送数据
    ssize_t bytes_written = write(uart_fd, send_data, str_len);

    if (bytes_written < 0) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, UART_TAG,
                   "Failed to send data: %{public}s", strerror(errno));
        free(send_data);
        napi_create_string_utf8(env, "Failed to send data", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, UART_TAG,
               "Sent %{public}zd bytes: %{public}s", bytes_written, send_data);

    free(send_data);

    char response[100];
    snprintf(response, sizeof(response), "Sent %zd bytes successfully", bytes_written);
    napi_create_string_utf8(env, response, NAPI_AUTO_LENGTH, &result);
    return result;
}

// 接收数据
static napi_value Receive_Data(napi_env env, napi_callback_info info)
{
    napi_value result;

    if (!uart_opened || uart_fd < 0) {
        napi_create_string_utf8(env, "UART is not opened", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    char buffer[1024];
    ssize_t bytes_read = read(uart_fd, buffer, sizeof(buffer) - 1);

    if (bytes_read < 0) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // 非阻塞模式下没有数据可读
            napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &result);
            return result;
        }
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, UART_TAG,
                   "Failed to read data: %{public}s", strerror(errno));
        napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    if (bytes_read == 0) {
        napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &result);
        return result;
    }

    buffer[bytes_read] = '\0';

    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, UART_TAG,
               "Received %{public}zd bytes: %{public}s", bytes_read, buffer);

    napi_create_string_utf8(env, buffer, NAPI_AUTO_LENGTH, &result);
    return result;
}

// 检查串口状态
static napi_value Get_UART_Status(napi_env env, napi_callback_info info)
{
    napi_value result;

    if (uart_opened && uart_fd >= 0) {
        napi_create_string_utf8(env, "opened", NAPI_AUTO_LENGTH, &result);
    } else {
        napi_create_string_utf8(env, "closed", NAPI_AUTO_LENGTH, &result);
    }

    return result;
}

// 模块初始化
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "Open_UART", nullptr, Open_UART, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "Close_UART", nullptr, Close_UART, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "Set_UART_Config", nullptr, Set_UART_Config, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "Send_Data", nullptr, Send_Data, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "Receive_Data", nullptr, Receive_Data, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "Get_UART_Status", nullptr, Get_UART_Status, nullptr, nullptr, nullptr, napi_default, nullptr }
    };

    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}
在 GitHub 上编辑此页
上次更新:
贡献者: fxx, hjf
Prev
09 PWM 控制
Next
11 TF卡