使用香橙派 学习Linux的串口开发

串口的回顾 & 硬件接线

关于串口也是之前学习过很多次了,详见:

认识串口 和 蓝牙模块HC08_hc08蓝牙模块_mjmmm的博客-CSDN博客

串口的再认识-CSDN博客

香橙派提供了两路串口第一路就是在刷机时串口连接的引脚(对应驱动ttyS0),第二路就是物理引脚8和10(对应驱动ttyS5

此处要请出老朋友CH340,这次连接物理引脚8和10的第二路串口: 

在使用串口连接香橙派的时候,使用的Mobaxterm就可以视为一个串口助手,但Moba更多的是提供一个基于指令交互的平台,所以串口助手的使用还是选择之前用过的AI Thinker:

在实际应用中,单片机作为比较简单的芯片,可以去负责数据的采集,然后通过串口接到相对高级的香橙派或其他芯片,香橙派读取数据并进行复杂的数据分析或开发,包括人工智能,UI,网络等在单片机中难以实现的功能,同时通过串口给单片机发送各种指令。

基于wiringPI库的串口开发

关于串口的代码,wiringPI库同样提供了demo代码:

cp一份过来:

(也可以使用SourceInsight来读代码!)

首先,发现打开默认的demo打开的是串口2的驱动,所以此处要改成串口5的驱动:

然后编译运行:(显示的就是串口助手中发来的字符的ASCII码形式)

串口助手中记得勾选HEX显示:(发送的就是16进制的0到256)

 

基于demo的优化

可以使用之前学习的线程相关概念来优化这个demo,关于线程的知识之前也学过,详见:

线程_mjmmm的博客-CSDN博客

Linux线程 --- 生产者消费者模型(C语言)-CSDN博客

serial_wiringPI_test.c:

#include <stdio.h>
#include <string.h>
#include <errno.h>#include <wiringPi.h>
#include <wiringSerial.h>#include <pthread.h>
#include <stdlib.h>void *read_serial(void *arg)
{char *sendbuf;sendbuf = (char *)malloc(32*sizeof(char));char *p = sendbuf;while(1){memset(sendbuf,'\0',32*sizeof(char));fgets(sendbuf,sizeof(sendbuf),stdin);//scanf("%s",sendbuf);while(*sendbuf != '\0'){serialPutchar (*((int *)arg), *sendbuf) ; //串口打印数据的函数 serialPutchar()sendbuf++;}sendbuf = p;}pthread_exit(NULL);}void *write_serial(void *arg)
{while(1){while(serialDataAvail (*((int *)arg))){ //当串口有数据的时候进入whileprintf ("%c", serialGetchar (*((int *)arg))) ; //串口接收数据的函数serialGetchar()fflush (stdout) ;}}pthread_exit(NULL);
}int main ()
{int fd ;int ret;pthread_t read_thread;pthread_t write_thread;if ((fd = serialOpen ("/dev/ttyS5", 115200)) < 0) //打开驱动文件,配置波特率{fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;return 1 ;}if (wiringPiSetup () == -1){fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;return 1 ;}ret = pthread_create(&read_thread,NULL,read_serial,(void *)&fd);if(ret != 0){printf("read_serial create error\n");return 1;}ret = pthread_create(&write_thread,NULL,write_serial,(void *)&fd);if(ret != 0){printf("write_serial create error\n");return 1;}pthread_join(read_thread,NULL);pthread_join(write_thread,NULL);return 0 ;
}

实现效果:

发送数据:

接收数据:

也可以一边发一边接,因为经过优化,接和发被封装在了不同的线程中! 

Linux原生串口开发 

通过sourceinsight查看跳转wiringPI库实现的串口代码,就会发现函数的实现并不困难,所以可以尝试不使用wiringPI库,自己通过Linux封装函数实现串口的通讯。

首先观察wiringPi库,其对于串口最核心的就是三个函数,serialOpen()serialPutchar()serialGetchar()所以我就自己写一个C文件来实现这三个函数(其实所谓的自己实现就是根据sourceinsight跳转这三个函数,然后删去一些我认为在使用中不必要的代码,与其说是自己实现,更不如说是对这三个函数进行一个删减,精简化),然后创建一个关于它的h文件,最后在串口通讯的函数里添加这个我写的h文件,使用我自己实现的这三个函数来完成串口的通讯。

步骤为:编写mjm_uart_tool.c -> 编写mjm_uart_tool.h -> 编写serial_mjm_test.c调用mjm_uart_tool.h来实现和刚刚使用wiringPI相同的效果

mjm_uart_tool.c:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "wiringSerial.h"int myserialOpen (const char *device, const int baud)
{struct termios options ;speed_t myBaud ;int status, fd ;switch (baud){case 9600: myBaud = B9600 ; break ;case 115200: myBaud = B115200 ; break ;}if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)return -1 ;fcntl (fd, F_SETFL, O_RDWR) ;// Get and modify current options:tcgetattr (fd, &options) ;cfmakeraw (&options) ;cfsetispeed (&options, myBaud) ;cfsetospeed (&options, myBaud) ;options.c_cflag |= (CLOCAL | CREAD) ;options.c_cflag &= ~PARENB ;options.c_cflag &= ~CSTOPB ;options.c_cflag &= ~CSIZE ;options.c_cflag |= CS8 ;options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;options.c_oflag &= ~OPOST ;options.c_cc [VMIN] = 0 ;options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds)tcsetattr (fd, TCSANOW, &options) ;ioctl (fd, TIOCMGET, &status);status |= TIOCM_DTR ;status |= TIOCM_RTS ;ioctl (fd, TIOCMSET, &status);usleep (10000) ; // 10mSreturn fd ;
}void serialSendstring (const int fd, const char *s)
{int ret;ret = write (fd, s, strlen (s));if (ret < 0)printf("Serial Puts Error\n");
}int serialGetstring (const int fd, char *buffer)
{int n_read;n_read = read(fd, buffer,32);return n_read;
}int serialDataAvail (const int fd) //用来判断串口有无数据的函数,直接复制黏贴过来的
{int result ;if (ioctl (fd, FIONREAD, &result) == -1)return -1 ;return result ;
}

mjm_uart_tool.h:

int myserialOpen (const char *device, const int baud);
void serialSendstring (const int fd, const char *s);
int serialGetstring (const int fd, char *buffer);
int serialDataAvail (const int fd);

serial_mjm_test.c:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include "mjm_uart_tool.h"void *read_serial(void *arg)
{char *sendbuf;sendbuf = (char *)malloc(32*sizeof(char));while(1){memset(sendbuf,'\0',32*sizeof(char));fgets(sendbuf,sizeof(sendbuf),stdin);serialSendstring (*((int *)arg), sendbuf) ;}pthread_exit(NULL);}void *write_serial(void *arg)
{char readbuf[32] = {'\0'};while(1){while(serialDataAvail (*((int *)arg))){serialGetstring (*((int *)arg),readbuf) ;printf("-> %s\n",readbuf);memset(readbuf,'\0',32);}}pthread_exit(NULL);
}int main ()
{int fd ;int ret;pthread_t read_thread;pthread_t write_thread;if ((fd = myserialOpen ("/dev/ttyS5", 115200)) < 0) //打开驱动文件,配置波特率{fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;return 1 ;}/*	if (wiringPiSetup () == -1){fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;return 1 ;}*/ret = pthread_create(&read_thread,NULL,read_serial,(void *)&fd);if(ret != 0){printf("read_serial create error\n");return 1;}ret = pthread_create(&write_thread,NULL,write_serial,(void *)&fd);if(ret != 0){printf("write_serial create error\n");return 1;}pthread_join(read_thread,NULL);pthread_join(write_thread,NULL);return 0 ;
}

注意,由于这里没有使用wiringPI库,所以编译不需要使用之前的build.sh脚本,直接使用gcc就可以,但是要记得链线程的库:

gcc serial_mjm_test.c mjm_uart_tool.c -lpthread

实现效果: 

发送数据:

接收数据:

可见,此时,我将serialOpen()serialPutchar()serialGetchar(),替换成了自己的myserialOpen()serialSendstring()serialGetstring();(还原封不动照搬了serialDataAvail函数),然后实现了和刚刚类似的效果,甚至还有所改进,因为我实现的接收函数可以直接介绍一整个字符串,所以可以在之前打印“->”用于区分,但是原来的serialgetchar是一个字符一个字符接收,很难实现这样的效果。

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

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

相关文章

MAC MINI 2012安装Montery折腾笔记

MAC MINI 2012安装Montery折腾笔记&#xff08;作为电视盒子/远程开发机&#xff09; 起因&#xff1a; 手头有个mac mini&#xff0c;2018年买的2手。一直都是10.12系统&#xff0c;处理python和苹果开发都受制于旧系统&#xff0c;很多软件也装不上&#xff0c;于是有了升级…

python有限差分法求解一维热传导方程

​1、方程及其离散 1.1一维热传导方程 1.2离散化 设定步长&#xff0c;依据上述方程得到递推关系&#xff1a; 2、python求解实现 import numpy as np import matplotlib.pyplot as plth 0.1#空间步长 N 30#空间步数 dt 0.0001#时间步长 M 10000#时间的步数 A dt/(h**2)…

Java8实战-总结29

Java8实战-总结29 并行数据处理与性能并行流将顺序流转换为并行流测量流性能 并行数据处理与性能 到目前为止&#xff0c;Stream接口最重要的好处是可以对这些集合执行操作流水线&#xff0c;能够自动利用计算机上的多个内核。 例如&#xff0c;在Java 7之前&#xff0c;并行…

如何开发你的第一个Vue.js插件:完整指南

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

ModbusTCP服务端

1在Device下&#xff0c;添加设备net&#xff1a; 公交车。 2在net下添加 ModbusTCP

【深度学习】 Python 和 NumPy 系列教程(十九):Matplotlib详解:2、3d绘图类型(5)3D等高线图(3D Contour Plot)

目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 0. 设置中文字体 1. 3D线框图&#xff08;3D Line Plot&#xff09; 2. 3D散点图&#xff08;3D Scatter Plot&#xff09; 3. 3D条形图&#xff08;3D Bar Plot&#xff09; 4. 3D曲面图…

MySQL数据库详解 三:索引、事务和存储引擎

文章目录 1. 索引1.1 索引的概念1.2 索引的作用1.3 如何实现索引1.4 索引的缺点1.5 建立索引的原则依据1.6 索引的分类和创建1.6.1 普通索引1.6.2 唯一索引1.6.3 主键索引1.6.4 组合索引1.6.5 全文索引 1.7 查看索引1.8 删除索引 2. 事务2.1 事务的概念2.2 事务的ACID特性2.2.1…

人机中的事实与价值时空、排序

人机结合智能与事实价值融合分析确实是未来解决复杂疑难问题的基本策略之一。该策略利用人类智慧和机器智能相结合&#xff0c;结合有效的事实和价值分析方法&#xff0c;以更全面、准确、高效地解决问题。 通过人机结合&#xff0c;可以充分发挥人类的主观能动性、判断力和创造…

2023年 python结合excel实现快速画图(零基础快速入门)

目录 1.适用人群 2.环境配置 3.基本用法 3.1 数据读取 3.2 数据分析 3.3 数据组装 3.4 制表&#xff1a; 4.快速提升 5.效果展示 1.适用人群 电脑有python环境&#xff0c;会python基本使用&#xff0c;需要短时间内完成大量画图任务的数据分析的人群。&#xff08;有…

JDK17特性

文章目录 一、JAVA17概述二、语法层面的变化1.密封类2.switch模式匹配&#xff08;预览&#xff09; 三、API层面变化1.Vector API&#xff08;第二个孵化器&#xff09;2.特定于上下文的反序列化过滤器 四、其他变化1.恢复始终严格的浮点语义2.JEP 增强型伪随机数生成器3.JEP …

C++库函数——map与set

目录 1.关联式容器是什么&#xff1f; 2.键值对 3.set ①set的介绍 ②set的模板参数列表 ③set的构造 ④set的迭代器 ⑤set的容量 ⑥set的修改与操作 ⑦set的使用举例 4.multiset ①multiset的介绍 ②multiset的使用举例 5.map ①map的介绍 ②map的模版参数列表…

HuggingFace Transformer

NLP简介 HuggingFace简介 hugging face在NLP领域最出名&#xff0c;其提供的模型大多都是基于Transformer的。为了易用性&#xff0c;Hugging Face还为用户提供了以下几个项目&#xff1a; Transformers(github, 官方文档): Transformers提供了上千个预训练好的模型可以用于不…

基于讯飞人脸算法(调用API进行人脸比对)

先看结果 必须遥遥领先 所需准备 这里我调用了&#xff1a; 人脸比对 API 文档 | 讯飞开放平台文档中心https://www.xfyun.cn/doc/face/xffaceComparisonRecg/API.html#%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E 代码里所涉及的APPID、APISecret、APIKey 皆从讯飞的控制台获取&…

市场,只能被操纵,不能被战胜

所谓市场&#xff0c;不过是千千万参与主体各自独立意志、自主行动所形成的复杂混沌的互动结果。价格&#xff0c;则是这一复杂混沌系统的涌现现象。 无数在市场中追风打浪的人&#xff0c;总是梦想着自己有朝一日能够战胜市场&#xff0c;获得超额回报。于是他们绞尽脑汁&…

Mybatis学习笔记3 在Web中应用Mybatis

Mybatis学习笔记2 增删改查及核心配置文件详解_biubiubiu0706的博客-CSDN博客 技术栈:HTMLServletMybatis 学习目标: 掌握mybatis在web应用中如何使用 Mybatis三大对对象的作用域和生命周期 关于Mybatis中三大对象的作用域和生命周期、 官网说明 ThreadLocal原理及使用 巩…

JAVA入坑之嵌套类

一、嵌套类入门 1.1概述 Java嵌套类是指在一个类中定义另一个类的一种方式&#xff0c;它可以提高代码的可读性、可维护性和封装性。Java嵌套类分为两种类型&#xff1a;静态嵌套类和非静态嵌套类。 静态嵌套类&#xff1a;Static nested classes,即类前面有static修饰符 非静…

【论文解读】Faster sorting algorithm

一、简要介绍 基本的算法&#xff0c;如排序或哈希&#xff0c;在任何一天都被使用数万亿次。随着对计算需求的增长&#xff0c;这些算法的性能变得至关重要。尽管在过去的2年中已经取得了显著的进展&#xff0c;但进一步改进这些现有的算法路线的有效性对人类科学家和计算方法…

2023-09-17 LeetCode每日一题(打家劫舍 II)

2023-09-17每日一题 一、题目编号 213. 打家劫舍 II二、题目链接 点击跳转到题目位置 三、题目描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房…

《golang设计模式》第二部分·结构型模式-05-门面模式Facade)

文章目录 1. 概述1.1 角色1.2 类图 2. 代码示例2.1 设计2.2 代码2.2 类图 1. 概述 门面&#xff08;Facade&#xff09;向客户端提供使用子系统的统一接口&#xff0c;用于简化客户端使用子系统的操作。 1.1 角色 门面角色&#xff08;Facade&#xff09; 客户端可以调用的接…

7、DVWA——SQL盲注

文章目录 一、概述二、low2.1 通关思路&#xff08;布尔盲注&#xff09;&#xff08;1&#xff09;判断是否存在SQL注入漏洞&#xff08;2&#xff09;判断属于数字型注入还是字符型注入&#xff08;3&#xff09;判断结果集中的字段数&#xff08;4&#xff09;猜数据库名长度…