串口通信问题-如何直接读写串口LCR寄存器(300分,帮顶有分) ( 积分: 100 )

  • 主题发起人 主题发起人 wino
  • 开始时间 开始时间
W

wino

Unregistered / Unconfirmed
GUEST, unregistred user!
最近遇到这样一个问题:PC与单片机通过RS232进行通信,通信过程中,需要来回切换串口的校验位,其它参数不变,现在PC发一条带参数的命令时,第一个字节的校验位为1,后面紧跟着发3字节的数据,它们的校验位为0(注:这里的校验位为0和为1时,都为无校验状态,仅让接收端单片机识别哪些是命令,哪些是数据),如:95 01 01 01 03, 其中 95为命令,发送时校验位=1,后面四字节的校验位=0

代码如下:
Dcb.Parity := 1;
SetCommState(hNewCommFile, Dcb);
if Connected then //判断串口是否打开
begin
if not WriteToComm(HexStrToStr('95')) then
ShowMessage('Write 95 Error!');
Dcb.Parity := 0;
SetCommState(hNewCommFile, Dcb);
if not WriteToComm(HexStrToStr('01 01 01 03')) then
ShowMessage('Write 95 Data Error!');
end;

问题出来了,这样发送出去的 命令字节'95' 和 数据字节'01 01 01 03',单片机接收无响应,后查出原来是由于超时引起的,也就是说在做 Dcb.Parity = 0/1 SetCommState(hNewCommFile, Dcb)时,超过了单片机接收的时间间隔(10ms),所以数据字节部分没有当成参数来处理。

现在我想通过直接IO操作的方式替代SetCommState来控制串口相关寄存器(IO读写的权限的问题已解决),在网上看了一些资料,通过ComBase + 3 来读写LCR寄存器,可是不管怎么设置,串口的校验位和波特率都不会改变,望哪位有这方面的经验的兄弟出手相助,另开贴送分,谢谢!
 
你这种方式很奇怪,在同一报文中,居然有的字节为效验,有的却无,是这样吗?难道是先将校验位为1的方式发出95,再以校验位为0的方式发出01 01 01 03,那你接受单片机的数据又是什么方式的呢?一个原则就是:如果你已什么效验方式或波特率发出数据对端就应当以什么方式接收数据!否则,你收到的数据就会难以解答
 
单片机的通信程序是自己写的吗? 如果是自己开发的, 我建议你重新定义通信协议.

如要直接读写串口, 可以参考下面的, 不过这是在DOS下的, 需要修改不少http://blog.csdn.net/flylonginsky/archive/2005/08/01/443595.aspx
 
谢谢上面的兄弟!

To: zxsdelphi
是的,协议中规定命令字节的校验位始终为1,参数字节为0,单片机那边是接收一个字节,先判断其校验位是否为1,然后再判断后面有没有跟合法参数(校验位为0),波特率都是19200

To:tseug
谢谢你提供的链接,一会儿仔细看看

问题有了新的进展,找到这样的资料:
线路控制寄存器(LCR) 00 xx0 011 00 11 10 11
LCR用于设置通讯所需的一些参数
位 注释
Bit7=1 允许访问波特率因子寄存器
Bit=0 允许访问接收/发送及中断允许寄存器
Bit6 设置间断;0-禁止,1-设置
Bit5,4,3=xx0 无校验
Bit5,4,3=001 奇校验
Bit5,4,3=011 偶校验
Bit5,4,3=101 奇偶保持为1
Bit5,4,3=111 奇偶保持为0
Bit2=0 一位停止位
Bit2=1 二位停止位(数据位6~8位),1.5位停止位(5位数据位)
Bit1,0=00 5位数据位
Bit1,0=01 6位数据位
Bit1,0=10 7位数据位
Bit1,0=11 8位数据位

NOPARITY No parity = 0
ODDPARITY Odd = 1
EVENPARITY Even = 2
MARKPARITY Mark = 3 校验和总为1
SPACEPARITY SPACE = 4 校验和总为0

于是,我用以下方式直接控制LCR寄存器:
OutPortb($3fb, $2b); //设置串口1 Parity = 1, ByteSize = 8
OutPortb($3f8, $90); //发送命令字节 '90'
OutPortb($3fb, $3b); //设置串口1 Parity = 0, ByteSize = 8
OutPortb($3f8, $00); //发送参数字节 '00'

现在的问题是如果用上面两行单独发90命令,命令被接受;如果上面4行一起执行,则命令和参数都没有被接受,看样子不是发送间隔超时的问题,好象是数据字节的校验位没有被接受,所以单片机没有响应

大家再帮忙看看,一起讨论一下,谢谢!
 
楼主用的是MCS-51的UART方式3,但这种硬件协议并不符合PC的串行口的规范,就算能从程序上解决,效率也是非常差的,不建议这样使用。
事实上,如果只是19200bps的通讯,是很容易用单片机先做一个通讯桥接部件来实现这样的功能的,PC端固定为MARK校验(第9位恒定为0),通过控制DTR线(DB9插座的第4脚)来实现帧启动,用中间的单片机来辅助发生那个“1”的第9位(用个或门)。
 
问题终于解决了,绕了一个大弯子,刚开始以为是用API来切换校验引起的超时,就起用IO方式来读写寄存器,最后发现发完命令字节后要加一个2ms的延时,这样单片机能正常响应了

Dcb.Parity := MARKPARITY;
SetCommState(hNewCommFile, Dcb);
if Connected then //判断串口是否打开
begin
if not WriteToComm(HexStrToStr('95')) then
ShowMessage('Write 95 Error!');

Application.ProcessMessages; //加了这两行
Sleep(2);

Dcb.Parity := SPACEPARITY;
SetCommState(hNewCommFile, Dcb);
if not WriteToComm(HexStrToStr('01 01 01 03')) then
ShowMessage('Write 95 Data Error!');
end;

再次感谢大家关注,看得出SupermanTm兄对硬件比较在行,有机会再向你请教!
 
结贴了,[:)]
 
后退
顶部