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;
}
}
}
同样,有段时间我的确对python很感兴趣,对于不要求效率的很多地方,的确很方便!但是各类的不兼容性,版本的稳定性,不同版本环境的各种奇怪问题。。。也许暂水平有限,精力有限,所以还是继续玩VC吧。。。 感谢分享!不知能否发布一个成品?能监控被占用的端口吗? zxxiaopi 发表于 2021-11-7 17:15
感谢分享!不知能否发布一个成品?能监控被占用的端口吗?
这个不了解,成品只需要 gcc 编译一下就可以了!
gcc source.c 多谢分享,下来试试好不好用 感谢发布原创作品,吾爱破解论坛因你更精彩! moonlune 发表于 2021-11-7 19:59
同样,有段时间我的确对python很感兴趣,对于不要求效率的很多地方,的确很方便!但是各类的不兼容性,版本 ...
没办法, 能用python的我还是喜欢它,人生苦短。哈哈! 谢谢分享。。。 直接用 PComm.dll 二次开发。方便。
多谢分享。
页:
[1]
2