Cool_Breeze 发表于 2021-11-7 16:30

C语言串口通信,自动连接设备

本帖最后由 Cool_Breeze 于 2021-12-8 13:13 编辑

这个问题到现在也没有解决(太多坑了!),只能换个语言干了!
能写出来,还是多亏了百度,和前辈们的分享!
但是有时候会报 do_IRQ 没有向量错误!


配置文件内容如下:
@*
/dev/ttyUSB 5
/dev/ttyS 5



#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>

#include <termios.h> //set baud rate

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>

// 读取配置文件最大行数
#define MAXLINEN 10
// 最多支持扫描的类型数
#define MAXDEVICE 6
// 开辟内存空间
#define CHARARRAY(LEN) (char*)calloc(LEN, sizeof(char))
#define DEVICENUMARRAY(LEN) (DeviceNumP)calloc(LEN, sizeof(DeviceNum))

//接受数据容器大小
#define buffLen 1024
// 延时
#define rcvTimeOut 200

// 遍历时用的串口名和数量
// eg: /dev/ttyUSB 5
typedef struct deviceNum{
    char Name;
    int Num;
}DeviceNum, *DeviceNumP;


// 配置文件名
static char* configName = "status";
// 文件第一行内容 核对的信息行
char* PASSWDSTR = {NULL};
// 配置文件设备类型, 扫描数量
// eg: /dev/ttyUSB 5
DeviceNumP DEVICEN = {NULL};

// 波特率
static int BPS;
// 串口名
static char DEVNAME;

// 命令行解析
static const struct option long_option[] = {
    {"send", required_argument, NULL, 's'},
    {NULL, 0, NULL, 0}
};

/*
自动扫描串口设备
连接上设备后,发送信息验证返回信息,确保连接正确。
passwd 指针数组
位置信息:
    0 要发送的信息
    1 核对的信息
返回值为 fdSerial 错误返回 0
*/
int autoMaticAddressing(char** passwd);

/*
设置串口信息
fdSerial 串口文件描述符
pbs 波特率
*/
int setSerialOpt(int fdSerial, int pbs);

/*
核对连接上的串口设备是正确的设备
fdSerial 串口文件描述符
send 要发送的信息
receive 核对的信息
*/
int checkDevice(int fdSerial, char* send, char* receive);

/*
调试串口使用
fdSerial 串口文件描述符
*/
void DEBUG(int fdSerial);

/*
输出已连接上设备的波特率
*/
void putBaudrate();

/*
读取本地文件中的配置信息
*/
void getConfigFile();

/*
释放指针数组空间
*/
void freeCharArray(char** array);
/*
释放指针数组空间
*/
void freeDeviceNumArray(DeviceNum** array);
/*
删除换行符 \r \n
*/
void delChangeLineChar(char* Line);
/*-----------------------------------------------------*/
/*******************************************************/

/*************Linux and Serial Port *********************/
/*************Linux and Serial Port *********************/
int openPort(char* devName)
{
    int fd = 0;

    fd= open(devName, O_RDWR | O_NOCTTY | O_NDELAY);
    if (-1 == fd)
    {
      // perror("Can't Open Serial Port");
      return(0);
    }

    // 阻塞文件
    if (fcntl(fd, F_SETFL, 0)<0)
    {
      //printf("fcntl failed!\n");
    }
    else
    {
      fcntl(fd, F_SETFL, 0);
      //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("is a tty success!\n");
    }
    //printf("fd-open=%d\n", fd);
    */
   
    strcpy(DEVNAME, devName);
    return fd;
}

int setOpt(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 38400:
      cfsetispeed(&newtio, B38400);
      cfsetospeed(&newtio, B38400);
      BPS = 38400;
      break;
    case 921600:
      cfsetispeed(&newtio, B921600);
      cfsetospeed(&newtio, B921600);
      BPS = 921600;
      break;
    case 115200:
      BPS = 115200;
      cfsetispeed(&newtio, B115200);
      cfsetospeed(&newtio, B115200);
      break;
    default:
      BPS = 38400;
      cfsetispeed(&newtio, B38400);
      cfsetospeed(&newtio, B38400);
      break;
    }
    if (nStop == 1)
    {
      newtio.c_cflag &= ~CSTOPB;
    }
    else if (nStop == 2)
    {
      newtio.c_cflag |= CSTOPB;
    }
    newtio.c_cc = 0;
    newtio.c_cc = 0;
    tcflush(fd, TCIFLUSH);
    if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
    {
      //perror("com set error");
      return -1;
    }
    //printf("---------- set done! ----------\n");
    return 0;
}

int readDataTty(int fd, char *rcv_buf, int TimeOut, int Len)
{
    int retval;
    fd_set rfds;
    struct timeval tv;
    int ret, pos;
    tv.tv_sec = TimeOut / 1000;//set the rcv wait time   
    tv.tv_usec = TimeOut % 1000 * 1000;//100000us = 0.1s   

    pos = 0;
    while (1)
    {
      FD_ZERO(&rfds);
      FD_SET(fd, &rfds);
      retval = select(fd + 1, &rfds, NULL, NULL, &tv);
      if (retval == -1)
      {
            //perror("select check is it readable error!");
            break;
      }
      else if (retval)
      {
            ret = read(fd, rcv_buf + pos, 1);
            if (-1 == ret)
            {
                break;
            }

            pos++;
            if (Len <= pos)
            {
                break;
            }
      }
      else
      {
            break;
      }
    }

    return pos;
}

int sendDataTty(int fd, char *send_buf, int Len)
{
    ssize_t ret;

    ret = write(fd, send_buf, Len);
    if (ret == -1)
    {
      printf("write device error\n");
      return -1;
    }

    return 1;
}




int main(int argc, char** argv)
{
    char argvSend = "";
    int opt = 0;
    while ((opt = getopt_long(argc, argv, "s:", long_option, NULL)) != -1){
      switch(opt){
            case 0: break;
            case 's': strcpy(argvSend, optarg);
      }
    }
    //printf("%s \n", argvSend);
    int fdSerial = 0;

    getConfigFile();
    char send = "";
    char receive = "";
    char* passwd = {send, receive};
    send = PASSWDSTR;
    receive = PASSWDSTR;

    //openPort
    if ((fdSerial = autoMaticAddressing(passwd)) == 0)
    {
      printf("Failed to connect to serial device!\n");
      freeCharArray(PASSWDSTR);
      freeDeviceNumArray(DEVICEN);   
      return 1;
    }

    //printf("Serial fdSerial=%d\n", fdSerial);

    tcflush(fdSerial, TCIOFLUSH);//清掉串口缓存
    fcntl(fdSerial, F_SETFL, 0);
    //DEBUG(fdSerial);

    char buffRcvData;
    sendDataTty(fdSerial, argvSend, sizeof(argvSend));
    int readDataNum = 0;
         readDataNum = readDataTty(fdSerial, buffRcvData, rcvTimeOut, buffLen);
    close(fdSerial);
   
    // 释放申请的内存空间
    freeCharArray(PASSWDSTR);
    freeDeviceNumArray(DEVICEN);   
   
    return 0;
}

// 自动寻址
int autoMaticAddressing(char** config){
    int fdSerial = 0;
    char devName;
    int max = 5;
    int i = 0;
    int devIndex = 0;
    int res = 0;
   
    for (devIndex = 0; devIndex < MAXDEVICE; devIndex++){
      if (!DEVICEN ||
            strlen(DEVICEN->Name) < 2 ){
            //printf("+++%s---\n", DEVICEN->Name);
            continue;
      }
      for (i = 0; i < DEVICEN->Num; i++){
            sprintf(devName, "%s%d", DEVICEN->Name, i);
            // printf("---%s---\n", devName);
            fdSerial =openPort(devName);
            if (fdSerial != 0){
                // printf("passwd:%s-%s-\n", config, config);
                if (setSerialOpt(fdSerial, 38400) > 0 &&
                  checkDevice(fdSerial, config, config)){
                        res = 1;
                        break;
                }
                else if (setSerialOpt(fdSerial, 921600) > 0 &&
                  checkDevice(fdSerial, config, config)){
                        res = 1;
                        break;
                }
            }
      }
      if (res){
            break;
      }
    }
    if (res){
      putBaudrate();
    }
    else{
      fdSerial = 0;
    }
    return fdSerial;
}

// 设置串口信息
int setSerialOpt(int fdSerial, int pbs){

    if (setOpt(fdSerial, pbs, 8, 'N', 1) < 0)
    {
      // perror("set_opt error");
      return 0;
    }
    // printf("--- OK ---\n");
    return 1;
}

// 验证设备
int checkDevice(int fdSerial, char* send, char* receive){
    char receiveData = "";
    int readDataNum = 0;
    sendDataTty(fdSerial, send, sizeof(send));
         readDataNum = readDataTty(fdSerial, receiveData, rcvTimeOut, buffLen);
    //printf("%d == %s\n", readDataNum, receiveData);
    if (readDataNum == 1){
      if (receive == receiveData){
                return 1;
      }
    }
    else if (readDataNum > 1){
      if (strcmp(receiveData, receive) == 0){
            return 1;
      }
      else{
            return 0;
      }
    }
    else{
      return 0;
    }
}

// 打印波特率
void putBaudrate(){
    printf("--------------------\n");
    printf("Device   = %s\n", DEVNAME);
    printf("Baudrate = %d\n", BPS);
    printf("--------------------\n");
}

// 读取配置文件
void getConfigFile(){
    FILE* fp = NULL;
    fp = fopen(configName, "r");
    int maxChar = 20;

    int line = 0;
    int line_1 = 0;
    DeviceNumP dev;
    do{
      //fseek(fp, SEEK_END, 0);
      if (line == 0){
            PASSWDSTR = CHARARRAY(maxChar);
            fgets(PASSWDSTR, maxChar, fp);
            delChangeLineChar(PASSWDSTR);
            //printf("%se\n", PASSWDSTR);
      }
      else{
            line_1 = line - 1;
            DEVICEN = DEVICENUMARRAY(1);
            dev = DEVICEN;
            fscanf(fp, "%s %d", dev->Name, &dev->Num);
      }
      if (feof(fp)){
            break;
      }
    }while( ++line < MAXLINEN);

    fclose(fp);
}

// DEBUG
void DEBUG(int fdSerial){
    char buffRcvData = { 0 };
    unsigned int readDataNum = 0;

    char c = "";
    int sendNum = 10;
    while (1){
      scanf("%s", c);
            printf("send: %s\n", c);
      sendDataTty(fdSerial, c, sendNum);
      printf("rec:      %s\n", buffRcvData);
      readDataNum = 0;
             readDataNum = readDataTty(fdSerial, buffRcvData, rcvTimeOut, buffLen);
            printf("recevie %d -----\n", readDataNum);
    }
}

//释放内存空间
void freeCharArray(char** array){
    char* line = NULL;
    int n = 0;
    for (n = 0; n < MAXLINEN; line = array, n++){
      if (!line){
            continue;
      }
      //printf("%d:%s\n",n, line);
      free(line);
    }
}

//释放内存空间
void freeDeviceNumArray(DeviceNum** array){
    DeviceNumP line = NULL;
    int n = 0;
    for (n = 0; n < MAXDEVICE; line = array, n++){
      if (!line){
            continue;
      }
      //printf("%s:%d\n",line->Name, line->Num);
      free(line);
    }
}
//删除换行符
void delChangeLineChar(char* Line){
    int Len = strlen(Line);
    int n = 0;
    for (n = 0; n < Len; n++){
      if (Line == 10 || Line == 13){
            Line = '\0';
            break;
      }
    }
}

moonlune 发表于 2021-11-7 19:59

同样,有段时间我的确对python很感兴趣,对于不要求效率的很多地方,的确很方便!但是各类的不兼容性,版本的稳定性,不同版本环境的各种奇怪问题。。。也许暂水平有限,精力有限,所以还是继续玩VC吧。。。

zxxiaopi 发表于 2021-11-7 17:15

感谢分享!不知能否发布一个成品?能监控被占用的端口吗?

Cool_Breeze 发表于 2021-11-7 17:41

zxxiaopi 发表于 2021-11-7 17:15
感谢分享!不知能否发布一个成品?能监控被占用的端口吗?

这个不了解,成品只需要 gcc 编译一下就可以了!
gcc source.c

endriver 发表于 2021-11-7 19:19

多谢分享,下来试试好不好用

Znyu 发表于 2021-11-7 20:32

        感谢发布原创作品,吾爱破解论坛因你更精彩!

Cool_Breeze 发表于 2021-11-7 20:37

moonlune 发表于 2021-11-7 19:59
同样,有段时间我的确对python很感兴趣,对于不要求效率的很多地方,的确很方便!但是各类的不兼容性,版本 ...

没办法, 能用python的我还是喜欢它,人生苦短。哈哈!

天南地北一群魔 发表于 2021-11-7 22:08

谢谢分享。。。

yjd333 发表于 2021-11-7 23:35

直接用 PComm.dll 二次开发。方便。

happyxuexi 发表于 2021-11-8 10:11

多谢分享。
页: [1] 2
查看完整版本: C语言串口通信,自动连接设备