地平线机器人 · 2022年07月28日

地平线旭日X3派试用-玩转串口通信

旭日X3派开发板提供了40PIN标准接口,方便用户扩展外围设备。其中物理引脚编号8和10为串口通信发送和接收使用(8-TXD,10-RXD)。
1.png
40PIN引脚功能和位置编号如下:
2.png
串口转USB设备引脚和功能描述如下:
3.png
我们可以使用3根杜邦线 + 一个串口转USB设备(旭日X3派开发包附赠) + 一台笔记本电脑 + putty(串口工具)搭建串口通信开发环境。

如下图示:

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

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

3)10号管脚和串口转USB TXD连接
4.jpg
从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接收并打印。
5.jpg
文中所有文件,均已打包在附件中。欢迎大家一起来玩转串口通信吧

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

**本文转自地平线开发者社区
原作者:大道至简
原链接:https://developer.horizon.ai/...**
推荐阅读
关注数
1251
内容数
65
我们的使命是 AI 赋能万物 共创智能未来。我们致力于打造最实用、最好用、最易用的边缘 AI 开发平台。通过地平线自研的高算力 AI 芯片,开发工具,让更多的 AI 开发者,中小企业,学习和加速 AI 产品开发和创新!
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息