串口驱动相关参数 串口驱动 win7

1 关于Termios
termios 函数族提供了一个常规的终端接口,用于控制非同步通信端口。

Linux中的控制台界面,要大量用到Termios库的内容。但是,总的来看,这些东西已经过时了,应该用更简单的方案来代替它了,尽管它是POSIX标准的一部分。

termios的实现中,有大量的参数设置,还有伪终端的说法。

这里描述的大部分属性有一个 termios_p 类型的参数,它是指向一个 termios结构的指针。这个结构包含了至少下列成员:

tcflag_t
c_iflag;
输入模式

tcflag_t
c_oflag;
输出模式

tcflag_t
c_cflag;
控制模式

tcflag_t
c_lflag;
本地模式

cc_t
c_cc[NCCS];
控制字符

1.1 c_iflag 标志常量:
c_iflag变量控制终端的输入属性,有下表这些属性可供设置。

IGNBRK 忽略输入中的 BREAK 状态
BRKINT 如果设置了 IGNBRK,将忽略 BREAK。如果没有设置,但是设置了 BRKINT,那么 BREAK将使得输入和输出队列被刷新,如果终端是一个前台进程组的控制终端,这个进程组中所有进程将收到 SIGINT 信号。如果既未设置IGNBRK 也未设置 BRKINT,BREAK 将视为与 NUL 字符同义,除非设置了 PARMRK,这种情况下它被视为序列377 。
IGNPAR 忽略桢错误和奇偶校验错。
PARMRK 如果没有设置 IGNPAR,在有奇偶校验错或桢错误的字符前插入 377 。如果既没有设置 IGNPAR 也没有设置PARMRK,将有奇偶校验错或桢错误的字符视为 。
INPCK 启用输入奇偶检测。
ISTRIP 去掉第八位。
INLCR 将输入中的 NL 翻译为 CR。

IGNCR 忽略输入中的回车
ICRNL 将输入中的回车翻译为新行 (除非设置了 IGNCR)
IUCLC (不属于 POSIX) 将输入中的大写字母映射为小写字母
IXON 启用输出的 XON/XOFF 流控制
IXANY (不属于 POSIX.1;XSI) 允许任何字符来重新开始输出
IXOFF 启用输入的 XON/XOFF 流控制。
IMAXBEL (不属于 POSIX) 当输入队列满时响零。Linux 没有实现这一位,总是将它视为已设置。

  

1.2 C_oflag标示常量
控制终端的输出属性,有如下属性可供设置:

OPOST 启用具体实现自行定义的输出处理
OLCUC 将输出中的小写字母映射为大写字母
ONLCR 将输出中的换行符映射为回车-换行
OCRNL 将输出中的回车映射为换行符

ONOCR 不在第 0 列输出回车
ONLRET 不输出回车
OFILL 发送填充字符作为延时,而不是使用定时来延时
OFDEL 填充字符是 ASCII DEL (0177)。如果不设置,填充字符则是 ASCII NUL。
NLDLY 新行延时掩码。取值为 NL0 和 NL1。
NL0
NL1
CRDLY 回车延时掩码。取值为 CR0, CR1, CR2, 或 CR3。
CR0
CR1
CR2
CR3
TABDLY 水平跳格延时掩码。取值为 TAB0, TAB1, TAB2, TAB3 (或 XTABS)。取值为 TAB3,即XTABS,将扩展跳格为空格 (每个跳格符填充 8 个空格)。
TAB0
TAB1
TAB2
TAB3
XTABS
BSDLY 回退延时掩码。取值为 BS0 或 BS1。
BS0
BS1
VTDLY 竖直跳格延时掩码。取值为 VT0 或 VT1。
VT0
VT1
FFDLY 进表延时掩码。取值为 FF0 或 FF1。
FF0
FF1

 


1.3 c_cflag 标志常量:
 

CBAUD 波特率掩码,可设置如下列所示波特率
B0 B50 B75 B110 B134 B150 B200 B300 B600 B1200B1800 B2400 B4800 B9600 B19200 B38400 B57600B115200 B230400 B460800 这些波特率是posix标准,所有系统都应该支持。
CBAUDEX 由用户指定波特率,这个操作不一定会被支持(POSIX 规定波特率存储在 termios结构中,并未精确指定它的位置,而是提供了函数 cfgetispeed() 和 cfsetispeed() 来存取它。一些系统使用c_cflag 中 CBAUD 选择的位,其他系统使用单独的变量,例如 sg_ispeed 和 sg_ospeed 。
CSIZE 字符长度掩码。取值为 CS5, CS6, CS7, 或 CS8。
CS5, CS6, CS7, CS8 所有系统都应该支持这个操作
CSTOPB 设置两个停止位,而不是一个。
CREAD 打开接受者。
PARENB 允许输出产生奇偶信息以及输入的奇偶校验。
PARODD 输入和输出是奇校验。
HUPCL 在最后一个进程关闭设备后,降低 modem 控制线 (挂断)
CLOCAL 忽略 modem 控制线
LOBLK 从非当前 shell 层阻塞输出(用于 shell )
CIBAUD 输入速度的掩码。CIBAUD 各位的值与 CBAUD 各位相同,左移了 IBSHIFT 位
CRTSCTS 启用 RTS/CTS (硬件) 流控制。

ISIG
当接受到字符 INTR, QUIT, SUSP, 或 DSUSP 时,产生相应的信号

ICANON
启用标准模式 (canonical mode)。允许使用特殊字符 EOF, EOL, EOL2,ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE,以及按行的缓冲

XCASE
如果同时设置了 ICANON,终端只有大写。输入被转换为小写,除了以 前缀的字符。输出时,大写字符被前缀 ,小写字符被转换成大写。

ECHO
回显输入字符。

ECHOE
如果同时设置了 ICANON,字符 ERASE 擦除前一个输入字符,WERASE擦除前一个词

ECHOK
如果同时设置了 ICANON,字符 KILL 删除当前行

ECHONL
如果同时设置了 ICANON,回显字符 NL,即使没有设置 ECHO。

NOFLSH
禁止在产生 SIGINT, SIGQUIT 和 SIGSUSP信号时刷新输入和输出队列。

TOSTOP
向试图写控制终端的后台进程组发送 SIGTTOU 信号。

ECHOCTL
在读入下一个字符时,输入队列中所有字符被重新输出。

ECHOPRT
如果同时设置了 ICANON 和 IECHO,字符在删除的同时被打印

ECHOKE
如果同时设置了 ICANON,回显 KILL 时将删除一行中的每个字符,如同指定了 ECHOE 和ECHOPRT 一样。

FLUSHO
输出被刷新。这个标志可以通过键入字符 DISCARD 来开关

PENDIN
在读入下一个字符时,输入队列中所有字符被重新输出。

IEXTEN
启用实现自定义的输入处理。这个标志必须与 ICANON 同时使用,才能解释特殊字符EOL2,LNEXT,REPRINT 和 WERASE,IUCLC 标志才有效。

  c_cc 数组定义了特殊的控制字符。符号下标 (初始值) 和意义如下列的内容所示:

VINTR (003, ETX, Ctrl-C, or also 0177, DEL, rubout) 中断字符。发出 SIGINT信号。当设置 ISIG 时可被识别,不再作为输入传递。
VQUIT (034, FS, Ctrl-) 退出字符。发出 SIGQUIT 信号。当设置 ISIG时可被识别,不再作为输入传递。
VERASE 0177, DEL, rubout, or 010, BS, Ctrl-H, or also #)删除字符。删除上一个还没有删掉的字符,但不删除上一个 EOF 或行首。当设置 ICANON 时可被识别,不再作为输入传递。
VKILL (025, NAK, Ctrl-U, or Ctrl-X, or also @) 终止字符。删除自上一个 EOF或行首以来的输入。当设置 ICANON 时可被识别,不再作为输入传递。
VEOF (004, EOT, Ctrl-D) 文件尾字符。更精确地说,这个字符使得 tty缓冲中的内容被送到等待输入的用户程序中,而不必等到 EOL。如果它是一行的第一个字符,那么用户程序的 read() 将返回0,指示读到了 EOF。当设置 ICANON 时可被识别,不再作为输入传递。
VTIME 非 canonical 模式读时的延时,以十分之一秒为单位。
VMIN 非 canonical 模式读的最小字符数。
VSWTC (not in POSIX; not supported under Linux; 0, NUL) 开关字符。(只为shl 所用。)
VSTART (021, DC1, Ctrl-Q) 开始字符。重新开始被 Stop 字符中止的输出。当设置 IXON时可被识别,不再作为输入传递。
VSTOP (023, DC3, Ctrl-S) 停止字符。停止输出,直到键入 Start 字符。当设置 IXON时可被识别,不再作为输入传递。
VSUSP (032, SUB, Ctrl-Z) 挂起字符。发送 SIGTSTP 信号。当设置 ISIG时可被识别,不再作为输入传递。
VEOL (0, NUL) 附加的行尾字符。当设置 ICANON 时可被识别。
VREPRINT (not in POSIX; 022, DC2, Ctrl-R) 重新输出未读的字符。当设置 ICANON 和IEXTEN 时可被识别,不再作为输入传递。
VDISCARD (not in POSIX; not supported under Linux; 017, SI, Ctrl-O)开关:开始/结束丢弃未完成的输出。当设置 IEXTEN 时可被识别,不再作为输入传递。
VWERASE (not in POSIX; 027, ETB, Ctrl-W) 删除词。当设置 ICANON 和 IEXTEN时可被识别,不再作为输入传递。
VLNEXT not in POSIX; 026, SYN, Ctrl-V)字面上的下一个。引用下一个输入字符,取消它的任何特殊含义。当设置 IEXTEN 时可被识别,不再作为输入传递。
VEOL2 (not in POSIX; 0, NUL) 另一个行尾字符。当设置 ICANON 时可被识别。


2. 串口驱动程序
编写Rtems的串口驱动程序比较简单,只需要填写一张驱动程序表即可:

typedef struct _console_fns {

bool(*deviceProbe)(int minor);

int(*deviceFirstOpen)(int major, int minor, void *arg);

int(*deviceLastClose)(int major, int minor, void *arg);

int(*deviceRead)(int minor);

int(*deviceWrite)(int minor, const char *buf, int len);

void(*deviceInitialize)(int minor);

void(*deviceWritePolled)(int minor, char cChar);

int(*deviceSetAttributes)(int minor, const struct termios *t);

booldeviceOutputUsesInterrupts;

} console_fns;

顾名思义:firstopen、lastclose是首次打开和最后一次关闭时调用的函数;我们可以不用管它。

Probe其实是一个钩子函数,目前还没有发现他的真实作用;

Deviceread是读取串口数据的函数,这个函数不涉及中断操作信号量,只是简单的读取数据,每次读取一个字节。如果设置了这个函数,rtems就会使用轮训的方式获取数据,否则应用程序会在驱动程序底层被挂起,直到中断中接收到数据为止。

deviceWrite功能也是直接把数据写入到串口fifo中,这个函数功能也比较简单,除非数据全部写入,否则不会退出。

deviceInitialize这个函数需要我们初始化串口,按照预先的配置:初始化比特率、设置中断处理函数、设置比特位、停止位等。这个函数是必须要完成的。

deviceWritePolled这个函数写一个字符到串口,除非写不成功,否则会一直等待下去。

deviceSetAttributes这个函数作用是设置串口的一些属性,例如波特率、数据位、停止位等信息.

deviceOutputUsesInterrupts这个参数至关重要,它有三个选项可供选择:

l为TERMIOS_POLLED这个选项时,底层就会一直轮训等待数据,但不会全部占用CPU,rtems也会隔一段时间查询一次串口的状态。

l为TERMIOS_IRQ_DRIVEN时,串口使用中断驱动的方式:一旦串口被打开,就会初始化一个tty,tty会同时包含一个发送缓冲和一个接收缓冲。发送与接收的数据都会被暂存在tty的数据结构中,一旦中断发生,中断处理程序中会把接收到的数据暂存在缓冲中。等待应用程序调用读取操作时再从缓冲中把数据取出,如果数据缓冲超出缓冲范围,而应用程序依然没有。需要注意的是,串口必须被打开后才会开启这个缓冲区。

l使用TERMIOS_TASK_DRIVEN这个选项时,rtems会分别为发送接收时间创建两个代理任务,代理任务里面不断的轮询串口状态,然后进行数据的发送与接收操作。这种模式对上的接口类似于TERMIOS_IRQ_DRIVEN的方式,只是使用任务扫描来实现中断的功能。

if (tty->device.outputUsesInterrupts ==TERMIOS_TASK_DRIVEN) {

sc = rtems_task_create (

rtems_build_name ('T', 'x', 'T', c),

TERMIOS_TXTASK_PRIO,

TERMIOS_TXTASK_STACKSIZE,

RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |

RTEMS_NO_ASR,

RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,

&tty->txTaskId);

if (sc != RTEMS_SUCCESSFUL)

rtems_fatal_error_occurred (sc);

sc = rtems_task_create (

rtems_build_name ('R', 'x', 'T', c),

TERMIOS_RXTASK_PRIO,

TERMIOS_RXTASK_STACKSIZE,

RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |

RTEMS_NO_ASR,

RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,

&tty->rxTaskId);

if (sc != RTEMS_SUCCESSFUL)

rtems_fatal_error_occurred (sc);

}

余下来以发送、接收数据为例,跟踪termios中处理的事情,首先看代码:

rtems_termios_puts (

const void *_buf, int len, structrtems_termios_tty *tty) {

constunsigned char *buf = _buf;

unsignedint newHead;

rtems_interrupt_level level;

rtems_status_code sc;

pooled方式的处理:直接发送、然后退出

if(tty->device.outputUsesInterrupts == TERMIOS_POLLED){

(*tty->device.write)(tty->minor,(void *)buf, len);

return;

}

IRQ_DRIVEN方式的处理:放置到缓冲区、触发第一次中断、然后等待退出

newHead =tty->rawOutBuf.Head;

while(len) {

newHead = (newHead + 1) % tty->rawOutBuf.Size;

rtems_interrupt_disable (level);

while (newHead == tty->rawOutBuf.Tail) {

tty->rawOutBufState = rob_wait;

rtems_interrupt_enable (level);

发送缓冲信号量作用很重要:获取操作权限,空闲状态、发送缓冲为空状态可以获取到该信号量。

sc = rtems_semaphore_obtain(tty->rawOutBuf.Semaphore,

RTEMS_WAIT,

RTEMS_NO_TIMEOUT);

if (sc != RTEMS_SUCCESSFUL)

rtems_fatal_error_occurred (sc);

rtems_interrupt_disable(level); 余下的操作需要在中断关闭的状态下完成

}

tty->rawOutBuf.theBuf[tty->rawOutBuf.Head]= *buf++;向缓冲写数据

tty->rawOutBuf.Head = newHead;

if (tty->rawOutBufState == rob_idle){如果发送队列处于空闲状态、

if (!(tty->flow_ctrl & FL_ORCVXOF)){如果硬件流控制没有禁止数据接收

(*tty->device.write)(tty->minor,发送一个字符,一旦发送完毕就会产生中断

(char*)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);

}

else{硬件流控制当前禁止发送数据

tty->flow_ctrl |=FL_OSTOP;记录标示:写操作被硬件流控制挂起

}

tty->rawOutBufState =rob_busy;进入忙状态

}

rtems_interrupt_enable (level);

len--;

}

}

如果使用中断的方式处理发送事件,中断中需要对应以上处理程序有套自己的方法。但是目前的处理上,发送事件并没有采用中断的方式,这里修改了源代码,直接把数据发送出去。日后会做修改,使用中断的方式发送数据。

接下来关注接收事件,关键代码如下:

if(rtems_termios_linesw[tty->t_line].l_read != NULL){是否存在度函数

sc =rtems_termios_linesw[tty->t_line].l_read(tty,args);

tty->tty_rcvwakeup = 0;

rtems_semaphore_release (tty->isem);

return sc;

}

if(tty->cindex == tty->ccount) {

tty->cindex = tty->ccount = 0;

tty->read_start_column =tty->column;

if (tty->device.pollRead != NULL

&&tty->device.outputUsesInterrupts ==TERMIOS_POLLED)

sc = fillBufferPoll(tty);轮询模式下读取数据

else

sc = fillBufferQueue(tty);使用队列缓冲读取数据

if (sc != RTEMS_SUCCESSFUL)

tty->cindex = tty->ccount = 0;

}

while(count &&(tty->cindex <tty->ccount)) {

*buffer++ =tty->cbuf[tty->cindex++];

count--;

}

队列缓冲模式下,串口中断通过操作接收信号量与发送队列进行互动操作。将要发送的数据首先被保存到缓冲队列中,然后在中断处理程序中读取缓冲队列的数据,放置到发送FIFO中。一旦发送缓冲中的数据被发送完毕,中断处理程序会知会发送fifo,发送FIFO就从等待信号量的状态中退出来,重新填入发送数据。

while (wait ) {

while ((tty->rawInBuf.Head !=tty->rawInBuf.Tail)&&

(tty->ccount < (CBUFSIZE-1))) {

unsigned char c;

unsigned int newHead;

newHead = (tty->rawInBuf.Head + 1) %tty->rawInBuf.Size;

c = tty->rawInBuf.theBuf[newHead];

tty->rawInBuf.Head = newHead;

if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)

% tty->rawInBuf.Size)

< tty->lowwater) {

tty->flow_ctrl &= ~FL_IREQXOF;

if (((tty->flow_ctrl & (FL_MDXON |FL_ISNTXOF))

==(FL_MDXON | FL_ISNTXOF))

&&((tty->rawOutBufState == rob_idle)

|| (tty->flow_ctrl & FL_OSTOP))){

(*tty->device.write)(tty->minor,

(void*)&(tty->termios.c_cc[VSTART]),

1);

}

else if (tty->flow_ctrl & FL_MDRTS){

tty->flow_ctrl &= ~FL_IRTSOFF;

if (tty->device.startRemoteTx != NULL) {

tty->device.startRemoteTx(tty->minor);

}

}

}

if (tty->termios.c_lflag & ICANON){

if (siproc (c, tty))

wait = 0;

}

else {

siproc (c, tty);

if (tty->ccount >=tty->termios.c_cc[VMIN])

wait = 0;

}

timeout = tty->rawInBufSemaphoreTimeout;

}

if ( wait ) {这部分操作有可能会被挂起,直至缓冲中数据全部发送完毕

sc = rtems_semaphore_obtain(tty->rawInBuf.Semaphore,

tty->rawInBufSemaphoreOptions,

timeout);

if (sc != RTEMS_SUCCESSFUL)

break;

}

}


3.设置串口
对串口的设置最好能够遵循标准,否则会引出不必要的麻烦。设置还是遵循unix的风格,使用ioctl函数。

以下是一个设置串口的示例,:

structtermiosss;1.定义一个串口设置选项

hCom2= open("/dev/com2", O_RDWR | O_EXCL, 0x777);

if(hCom2 == 0) {

printk("dev/com2 open failed!");

}

ioctl(hCom2, RTEMS_IO_GET_ATTRIBUTES,&ss); 2.首先读取当前设置,在这个基础上进行修改

cfsetospeed(&ss,B115200);3.设置波特率为115200

ss.c_cflag = CS8 | (~CSIZE &ss.c_cflag);4.设置8位数据模式

ioctl(hCom2, RTEMS_IO_SET_ATTRIBUTES,&ss); 5.写入串口设置新内容

close(hCom2);

termios这个结构体在termios.h这个头文件中被定义,所以必须包含这个头文件。同样也必须包含<sys/ioccom.h>这个头文件,因为RTEMS_IO_SGT_ATTRIBUTESRTEMS_IO_SET_ATTRIBUTES在这个文件中被定义。

第一步第二步首先读取串口当前的默认设置选项,然后在这个基础上进行设置。

第2步首先读出当前串口的状态,在这个状态的基础上再做更改.

第3、4步操作是设置具体的内容,虽然第3步是通过调用一个函数实现设置termios结构,但事实上都是通过本节介绍的一些宏对数据进行操作。跟进cfsetospeed函数会发现进行的操作实际上也只是操作了一个宏而已。

设置波特率、数据模式之后,最后一步写数据进入串口,即完成了串口的操作。

  

爱华网本文地址 » http://www.413yy.cn/a/25101010/17622.html

更多阅读

华硕fn键驱动下载 华硕fn键驱动win7

? ? 华硕笔记本的Fn热键驱动名称叫ATK,到华硕官网上可以找到,进入官网后,直接搜索ATK即可。但这里需要说明的是,ATK共有七个驱动,这七个都需要安装。如果只安装其中一个或部分安装,则有可能导致热键不管用或部分不管用。?具体操作如下:

Win7系统下创新声卡调试之驱动如何安装 声卡驱动调试

Win7系统下创新声卡调试之驱动如何安装——简介多数使用者购买创新声卡5.1或者创新声卡7.1遇到不知怎么安装驱动,本经验以图文并茂形式简单的讲解如何安装。Win7系统下创新声卡调试之驱动如何安装——工具/原料创新5.1声卡驱动 WIN7

无法安装显卡驱动 win7无法安装显卡驱动

无法安装显卡驱动——简介本经验将完美解决NVIDIA安装程序无法找到和您现有硬件兼容的任何驱动程序的情况。 无法安装显卡驱动——方法/步骤无法安装显卡驱动 1、右键"计算机"点“属性”打开你的设备管理器,然后在显示适配器里面。

如何看懂视力验光单转 视力验光单怎么看

孩子戴眼镜最基本的作用是矫正视力。一般需要先进行科学、正规的医学验光,检验出眼睛的度数及其它相关参数,并严格按照处方单来加工制作,才能配出合格及适合的眼镜。许多家长虽然经过医生的反复讲解仍不能准确的记住孩子的眼镜度数,下面

声明:《串口驱动相关参数 串口驱动 win7》为网友若雪樱花草分享!如侵犯到您的合法权益请联系我们删除