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

一、需求描述:

        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-官网

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32单片机实现串口IAP升级

一.概述 1.要实现串口IAP升级,首先要编写一个bootloader程序,然后再写支持IAP的app程序; 2.keil下bootloader的程序rom和ram设置 3.app程序要用bin文件 注:本文以STM32H743举例,其他stm32单片机IAP升级原理类似。 …

有哪些方法可以恢复ios15不小心删除的照片?

ios15怎么恢复删除的照片?在手机相册里意外删除了重要的照片?别担心!本文将为你介绍如何在iOS 15系统中恢复已删除的照片。无需专业知识,只需要按照以下步骤操作,你就能轻松找回宝贵的回忆。 一、从iCloud云端恢复删除…

easyui的topjui前端框架使用指南

博主今天也是第一次点开easyui的商业搜权页面,之前虽然一直在使用easyui前端框架(easyui是我最喜欢的前端ui框架),但是都是使用的免费版。 然后就发现了easyui的开发公司居然基于easyui开发出了一个新的前端框架,于是我…

句法分析概述

第1关:句法分析概述 任务描述 本关任务:通过对句法分析基本概念的学习,完成相应的选择题。 相关知识 为了完成本关任务,你需要掌握: 句法分析的基础概念; 句法分析的数据集和评测方法。 句法分析简介…

Potato(土豆)一款轻量级的开源文本标注工具(二)

示例项目(模版) Potato 旨在提高数据标注的可复制性,并降低研究人员设置新标注任务的成本。因此,Potato 提供了一系列预定义的示例项目,并欢迎公众向项目中心贡献。如果您使用 Potato 进行了自己的标注工作&#xff0…

【字符串】【双指针】1、仅仅反转字母+2、回文子串+ 3、最长回文子串+4、验证回文串+5、反转字符串中的单词

今天依旧是字符串!2道简单+3道中等 1、仅仅反转字母(难度:简单) 该题对应力扣网址 错误做法 一开始是“原始”思路,交了之后果然不对,错误的思路我也就不解释了。 class Solution { public:…

计算机毕业设计Python+LSTM+Tensorflow股票分析预测 基金分析预测 股票爬虫 大数据毕业设计 深度学习 机器学习 数据可视化 人工智能

基于TensorFlow-LSTM的股票预测系统开题报告 一、研究背景与意义 随着信息技术的飞速发展,股票市场作为现代经济活动的重要组成部分,其价格波动受到广泛关注。投资者们迫切希望通过科学的方法预测股票价格,以优化投资决策,实现利…

达梦数据库的系统视图v$database

达梦数据库的系统视图v$database 基础信息 OS版本: Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本: DM Database Server 64 V8 DB Version: 0x7000c 03134284132-20240115-215128-20081在达梦数据库(Dameng Database&#xf…

yolov10打包为exe

一、前言 本节实验将官方yolov10推理程序打包为exe运行 二、代码 首先下载官方代码至本机,并使用conda创建虚拟环境,并安装好yolov10所需库 conda create --prefix E:/pyenv/myYolo10 python3.8 pip install -r requirements.txt 下载官方模型权重 …

最新Adobe2024全家桶下载,PS/PR/AE/AI/AU/LR/ID详细安装教程

如大家所熟悉的,Adobe全家桶系列常用的软件有Photoshop(PS)、Premiere(PR)、After Effects(AE)、illustrator(AI)、Audition(AU)、Lightroom&…

计算机二级Access操作题总结——综合应用

属性表相关 例1: 不允许输入和修改其中的数据→【是否锁定】 例2: 单击“退出”按钮(名为“bt2”),调用设计好的宏“mEmp”来关闭窗体。 分组和汇总 对“rSell”报表进行适当设置,使每名雇员的姓名显示在该雇员所售书籍信…

第四天 怎么又迟到了呀 哎啥时候来准时上个课呀

泛型编程 Traits实现,是什么 泛型编程(Generic Programming)是一种通过编写与特定类型无关的代码来实现代码复用和抽象的编程范式。 在C中,模板(Templates)是实现泛型编程的主要手段。 Traits&#xff0…

基于ssh框架的个人博客源码

基于ssh的个人博客源码,页面清爽简洁,原先有部分bug,运行不了,现已修复 1.博客首页 (本地访问地址 :localhost:8080/Blog/index/index) 2.关于我 3.慢生活 4.留言板 5.我的相册 微信扫码下载源码

《分析模式》漫谈07-怎样把一张图从不严谨改到严谨

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 下图是《分析模式》原书第2章的图2.10,里面有一些错误和考虑不周的地方: 2004中译本和2020中译本的翻译如下: 基本上都是照搬,没有改过…

widows下 vscode 的 terminal / powershell,ctrl+v失灵,输出^v

问题 原因 最近装了PSReadLine Import-Module PSReadLineSet-PSReadLineOption -PredictionSource History Set-PSReadLineOption -PredictionViewStyle InlineView Set-PSReadLineOption -EditMode Emacsvscode不兼容 解决方法 注释掉最后面的 Import-Module PSReadLineS…

2021年12月电子学会青少年软件编程 中小学生Python编程等级考试三级真题解析(选择题)

2021年12月Python编程等级考试三级真题解析 选择题(共25题,每题2分,共50分) 1、小明在学习计算机时,学习到了一个十六进制数101,这个十六进制数对应的十进制数的数值是 A、65 B、66 C、256 D、257 答案&#xff…

浅析Resource Quota中limits计算机制

前言 在生产环境中,通常需要通过配置资源配额(Resource Quota)来限制一个命名空间(namespace)能使用的资源量。在资源紧张的情况下,常常需要调整工作负载(workload)的请求值&#xf…

MySQL周内训参照4、触发器-插入-修改-删除

触发器 1、用户购买商品时,要求库存表中的库存数量自动修改 详细示例 delimiter $$ create trigger stock_change after -- 事件触发在 下订单之后 insert -- 监视插入事件 on stock -- 监视 order订单表 for each row begin update stock set stockstock-new.st…

ROT5、ROT13、ROT18、ROT47全系列加解密小程序

ROT5、ROT13、ROT18、ROT47全系列加解密小程序 这几天在看CTF相关的课程,涉及到古典密码学和近代密码学还有现代密码学。自己编了一个关于ROT全系列的加、解密小程序。 ​ ROT5、ROT13、ROT18、ROT47 编码是一种简单的码元位置顺序替换暗码。此类编码具有可逆性&a…

音视频入门基础:H.264专题(8)——H.264官方文档的描述符

音视频入门基础:H.264专题系列文章: 音视频入门基础:H.264专题(1)——H.264官方文档下载 音视频入门基础:H.264专题(2)——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…