Linux下可以使用9位串口通信吗?

发布于 2024-09-07 07:02:05 字数 136 浏览 4 评论 0原文

RS-232 通信有时使用 9 位字节。这可用于与总线上的多个微控制器进行通信,其中 8 位是数据,额外的位表示地址字节(而不是数据)。不活动的控制器仅针对地址字节生成中断。

Linux 程序可以通过串行设备发送和接收 9 位字节吗?如何?

RS-232 communication sometimes uses 9-bit bytes. This can be used to communicate with multiple microcontrollers on a bus where 8 bits are data and the extra bit indicates an address byte (rather than data). Inactive controllers only generate an interrupt for address bytes.

Can a Linux program send and receive 9-bit bytes over a serial device? How?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

棒棒糖 2024-09-14 07:02:05

termios 系统不直接支持 9 位操作,但可以通过使用 CMSPAR 标志在某些系统上进行模拟。它没有记录,并且没有出现在所有实现中。

以下是有关如何完成 9 位仿真的详细文章的链接:

http: //www.lothosoft.ch/thomas/libmip/markspaceparity.php

The termios system does not directly support 9 bit operation but it can be emulated on some systems by playing tricks with the CMSPAR flag. It is undocumented and my not appear in all implementations.

Here is a link to a detailed write-up on how 9-bit emulation is done:

http://www.lothosoft.ch/thomas/libmip/markspaceparity.php

一口甜 2024-09-14 07:02:05

9 位数据是 RS-485 的标准部分,用于多点应用。基于 16C950 设备的硬件可能支持 9 位,但前提是 UART 在 950 模式下使用(而不是用于 RS-232 的更常见的 450/550 模式)。

可以在此处找到 16C950 的说明。

页面总结了 Linux RS-485 支持,该支持已融入到更新的内核中(>=3.2 rc3)。

9-bit data is a standard part of RS-485 and used in multidrop applications. Hardware based on 16C950 devices may support 9-bits, but only if the UART is used in its 950 mode (rather than the more common 450/550 modes used for RS-232).

A description of the 16C950 may be found here.

This page summarizes Linux RS-485 support, which is baked into more recent kernels (>=3.2 rc3).

治碍 2024-09-14 07:02:05

即使现实世界中的 UART 无法实现 9 位数据帧,也是可能的。
找到一个在 Windows 和 Linux 下也可以执行此操作的库。
请参阅http://adontec.com/9-bit-serial-communication.htm

9-bit data framing is possible even if a real world UARTs doesn't.
Found one library that also does it under Windows and Linux.
See http://adontec.com/9-bit-serial-communication.htm

天赋异禀 2024-09-14 07:02:05

基本上他想要的是从linux盒子输出数据,然后将其发送到带有一堆max232 ic的2线总线上 - >一些具有 uart 或软件 RS232 实现的微控制器,

只要各个微控制器之间不存在电压效力问题(例如,在同一 PCB 上,而不是在不同的建筑物中;),就可以保留各个 max232 电平转换器,直到达到最大值max232(或克隆,或电阻器和反相器/晶体管)IC的输出(ttl)负载。

找不到 MARK 或 SPACE 奇偶校验的 linux termios 设置(我确信硬件 uart 实际上支持,只是不支持 linux tty 实现),所以我们只需稍微修改一下实际的奇偶校验生成。

8 个数据位、2 个停止位与 8 个数据位、1 个奇偶校验位、1 个停止位的长度相同。 (其中第一个停止位是逻辑 1,负线电压)。

然后,可以使用第 9 位作为指示符,表明其他 8 位是单个或一组微控制器的地址,然后将接下来的字节作为某种命令或数据,并且它们也被“寻址”。

这提供了 8 位透明,虽然是单向流量,但意味着在同一总线上处理“很多事物”(实际上是 256 个不同(组)事物;)。这是一种方式,因为当想要采用两种方式时,您需要 2 对线,或者以多个频率进行调制,或者实现碰撞检测等等。

PIC 微控制器可以通过嗯“一些技巧”进行 9 位串行通信(第 9 位实际上在另一个寄存器中;)

现在...考虑到在 Linux 和类似平台上它并不那么简单...

你有吗考虑简单地打开“地址字”的奇偶校验(您需要 9 位;),然后将其设置为奇数或偶数,计算它,以便选择正确的一个来生成第 9 位(奇偶校验)' 1',奇偶校验打开,8 位“数据”,然后关闭奇偶校验并打开 2 个停止位。 (就您的微控制器而言,它仍然保持 9 位字长;)...这是很久以前的事了,但据我记得,停止位与时序中的数据位一样长。

这应该适用于任何可以执行 8 位输出、具有奇偶校验和 2 个停止位的设备。其中包括 PC 硬件和 Linux。 (以及dos等)

如果我正确地回忆起“过去”的话,PC硬件还可以选择打开或关闭所有单词的“奇偶校验”(无需实际计算),

此外,图片数据表谈到的第9位,实际上是 RS-232 规范中的奇偶校验位。只是您可以自由地关闭或打开它。 (无论如何,在 PIC 上 - 在 Linux 中,情况比这更复杂)

(我认为,Linux 上的一些 termios 设置无法解决...只需打开和关闭它...我们已经让这些东西变得更奇怪了事情;)

pic 微控制器实际上执行完全相同的操作,只是它不像数据表中的“实际情况”那样呈现。他们实际上称之为“第九位”之类的东西。在 PC 上,因此在 Linux 上,它的工作方式几乎相同。

无论如何,如果这个东西应该“双向”工作,那么祝你好运,用 2 对线连接它,或者找出某种方法来进行碰撞检测,这比取出 9 位要麻烦得多。

不管怎样,它只不过是一个被高估的移位寄存器。如果PC上的uart不想这样做(我对此表示怀疑),只需滥用DTR引脚来手动移出数据,或者滥用打印机端口来做同样的事情,或者连接一个移位寄存器打印机端口...但是通过奇偶校验技巧,它应该可以正常工作。

   #include<termios.h>
   #include<stdio.h>
   #include<sys/types.h>
   #include<sys/stat.h>
   #include<fcntl.h>
   #include<unistd.h>
   #include<stdint.h>
   #include<string.h>
   #include<stdlib.h>

   struct termios com1pr;
   int com1fd;

   void bit9oneven(int fd){
   cfmakeraw(&com1pr);
   com1pr.c_iflag=IGNPAR;
   com1pr.c_cflag=CS8|CREAD|CLOCAL|PARENB;
   cfsetispeed(&com1pr,B300);
   cfsetospeed(&com1pr,B300);
   tcsetattr(fd,TCSANOW,&com1pr);
   };//bit9even

   void bit9onodd(int fd){
   cfmakeraw(&com1pr);
   com1pr.c_iflag=IGNPAR;
   com1pr.c_cflag=CS8|CREAD|CLOCAL|PARENB|PARODD;
   cfsetispeed(&com1pr,B300);
   cfsetospeed(&com1pr,B300);
   tcsetattr(fd,TCSANOW,&com1pr);
   };//bit9odd

   void bit9off(int fd){
   cfmakeraw(&com1pr);
   com1pr.c_iflag=IGNPAR;
   com1pr.c_cflag=CS8|CREAD|CLOCAL|CSTOPB;
   cfsetispeed(&com1pr,B300);
   cfsetospeed(&com1pr,B300);
   tcsetattr(fd,TCSANOW,&com1pr);
   };//bit9off

   void initrs232(){
   com1fd=open("/dev/ttyUSB0",O_RDWR|O_SYNC|O_NOCTTY);
   if(com1fd>=0){
   tcflush(com1fd,TCIOFLUSH);
   }else{printf("FAILED TO INITIALIZE\n");exit(1);};
   };//initrs232

   void sendaddress(unsigned char x){
   unsigned char n;
   unsigned char t=0;
   for(n=0;n<8;n++)if(x&2^n)t++;
   if(t&1)bit9oneven(com1fd);
   if(!(t&1))bit9onodd(com1fd);
   write(com1fd,&x,1);
   };

   void main(){

   unsigned char datatosend=0x00; //bogus data byte to send
   initrs232();
   while(1){
   bit9oneven(com1fd);
   while(1)write(com1fd,&datatosend,1);
   //sendaddress(223); // address microcontroller at address 223;
   //write(com1fd,&datatosend,1); // send an a
   //sendaddress(128); // address microcontroller at address 128;
   //write(com1fd,&datatosend,1); //send an a
   }
   //close(com1fd);
   };

有点有效..也许有些事情是错误的,但它确实发送了 9 位。 (CSTOPB 设置 2 个停止位,这意味着在 8 位透明数据上,第 9 位 = 1,在寻址模式下,第 9 位 = 0;)

还要注意,实际的 rs232 线路电压电平与软件读取的电压电平相反(这与您的 pic 微控制器从晶体管或逆变器或 max232 克隆 ic 获得的“反向”5v ttl 电平相同)。 (-19v 或 -10v (pc) 表示逻辑 1,+19/+10 表示逻辑 0),停止位是负电压,类似于 1,并且长度相同。

位输出 0-7(在本例中为:8;)...所以起始位 -> 0 ,1,2,3,4,5,6,7,

这有点hacky,但似乎在范围内有效。
输入图片此处描述

basically what he wants is to output data from a linux box, then send it on let's say a 2 wire bus with a bunch of max232 ic's -> some microcontroller with uart or software rs232 implementation

one can leave the individual max232 level converter's away as long as there are no voltage potency issues between the individual microcontrollers (on the same pcb, for example, rather than in different buildings ;) up until the maximum output (ttl) load of the max232 (or clones, or a resistor and invertor/transistor) ic.

can't find linux termios settings for MARK or SPACE parity (Which i'm sure the hardware uarts actually do support, just not linux tty implementation), so we shall just hackzor the actual parity generation a bit.

8 data bits, 2 stop bits is the same length as 8 databits, 1 parity bit, 1 stop bit. (where the first stopbit is a logic 1, negative line voltage).

one would then use the 9th bit as an indicator that the other 8 bits are the address of the individual or group of microcontrollers, which then take the next bytes as some sort of command, or data, as well, they are 'addressed'.

this provides for an 8 bit transparant, although one way traffic, means to address 'a lot of things' (256 different (groups of) things, actually ;) on the same bus. it's one way, for when one would want to do 2 way, you'd need 2 wire pairs, or modulate at multiple frequencies, or implement colission detection and the whole lot of that.

PIC microcontrollers can do 9 bit serial communication with ehm 'some trickery' (the 9th bit is actually in another register ;)

now... considering the fact that on linux and the likes it is not -that- simple...

have you considered simply turning parity on for the 'address word' (the one in which you need 9 bits ;) and then either setting it to odd or even, calculate it so that the right one is chosen to make the 9th (parity) bit '1' with parity on and 8 bit 'data', then turn parity back off and turn 2 stop bits on. (which still keeps a 9 bit word length in as far as your microcontroller is concerned ;)... it's a long time ago but as far as i recall stop bits are just as long as data bits in the timing of things.

this should work on anything that can do 8 bit output, with parity, and with 2 stop bits. which includes pc hardware and linux. (and dos etc)

pc hardware also has options to just turn 'parity' on or off for all words (Without actually calculating it) if i recall correctly from 'back in the days'

furthermore, the 9th bit the pic datasheet speaks about, actually IS the parity bit as in RS-232 specifications. just that you're free to turn it off or on. (on PIC's anyway - in linux it's a bit more complicated than that)

(nothing a few termios settings on linux won't solve i think... just turn it on and off then... we've made that stuff do weirder things ;)

a pic microcontroller actually does exactly the same, just that it's not presented like 'what it actually is' in the datasheet. they actually call it 'the 9th bit' and things like that. on pc's and therefore on linux it works pretty much the same way tho.

anyway if this thing should work 'both ways' then good luck wiring it with 2 pairs or figuring out some way to do collission detection, which is hell a lot more problematic than getting 9 bits out.

either way it's not much more than an overrated shift register. if the uart on the pc doesn't want to do it (which i doubt), just abuse the DTR pin to just shift out the data by hand, or abuse the printer port to do the same, or hook up a shift register to the printer port... but with the parity trick it should work fine anyway.

   #include<termios.h>
   #include<stdio.h>
   #include<sys/types.h>
   #include<sys/stat.h>
   #include<fcntl.h>
   #include<unistd.h>
   #include<stdint.h>
   #include<string.h>
   #include<stdlib.h>

   struct termios com1pr;
   int com1fd;

   void bit9oneven(int fd){
   cfmakeraw(&com1pr);
   com1pr.c_iflag=IGNPAR;
   com1pr.c_cflag=CS8|CREAD|CLOCAL|PARENB;
   cfsetispeed(&com1pr,B300);
   cfsetospeed(&com1pr,B300);
   tcsetattr(fd,TCSANOW,&com1pr);
   };//bit9even

   void bit9onodd(int fd){
   cfmakeraw(&com1pr);
   com1pr.c_iflag=IGNPAR;
   com1pr.c_cflag=CS8|CREAD|CLOCAL|PARENB|PARODD;
   cfsetispeed(&com1pr,B300);
   cfsetospeed(&com1pr,B300);
   tcsetattr(fd,TCSANOW,&com1pr);
   };//bit9odd

   void bit9off(int fd){
   cfmakeraw(&com1pr);
   com1pr.c_iflag=IGNPAR;
   com1pr.c_cflag=CS8|CREAD|CLOCAL|CSTOPB;
   cfsetispeed(&com1pr,B300);
   cfsetospeed(&com1pr,B300);
   tcsetattr(fd,TCSANOW,&com1pr);
   };//bit9off

   void initrs232(){
   com1fd=open("/dev/ttyUSB0",O_RDWR|O_SYNC|O_NOCTTY);
   if(com1fd>=0){
   tcflush(com1fd,TCIOFLUSH);
   }else{printf("FAILED TO INITIALIZE\n");exit(1);};
   };//initrs232

   void sendaddress(unsigned char x){
   unsigned char n;
   unsigned char t=0;
   for(n=0;n<8;n++)if(x&2^n)t++;
   if(t&1)bit9oneven(com1fd);
   if(!(t&1))bit9onodd(com1fd);
   write(com1fd,&x,1);
   };

   void main(){

   unsigned char datatosend=0x00; //bogus data byte to send
   initrs232();
   while(1){
   bit9oneven(com1fd);
   while(1)write(com1fd,&datatosend,1);
   //sendaddress(223); // address microcontroller at address 223;
   //write(com1fd,&datatosend,1); // send an a
   //sendaddress(128); // address microcontroller at address 128;
   //write(com1fd,&datatosend,1); //send an a
   }
   //close(com1fd);
   };

somewhat works.. maybe some things the wrong way around but it does send 9 bits. (CSTOPB sets 2 stopbits, meaning that on 8 bit transparant data the 9th bit = 1, in addressing mode the 9th bit = 0 ;)

also take note that the actual rs232 line voltage levels are the other way around from what your software 'reads' (which is the same as the 'inverted' 5v ttl levels your pic microcontroller gets from the transistor or inverter or max232 clone ic). (-19v or -10v (pc) for logic 1, +19/+10 for logic 0), stop bits are negative voltage, like a 1, and the same lenght.

bits go out 0-7 (and in this case: 8 ;)... so start bit -> 0 ,1,2,3,4,5,6,7,

it's a bit hacky but it seems to work on the scope.
enter image description here

淡淡的优雅 2024-09-14 07:02:05

我还制作了 9 位 UART 仿真的完整演示(基于偶/奇校验)。您可以在此处找到它。

所有来源均可在 git 上找到。

您可以轻松地将其调整为适合您的设备。希望你喜欢它。

I also made complete demo for 9-bit UART emulation (based on even/odd parity). You can find it here.

All sources available on git.

You can easily adapt it for your device. Hope you like it.

罪#恶を代价 2024-09-14 07:02:05

Linux 程序可以通过串行设备发送和接收 9 位字节吗?

标准 UART 硬件(8251 等)不支持 9 位数据模式。

Can a Linux program send and receive 9-bit bytes over a serial device?

The standard UART hardware (8251 etc.) doesn't support 9-bit-data modes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文