我的termios设置是使用read()修改从串口读取的第一个字符。我有一个微控制器与linux盒子交谈。微控制器响应从linux机器发送的命令。设置如下:
当我运行像Cutecom这样的终端程序时,一切都按计划进行。我向PIC发送一个命令字符然后我得到一个响应,但是当我使用我的命令行程序时,第一个字符正在被修改。这是我的代码:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#define DEVICE "/dev/ttyUSB0"
#define SPEED B38400
int main()
{
struct termios tio; //to hold serial port settings
struct termios stdio; //so we can accept user input
struct termios old_stdio; //save the current port settings
int tty_fd; //file descriptor for serial port
int res, n, res2, read1, wri;
char buf[255];
char buf2[255];
//save the current port settings
tcgetattr(STDOUT_FILENO,&old_stdio);
//setup serial port settings
bzero(&tio, sizeof(tio));
tio.c_iflag = 0;
tio.c_iflag = IGNPAR | IGNBRK | IXOFF;
tio.c_oflag = 0;
tio.c_cflag = CS8 | CREAD | CLOCAL; //8n1 see termios.h
tio.c_lflag = ICANON;
//open the serial port
tty_fd=open(DEVICE, O_RDWR | O_NOCTTY);
//set the serial port speed to SPEED
cfsetospeed(&tio,SPEED);
//apply to the serial port the settings made above
tcsetattr(tty_fd,TCSANOW,&tio);
for(n = 5; n > 0; n--)
{
printf("Please enter a command: ");
(void)fgets(buf2, 255, stdin);
(void)write(tty_fd, buf2, strlen(buf2));
printf("Ok. Waiting for reply.");
res = read(tty_fd, buf, 255);
printf("Read:%d START%d %d %d %d %dFINISH\n",res,buf[0],buf[1],buf[2],buf[3],
buf[4]);
}
//close the serial port
close(tty_fd);
//restore the original port settings
tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio);
return EXIT_SUCCESS;
}
以下是我得到的结果示例。
出于某种原因,第一个角色被某些termios设置搞砸了。它必须是termios设置,因为上面相同的测试输入完全在我运行Cutecom时返回。我一遍又一遍地阅读手册页,尝试输入控件上的所有不同设置,但无论我做什么都不能解决这个问题。
为了方便修复,我可以将数据移到1个字符上,但是要避免这样做。
有没有人遇到过这样的问题,或者知道该怎么办?
非常感谢。
28/3/13 伟大的建议奥斯汀。对于那些感兴趣的人来说,有两个输出:
首先是我的程序中的termios设置
速度38400波特;行0;第0列; line = 0; intr =;退出=; erase =; kill =; eof =; eol =; eol2 =; swtch =; start =;停止=; susp =; rprnt =; werase =; lnext =; flush =; min = 0;时间= 0; -parenb -parodd cs8 -hupcl -cstopb cread clocal -crtscts ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke
以及cutecom使用的设置
速度38400波特;行0;第0列; line = 0; intr = ^ C;退出= ^ \; erase = ^?; kill = ^ U; eof = ^ D; eol =; eol2 =; swtch =; start = ^ Q; stop = ^ S; susp = ^ Z; rprnt = ^ R; werase = ^ W; lnext = ^ V; flush = ^ O; min = 60;时间= 1; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke
我仍在经历这一切,并会在我取得进展时更新帖子。
29/3/13 还是有同样的问题。我甚至找到了Cutecom的源代码,并遵循他们使用的termios设置。问题仍然存在。第一个角色已损坏!!!!
以下是我程序中的Termios设置。由于某种原因无法设置刷新。
速度38400波特;行0;第0列; line = 0; intr = ^?;退出= ^ \; erase = ^ H; kill = ^ U; eof = ^ D; eol =; eol2 =; swtch =; start = ^ Q; stop = ^ S; susp = ^ Z; rprnt = ^ R; werase = ^ W; lnext = ^ V; flush =; min = 60;时间= 1; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke
我的新代码:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#define DEVICE "/dev/ttyUSB0"
#define SPEED B38400
int main()
{
struct termios tio; //to hold serial port settings
struct termios stdio; //so we can accept user input
struct termios old_stdio; //save the current port settings
int tty_fd; //file descriptor for serial port
int retval, res, n, res2, read1, wri;
char buf[255];
char buf2[255];
tty_fd = open(DEVICE, O_RDWR | O_NDELAY);
if(tty_fd < 0)
{
perror(DEVICE);
exit(-1);
}
printf("Init 1 complete.\n");
tcflush(tty_fd, TCIOFLUSH);
int f = fcntl(tty_fd, F_GETFL, 0);
fcntl(tty_fd, F_SETFL, f & ~O_NDELAY);
retval = tcgetattr(tty_fd, &old_stdio);
if(retval != 0)
{
perror(DEVICE);
exit(-1);
}
printf("Init 2 complete.\n");
struct termios newtio;
retval = tcgetattr(tty_fd, &newtio);
if(retval != 0)
{
perror(DEVICE);
exit(-1);
}
printf("Init 3 complete.\n");
cfsetospeed(&newtio, SPEED);
cfsetispeed(&newtio, SPEED);
newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8;
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~(PARENB | PARODD);
newtio.c_cflag &= ~CRTSCTS;
newtio.c_cflag &= ~CSTOPB;
newtio.c_iflag = IGNBRK;
newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
newtio.c_lflag = 0;
newtio.c_oflag = 0;
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 60;
newtio.c_cc[VINTR] = 127;
newtio.c_cc[VQUIT] = 28;
newtio.c_cc[VERASE] = 8;
newtio.c_cc[VKILL] = 21;
newtio.c_cc[VEOF] = 4;
newtio.c_cc[VSTOP] = 19;
newtio.c_cc[VSTART] = 17;
newtio.c_cc[VSUSP] = 26;
newtio.c_cc[VREPRINT] = 18;
newtio.c_cc[VFLSH] = 15;
newtio.c_cc[VWERASE] = 23;
newtio.c_cc[VLNEXT] = 22;
retval = tcsetattr(tty_fd, TCSANOW, &newtio);
if(retval != 0)
{
perror(DEVICE);
exit(-1);
}
printf("Init 4 complete.\n");
int mcs = 0;
ioctl(tty_fd, TIOCMGET, &mcs);
mcs |= TIOCM_RTS;
ioctl(tty_fd, TIOCMSET, &mcs);
retval = tcgetattr(tty_fd, &newtio);
if(retval != 0)
{
perror(DEVICE);
exit(-1);
}
printf("Init 5 complete.\n");
newtio.c_cflag &= ~CRTSCTS;
retval = tcsetattr(tty_fd, TCSANOW, &newtio);
if(retval != 0)
{
perror(DEVICE);
exit(-1);
}
printf("Init 6 complete.\n");
for(n = 5; n > 0; n--)
{
printf("Please enter a command: ");
(void)fgets(buf2, 255, stdin);
(void)write(tty_fd, buf2, strlen(buf2));
printf("Ok. Waiting for reply\n");
res = read(tty_fd, buf, 255);
printf("Read:%d START%d %d %d %d %dFINISH\n",res,buf[0],buf[1],buf[2], buf[3],
buf[4]);
}
//restore the original port settings
tcsetattr(tty_fd, TCSANOW, &old_stdio);
close(tty_fd);
return EXIT_SUCCESS; //return all good
}
我完全迷失了可以做什么或者我应该从哪里开始。
答案 0 :(得分:2)
快速扫描代码时,我看不出任何明显错误。如果您希望使用8位值,则可能需要考虑转移到unsigned char buf[]
。
由于您在Cutecom中有一个工作程序,您可以使用他们的termios设置作为调试您自己的程序的参考。
在/dev/ttyUSB0
上运行Cutecom时,在另一个终端中运行以下命令以转储tty设置:
stty -a -F /dev/ttyUSB0
在运行程序时执行相同操作并查找两种配置之间的差异。尝试在程序中设置终端设置,使其与Cutecom报告的设置完全匹配。
<强>更新强>
由于修复termios设置尚未解决问题,因此可以尝试以下一些方法。我猜测某个地方有时间问题。在Cutecom控制台上键入时,您一次向设备发送1个字符,字符之间的间隔为毫秒。使用程序时,输入命令后将发送一个完整的字符缓冲区,字符将以驱动程序允许的速度背靠背发送。也许您的PIC程序无法处理数据流的时序,或者预期两个停止位而不是一个,这会产生一些奇怪的返回码。
可能最好的起点是从源头回来。掌握示波器或逻辑分析仪,确认PIC发送的数据实际上是正确的。您必须了解位级波形,允许启动和停止位。比较Cutecom和您的程序的波形。如果使用逻辑分析仪,请确保使用的时钟是波特率的高倍。例如32乘法器。
另一种调试方法是使用strace
来验证驱动程序返回的字符实际上是不正确的,这对您的程序来说不是问题。使用strace
,您将能够看到程序的原始读/写以及内核返回的内容。在程序运行时使用strace -o ~/tmp/strace_output.txt -ttt -xx your_program
转储所有系统调用。有时候,只需要对程序进行处理就会减慢它的速度以显示计时错误。您可以将读/写的时间与Cutecom的strace
进行比较。仅用于测试,您可以添加自己的write()
函数,该函数发送字符串但在每个字符之间延迟少量。
答案 1 :(得分:0)
我终于解决了。这就是修正它的原因:
问题是固定的,但并不是100%确定它为什么会这样做。问题是我的程序将一个\ n附加到微控制器写入。当我对Cutecom和我的程序进行了扫描时,我发现Cutecom只写'1'而我的程序会写“1 \ n”。我只是觉得不够,因为当使用Cutecom发送你在用户提示中键入例如1的字符然后点击回车。在PIC方面,我的程序看起来像这样:
while(1)
{
WATCHDOG();
if(flag == 1)
{
char *start = str2;
RS485_TXEN1();
indicator = UART1_getch(); //get character sent from PC
switch(indicator)
{
case '1' :
UART1_putstr("00000\n");
DAC_Write( DAC_CH_2, 4095);
break;
case '2' :
UART1_putstr("23456\n");
DAC_Write( DAC_CH_2, 0);
break;
case '3' :
UART1_putstr("34567\n");
break;
case '4' :
UART1_putstr("45678\n");
break;
case '\n' :
UART1_putch('\n');
break;
default :
UART1_putstr("56789\n");
break;
}
RS485_RXEN1();
flag = 0;
}
}
当字符到达UART RX时,会产生中断。我在此中断服务程序中设置“flag”,然后在main()中处理接收到的命令。不确定第一个字符是如何被修改的,但看起来由于“case'\ n':”而发生了一些覆盖或写入中断。
最后简单修复,甚至学习了一些使用Linux系统和调试的宝贵经验。感谢所有提出建议的人。对于任何想要开始连接linux盒子和微控制器的人来说,上面的代码可能对你有所帮助。