打印
[技术问答]

N73E003 IO口如何模拟串口

[复制链接]
2312|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hellobbx|  楼主 | 2018-5-22 20:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
现在一个项目需要用到4个串口,所以准备用IO模拟2个串口,这两个串口只接收数据。但是没什么思路,不知道怎么判断接收数据,大神给点提示呗。
沙发
antusheng| | 2018-5-22 20:44 | 只看该作者
如果是只接收那超级简单的,你直接用两个IO就行了。只要按照串行通信的时序搞就可以。

使用特权

评论回复
板凳
antusheng| | 2018-5-22 20:45 | 只看该作者
用普通 I/O 口也可以模拟标准 UART 串行口,进行串行通信。




UART 通信规范是以 8 位二进制数为一帧,低位在前,逐位的传输。

为了区分各个帧,在每一帧之前,要有一个 0 作为起始标记,之后,有一个 1,作为结束符。


在结束符之前,还可选发一个“校验位”,但是,目前多数的应用都不选择这个位。

那么,每次的串行通信,就是传送一个字节,加上前后的标记,共 10 位二进制数。

空闲时,发送的都是 1;一旦出现了 0,就说明开始传输数据了。

使用特权

评论回复
地板
antusheng| | 2018-5-22 20:45 | 只看该作者
波特率

串行通信的一个重要指标就是传输速度,就是每秒传送了多少位二进制数。

这个速度称为波特率,单位是 bps,中文就是“位/秒”。

使用特权

评论回复
5
antusheng| | 2018-5-22 20:46 | 只看该作者
时间设定



当以 9600bps 来传送数据时,每一位数的持续时间是 (1/9600)s,这也就是间隔时间。



如果选用晶振频率是 11059200Hz,一个机器周期T的时间就是 (12/11059200)s



那么,一位数的持续时间 (1/9600)s,是多少个机器周期T呢 ?



这是很容易算的,就是下面的这个算式:



    X = (1/9600) / (12/11059200) = 11059200 / 12 / 9600 = 96T



为了精确定时,可以利用定时器来定时,每当 96T 时间到了,就发送出去一位二进制数,这就行了。

使用特权

评论回复
6
antusheng| | 2018-5-22 20:46 | 只看该作者
给你个参考,不是这个单片机的,你按照这种思路做
实验程序



用 IO 口模拟串口输出的程序如下:



#include<reg52.h>



sbit TXD1 = P2^0;     //用IO口模拟串口发送端

sbit RXD1 = P2^1;     //用IO口模拟串口接收端



bit T96;              //位变量

//----------------------------------------

void Wait96(void)     //延时,控制波特率

{

    while(T96);       //等待出现0

    T96 = 1;          //清标志

}

//----------------------------------------

void WByte(char x)    //发送一帧数据

{

    char i;



    TL0 = 160;        //初值=256-96=160

    TXD1 = 0;         //发送起始位0

    TR0 = 1;          //启动定时器

    Wait96();         //等待96T

   

    for (i = 0; i < 8; i++)  { //8位数

      TXD1 = x & 1;   //先传低位

      x >>= 1;

      Wait96();       //等待96T

    }

   

    TXD1 = 1;         //发送结束位1

    Wait96();         //等待96T

    TR0 = 0;          //关闭定时器

}

//----------------------------------------

void main()

{

    char  i;

    TMOD = 0x02;      //T0定时方式2

    TH0 = 160;        //初值=256-96=160

    IE = 0x82;

    T96 = 1;          //清标志

    while(1)   {

      for (i = 0x41; i < 0x5b; i++) //A~Z

        WByte(i);

      WByte(0x0D);

      WByte(0x0A);

    }

}

//----------------------------------------

void inttime0() interrupt 1 //T0中断

{

    T96 = 0;          //设置标志

}

使用特权

评论回复
7
antusheng| | 2018-5-22 20:47 | 只看该作者
用 IO 口模拟串口输入也是可行的。

但是,这种模拟方法,编程的工作量,可以说相当的大;CPU 的工作时间,也被大量占用;

而且,还占用了定时器,那么在硬件资源方面,也浪费很多。

如果讨论模拟串口的接收问题,那还得搭上一个外部中断。

使用特权

评论回复
8
antusheng| | 2018-5-22 20:47 | 只看该作者
你用一个定时器配合一个IO中断就很容易实现了。自己摸索吧,方法给你讲了。

使用特权

评论回复
9
hellobbx|  楼主 | 2018-5-23 09:09 | 只看该作者
antusheng 发表于 2018-5-22 20:47
你用一个定时器配合一个IO中断就很容易实现了。自己摸索吧,方法给你讲了。 ...

谢谢,思路清晰了

使用特权

评论回复
10
wahahaheihei| | 2018-5-23 22:24 | 只看该作者
楼主搞出来没,分享一下代码。

使用特权

评论回复
11
天灵灵地灵灵| | 2018-5-23 23:39 | 只看该作者
跟51 的类似,之前51经常模拟的。

使用特权

评论回复
12
hellobbx|  楼主 | 2018-5-28 09:42 | 只看该作者
wahahaheihei 发表于 2018-5-23 22:24
楼主搞出来没,分享一下代码。

我是用IO口中断加定时器延时去实现的,就是延时一段时间后去读取一次IO口状态,这样就可以获取数据了。但是有时识别的不准,还在弄。

使用特权

评论回复
13
hellobbx|  楼主 | 2018-5-28 09:42 | 只看该作者
wahahaheihei 发表于 2018-5-23 22:24
楼主搞出来没,分享一下代码。

我是用IO口中断加定时器延时去实现的,就是延时一段时间后去读取一次IO口状态,这样就可以获取数据了。但是有时识别的不准,还在弄。

使用特权

评论回复
14
hellobbx|  楼主 | 2018-5-28 09:45 | 只看该作者
antusheng 发表于 2018-5-22 20:47
你用一个定时器配合一个IO中断就很容易实现了。自己摸索吧,方法给你讲了。 ...

大神,我用IO口中断加定时器延时去实现的。进入中断之后,循环的延时一段时间(一次电平变化的时间)后去读取一次IO口状态,但是有时识别的不准,能怎么改进呢?

使用特权

评论回复
15
wangshujun| | 2018-5-28 22:17 | 只看该作者
模拟发送占用资源很少,基本上有一个位中断就能可靠的发送了,程序也简单
模拟接收有两种策略可用:
1、使用外部中断捕获起始位的下降沿,然后设置一个1.5位的计时,这时采样的是数据的第一位的中点,比较可靠,之后的每一次延时都用1位的计时,知道收完一个字节后,重新变成外部中断模式。
2、使用2倍或更高的定时中断频率捕获io线状态,并记录过去至少4次的io状态,可以很方便的获取到需要的每一位数据

使用特权

评论回复
16
tianxj01| | 2018-5-29 11:16 | 只看该作者
考虑到串口接受用中断是最节约资源的,因此,用中断,可以把另外2个软串口设置到芯片的按键中断引脚作为带接受中断的串口RX端。中断服务程序就是启动定时器,并根据标记和定时器中断读取本端口。
然后根据设置的波特率第一个延时为1.5位,以后都是1位,该定时器中断来采样模拟的RX输入端电平,确定输入数据。等停止位后,关闭定时器本身,并打开软串口接受中断。
发送道理采用定时器的做法也是大同小异,这样就完美的模拟了一个带中断的软串口。而且占的时间资源非常低。

使用特权

评论回复
17
hellobbx|  楼主 | 2018-5-29 17:04 | 只看该作者
tianxj01 发表于 2018-5-29 11:16
考虑到串口接受用中断是最节约资源的,因此,用中断,可以把另外2个软串口设置到芯片的按键中断引脚作为带 ...

确实是这样做的,有时还是会出错

使用特权

评论回复
18
tianxj01| | 2018-5-29 17:23 | 只看该作者
hellobbx 发表于 2018-5-29 17:04
确实是这样做的,有时还是会出错

如果这样做,必须要考虑的问题有下面几个,如果做好了,理论上不会出错。
1、定时器和模拟串口中断的同步问题。这个必须严格,否则就会产生波特率错误。
2、2个软中断的并发问题,这个稍微有点复杂,但并不是不能解决,变换一下思路,用2倍波特率或者更高偶数倍的定时器中断,连续轮流采样软串口端口,就可以保证不丢掉任何一个串口接受端的信号,考虑到高速度定时采样比较占用时间资源,因此中断采样程序优先级必须设定比较高,而且程序必须非常精简,采样,转缓存、起始判断,通过计数完成,立刻申请软中断(芯片所有中断标志都可以软件置位,用这个思路就可以非常方便的做软中断),由软中断来完成数据处理,转换,写出,TX端口回复。这样编程,理论上就不可能错误。

使用特权

评论回复
19
734774645| | 2018-5-30 20:55 | 只看该作者
是不是也用了其他的中断啊,影响了这个响应。

使用特权

评论回复
20
玛尼玛尼哄| | 2018-5-30 21:55 | 只看该作者
是不是在读取的时候发生了其他中断影响了这个,如果不是那不该有差错。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

17

帖子

0

粉丝