slk231 slk231
关注数: 10 粉丝数: 23 发帖数: 84 关注贴吧数: 15
CC800/PC1000串行通讯原理详解   在CC800/PC1000机子的旁侧,可以看到的一个插孔,就是CC800/PC1000的串行通讯口,CC800/PC1000用这个口与电脑或其他机子连线进行数据的传输,所以一般称之为串口。长期以来,网上的文曲星论坛里一直没有介绍关于CC800/PC1000的这个串口的通讯原理和编程的文章,使得广大星迷们对CC800/PC1000的通讯原理一知半解,更谈不上对串口进行编程了,本人sel.mocker通过一段时间的研究,最终得出一些结论,现在贴出来与广大CC800/PC1000星迷们共享。   以下都是本人对CC800/PC1000通讯原理的个人理解,其中肯定有不足不正之处,还请高手们不吝赐教。   其实CC800并没有真正意义上的串口。真正的串口有波特率这样一个概念,是指串行通信中每秒传送的数据位。一般单片机中都有SBUF这样一个寄存器,只要事先设定好波特率,再将要发送的字节写入SBUF,串行通信装置就能以设定好的波特率将数据通过一根串行线将数据发送出去,接收亦是同理,只需读取SBUF即可。所以两台单片机只要在波特率相同的情况下就能正确收发数据,进行正常的串行通信。   但是CC800/PC1000并没有真正的串口(这是它的硬件设计师决定的,NC1020,NC2000等就有真正的串口),这样的情况下,要进行串行通信只能用普通的I/O口来模拟串口,就是以固定的时间间隔控制这条I/O口高电平或低电平,就能模拟出一个固定的波特率来。注意这波特率必须是“固定”的,这在有可编程中断和定时器的单片机中是容易实现的,但关键是,CC800/PC1000的中断是固定好了的,没法编程,定时器似乎也没法编程。所以,考虑到CPU的速度并不稳定,CC800/PC1000根本无法做到精确地以“固定的时间间隔来控制那条I/O口”,也就是说,在一条I/O线的情况下,CC800/PC1000根本无法做到波特率固定。波特率不稳定的情况下进行串口通信是很冒险的,因为数据错误率会高到你无法接受的地步。   幸运的是,CC800/PC1000在设计之初就绕过了波特率不稳定这一难题,因为CC800/PC1000使用两条I/O线,而不是一条!   那么多出来的那条I/O线是作什么用的呢?你可能想到了:用于同步信号!我们可以称之为同步线,那么另一条I/O线就成了数据线。两条I/O线可以比作正跟你对话的两个人A和B,A先对你说:“B要和你说话。”(相当于发出一个同步信号),你就会知道B要跟你说什么话,才放下手中的工作准备仔细聆听B对你说的话(相当于准备接受一个数据位),这样,只有当同步线有信号时,接收方才会接收数据线上的一个数据位。这样的设计使得通信非常地自由,只要你发送数据的时间间隔没有超过接收方的超时时间限制,什么时候传都可以,根本不用考虑去固定波特率。   CC800/PC1000中真正用于通信的代码原理就是这样,发送一个数据位时先将数据位传到数据线,然后让同步线有一个负跳变,当作一个同步信号,接收方检测到同步线有负跳变时,就读取数据线上的电平信号,这样就完成了一个数据位的传输,传输一个字节就需要八次上述的操作。   上面已经讲了CC800/PC1000传输一个数据位的基本通信原理,下面让我们上升到整套的完整的通信协议。   任何串行通信的开始都需要一个握手程序,以确保双方做好通信准备。这相当于有个人想和你聊天,他会先打个招呼:“Hi,可以和你聊聊吗?”这时若你拒绝了,那么那个人与你的谈话无法开始,若你不理睬他,谈话也同样无法进行,只有当你接受了,回答他说:“可以啊。”表示你已经准备好与他开始谈话,握手程序才顺利通过。   CC800/PC1000的握手程序基本上也就是让一条I/O线一直跳变,发出请求,另一条接收对方的响应,接收方若同意了就会做出响应,握手程序顺利通过,通信就可以开始了。若连线有问题或对方未准备好,请求方的那条接受线上一直无对方响应,那么超过一定时间后(也就是超时),握手失败。   握手程序通过后,真正的数据传输就可以开始了,总之每个字节都是通过我前面所说的一个数据位一个数据位地传输,具体先传什么数据,还有如何校验,都是编程者自己设定的,这都属于通信协议的高层部分,本文仅是介绍CC800/PC1000底层的通信原理而已。   原理解释完了,但大家还不知道具体编程中怎么控制I/O线呢。   大家知道,文曲星中各外部接口都是映射到内存中的,如LCD液显的显存映射在内存中的$09C0--$0FFF,而存储器页码寄存器的映射地址就是$00,等等。这两条I/O线也有映射地址,那就是$18中的第5,第6位。 (不知道第5位和第6位?比如一个字节:bit bit bit bit bit bit bit bit           对应的位数就是 7  6  5  4  3  2  1  0    )   要知道CC800/PC1000串口里有三条线,若插上连接线,你握着连线的另一头,就会看到这个插头很像随身听耳机插头,共有三片金属片。最外的那个金属片对应着$18中的第六位,中间那个金属片对应$18中的第五位。最里的那个金属片是GND(地线),作为电平零基准。$18中第5,6位的电平会放映到插头上的两块金属片上来。同样若金属片接着高低电平也会放映到$18中的第5,6位上来。这样就能实现像读写内存的方式来控制两条I/O线的电平,很方便吧?   还要告诉你,这两条I/O线并不是同时双向的,在某一时刻一条I/O线只能是收或发,需要通过设定来规定某条I/O线是接收还是发送。某条I/O线设为发送时,才能往$18中的对应位上写数据位,而设为接收时仅能从$18中对应的位上读数据位并不能改写。怎么设定呢?同样是映射内存,$07的第5,6位分别设定$18中的第5,6位是发送还是接收,1表示发送,0表示接收。如设定$07的第5,6位为01,表示$18中的第5位是接收,第6位是发送。CC800/PC1000中的串行通信代码中,作为发送端的机子将$07设为11,接收的机子将$07设为00,这样发送端才能控制同步线的电平并往数据线里写数据位。而接收端两条I/O线都是接收。具体哪条作为同步线哪条为数据线都是看编程者自己设定的。在握手程序中,一台机将$07设为01,那么另一台机就得设为10。 但是设定完$07还不能通过$18中的第5,6位直接控制两条I/O线,为方便大家应用,一般是使用如下的初始化代码:    LDA #$9F    AND #04C0    STA $19    LDA $04BA    AND #$9F    STA $07    LDA #$00    STA $BC    LDA $04BA    ORA #$40 *    AND #$DF *    STA $07    STA $04BA (带*的语句中的数据仅用于举例) 本例中$07的第6,5位被分别设为10,即$18中第6位用于发送,第5位用于接收。 初始化$07之后,就可以直接对$18读写了: 写(发送):    LDA $04BD    ORA #$40 *    AND #$DF *    STA $O4BD    STA $18 (带*的语句中的数据仅用于举例) 这样$18中的第六位对应的I/O线就升为高电平了。 读(接收):    LDA $18    AND #$20 * (带*的语句中的数据仅用于举例) 这样$18中的第五位即对应那个I/O线上的电平就被过滤出来到A寄存器中了 接下来加一个BNE语句就可以依照读到的I/O线电平进行跳转了。   特别要注意的是:若你要改变两条I/O线的收发设定,比如说握手程序之前和之后,都要记得运行一下前面的初始化$07的代码,当然,怎么设定,看你自己的了。   至此,CC800/PC1000的通讯原理讲得也差不多了,希望这篇文章能给你一点帮助。我想我已经讲得很详细了,有什么不清楚的地方可以问我sel.mocker,其他的具体编程的细节就请你自己研究吧。若这篇文章对你没多大用处,也还是请你支持一下,至少我打了这么多字,也有苦劳吧。呵呵。 还是很谢谢你把它看完了! 手酸死了。。。 [转帖](WQXNET) by sel.mocker
1 下一页