Jetson Nano 入坑之路 ---- (10)C/C++语言读写UART或USB串口数据

在上一篇“Jetson Nano 入坑之路 ”系列博客中笔者讲到笔者封装的一个串口函数,本篇博客,笔者会简单易懂的讲解C语言读写串口的方法。

优化:其他博主的博客在这个串口部分大部分都有个问题,就是十六进制读取的时候,会发现,0x7F以上后,第八位被吃了。你发0xFF,但是程序始终读出来的是0x7F。因为最高位“被吃”了。本博客的程序是博主亲测实用程序。


环境准备

Jetson自带了ch34x的驱动,所以可以直接使用CH34x系列的USB-TTL作为USB串口与Jetson进行交互。在SYN6288语言播报模块笔者也用USB-TTL尝试过。

为了测试,可以安装个mincom,然后把TX和RX短接一下。


代码实现

就不吊胃口了,直接上正菜。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <iconv.h>
#include <string>
#include <iostream>

// 函数声明部分
int open_port(int com_port);
int set_uart_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits);

// 使用实例
int main()
{
    // begin::第一步,串口初始化
    int UART_fd = open_port(0);
	if (set_uart_config(UART_fd, 115200, 8, 'N', 1) < 0)
	{
		perror("set_com_config");
		exit(1);
	}
    // end::串口初始化
    
    // begin::第二步,读下位机上发的一行数据
    char str[128];
	char buff[1];
	int len = 0;
	while (1)
	{
		if (read(UART_fd, buff, 1)) {
			if (buff[0] == '\n') {
				break;
			}else {
				str[len++] = buff[0];
			}
		}
	}
    printf("content:%s\n",str);
    // end::读下位机上发的一行数据

    // begin::第三步,向下位机发送数据
    write(UART_fd, str, len);
    // end::向下位机发送数据

    return 0;
}

/*
* 打开串口
*/
int open_port(int com_port)
{
    int fd;
    /* 使用普通串口 */
    // TODO::在此处添加串口列表
    char* dev[] = { "/dev/ttyTHS1", "/dev/ttyUSB0" };

    //O_NDELAY 同 O_NONBLOCK。
    fd = open(dev[com_port], O_RDWR | O_NOCTTY);
    if (fd < 0)
    {
        perror("open serial port");
        return(-1);
    }

    //恢复串口为阻塞状态 
    //非阻塞:fcntl(fd,F_SETFL,FNDELAY)  
    //阻塞:fcntl(fd,F_SETFL,0) 
    if (fcntl(fd, F_SETFL, 0) < 0)
    {
        perror("fcntl F_SETFL\n");
    }
    /*测试是否为终端设备*/
    if (isatty(STDIN_FILENO) == 0)
    {
        perror("standard input is not a terminal device");
    }

    return fd;
}

/*
* 串口设置
*/
int set_uart_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits)
{
    struct termios opt;
    int speed;
    if (tcgetattr(fd, &opt) != 0)
    {
        perror("tcgetattr");
        return -1;
    }

    /*设置波特率*/
    switch (baud_rate)
    {
    case 2400:  speed = B2400;  break;
    case 4800:  speed = B4800;  break;
    case 9600:  speed = B9600;  break;
    case 19200: speed = B19200; break;
    case 38400: speed = B38400; break;
    default:    speed = B115200; break;
    }
    cfsetispeed(&opt, speed);
    cfsetospeed(&opt, speed);
    tcsetattr(fd, TCSANOW, &opt);

    opt.c_cflag &= ~CSIZE;

    /*设置数据位*/
    switch (data_bits)
    {
    case 7: {opt.c_cflag |= CS7; }break;//7个数据位  
    default: {opt.c_cflag |= CS8; }break;//8个数据位 
    }

    /*设置奇偶校验位*/
    switch (parity) //N
    {
    case 'n':case 'N':
    {
        opt.c_cflag &= ~PARENB;//校验位使能     
        opt.c_iflag &= ~INPCK; //奇偶校验使能  
    }break;
    case 'o':case 'O':
    {
        opt.c_cflag |= (PARODD | PARENB);//PARODD使用奇校验而不使用偶校验 
        opt.c_iflag |= INPCK;
    }break;
    case 'e':case 'E':
    {
        opt.c_cflag |= PARENB;
        opt.c_cflag &= ~PARODD;
        opt.c_iflag |= INPCK;
    }break;
    case 's':case 'S': /*as no parity*/
    {
        opt.c_cflag &= ~PARENB;
        opt.c_cflag &= ~CSTOPB;
    }break;
    default:
    {
        opt.c_cflag &= ~PARENB;//校验位使能     
        opt.c_iflag &= ~INPCK; //奇偶校验使能          	
    }break;
    }

    /*设置停止位*/
    switch (stop_bits)
    {
    case 1: {opt.c_cflag &= ~CSTOPB; } break;
    case 2: {opt.c_cflag |= CSTOPB; }   break;
    default: {opt.c_cflag &= ~CSTOPB; } break;
    }

    /*处理未接收字符*/
    tcflush(fd, TCIFLUSH);

    /*设置等待时间和最小接收字符*/
    opt.c_cc[VTIME] = 1000;
    opt.c_cc[VMIN] = 0;

    /*关闭串口回显*/
    opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH);

    /*禁止将输入中的回车翻译为新行 (除非设置了 IGNCR)*/
    opt.c_iflag &= ~ICRNL;
    /*禁止将所有接收的字符裁减为7比特*/
    opt.c_iflag &= ~ISTRIP;

    /*激活新配置*/
    if ((tcsetattr(fd, TCSANOW, &opt)) != 0)
    {
        perror("tcsetattr");
        return -1;
    }

    return 0;
}

简单讲解

将头文件和两个串口初始化和配置函数封装到uart.c或cpp里后,就可以随意使用write和read方法进行串口读写了。

第一步的串口配置方法很重要哦!!!建议也将其封装到uart库里。方便日后使用。


建议结合minicom教程SYN6288语音合成模块一起看看,这样会有更牢固的理解。

结语:喜欢本系列博客的朋友一键三连支持一下吧。想要了解相关的内容可以评论文章或私信,笔者有空就写。

  • 13
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星羽空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值