rk3568 OpenHarmony 串口uart与电脑通讯开发案例

news2024/11/24 15:18:27

一、需求描述:

        rk3568开发板运行OpenHarmony4.0,通过开发板上的uart串口与电脑进行通讯,相互收发字符串。

二、案例展示

        1、开发环境:

        (1)rk3568开发板

        (2)系统:OpenHarmony

        (3)电脑:Windows11笔记本,串口调试助手

        (4)Deveco Studio:evEco Studio 4.0 Release (4.0.0.600)

2、下载并运行开发案例

        下载开发案例,使用Deveco Studio打开运行编译、下载应用到rk3568开发板。开发板运行demo界面如下图所示。(.hap应用文件,见附件)

        (1)点击波特率选择按钮,选择相应的波特率;点击地址输入框,输入使用的串口的设备地址,这里以uart5(设备地址/dev/ttyS5)为例,选择波特率9600。  
 

        (2)将开发板通过串口转USB的转接线,将开发板与笔记本连接起来,电脑打开一个串口调试助手,如下图所示。

        (3)开发板点击“开启按钮”打开串口,然后点击“发送”按钮,想电脑通过串口发送输入框的字符串,电脑运行的串口调试助手接信息,并回显接收到的字符串;同理电脑通过串口调试助手想开发板发送字符串,开发板接收信息,并在回显框中回显接收到的字符串,如下图所示。

        (4)测试效果

OpenHarmony串口通讯展示

        注意:运行demo,应确保开发板的串口节点已被引出可用,且读写权限已被允许

三、应用开发流程

       该应用的开发,使用NAPI方式来编写使用串口的NAPI函数,通过这些函数,来对串口进行设置,打开,发送和接收数据(NAPI使用,详见NAPI篇)。在应用界面编写中,引用NAPI函数进行逻辑构建,完成应用开发。

         1、应用界面编写(Index.ets)



import BQNapi from 'libentry.so';//引入NAPI
import promptAction from '@ohos.promptAction';

const TAG = "uartToComputer"

@Entry
@Component
struct Index {
  @State isStart: boolean = false;
  private dateTime: Date = new Date();
  private scroller: Scroller = new Scroller()
  @State receiveMessage: string = '';
  @State sendMessage: string = 'https://www.bearkey.net/';
  @State currentUart: string = '';
  private UartPort: string = '/dev/ttyS5'
  private UartBand: string[] = ['9600', '19200', '38400', '57600', '115200']
  private UartBand_N: number[] = [9600, 19200, 38400, 57600, 115200]
  @State currentUartBandIndex: number = 0
  @State bandRate: number = 0;
  private fd: number = -1;
  private setIntervalID: number = -1;

  aboutToAppear() {

    // this.fd = BQNapi.open_port(this.currentUart, 115200);
    // console.log(TAG, `打开串口${this.currentUart},ret=${this.fd}`)
    this.setIntervalID = setInterval(() => {
      //判断是否有串口开启
      if (this.fd > 0) {
        //获取开启状态
        this.isStart = true
        //获取波特率
        this.bandRate = BQNapi.getBandRate(this.fd)
        let temp: string = BQNapi.series_receive_data(this.fd);
        if (temp === "-1") {
          console.log(TAG, '未接收到数据或接收失败');

        } else {
          this.dateTime = new Date();
          let year: number = this.dateTime.getFullYear(); //当前年
          let month = this.dateTime.getMonth() + 1;
          let date = this.dateTime.getDate();
          let hours = this.dateTime.getHours();
          let minutes = this.dateTime.getMinutes();
          let seconds = this.dateTime.getSeconds();
          let curryDateTime: string = year + '-' + month + '-' + date + ' ' + hours + ':' + minutes + ':' + seconds;
          temp = curryDateTime + '\n' + temp;
          this.receiveMessage = temp + this.receiveMessage
          this.scroller.scrollTo({ xOffset: 0, yOffset: 0 })
        }
      } else {
        this.isStart = false
        this.bandRate = 0;
        this.currentUart = '-'
      }
    }, 300)

  }

  aboutToDisappear() {
    console.log(TAG, `退出应用`)
    clearInterval(this.setIntervalID);
    if (this.fd > 0) {
      let e: number = BQNapi.close_port(this.fd);
      console.log(TAG, `关闭串口${this.currentUart},ret=${e}`)
      if (e == 0) {
        console.log(TAG, `关闭成功`)
      } else {
        console.log(TAG, `关闭失败`)
      }
    }
  }

  build() {
    Column() {
      Row() {
        Text('回显框')
          .fontSize(25)
          .size({ width: '50%', height: 30 })

        Button('清空窗口')
          .fontSize(30)
          .size({ width: 160, height: 40 })
          .onClick(() => {
            this.receiveMessage = '';
          });
      }
      .justifyContent(FlexAlign.SpaceAround)
      .margin({ top: 10, })
      .size({ width: '100%', height: 50 })

      Scroll(this.scroller) {
        Column() {
          Text(this.receiveMessage)
            .fontSize(20)
            .size({ width: '100%' })
            .constraintSize({ minHeight: 30 })
            .margin({ top: 10, bottom: 10 })
            .padding(10)
            .textAlign(TextAlign.Start)
        }.size({ width: '100%' })
        .constraintSize({ minHeight: 300 })
        .justifyContent(FlexAlign.Start)

      }.size({ width: '100%', height: 150 })
      .border({ width: 1, style: BorderStyle.Solid, radius: 10 })


      Row() {
        Text('输入框')
          .fontSize(25)
          .size({ width: '100%', height: 40 })
      }
      .justifyContent(FlexAlign.SpaceAround)
      .margin({ top: 10, })
      .size({ width: '100%', height: 50 })


      TextInput({ placeholder: "请输入需要发送的内容...", text: this.sendMessage })
        .fontSize(25)
        .size({ width: '100%', height: 50 })
        .border({ width: 1, style: BorderStyle.Solid, radius: 10 })
        .margin({ bottom: 10 })
        .onChange((value) => {
          this.sendMessage = value;
        })
      Row() {

        Button('发送')
          .fontSize(30)
          .enabled(this.isStart)
          .size({ width: 120, height: 40 })
          .onClick(() => {
            let a: number = BQNapi.series_send_data(this.sendMessage, this.fd)
            if (a === 0) {
              console.log(TAG, "发送成功!");
            } else {
              console.log(TAG, "发送失败!");
            }
          })
        Button('清空')
          .fontSize(30)
          .enabled(this.isStart)
          .size({ width: 120, height: 40 })
          .onClick(() => {
            this.sendMessage = '';
          })

      }
      .justifyContent(FlexAlign.SpaceAround)
      .margin({ top: 10, })
      .size({ width: '100%', height: 50 })

      Row() {
        Text('当前串口信息')
          .fontSize(25)
          .size({ width: '100%', height: 30 })

      }
      .justifyContent(FlexAlign.SpaceAround)
      .margin({ top: 10, })
      .size({ width: '100%', height: 50 })

      Column() {
        Row() {
          Text('波特率:')
            .fontSize(25)
            .size({ width: '40%', height: 30 })
            .textAlign(TextAlign.Center)
          Text(this.bandRate.toString())
            .fontSize(28)
            .size({ width: '60%', height: 30 })
            .textAlign(TextAlign.Center)

        }
        .justifyContent(FlexAlign.SpaceAround)
        .size({ width: '100%', height: 40 })

        Row() {
          Text('当前串口:')
            .fontSize(25)
            .size({ width: '40%', height: 30 })
            .textAlign(TextAlign.Center)
          Text(this.currentUart)
            .fontSize(28)
            .size({ width: '60%', height: 30 })
            .textAlign(TextAlign.Center)
        }
        .justifyContent(FlexAlign.SpaceAround)
        .size({ width: '100%', height: 40 })
      }
      .size({ width: '100%', height: 100 })
      .justifyContent(FlexAlign.SpaceAround)
      .border({ width: 1, style: BorderStyle.Solid, radius: 10 })


      Row() {

        Button(this.UartBand[this.currentUartBandIndex])
          .fontSize(25)
          .size({ width: '30%', height: 45 })
          .onClick(() => {
            this.showPickerDialogForUartBand()
          })
        TextInput({ placeholder: "请输入串口地址", text: this.UartPort })
          .fontSize(25)
          .border({ width: 1, style: BorderStyle.Solid, radius: 10 })
          .size({ width: '60%', height: 45 })
          .onChange((value) => {
            this.UartPort = value;
          })


      }
      .justifyContent(FlexAlign.SpaceAround)
      .margin({ top: 10, })
      .size({ width: '100%', height: 50 })

      Row() {
        Button("开启")
          .fontSize(35)
          .size({ width: '30%', height: 45 })
          .backgroundColor(this.isStart ? Color.Green : Color.Blue)
          .onClick(() => {
            if (this.isStart) {
              promptAction.showToast({
                message: "请先停止当前串口",
                duration: 500
              })
            } else {
              this.fd = BQNapi.open_port(this.UartPort, this.UartBand_N[this.currentUartBandIndex]);
              if (this.fd > 0) {
                console.log(TAG, `打开串口${this.currentUart},ret=${this.fd}`)
                this.currentUart = this.UartPort;
                promptAction.showToast({
                  message: "开启成功",
                  duration: 500
                })
              } else {
                promptAction.showToast({
                  message: "开启失败",
                  duration: 500
                })
              }
            }

          })
        Button('停止')
          .fontSize(35)
          .size({ width: '30%', height: 45 })
          .backgroundColor(this.isStart ? Color.Red : Color.Blue)
          .onClick(() => {
            if (this.isStart) {
              let e: number = BQNapi.close_port(this.fd);
              console.log(TAG, `关闭串口${this.currentUart},ret=${e}`)
              if (e == 0) {
                promptAction.showToast({
                  message: "关闭成功",
                  duration: 500
                })
                this.fd = -1;
                this.currentUart = '...'
                console.log(TAG, `关闭成功`)
              } else {
                console.log(TAG, `关闭失败`)
                promptAction.showToast({
                  message: "关闭失败",
                  duration: 500
                })
              }
            } else {
              promptAction.showToast({
                message: "未启用串口",
                duration: 500
              })
            }

          })
      }
      .justifyContent(FlexAlign.SpaceAround)
      .margin({ top: 20, })
      .size({ width: '100%', height: 50 })

    }
    .size({ width: '100%', height: '100%' })
    .padding(10)
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Center)
  }

  showPickerDialogForUartBand() {
    TextPickerDialog.show({
      range: this.UartBand,
      selected: this.currentUartBandIndex,
      disappearTextStyle: { color: Color.Red, font: { size: 15, weight: FontWeight.Lighter } },
      textStyle: { color: Color.Black, font: { size: 20, weight: FontWeight.Normal } },
      selectedTextStyle: { color: Color.Blue, font: { size: 30, weight: FontWeight.Bolder } },
      onAccept: (value: TextPickerResult) => {
        let temp = value.value as string
        this.currentUartBandIndex = value.index as number

      },
      onCancel: () => {
        console.info(TAG, "TextPickerDialog:onCancel()")
      },
      onChange: (value: TextPickerResult) => {
        console.info(TAG, "TextPickerDialog:onChange()" + JSON.stringify(value))
      }
    })
  }
}

        2、NAPI函数引出声明(index.d.ts)

export const open_port: (port_address: string, band_rate: number) => number; //打开串口,打开成功返回描述符(int),失败-1

export const close_port: (serial_port: number) => number; //关闭串口,关闭成功返回0,失败则返回-1.

export const series_send_data: (tx_data: string, serial_port: number) => number; //发送数据

export const series_receive_data: (serial_port: number) => string; //接收数据,成功返回接收字符串,失败返回-1

export const getBandRate: (serial_port: number) => number; //查询波特率,成功返回波特率,失败返回-1

        3、完整应用工程源码,私信

声明:非本人允许,严禁转载,演示开发板为厦门贝启科技的BQ3568HM产品

(1)首页-贝启科技官方企业店-淘宝网

(2)厦门贝启科技有限公司-Bearkey-官网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1871110.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

桃园三结义 | 第1集 | 三人一条心,黄土变成金,有你带着俺,大事定能成功啊!| 正所谓择木之禽,得其良木,择主之臣,得遇明主 | 三国演义 | 群雄逐鹿

🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 📌这篇博客是毛毛张结合三国演义原著分享三国演义文学剧本中的经典台词和语句,本篇分享的是《三国演义》第Ⅰ部分《群雄逐鹿》的第1️⃣集《桃…

薄冰英语语法学习--名词2-格

名词后面 s,代表后面这个东西属于前面的。 比如toms book,汤姆的书。 末尾是s,那么直接在最后加就行了。比如boys,男孩们的 表示几个词共同 的所有关系在最后一个词的词尾加 sMary and Toms books 玛丽和汤姆共有的书表示几个词…

风水研究会官网源码系统-可展示自己的领域内容-商品售卖等

一款用于展示风水行业,周易测算行业,玄学行业的系统,并支持售卖自己的商品。 整洁大气,非常漂亮,前端内容均可通过后台修改。 大致功能: 支持前端内容通过后端自定义支持开启关闭会员功能,会…

基于PHP的初中数学题库管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的初中数学题库管理系统 一 介绍 此初中数学题库管理系统基于原生PHP开发,数据库mysql,系统角色分为学生,教师和管理员。(附带参考设计文档) 技术栈:phpmysqlphpstudyvscode 二 功能 …

电子电器及家电制造行业MES系统解决方案介绍

电子电器及家电制造行业是一个技术高度密集、生产工艺复杂且市场需求变化迅速的行业。为了提升生产效率、保证产品质量并快速响应市场变化,越来越多的电子电器及家电制造企业引入了MES系统。本文将详细介绍MES系统在电子电器及家电制造行业的应用方法及其价值。 一…

C++11 右值引用和移动语义,完美转发和万能引用,移动构造和移动赋值,可变参数模板,lambda表达式,包装器

文章目录 C11简介统一的列表初始化{}初始化std::initializer_list声明autodecltypenullptr 范围for循环 智能指针STL中一些变化右值引用和移动语义左值引用和右值引用左值引用与右值引用比较 右值引用使用场景和意义右值引用引用左值及其一些更深入的使用…

大数据------JavaWeb------Maven(完整知识点汇总)

额外知识点 IDE IDE是集成开发环境的缩写,它是一种软件应用程序,提供了编码、调试和部署软件的一站式解决方案。这些功能集成在一起,使开发人员能够在一个环境中完成整个软件开发过程,从编写代码到调试和测试,直到最终…

机械装备制造行业MES,实时监控生产流程

装备制造行业MES,是专门为装备制造行业设计的生产信息化管理系统。旨在实时监控装备制造生产流程,实现全流程的精细化管理和监控,提高生产效率、降低生产成本、提升产品质量。 本文将详细介绍装备制造行业MES的概念、技术及应用,…

七天速通javaSE:第四天 数组基础

文章目录 前言一、认识数组二、数组的声明和创建1. 声明数组变量2. 创建数组3. 变量的初始化(赋值)3.1 静态初始化3.2 动态初始化 3. 示例 三、数组的使用1. 循环1.1 普通for循环1.2 For-Each 循环 2. 数组作为函数的参数和返回值 前言 本文将为大家介绍…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(十九)

课程地址: 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程,一套精通鸿蒙应用开发 (本篇笔记对应课程第 29 节) P29《28.网络连接-第三方库axios》 要想使用第三方库axios,需要先安装ohpm,因为 axios…

Redis优化之持久化

目录 1.Redis高可用 2.Redis持久化 2.1 RDB持久化 2.1.1 触发条件 2.1.2 执行流程 2.1.3 启动时加载 2.2 AOF持久化 2.2.1 开启AOF 2.2.2 执行流程 2.2.3 文件重写触发方式 2.2.4 文件重写的流程 2.2.5 启动时加载 2.3 RDB和AOF的优缺点 3.Redis性能管理 3.1 查看…

LEED绿色建筑认证的优缺点是什么

LEED绿色建筑认证的优缺点: 优点: 环保可持续性:LEED认证强调建筑的节能、节水以及材料循环利用等环保策略,有助于减少资源消耗和降低对环境的负面影响,推动建筑行业向更加环保的方向转变。 降低运营成本&#xff1a…

『Z-Workshop』 6月22日线下ALCOVE分享活动

2024 求是创新 ZJUBCA Sponsored by the ALCOVE Community TIME:2024/06/22 ADD:浙江大学紫金港校区 --- Alcove 是 Aptos 公链与 Alibaba Cloud 共同打造的亚洲首个 Move 开发者社区,致力于支持开发者使用 Move 语言构建下一代 Web3 应用&am…

华为笔记本电脑d盘数据丢失:原因、恢复方案与防范建议

华为笔记本电脑以其高性能和稳定的品质赢得了众多用户的青睐,但即使是如此优质的设备,也难免遭遇数据丢失的困境。本文将围绕华为笔记本电脑D盘数据丢失这一问题,探讨其常见原因、恢复方案,并提出未来防范的建议,以帮助…

用户订单管理API:轻松管理,购物无忧

在当今数字化时代,电子商务已经成为人们购物的首选方式。与传统的实体店相比,电商的优势在于便捷、快速、多样化等特点,使得更多的消费者选择了通过网络购物。而作为电商平台,如何提供更好的购物体验,是每个平台都需要…

ForkJoin框架与工作窃取算法详解

文章目录 一、ForkJoin框架概述1_核心概念2_主要类和方法1_ForkJoinPool2_ForkJoinTask 二、启用异步模式与否的区别三、ForkJoinPool的三种任务提交方式四、执行逻辑及使用示例1_示例&#xff1a;并行计算数组元素和2_forkJoinPool.submit3_ForkJoinTask<?>中任务的执行…

支持向量回归原理详解及Python代码示例

支持向量回归原理详解 支持向量回归&#xff08;Support Vector Regression, SVR&#xff09;是支持向量机&#xff08;SVM&#xff09;的一种扩展&#xff0c;用于回归问题。SVR通过寻找一个最佳的回归超平面&#xff0c;使得尽可能多的数据点落在超平面附近的ε-管内&#xf…

ubuntu16安装DHCP

一、安装dns server软件包 $ apt-get install bind9 二、配置BIND9 配置文件的目录默认为/etc/bind cd /etc/bind 进入该目录。。。 1、vi /etc/bind/named.conf.local zone "xuehai.com" {type master;file "/etc/bind/db.xuehai.com"; }; image.png …

win11记事本错误打开一次非常多的文件再次使用时造成卡住

错误地不小心一次性打开数十个数百个文件造成再次使用时&#xff0c;文件卡住。 亲测有效。

ISP IC/FPGA设计-第一部分-SC130GS摄像头分析-IIC通信(1)

1.摄像头模组 SC130GS通过一个引脚&#xff08;SPI_I2C_MODE&#xff09;选择使用IIC或SPI配置接口&#xff0c;通过查看摄像头模组的原理图&#xff0c;可知是使用IIC接口&#xff1b; 通过手册可知IIC设备地址通过一个引脚控制&#xff0c;查看摄像头模组的原理图&#xff…