吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3525|回复: 17
收起左侧

[C&C++ 原创] C语言串口通信,自动连接设备

  [复制链接]
Cool_Breeze 发表于 2021-11-7 16:30
本帖最后由 Cool_Breeze 于 2021-12-8 13:13 编辑

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


配置文件内容如下:
[Asm] 纯文本查看 复制代码
@*
/dev/ttyUSB 5
/dev/ttyS 5



[C] 纯文本查看 复制代码
#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[30];
    int Num;
}DeviceNum, *DeviceNumP;


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

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

// 命令行解析
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[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 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[30] = "";
    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[20] = "";
    char receive[20] = "";
    char* passwd[2] = {send, receive};
    send[0] = PASSWDSTR[0][0];
    receive[0] = PASSWDSTR[0][1];

    //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[buffLen];
    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[50];
    int max = 5;
    int i = 0;
    int devIndex = 0;
    int res = 0;
    
    for (devIndex = 0; devIndex < MAXDEVICE; devIndex++){
        if (!DEVICEN[devIndex] || 
            strlen(DEVICEN[devIndex]->Name) < 2 ){
            //printf("+++%s---\n", DEVICEN[devIndex]->Name);
            continue;
        }
        for (i = 0; i < DEVICEN[devIndex]->Num; i++){
            sprintf(devName, "%s%d", DEVICEN[devIndex]->Name, i);
            // printf("---%s---\n", devName);
            fdSerial =  openPort(devName);
            if (fdSerial != 0){
                // printf("passwd:%s-%s-\n", config[0], config[1]);
                if (setSerialOpt(fdSerial, 38400) > 0 &&
                    checkDevice(fdSerial, config[0], config[1])){
                        res = 1;
                        break;
                }
                else if (setSerialOpt(fdSerial, 921600) > 0 &&
                    checkDevice(fdSerial, config[0], config[1])){
                        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[buffLen] = "";
    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[0] == receiveData[0]){
                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[line] = CHARARRAY(maxChar);
            fgets(PASSWDSTR[line], maxChar, fp);
            delChangeLineChar(PASSWDSTR[line]);
            //printf("%se\n", PASSWDSTR[line]);
        }
        else{
            line_1 = line - 1;
            DEVICEN[line_1] = DEVICENUMARRAY(1);
            dev = DEVICEN[line_1];
            fscanf(fp, "%s %d", dev->Name, &dev->Num);
        }
        if (feof(fp)){
            break;
        }
    }while( ++line < MAXLINEN);

    fclose(fp);
}

// DEBUG
void DEBUG(int fdSerial){
    char buffRcvData[buffLen] = { 0 };  
    unsigned int readDataNum = 0;  
  
    char c[10] = "";
    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], 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], 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[n] == 10 || Line[n] == 13){
            Line[n] = '\0';
            break;
        }
    }
}

免费评分

参与人数 3威望 +1 吾爱币 +22 热心值 +3 收起 理由
michiless + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zhczf + 1 + 1 我很赞同!
苏紫方璇 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

  • · Aarow|主题: 988, 订阅: 305

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

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
多谢分享。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-1-11 23:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表