赞不绝口的UART库 uart.c uart.h

71 阅读6分钟
#ifndef UART_H
#define UART_H

#include <termios.h>
#include <stdint.h>

// 打开串口
int open_port(int fd, int comport);

// 设置串口参数
int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop);

// 写入4字节数据
int write_4byte(int fd, unsigned int addr, unsigned int value);

// 读取4字节数据
uint32_t read_4byte(int fd, unsigned int addr, unsigned int *value);

// 关闭串口
int close_port(int fd);

// 测试串口通信
void test(void);

#endif // UART_H
#include "uart.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>


//#define DELAY_TIME 100000
#define DELAY_TIME 30000

int open_port(int fd, int comport)
{
    switch (comport)
    {
    case 0:
        fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
        break;
    case 1:
        fd = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NDELAY);
        break;
    case 2:
        fd = open("/dev/ttyUSB2", O_RDWR | O_NOCTTY | O_NDELAY);
        break;
    case 3:
        fd = open("/dev/ttyUSB3", O_RDWR | O_NOCTTY | O_NDELAY);
        break;
    case 4:
        fd = open("/dev/ttyUSB4", O_RDWR | O_NOCTTY | O_NDELAY);
        break;
    default:
        perror("Invalid comport number");
        return -1;
    }

    if (fd == -1)
    {
        perror("Can't Open Serial Port");
        return -1;
    }
    /*恢复串口为阻塞状态*/

    if (fcntl(fd, F_SETFL, 0) < 0)
    {
        printf("fcntl failed!\n");
    }
    else
    {
        printf("fcntl=%d\n", fcntl(fd, F_SETFL, 0));
    }
    /*测试是否为终端设备*/
    if (isatty(STDIN_FILENO) == 0)
    {
        printf("standard input is not a terminal device\n");
    }
    else
    {
        printf("isatty success!\n");
    }

    printf("fd-open=%d\n", fd);
    return fd;
}

int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio, oldtio;
    /*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/
    if (tcgetattr(fd, &oldtio) != 0)
    {
        perror("SetupSerial 1");
        return -1;
    }

    bzero(&newtio, sizeof(newtio));
    /*步骤一,设置字符大小*/
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
    /*设置停止位*/
    switch (nBits)
    {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    default:
        perror("Invalid number of bits");
        return -1;
    }
    /*设置奇偶校验位*/
    switch (nEvent)
    {
    case 'O': // 奇数
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= (INPCK | ISTRIP);
        break;
    case 'E': // 偶数
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        break;
    case 'N': // 无奇偶校验位
        newtio.c_cflag &= ~PARENB;
        break;
    default:
        perror("Invalid parity");
        return -1;
    }
    /*设置波特率*/
    switch (nSpeed)
    {
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    case 460800:
        cfsetispeed(&newtio, B460800);
        cfsetospeed(&newtio, B460800);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
    /*设置停止位*/
    if (nStop == 1)
    {
        newtio.c_cflag &= ~CSTOPB;
    }
    else if (nStop == 2)
    {
        newtio.c_cflag |= CSTOPB;
    }
    else
    {
        perror("Invalid stop bits");
        return -1;
    }
    /*设置等待时间和最小接收字符*/
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;
    /*处理未接收字符*/
    tcflush(fd, TCIFLUSH);
    /*激活新配置*/
    if (tcsetattr(fd, TCSANOW, &newtio) != 0)
    {
        perror("com set error");
        return -1;
    }

    printf("set done!\n");
    return 0;
}

int close_port(int fd)
{
    if (close(fd) == -1)
    {
        perror("Failed to close the port");
        return -1;
    }
    printf("Port closed successfully\n");
    return 0;
}

// 写入4字节数据
int write_4byte(int fd, unsigned int addr, unsigned int value)
{
    char command[32];
    snprintf(command, sizeof(command), "mw 0x%x 0x4 0x%x\n", addr, value);
    int nwrite = write(fd, command, strlen(command));
    if (nwrite < 0)
    {
        perror("write error");
    }
    usleep(DELAY_TIME);
    char buf[1024] = {0};
    int nread = read(fd, buf, sizeof(buf));
    if (nread < 0)
    {
        perror("read error");
        return nread;
    }
    usleep(DELAY_TIME);
    // printf("\n---------------8082\n%s\n", buf);

    return nwrite;
}

int strstr_custom(const char *haystack, const char *needle)
{
    // 如果needle为空字符串,则认为是找到了,位置为0
    if (!*needle)
        return 0;

    // 遍历haystack字符串
    for (const char *p = haystack; *p != '\0'; p++)
    {
        // 如果当前字符与needle的第一个字符匹配
        if (*p == *needle)
        {
            // 尝试匹配needle的剩余部分
            const char *begin = p, *q = needle;
            while (*q != '\0' && *p == *q)
            {
                p++;
                q++;
            }
            // 如果完全匹配了needle
            if (!*q)
            {
                // 返回匹配开始的位置(基于haystack的起始位置)
                return begin - haystack;
            }
            // 如果不匹配,p回退到下一个字符继续比较
            p = begin;
        }
    }

    // 没有找到匹配项
    return -1;
}

// 读取4字节数据
uint32_t read_4byte(int fd, unsigned int addr, unsigned int *value)
{
    char command[32];
    snprintf(command, sizeof(command), "mr 0x%x 0x4 0x1\n", addr);

    int nwrite = write(fd, command, strlen(command));
    if (nwrite < 0)
    {
        perror("write error");
        return nwrite;
    }

    usleep(DELAY_TIME);

    char buf[1024] = {0};
    int nread = read(fd, buf, sizeof(buf));
    if (nread < 0)
    {
        perror("read error");
        return nread;
    }
    usleep(DELAY_TIME);

    char strAddr[32] = {0};
    sprintf(strAddr, "%x:", addr);
    // printf("\n---------------strAddr\n%s\n", strAddr);
    int pos = strstr_custom(buf, strAddr);
    if (pos == -1)
        return 0;

    char strValue[11] = {0};
    pos += 10;
    for (size_t i = 0; i < 8; i++)
    {
        strValue[i] = buf[pos++];
    }
    // printf("\n---------------strValue\n%s\n", strValue);
    *value = strtol(strValue, NULL, 16);

    return nread;
}

/*测试串口程序*/
void test(void)
{
    int fd = 0; // 初始化 fd 变量
    if ((fd = open_port(fd, 0)) < 0)
    {
        perror("open_port error");
        return;
    }

    if (set_opt(fd, 115200, 8, 'N', 1) < 0)
    {
        perror("set_opt error");
        close_port(fd);
        return;
    }

    printf("fd=%d\n", fd);
    unsigned int addr  = 0x5a10b030;
    unsigned int value = 0xffffffff;
    // 写入4字节数据
    write_4byte(fd, addr, value);

    // 读取4字节数据
    read_4byte(fd, addr, &value);
    close_port(fd);
}

/*写串口程序*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>

int open_port(int fd, int comport)
{
     char *dev[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2"};
     long vdisable;

     if (comport == 1) // 串口1
     {
          fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
          if (-1 == fd)
          {
               perror("Can't Open Serial Port");
               return (-1);
          }
     }
     else if (comport == 2) // 串口2
     {
          fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY);
          if (-1 == fd)
          {
               perror("Can't Open Serial Port");
               return (-1);
          }
     }
     else if (comport == 3) // 串口3
     {
          fd = open("/dev/ttyS2", O_RDWR | O_NOCTTY | O_NDELAY);
          if (-1 == fd)
          {
               perror("Can't Open Serial Port");
               return (-1);
          }
     }
     /*恢复串口为阻塞状态*/
     if (fcntl(fd, F_SETFL, 0) < 0)
          printf("fcntl failed!\n");
     else
          printf("fcntl=%d\n", fcntl(fd, F_SETFL, 0));
     /*测试是否为终端设备*/
     if (isatty(STDIN_FILENO) == 0)
          printf("standard input is not a terminal device\n");
     else
          printf("isatty success!\n");
     printf("fd-open=%d\n", fd);
     return fd;
}

int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
     struct termios newtio, oldtio;
     /*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/
     if (tcgetattr(fd, &oldtio) != 0)
     {
          perror("SetupSerial 1");
          return -1;
     }
     bzero(&newtio, sizeof(newtio));
     /*步骤一,设置字符大小*/
     newtio.c_cflag |= CLOCAL | CREAD;
     newtio.c_cflag &= ~CSIZE;
     /*设置停止位*/
     switch (nBits)
     {
     case 7:
          newtio.c_cflag |= CS7;
          break;
     case 8:
          newtio.c_cflag |= CS8;
          break;
     }
     /*设置奇偶校验位*/
     switch (nEvent)
     {
     case 'O': // 奇数
          newtio.c_cflag |= PARENB;
          newtio.c_cflag |= PARODD;
          newtio.c_iflag |= (INPCK | ISTRIP);
          break;
     case 'E': // 偶数
          newtio.c_iflag |= (INPCK | ISTRIP);
          newtio.c_cflag |= PARENB;
          newtio.c_cflag &= ~PARODD;
          break;
     case 'N': // 无奇偶校验位
          newtio.c_cflag &= ~PARENB;
          break;
     }
     /*设置波特率*/
     switch (nSpeed)
     {
     case 2400:
          cfsetispeed(&newtio, B2400);
          cfsetospeed(&newtio, B2400);
          break;
     case 4800:
          cfsetispeed(&newtio, B4800);
          cfsetospeed(&newtio, B4800);
          break;
     case 9600:
          cfsetispeed(&newtio, B9600);
          cfsetospeed(&newtio, B9600);
          break;
     case 115200:
          cfsetispeed(&newtio, B115200);
          cfsetospeed(&newtio, B115200);
          break;
     case 460800:
          cfsetispeed(&newtio, B460800);
          cfsetospeed(&newtio, B460800);
          break;
     default:
          cfsetispeed(&newtio, B9600);
          cfsetospeed(&newtio, B9600);
          break;
     }
     /*设置停止位*/
     if (nStop == 1)
          newtio.c_cflag &= ~CSTOPB;
     else if (nStop == 2)
          newtio.c_cflag |= CSTOPB;
     /*设置等待时间和最小接收字符*/
     newtio.c_cc[VTIME] = 0;
     newtio.c_cc[VMIN] = 0;
     /*处理未接收字符*/
     tcflush(fd, TCIFLUSH);
     /*激活新配置*/
     if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
     {
          perror("com set error");
          return -1;
     }
     printf("set done!\n");
     return 0;
}

/*读串口程序*/
int main(void)
{
     int fd;
     int nread, nwrite, i;
     char buff[] = "Hello\n";

     if ((fd = open_port(fd, 1)) < 0)
     { // 打开串口
          perror("open_port error");
          return;
     }
     if ((i = set_opt(fd, 115200, 8, 'N', 1)) < 0)
     { // 设置串口
          perror("set_opt error");
          return;
     }
     printf("fd=%d\n", fd);
     fd = 3;
     nread = read(fd, buff, 8); // 读串口
     printf("nread=%d,%s\n", nread, buff);
     nwrite = write(fd, buff, 8); // 写串口
     printf("nread=%d,%s\n", nread, buff);
     close(fd);
     return;
}