旭日X3派开发板提供了40PIN标准接口,方便用户扩展外围设备。其中物理引脚编号8和10为串口通信发送和接收使用(8-TXD,10-RXD)。

40PIN引脚功能和位置编号如下:

串口转USB设备引脚和功能描述如下:

我们可以使用3根杜邦线 + 一个串口转USB设备(旭日X3派开发包附赠) + 一台笔记本电脑 + putty(串口工具)搭建串口通信开发环境。

如下图示:

1)6号管脚和串口转USB GND连接

2)8号管脚和串口转USB RXD连接

3)10号管脚和串口转USB TXD连接

从40PIN管脚功能图我们知道,8号和10号管脚为UART3,对应的设备文件为 /dev/ttyS3。

环境搭建完成后,我们来编写一个简单的程序库操作串口。

//头文件

#ifndef SERIAL_H
#define SERIAL_H

typedef struct Serial Serial;

struct Serial
{
int (*Open)(Serial *pDevice, const char *sDevice, int baudrate);
void (*Close)(Serial *pDevice);
int (*Write)(Serial *pDevice, const char *buf, int len);
int (*Read)(Serial *pDevice, char *buf, int len);
};

Serial* CreateSerialDevice();

void DestroySerialDevice(Serial *pDevice);

#endif //SERIAL

//实现文件

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include "serial.h"

typedef struct SerialImpl
{
Serial base;
int handle;
int baudrate;
char sDevice[64];

}SerialImpl;

int speed_arr[] = {B1500000, B1152000, B1000000, B921600,
B576000, B500000, B460800, B230400, B115200, B57600,
B38400, B19200, B9600, B4800, B2400, B1800, B1200,
B600, B300, B200, B150, B134, B110, B75, B50, B0};

int baudrate_arr[] = {1500000, 1152000, 1000000, 921600,
576000, 500000, 460800, 230400, 115200, 57600,
38400, 19200, 9600, 4800, 2400, 1800, 1200,
600, 300, 200, 150, 134, 110, 75, 50, 0};

int serial_setting(Serial *pDevice, int baudrate);
void serial_close(Serial *pDevice);

int serial_comspeed_get(int baudrate)
{
for (int i = 0; i < sizeof(baudrate_arr)/ sizeof(baudrate_arr[0]); ++i)
{
if (baudrate_arr[i] == baudrate)
{
return speed_arr[i];
}
}

return -1;
}

int serial_open(Serial *pDevice, const char *sDevice, int baudrate)
{
int handle = -1;
SerialImpl *impl = (SerialImpl*)pDevice;
if (!impl)
{
return -1;
}

if (!sDevice || sDevice[0] == '\0')
{
return -2;
}

handle = open(sDevice, O_RDWR, 0);
if (-1 == handle)
{
perror("open");
return -3;
}

impl->handle = handle;
snprintf(impl->sDevice, sizeof(impl->sDevice), "%s", sDevice);

if (0 != serial_setting(pDevice, baudrate))
{
serial_close(pDevice);
return -4;
}

return 0;
}

int serial_setting(Serial *pDevice, int baudrate)
{
int handle = -1;
int speed = 0;
struct termios options;
SerialImpl *impl = (SerialImpl*)pDevice;
if (!impl)
{
return -1;
}

handle = impl->handle;
if (handle <= 0)
{
return -2;
}

speed = serial_comspeed_get(baudrate);
if (speed < 0)
{
return -3;
}

impl->baudrate = baudrate;

if (tcgetattr(handle, &options) != 0)
{
perror("tcgetattr");
return -4;
}

if (cfsetispeed(&options, speed) != 0 || cfsetispeed(&options, speed) != 0)
{
perror("cfsetispeed");
return -5;
}

//no partity
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;

//8bits
options.c_cflag |= CS8;

//stop 1bits
options.c_cflag &= ~CSTOPB;

//no flow control
options.c_cflag &= ~CRTSCTS;

options.c_cflag &= ~CSIZE;

if (tcsetattr(handle, TCSANOW, &options) != 0)
{
perror("tcsetattr");
return -6;
}

return 0;
}

int serial_read(Serial *pDevice, char *buf, int len)
{
int handle = -1;
int size = 0;
SerialImpl *impl = (SerialImpl*)pDevice;
if (!impl)
{
return -1;
}

handle = impl->handle;
if (handle <= 0)
{
return -2;
}

if (!buf || len <= 0)
{
return -3;
}

size = read(handle, buf, len);
if (-1 == size)
{
perror("read");
return -4;
}

return size;
}

int serial_write(Serial *pDevice, const char *buf, int len)
{
int handle = -1;
int size = 0;
SerialImpl *impl = (SerialImpl*)pDevice;
if (!impl)
{
return -1;
}

handle = impl->handle;
if (handle <= 0)
{
return -2;
}

if (!buf || len <= 0)
{
return -3;
}

size = write(handle, buf, len);
if (-1 == size)
{
perror("write");
return -4;
}

return size;
}

void serial_close(Serial *pDevice)
{
int handle = -1;
SerialImpl *impl = (SerialImpl*)pDevice;
if (!impl)
{
return;
}

handle = impl->handle;
if (handle != -1)
{
close(handle);
}
}

Serial* CreateSerialDevice()
{
SerialImpl *pDevice = (SerialImpl*)malloc(sizeof(SerialImpl));
if (pDevice)
{
pDevice->base.Open = serial_open;
pDevice->base.Close = serial_close;
pDevice->base.Write = serial_write;
pDevice->base.Read = serial_read;
pDevice->handle = -1;
pDevice->baudrate = 0;
pDevice->sDevice[0] = '\0';
}

return (Serial*)pDevice;
}

void DestroySerialDevice(Serial *pDevice)
{
if (pDevice)
{
pDevice->Close(pDevice);
free(pDevice);
}
}

//测试文件

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include "serial.h"

int main(int argc, char *argv[])
{
char sbuf[128];
int count;
int size;
int ret;

Serial *port = CreateSerialDevice();
assert(port != NULL);

ret = port->Open(port, "/dev/ttyS3", 921600);
assert(ret == 0);

while (1)
{
snprintf(sbuf, sizeof(sbuf), "%d", count++);
size = port->Write(port, sbuf, strlen(sbuf));
assert(size != -1);
usleep(1000*1000);
}

port->Close(port);
DestroySerialDevice(port);

return 0;
}

//工程文件

cmake_minimum_required(VERSION 3.0)
project(serial)
set(CMAKE_BUILD_TYPE "Debug")
add_library(serial SHARED serial.c)
add_executable(echo echo.c)
target_link_libraries(echo serial)

测试结果:

X3派侧echo每隔1s发送一次递增数据,PC侧putty接收并打印。

文中所有文件,均已打包在附件中。欢迎大家一起来玩转串口通信吧

「地平线旭日X3派,开启你的嵌入式开发之旅」,欢迎正在阅读的你申请试用,一起交流开发心得

本文转自地平线开发者社区

原作者:大道至简

原链接:https://developer.horizon.ai/forumDetail/98129540173361338