OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2931回复:23

Dazzy,能看看吗?模拟串口的问题。

楼主#
更多 发布于:2002-09-30 16:27
我用一个usb芯片来模拟多个串口,就需要使用单片机的I/O引脚模拟RXD,TXD。
我的想法是这样的,比如我要模拟一个2400bps的串口,我选两条pin作为RXD和TXD。那么每一位的时间大概是0.41666毫秒。我可以利用一个定时器中断来得到这个时间。

当有数据要发送的时候,我就按照数据的各个位,每0.4166毫秒改变一次TXD引脚的电平,(当然了,在数据前还要开始位,后面还有结束位,可能有奇偶位,都按0。4166毫秒一位改变引脚电平),不知道这样的做法对不对呢?

对于数据的接收,同样,我每0.4166毫秒去读一次RXD引脚,如果发现一个开始位,就按每0.4166毫秒一次对该引脚进行采样,得到各个数据位,奇偶位等,直到一个停止位。这个方法可行吗?

如果可行,那么,会不会出现我对引脚进行采样的时候正好是在电平变换的边缘?那么读到的值可能会有影响吧?用什么方法避免呢?

如果收到数据后,发现奇偶校验不对,应怎么处理?


问题太多了,请你指点,谢谢!
I know nothing!
dazzy
驱动中牛
驱动中牛
  • 注册日期2001-03-23
  • 最后登录2008-08-12
  • 粉丝1
  • 关注0
  • 积分0分
  • 威望10点
  • 贡献值1点
  • 好评度10点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-10-04 00:59
1. 发送没有什么要求,只要时钟,电平准确就行!并不是每0.4166毫秒改变一次TXD引脚的电平,如果相邻的两位值一样,你就没有必要改变电平吗。
2. 接收就要求严格了。按照你说的方法是不可取的。接收时,你首先要做的是取得起始位的时基。关键是看你如何取得起始位的时基?如过时基正确,就不会出现你所说的“对引脚进行采样的时候正好是在电平变换的边缘”。首先要求你的定时器可编程。在采样起始位阶段,定时精度应该更细,比如可以定为0.41666/4毫秒为采样周期,连续采样两次如果电平为起始位电平,则从此时起,开始将定时周期设为0.41666毫秒,每隔0.41666毫秒读取端口的值。这样就可以将采样数据的时间限定在(0.41666)/2与(0.41666*3)/4之间了。不会出现边沿采样的情况了。这样做,还可以解决定时精度问题,使得传输的数据的定时精度可以限定在一定范围内。
3. 收到的数据奇偶校验不对的问题,是你自己的事。你可以选择ignore,也可以选择请求resend,总之,是你自己的事。模拟串口只需将取的数据存放,并计算出奇偶校验位即可。
4.在家用猫上网极为不便, 答的不够详细, 请谅。
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-10-04 08:35
谢谢大虾指点。
偶正在设计一个模拟6个串口的东西,大虾的主意解决了我好几天的疑虑。我估算了一下,这样做,大概能达到19200bps,不知道大虾认为这个速度怎么样?
如果其中一个串口利用了单片机的UART,那么中断处理是不是更不好,就是说,又有串口中断,又有时间中断,是不是更容易打乱时钟中断的精确性?我考虑所有的串口都模拟,不使用UART,不知道你认为怎么样?

再有就是,如果UART收到一个字符后,如果不能及时的把字符取出来,是否可能造成下一个字符丢失?


不是你回答的不详细,是我的问题太多了。谢谢! :)
I know nothing!
dazzy
驱动中牛
驱动中牛
  • 注册日期2001-03-23
  • 最后登录2008-08-12
  • 粉丝1
  • 关注0
  • 积分0分
  • 威望10点
  • 贡献值1点
  • 好评度10点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-10-04 12:35
1. 这个速度对于模拟串口而言已经可以了,如果处理的好,cpu速度快一些,速度应该更高一些,一般模拟串口能达到38400bps(12M),达到这样的要求是要你的中断处理时间尽可能的短,没有冗余代码,如果你的代码里有一段中断处理代码太长,你的定时精度肯定是不够的了。
2. UART处理的时间短是可以想想的,如果是我自己处理,并且又要求模拟串口的速度快,我是不会既用UART又用模拟串口的,因为,你首先要保证你的数据的准确性。
3. 如果UART有缓冲(比如80c19x的UART),下一个字符不会丢失,如果没有那就会丢失了。
4. 上一贴里忘了说,在你接收到停止位后,你的定时器应该进入检测起始位阶段。
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-10-04 18:32
谢谢你,Dazzy大虾。
我现在采取了你的建议,打算六个模拟串口都用一个定时器中断来管理。我想把这个定时器设置为最大的波特率的周期的四分之一,六条接收线都用中断引入。当有一个起始位时,会产生外部中断,我就在对这个中断对应的输入引脚等待一段时间(取决于该脚的波特率),然后进行采样(9次)。 当然,收到起始位后,就把 那个外中断disable,等收到停止位后,就打开它。

但是,这样的话,虽然可以用一个时钟中断搞定,但是由于该时钟设置为最大波特率的一个位的周期的四分之一,可以想象,中断较为频繁。不知道大虾你认为怎么样?

谢谢!  :) (我也是在家用猫上网,呵呵)
I know nothing!
dazzy
驱动中牛
驱动中牛
  • 注册日期2001-03-23
  • 最后登录2008-08-12
  • 粉丝1
  • 关注0
  • 积分0分
  • 威望10点
  • 贡献值1点
  • 好评度10点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-10-05 01:02
你是否每个模拟串口都用独立的一个外部中断源?

你的6个串口是否允许同时传输数据?我想应该是可以的。

每个串口传输的速度是否一样?我想可以不一样。

如果多个串口数据同时传输,你是否都要保证无误接收?如果只有一个模拟串口,那么采用一个定时周期即可。对于两个或者两个以上,采用一个定时周期肯定是不行的。除非每个串口都用一个定时器。至于这个是否为1/4周期,你可以进行测定,选择合适的值。
以前的贴子我所说的方法用于“起始位不是用中断检测的“。如果起始位用中断检测,应该更简单一些。

这样做,中断确实比较频繁。但是换来的是底成本,当然软件复杂度升高,传输速度降低。这就看你如何取舍了。还得看你的CPU处理速度如何?如果快速CPU,那么是能够解决你的问题的。当然,编码时最好用汇编或者关键代码用汇编,以减少冗余代码。如果选用传统的低速51系列CPU,估计传输速度是不会让你满意的。
确定你的最大传输速度是很重要的,这要考虑多种情况。

我说的无用话可能太多,主意还的你自己拿。

祝你好运!


[编辑 -  10/5/02 by  dazzy]
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2002-10-05 17:47
Dazzy,你好!
你说的模拟串口能达到38400bps,是指什么情况下啊?

我现在用的20mhz单片机,5个外部中断,模拟六个串口,恐怕要达到这个速度不可能吧。要求到也不高,有4800,9600就可以了。我估计了一下,可能9600都很难,因为虽然中断源足够,但是由于要支持六个口同时全双工工作,那么时钟中断怎么也不够啊。
所以我想了一个笨办法,利用一个时钟中断,定时为最大波特率周期的四分之一,对每个串口采取不同的计数器来计算时间,都是用这一个定时器来管理,每次中断都更新这些计数器,然后根据是否达到一定的时间来决定采样时间。

你有没有更好的办法? 谢谢!
I know nothing!
dazzy
驱动中牛
驱动中牛
  • 注册日期2001-03-23
  • 最后登录2008-08-12
  • 粉丝1
  • 关注0
  • 积分0分
  • 威望10点
  • 贡献值1点
  • 好评度10点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2002-10-06 00:50
38400是对于单串口。

9600是可以达到的。 如果采用单定时器,对定时中断次数记数的方法是不错的方法,也是唯一的方法。根据不同的波特率周期采样记数值就不一样。

你完全可以采用定时查询的方式来检测起始位的。要知道你引入的6个外部中断源要占用宝贵的CPU处理时间。既然你可以采用定时查询的方式完成对起始位的检测,大可不必再加上中断方式检测起始位。
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2002-10-06 01:46
Dazzy大虾,你太热心了。真的应该好好谢谢你。等搞掂后给你猛加分,呵呵 (当然,如果还有问题,偶就继续请教你,呵呵)

Thank you, very much! :)
I know nothing!
dazzy
驱动中牛
驱动中牛
  • 注册日期2001-03-23
  • 最后登录2008-08-12
  • 粉丝1
  • 关注0
  • 积分0分
  • 威望10点
  • 贡献值1点
  • 好评度10点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2002-10-06 08:04
分我无所谓的。

我知道的告诉你,能帮助你提供一点信息就行了。
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2002-10-06 11:30
好像除了分,我也不能提供什么帮助给你了,呵呵

只好多次的感谢你了  :)

[编辑 -  10/6/02 by  OS_Dev]
I know nothing!
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2002-10-07 15:56
Dazzy大虾,又来麻烦你一下了。
什么时候把endpoint设为stall状态?有没有什么规律可循?谢谢
I know nothing!
dazzy
驱动中牛
驱动中牛
  • 注册日期2001-03-23
  • 最后登录2008-08-12
  • 粉丝1
  • 关注0
  • 积分0分
  • 威望10点
  • 贡献值1点
  • 好评度10点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2002-10-08 11:35
关于STALL endpoint, usb规范上讲了一些。另外看你的实际应用了。

比如说:对于串口传输数据而言,你传输的数据要求一次传输特定的字节数(里面的数据的特定定义),如果由于设备原因(故障),你不能完成传输,这时,你需要STALL.

另外,如果你用BULK PIPE发送一个命令,device接收的命令不正确,需要STALL.

用设备PIPE BULK IN 取状态值时,状态不正常,应该STALL 此PIPE BULK IN.

如果你用BULK PIPE发送一个device不支持的命令,应该STALL此命令.

如果你的串口设备用bulk发送命令取得串口的portnumber, 而此串口不支持多portnumber, 你应该STALL.

用control pipe 发送vendor request, 如果有误,应该对其STALL.
x_zhao
驱动牛犊
驱动牛犊
  • 注册日期2002-07-23
  • 最后登录2002-10-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2002-10-08 22:09
请问OS_Dev,你的多个串口是如何分别与主机通讯的,也就是说主机如何表明它想与哪一个串口通讯,是不是要在传送的USB数据中包括寻址信息,你是如何做到的?
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2002-10-08 23:48
很多方法,对于端点较多的usb,你可以用一对端点来模拟一个串口。
对端点少的usb,你可以采用一对端点分用的方法。比如,你可以自己定义一个两个byte的数据结构,第一个byte表示操作的串口,第二个才是数据,每次都发2个byte过来,firmware自己分析。当然,这是个比喻,总之你可以随意控制,方便得很。
I know nothing!
dazzy
驱动中牛
驱动中牛
  • 注册日期2001-03-23
  • 最后登录2008-08-12
  • 粉丝1
  • 关注0
  • 积分0分
  • 威望10点
  • 贡献值1点
  • 好评度10点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2002-10-09 08:38
os_dev说得很好,一般的usb串口都是这么做的,用bulk管道传输数据;控制管道(vendor request)传输串口的一些设置等命令(比如波特率等),它的portnumber由index指定。
x_zhao
驱动牛犊
驱动牛犊
  • 注册日期2002-07-23
  • 最后登录2002-10-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2002-10-09 09:08
请问dazzy,我如何将自己的寻址字节加入USB数据中呢?是不是在驱动程序中来实现。
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2002-10-09 10:05
什么寻址字节?能说明白点吗?
I know nothing!
x_zhao
驱动牛犊
驱动牛犊
  • 注册日期2002-07-23
  • 最后登录2002-10-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2002-10-09 14:51
比如说我现在需要控制用一条USB线来模拟6个串口,而我选的接口芯片只有3个端口,那只能用你说的第二种方法,这就必须在传送的真实数据前加一个字节来指定这次传输是向哪个串口进行。我想要实现这种方法是不是必须在驱动程序中做文章,由驱动程序根据情况自动添加前面的字节?但是具体怎么实现,你实现过吗?
OS_Dev
驱动中牛
驱动中牛
  • 注册日期2002-01-09
  • 最后登录2004-03-04
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2002-10-09 14:57
一般说都是在驱动程序里做,至于怎么做,是你自己定义的,这个无所谓,每个人考虑的方法不一样,需要处理的场合不一样。
我说的那个方法只是最简单的一种,不一定适合你。反正,怎么定义这个数据结构是你自己规定的一个协议:你只要保证你的设备端的firmware能够理解驱动程序发来的数据就行了。就这么简单。
I know nothing!
上一页
游客

返回顶部