【问题标题】:serial communication with mark and space parity带有标记和空间奇偶校验的串行通信
【发布时间】:2014-05-05 06:40:55
【问题描述】:

在通过how to open, read, and write from serial port in C 中的@wallyk 回答后,我编写了一个程序来通过我的USB 端口发送数据。我需要发送一个 6 字节的数据,其中第一个字节应该是标记奇偶校验,其余的应该是空间奇偶校验。这就是我声明 2 个变量 msg1 和 msg2 的原因

#include<stdio.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include<fcntl.h>// used for opening ttys0
#include<sys/ioctl.h>
#include<sched.h>
#include<string.h> // for memset
#include<time.h>

int set_interface_attribs (int fd, int speed, int parity)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty); // initialize all in struct tty with 0
        if (tcgetattr (fd, &tty) != 0)// gets parameters from fd and stores them in tty struct 
        {
                perror("error from tcgetattr");
                return -1;
        }

        cfsetospeed (&tty, speed);
        cfsetispeed (&tty, speed);

        tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars, CSIZE -> character size mask
        // disable IGNBRK for mismatched speed tests; otherwise receive break
        // as \000 chars
        tty.c_iflag &= ~IGNBRK;         // ignore break signal
        tty.c_lflag = 0;                // no signaling chars, no echo,
                                        // no canonical processing
        tty.c_oflag = 0;                // no remapping, no delays
        tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
        tty.c_cflag |= parity;
        tty.c_cflag &= ~CSTOPB;// 1 stop bit    
        tty.c_cflag &= ~CRTSCTS;

        if (tcsetattr (fd, TCSANOW, &tty) != 0) // TCSANOW -> the change takes place immediately
        {
                perror("error from tcsetattr");
                return -1;
        }
        return 0;
}

int main()
{
char *portname = "/dev/ttyUSB0";
int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
        perror("error opening");
        return;
}
char msg1[1]={0x01};
char msg2[5]={0x02,0x08,0x00,0xff,0xf5};    
set_interface_attribs (fd, B115200,PARENB|PARODD|CMSPAR);  // set speed to 115200, bps,mark parity
                // set no blocking
write (fd, msg1, sizeof msg1);    
set_interface_attribs (fd, B115200,PARENB|CMSPAR); // set speed to 115200 bps, space parity   
write (fd,msg2,sizeof msg2);
close(fd);
return 0;
}

但是现在我发送的所有数据似乎都是空间奇偶校验而不是标记奇偶校验。即,如果我已将第一个字节配置为以标记奇偶校验发送,其余字节以空间奇偶校验发送,那么所有字节都以空间奇偶校验发送。现在,如果我将第一个字节配置为以空间奇偶校验发送,其余字节以标记奇偶校验发送,那么所有字节都以标记奇偶校验发送。

【问题讨论】:

  • 当您调用write 时,可能不会立即写入数据,因为内核可能有自己的缓冲。如果您正在使用例如USB 转串行加密狗它也可能有自己的缓冲区。因此,您可以在发送任何数据之前第二次更改属性。
  • @ Joachim Pileborg 好吧,我什至尝试在发送第一个字节后使用 15 毫秒的延迟。输出还是一样的
  • 在写完msg1之后尝试调用tcdrain(fd);
  • tcdrain(fd) 也没有提供所需的 o/p,但如果我创建 25 毫秒或以上的延迟,我将正确获得 o/p。感谢您的帮助
  • 尝试在第一个字节后关闭端口,然后再次重新打开并在发送其余部分之前调整设置。

标签: c linux serial-port


【解决方案1】:

我遇到了类似的问题,尝试发送带有奇偶校验“标记”的第一个字节,其余所有字节带有奇偶校验“空格”,而我拥有的 USB 到串行驱动程序忽略了“标记/空格”选项,我注意到使用协议分析器,它使用“奇/偶”代替。 因此,我最终创建了一个查找表,其中包含在发送每个字节之前需要使用的奇偶校验(奇/偶),以模拟“标记/空格”奇偶校验,并且在发送每个字节之前我会相应地更改奇偶校验。 显然这会在每次奇偶校验交换时引入许多毫秒的延迟,因此由于这仅适用于以单一波特率运行的单一用途嵌入式设备,因此修改了 USB 到串行驱动程序以删除一些检查它正在执行(如波特率变化)并使奇偶校验的切换速度提高一倍。 如果驱动程序用于通用用途,我不建议更改驱动程序,但如果您能承受在每次奇偶校验更改之前引入的字符间延迟,那么这可能会有所帮助。

查找表是这样的:

static const char parity[256]= {

0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
};

要发送带有奇偶校验“标记”的第一个字节,我使用的是这个:

if (parity[buff[0]]==1)
    SetParity (fd,EVEN_PARITY);
else
    SetParity (fd,ODD_PARITY);

这就是“SetParity()”函数

int SetParity(int fd, int parity) {

struct termios options,options1;
string strToLog;

bzero (&options, sizeof (options));
bzero (&options1, sizeof (options1));

if (tcgetattr (fd, &options) ==-1) {
    usleep (500);
    int aa=tcgetattr (fd, &options);
    ostringstream osString (" ");
    osString<<std::dec<<fd<<"FD error! Get A";
    if (aa==-1)
        osString<<std::dec<<fd<< "FD error! Get B";
    strToLog.append (osString.str());
      Log(LOG_ALERT,strToLog.c_str());
    if (aa==-1)
        return -1;
}
options.c_cflag |= (CLOCAL | CREAD);

switch (parity) {
    case NO_PARITY:
        options.c_cflag &= ~PARENB;
        options.c_cflag &= ~CSTOPB;
        options.c_cflag &= ~CSIZE;
        options.c_cflag |= CS8;
        break;
    case ODD_PARITY:
        options.c_cflag|=PARODD;
        options.c_cflag|=PARENB;
        options.c_cflag&=~CMSPAR;
        break;

    case EVEN_PARITY:
        options.c_cflag&=~PARODD;
        options.c_cflag|=PARENB;
        options.c_cflag&=~CMSPAR;
        break;

    case MARK_PARITY:
        options.c_cflag|=PARODD;
        options.c_cflag|=PARENB;
        options.c_cflag|=CMSPAR;
        break;

    case SPACE_PARITY:
        options.c_cflag&=~PARODD;
        options.c_cflag|=PARENB;
        options.c_cflag|=CMSPAR;
        break;
    default:
        return (-1);
}

if (-1 == tcsetattr (fd, TCSADRAIN, & (options))) {
    printf ("ERROR--------------------------------setParity\n");
    ostringstream osString (" ");
    osString<<std::dec<<fd<<"FD error! Set A";
    usleep (500);
    int aa= tcsetattr (fd, TCSADRAIN, & (options));
    if (aa==-1)
        osString<<std::dec<<fd<<" FD error! Set B";
    strToLog.append (osString.str());

    printf(strToLog.c_str());
    if (aa==-1)
        return -1;
}

return 1;
}

【讨论】:

    猜你喜欢
    • 2017-07-19
    • 2012-12-06
    • 2015-01-10
    • 2015-12-03
    • 2011-12-10
    • 2014-05-01
    • 1970-01-01
    • 2015-06-29
    • 2019-05-19
    相关资源
    最近更新 更多