打印
[CW32F030系列]

普通IO口模拟串口功能

[复制链接]
101|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
i1mcu|  楼主 | 2024-6-21 19:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
要模拟串口首先要清楚串口数据传输过程中的原理。

所以最简单的串口传输一个字节总共有10个电平变化,每个电平的宽度由波特率决定的。

下面看一个通过波特率如何计算每个位的电平宽度。

可以计算出传输1位所需要的时间 T1 = 1/9600 约为104us。

上图中就是一个字节的完整波形,起始位为低电平,结束位为高电平,中间8位为数据位,无校验位。数据位是低位在前,高位在后。也就是和起始位挨着的是最低位,和结束位挨着的是最高位。通过这个波形就可以分析出,发送的数据是0x00。

起始位为低电平,结束位为高电平,中间数据位有一个高电平,其余都是低电平,按照低位在前,高位在后规律,数据位就是0000 0001 刚好是16进制的0x01。

//输出1
{
}
void Send_0( void )
    SIM_TXD = 0;
//发送一个字节
{
    unsigned char i;
    //发送起始位
    delay_us( 100 );
    for( i = 0; i < 8; i++ )
        value = ( sdata & 0x01 ); //先传低位
        {
        }
        {
        }
        sdata = sdata >> 1;
    //停止位
    delay_us( 100 );           
首先发送起始位,将IO口电平拉低,延时104us,下来发送8位数据位,低位在前,高位在后,每发送一位就延时104us。最后发送结束位,将IO口电平置高,在延时104us。这样一个字节就发送结束了。

下面再看接收程序

void ReadByte( void )
    unsigned char i, value = 0;
    {
        delay_us( 100 );
        for( i = 0; i < 8; i++ )
            value >>= 1;
            {
            }
        }
        //delay_us(100);  //一次性接收大量数据时,防止程序执行代码时浪费时间,在结束符时可以不用等待
        RecBuf = value;
    }
接收数据就更好理解了,读取IO口的电平,如果出现低电平就开始接收数据,然后读取8个数据位的电平,在等待结束位结束。这样一个字节的数据就接收完成了。

有两种方式去实现,一种是在死循环中用查询方式去判断,一直读取IO的的电平,如果出现低电平就认为串口有数据发送进来了。

//查询方式接收数据
{
    unsigned char recstr[100] = {0};
    while( 1 )
        if( !RecFlag )            //未收到数据时扫描
            ReadByte();          //扫描数据
        }
        {
            RecFlag = 0;
            RecBuf = 0;
        }
        {
            WriteString( recstr );  //发送接收到的数据
            i = 0;                  //清除接收数据数组下标
            {
            }
        }
        {
            return;
    }
这种方式实现起来比较简单,但是对于程序编写比较麻烦,因为要一直监视者IO口,所以程序干其他事情时,很有可能错过数据的接收。可以用第二种方式,IO口中断来判断什么时候要开始接收数据,将IO口设置为下降沿中断,当有下降沿出现时,说明串口有数据进来了,然后再去读取串口数据。没有中断发生时,程序就可以干其他事情了。

//通道PC3口的下降沿中断检测数据
#pragma vector = 7                  // IAR中的中断号,要在STVD中的中断号上加2
{
    ReadByte();
    {
        {
            recCNT = 0;
    }
    {
        {
            RecBuf = 0;
        else if( RecBuf == 0x0d )   //收到0x0d 标记结束符开始
            recEnd |= 0x01;
    }
}

当出现下降沿之后进入中断程序,这时候要关闭外部中断,开始读取IO口电平状态。若不关闭中断,在读取IO电平的过程中中断还会不停的进入,这样就会影响读取数据的准确性。所以进入中断会首先要关闭中断,接收完一个字节之后,在打开中断,接收下一个字节。直到收到了回车换行符(也就是0x0D 0x0A),就认为数据发送已经结束。就退出接收过程,然后主程序就可以去处理接收到的数据了。

使用特权

评论回复
沙发
OKAKAKO| | 2024-6-21 20:07 | 只看该作者
模拟IO能够说明原理性的文件

使用特权

评论回复
板凳
中国龙芯CDX| | 2024-6-26 16:51 | 只看该作者
计算出传输1位所需要的时间 T1 = 1/9600 约为104us

使用特权

评论回复
地板
jf101| | 2024-6-27 16:36 | 只看该作者
一个字节的完整波形,起始位为低电平,结束位为高电平,中间8位为数据位,无校验位

使用特权

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

本版积分规则

275

主题

8454

帖子

9

粉丝