【Orangepi Zero2】串口通信

【Orangepi Zero2】串口通信

1.串口基本认知

​ 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方 式的扩展接口。串行接口(Serial Interface)是指数据一位一位地顺序传送。其特点是通信线路简 单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成 本,特别适用于远距离通信,但传送速度较慢

  • 是设备间接线通信的一种方式
  • 数据一位一位地顺序传送
  • 双向通信,全双工
  • 传送速度相对较慢

1.1关于电器标准和协议

​ 串行接口按电气标准及协议来分包括RS-232-CRS-422RS485等。RS-232-C、RS-422与RS-485 标准只对接口的电气特性做出规定,不涉及接插件、电缆或协议。

RS-232

​ 也称标准串口,最常用的一种[串行通讯接口,比如我们的电脑主机的9针串口 ,最高速率为20kb/s RS-232是为点对点(即只用一对收、发设备)通讯而设计的,其传送距离最大为约15米。所以RS-232适 合本地设备之间的通信

image-20240508094737999

RS-422

​ 由于接收器采用高输入阻抗和发送驱动器比RS232更强的驱动能力,故允许在相同传输线上连接多个接 收节点,最多可接10个节点。即一个主设备(Master),其余为从设备(Slave),从设备之间不能通 信,所以RS-422支持点对多的双向通信。 RS-422的最大传输距离为1219米,最大传输速率为10Mb/s。平衡双绞线的长度与传输速率成反比

RS-485

是从RS-422基础上发展而来的,无论四线还是二线连接方式总线上可多接到32个设备。

image-20240508094904402

1.2.关于串口的电平

经常听说的UART

异步串行是指UART(Universal Asynchronous Receiver/Transmitter),通用异步接收/发送。 UART包含TTL电平的串口RS232电平的串口

RS232电平

逻辑1为-3~-15V的电压, 逻辑0为3~15V的电压

  • 笔记本通过RS232电平和单片机通信
image-20240508095407730image-20240508095416489

TTL电平
​ TTL是Transistor-Transistor Logic,即晶体管-晶体管逻辑的简称,它是计算机处理器控制的设备 内部各部分之间通信的标准技术。TTL电平信号应用广泛,是因为其数据表示采用二进制规定, +5V等价于逻辑”1”,0V等价于逻辑”0”。 数字电路中,由TTL电子元器件组成电路的电平是个电压范围,规定: 输出高电平>=2.4V,输出低电平<=0.4V; 输入高电平>=2.0V,输入低电平<=0.8V

  • 笔记本电脑通过TTL电平与单片机通信

  • TX发送线(端口)3.1

  • RX接收线 (端口)3.0

  • USB转TTL,使用ch340通信

USB转TTL,使用ch340通信

image-20240508100050034

1.3.串口通信引脚接线

  • RXD:数据输入引脚,数据接受,STC89系列对应P3.0口
  • TXD:数据发送引脚,数据发送,STC89系列对应P3.1口
  • 接线方式

image-20240508100950626

image-20240508101003421

1.3.1.串口编程要素
  • 输入/输出数据缓冲器都叫做SBUF, 都用99H地址码,但是是两个独立的8位寄存器
  • 代码体现为: 想要接收数据 char data = SBUF 想要发送数据 SBUF = data

image-20240508101146023

  • UART是异步串行接口,通信双方使用时钟不同,因为双方硬件配置不同,但是需要约定通信 速度,叫做波特率

对于电脑来说,别人做好了软件,鼠标点点点就能配置好,而苦逼单片机的波特率配置需要我们写 代码

点点点配置什么,我们代码也要配置对应参数

image-20240508101606728

89C51单片机寄存器的配置以及串口的工作模式

image-20240508101649995

字符 ‘a’ 是如何从单片机上传到PC的

a的ASSII码是97,16进制就是0x61, 二进制是01010001,这个8位就是数据位 串口工作模式1,一帧数据有10位,起始位(0),数据位,停止位(1) 那么a的一帧数据就是 0 1000 1010 1 起始位,a的低位到高位,停止位

除了速度要求,还要有数据格式,双方 暗号 对上了再发数据,所以有起始位,和停止位 的概念

image-20240508101756208

一个字节有8位,比如字母‘a’的ASSII码是十进制97,二进制是 0110 0001 ,一次从地位到高位发 送,接收也是

image-20240508101814943

2.Orangepi Zero2串口通信开发

image-20240508103305930

image-20240508103332863

Orangepi Zero2开发板有两组串口,上图那个串口是开发板刚开始登录的时候用到的,还有一组可以通过输入:gpio readall来查询,都是用的TTL针脚型接口,串口接线:TXD和RXD交叉接线,不要接错了。

串口查询

wiringP库源码:链接:https://pan.baidu.com/s/1eldtWVRGJITLHnOGZSf2bA?pwd=jq46 提取码:jq46

/*在配套的wiringPi库里面有官方给的对应的原码给它复制过来*/
cp ../wiringPiFromWindows/wiringOP-master/examples/serialTest.c .
    
    
/*LINUX里面一切皆文件每个硬件设备对应一个文件,查询串口文件*/
 ls /dev/ttyS*
/*dev串口S0用来调试信息,当然S0串口禁用掉默认串口的系统消息,也可以当成通信串口来使用,网上有各种命令和配置方式,供大家各自去研究.   dev串口S1这个板子是不支持的.
dev串口S5用来信息交互	*/
/dev/ttyS0  /dev/ttyS1  /dev/ttyS5

linux串口

2.1串口调试工具

​ 串口调试需要用到软件安信可串口调试助手,亲测好用,可以调节波特率,可以设置快捷键等。
相关下载链接:链接: https://pan.baidu.com/s/1nrq_xCjEuo78BR5pEIcDMA?pwd=vbn9 提取码: vbn9

2.2.wiringPi的串口开发与优化

/*wiringPi的串口开发与优化和串口信息交互*/
/*本代码,使用了两个线程:一个用于发送数据,另一个用于接收数据。程序首先尝试打开一个串口设备,然后创建两个线程分别处理发送和接收。发送线程从标准输入读取字符串,并通过串口发送出去。接收线程则循环检查串口是否有数据到达,并打印出来。主线程在启动了发送和接收线程后,进入一个无限循环,每10秒休眠一次*/

#include <stdio.h>    // 标准输入输出库
#include <string.h>   // 字符串操作函数库
#include <errno.h>     // 错误号定义
#include <pthread.h>   // POSIX线程库
#include <wiringPi.h>  // Wiring Pi GPIO库
#include <wiringSerial.h> // Wiring Pi 串口通信库
#include <stdlib.h>    // 通用工具库,如内存分配
#include <unistd.h>    // UNIX标准函数库,如sleep

// 串口文件描述符
int fd;

// 发送线程处理函数
void* Sendhandler() {
    char *sendBuf; // 定义发送缓冲区指针
    sendBuf = (char*)malloc(32 * sizeof(char)); // 分配32个字符的内存
    while (1) { // 无限循环
        memset(sendBuf, '\0', 32); // 清空缓冲区
        scanf("%s", sendBuf); // 从标准输入读取字符串到缓冲区
        while (*sendBuf) { // 循环直到缓冲区字符串结束
            serialPutchar(fd, *sendBuf++); // 通过串口发送当前字符
        }
    }
}

// 接收线程处理函数
void* Revhandler() {
    while (1) { // 无限循环
        while (serialDataAvail(fd)) { // 检查串口是否有数据可读取
            printf("%c", serialGetchar(fd)); // 串口接收字符并打印
            fflush(stdout); // 清空输出缓冲区,确保立即打印
        }
    }
}

// 主函数,程序的入口点
int main() {
    int count; // 用于循环计数的变量
    unsigned int nextTime; // 用于记录下一次操作的时间

    pthread_t idSend; // 发送线程的线程ID
    pthread_t idRev; // 接收线程的线程ID

    // 尝试打开串口设备,失败则打印错误并退出
    if ((fd = serialOpen("/dev/ttyS5", 115200)) < 0) {
        fprintf(stderr, "Unable to open serial device: %s\n", strerror(errno));
        return 1;
    }

    // 创建发送和接收线程
    pthread_create(&idSend, NULL, Sendhandler, NULL);
    pthread_create(&idRev, NULL, Revhandler, NULL);

    // 初始化Wiring Pi库,失败则打印错误并退出
    if (wiringPiSetup() == -1) {
        fprintf(stdout, "Unable to start wiringPi: %s\n", strerror(errno));
        return 1;
    }

    while (1) { // 主循环
        sleep(10); // 休眠10秒
    }

    printf("\n");
    return 0; // 正常退出
}

代码验证:

linux串口交互信息安信可串口交互信息

2.3.不用wiringPi,自己封装实现串口通信

如果使用的为Linux5.16内核的系统,uart5默认是关闭的,需要手动打开才能使用。
在/boot/orangepiEnv.txt中加入下面红色字体部分的配置,然后输入指令reboot,重启 Linux系统就可以打开uart5。
orangepi@orangepizero2:~$ sudo vim /boot/orangepiEnv.txt

内核

进入linux系统后,先确认下/dev下是否存在uart5的设备节点

ls /dev/ttyS5

111111

头文件:

/**
 * 打开指定的串口设备,并设置波特率。
 *
 * @param device 串口设备的路径,如 "/dev/ttyS0"。
 * @param baud 波特率值,如 B9600, B115200 等。
 * @return 如果成功,返回一个非负的文件描述符;如果失败,返回 -1。
 */
int my_serialOpen (const char *device, const int baud);

/**
 * 向指定的串口文件描述符写入一个字符串。
 *
 * @param fd 串口的文件描述符,由 my_serialOpen 函数返回。
 * @param s 要发送的字符串。
 */
void my_serialPuts(const int fd, const char *s);

/**
 * 从指定的串口文件描述符读取数据,直到遇到换行符或者读取到指定数量的字符。
 *
 * @param fd 串口的文件描述符。
 * @param buffer 存储读取数据的缓冲区。
 * @return 读取的字符数量,如果出错或到达文件末尾返回 -1。
 */
int my_serialGets(const int fd, const char *buffer);

/**
 * 从指定的串口文件描述符读取单个字符。
 *
 * @param fd 串口的文件描述符。
 * @return 如果有可用的字符,返回该字符;如果到达文件末尾或出错,返回 NULL。
 */
char* serialGetchar(const int fd);

头文件函数程序

#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>

/**
 * 打开指定的串口设备,并设置给定的波特率。
 *
 * @param device 串口设备的路径,如 "/dev/ttyS0"。
 * @param baud 波特率值,支持 9600 和 115200。
 * @return 成功返回文件描述符,失败返回 -1 或 -2。
 */
int my_serialOpen (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;
        default: return -2; // 不支持的波特率返回错误码
    }

    // 打开串口设备
    if ((fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
        return -1;

    // 设置文件描述符的标志为读写模式
    fcntl(fd, F_SETFL, O_RDWR);

    // 获取当前串口配置
    tcgetattr(fd, &options);

    // 设置串口为原始模式,无特殊处理
    cfmakeraw(&options);
    // 设置输入波特率
    cfsetispeed(&options, myBaud);
    // 设置输出波特率
    cfsetospeed(&options, myBaud);

    // 清除标志位并设置数据格式
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB; // 无奇偶校验位
    options.c_cflag &= ~CSTOPB; // 1个停止位
    options.c_cflag &= ~CSIZE; // 清除数据位
    options.c_cflag |= CS8; // 设置为8位数据位
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 非规范模式,不执行输入处理
    options.c_oflag &= ~OPOST; // 输出处理

    // 设置读取时的超时和最小接收字符数
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 100; // 10秒超时

    // 应用串口配置
    tcsetattr(fd, TCSANOW, &options);

    // 使用ioctl设置串口的DTR和RTS信号
    ioctl(fd, TIOCMGET, &status);
    status |= TIOCM_DTR;
    status |= TIOCM_RTS;
    ioctl(fd, TIOCMSET, &status);

    // 短暂延时
    usleep(10000); // 10毫秒延时

    return fd; // 返回文件描述符
}

/**
 * 向串口发送字符串。
 *
 * @param fd 串口的文件描述符。
 * @param s 要发送的字符串。
 */
void my_serialPuts(const int fd, const char *s)
{
    int n_write = write(fd, s, strlen(s)); // 写入字符串

    if(n_write == -1) // 写入失败
    {
        perror("write"); // 输出错误信息
        exit(-1); // 退出程序
    }
}

/**
 * 从串口读取数据到缓冲区。
 *
 * @param fd 串口的文件描述符。
 * @param buffer 用于存储读取数据的缓冲区。
 * @return 成功读取的字节数,失败返回 -1。
 */
int my_serialGets(const int fd, char *buffer)
{
    int n_read = read(fd, buffer, 32); // 从串口读取最多32个字节

    if(n_read == -1) // 读取失败
    {
        perror("read"); // 输出错误信息
        exit(-1); // 退出程序
    }

    return n_read; // 返回读取的字节数
}

/**
 * 从串口读取单个字符。
 *
 * @param fd 串口的文件描述符。
 * @return 成功读取的字符指针,失败返回 NULL。
 */
char* serialGetchar (const int fd)
{
    char buffer[1]; // 创建一个单字节的缓冲区
    if (read(fd, buffer, 1) != 1) // 尝试读取一个字节
        exit(-1); // 读取失败则退出

    return buffer; // 返回读取的字符
}

主程序:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

#include "mySerial.h"

// 定义串口文件描述符
int fd;

/**
 * 用于发送数据的线程函数。
 */
void* serialSend() {
    char *send_buf; // 发送缓冲区指针
    // 分配32字节的内存用于发送缓冲区,注意这里可能存在错误,sizeof(send_buf)会返回指针的大小而非所需
    send_buf = (char *)malloc(32 * sizeof(char)); // 应使用sizeof(char)

    while(1) {
        // 清除缓冲区内容
        memset(send_buf, '\0', 32);
        // 从标准输入读取一行数据到发送缓冲区
        fgets(send_buf, 32, stdin);
        // 调用自定义函数发送数据
        my_serialPuts(fd, send_buf);
    }
}

/**
 * 用于接收数据的线程函数。
 */
void* serialRecieve() {
    char *recieve_buf; // 接收缓冲区指针
    // 分配32字节的内存用于接收缓冲区,同上,sizeof(recieve_buf)可能不是期望的数值
    recieve_buf = (char *)malloc(32 * sizeof(char)); // 应使用sizeof(char)
    
    // 无限循环接收数据
    while(1) {
        // 清除缓冲区内容
        memset(recieve_buf, '\0', 32);
        // 调用自定义函数接收数据
        my_serialGets(fd, recieve_buf);
        // 打印接收到的数据
        printf("GET->%s\n", recieve_buf);
        // 刷新输出缓冲区,确保立即打印
        fflush(stdout);
    }
}

/**
 * 主函数,用于初始化和创建线程。
 */
int main() {
    pthread_t t1, t2; // 线程标识符

    // 尝试打开串口设备并设置波特率为115200
    if ((fd = my_serialOpen("/dev/ttyS5", 115200)) < 0) {
        // 如果打开串口失败,输出错误信息并退出
        fprintf(stderr, "Unable to open serial device: %s\n", strerror(errno));
        return 1;
    }

    // 创建用于发送数据的线程
    pthread_create(&t1, NULL, serialSend, NULL);
    // 创建用于接收数据的线程
    pthread_create(&t2, NULL, serialRecieve, NULL);
    
    // 主线程进入一个无限休眠状态,这里可能应该加入对线程的适当管理或退出机制
    while(1) {
        sleep(3);
    }

    // 关闭主线程,不会执行到这里,因为前面的while循环是无限的
    printf("\n");
    return 0;
}

运行结果:

串口编译

串口显示

香橙派 Orange Pi Zero2 是一款基于 ARM 架构的单板计算机,支持多种外设接口,其中包括串口通信功能。在进行串口调试时,通常需要配置硬件连接、驱动程序以及软件设置,以便实现设备与主机之间的数据交互。 ### 3.1 硬件连接 Orange Pi Zero2 提供了 UART(通用异步收发器)接口用于串口通信。常见的引脚包括: - **TXD**:发送数据引脚 - **RXD**:接收数据引脚 - **GND**:接地引脚 为了进行串口调试,用户通常需要将 Orange Pi Zero2 的 TXD 和 RXD 引脚分别连接到 USB 转 TTL 串口模块的 RXD 和 TXD 引脚,并确保 GND 连接正确。这种连接方式允许通过 USB 接口在 PC 上使用串口终端工具(如 `minicom` 或 `screen`)与 Orange Pi Zero2 进行通信。 ### 3.2 内核模块与驱动支持 在 Linux 系统中,串口设备通常由内核中的 `tty` 子系统管理。对于 Orange Pi Zero2,其使用的 Allwinner H6 芯片组依赖于内核提供的 UART 驱动程序支持。用户可以通过检查 `/dev/ttyS*` 或 `/dev/ttyAMA*` 设备文件是否存在来确认串口是否被正确识别。如果设备未被加载,可能需要手动加载相关模块或检查设备树配置。 此外,用户可能需要安装或更新适用于开发板的 Linux 内核镜像和固件包,例如 `linux-image-dev-sunxi` 和 `linux-firmware-image-dev-sunxi`,以确保串口驱动程序已包含在内核构建中 [^1]。 ### 3.3 串口终端工具配置 在完成硬件连接和驱动配置后,可以使用串口终端工具进行调试。常用的命令行工具包括: ```bash screen /dev/ttyUSB0 115200 ``` 或者使用 `minicom`: ```bash sudo minicom -D /dev/ttyUSB0 -b 115200 ``` 其中 `/dev/ttyUSB0` 是串口设备路径,`115200` 是波特率设置。这些参数应根据实际连接情况调整。 ### 3.4 应用场景 串口调试常用于以下场景: - **系统启动调试**:查看引导过程中的日志输出,帮助诊断启动失败问题。 - **应用程序调试**:通过串口打印调试信息,便于分析运行时错误。 - **嵌入式开发**:在没有图形界面的情况下,直接与设备交互执行命令。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值