zoukankan      html  css  js  c++  java
  • 教你如何在51单片机上模拟串口通信!!!

    我们可以不使用单片机本身带有的串口,而自己用程序去模拟一个串口并达到和本身的串口具有同样的功能,

    首先,我们需要用到CH340串口模块,大家可以上某宝自行购买。

    正面:

    反面:

    然后我们需要了解一下这串口模块上的引脚:

    5V  :与VCC短路为5V TLL输出(电源和信号输出都是5V

    VCC:可以与3.3V5V用跳帽连接

    3.3V:与VCC短路为3.3V TLL输出(电源和信号输出都是3.3V

    TXD:发送数据端口(与单片机上的接收引脚用杜邦线连接)

    RXD:接收数据端口(与单片机上的发送引脚用杜邦线连接)

    GND:地线

     

    因为我是有另外一条串口提供了51单片机的电源,所以就没连接5V和VCC,只与单片机连发送、接收和地端口。

    现在,让我们一起了解一下串口通信协议是怎样的

    我们可以将该协议分成三部分

    一、            起始信号

    二、            数据位

    三、            结束信号

     

    首先,串口主要有发送和接受两个主要功能,

    发送

    比如说我们需要发送一个0X48的十六进制数,它的二进制为 01001011

    则过程为

    一、起始信号

      默认电平为高(1),先将发送端的引脚电平拉低(0)持续104us,来作为一个起始信号

     

    二、八个数据位

      数据的发送,是从最低位开始到最高位一位一位发送的,每一个数据位都需要持续104us(串口助手上选择了9600波特率,所以延迟时间 104us = 1s / 9600,如果波特率为其他,需要自行换算

     

    三、结束信号

      需要将发送端的引脚电平拉高(1)持续104us以上。

     

    接收

    其实接收也很好理解的,怎样发送就怎样接收,只是看接收的技巧而已

    比如说刚刚发送的0X48从主机发送到了单片机上,我们需要接收

    则过程为

    一、起始信号

      我们需要读取到它的起始信号,就是当它把你的接收端引脚持续拉低104us之后,就可以当作是开始接收了。

    二、八个数据位

      因为是八个数据位了,所以所接收的数据也会按照发送一样一个一个发送,我们只要去读取这时候的引脚电平就好。

     三、结束信号

      最后也是一样,再需要确认一次结束信号,读取电平是否为高电平,如果全部确认成功后,就可以认为是接收一个有效的数据了。

     

    下面为个人图解

    理论已经说完,接下来就是怎样用代码实现了

    那我们一步一步开始吧

    第一、创建工程

     

    第二、创建延时函数

     

    代码:

     1 void Delay_us(int x)      //微秒
     2 {
     3    while( x-- != 0 )
     4    {
     5       _nop_();
     6       _nop_();
     7    }
     8 }
     9 void Delay_ms(int x)        //毫秒
    10 {
    11    int i,j;
    12    while( x-- !=0 )
    13    {
    14       for(j=0;j<10;j++)
    15       for(i=0;i<85;i++);  
    16   }
    17 }

    这里的Delay.c里面有两个延时函数,一个为微秒级,一个为毫秒级。

    我们还需要再创建一个Delay.h头文件来向外声明这两个函数。

    头文件的话,我们还需要把它的路径添加到工程里,步骤如图

    我不把这两个函数写进main.c的原因是如果以后写的代码过长了,全部都堆在主函数里的话不方便管理,而这样分开的话可以降低他们的耦合关系,下面也同理了。

     

    第三、串口函数

    这里的函数创建和上面的步骤是一样的了

    发送函数:

    代码:

    void vFn_Uart_Send(unsigned char uContent)
    {
       unsigned int i;
       unsigned char uSendContent =0xff;         //定义一个发送数据的变量
       uSendContent = uContent;                //将要发送的值赋给该变量
     
       //起始信号
       P05 = 0;                            //P05作为发送端的引脚
       Delay_us(61);                         //延迟104us
     
       //数据发送
       for(i=0;i<8;i++)
       {  
        P05 = uSendContent & 0x01;               //将所要发送的八位数据的最低位和0x01进行于运算,若最低位为1,相于后的结果为1,则P05电平为高,否则为0
        uSendContent = uSendContent >> 1;         //将第二位数据位移到最低位,重复进行七次移动
        Delay_us(61);  
     
       }  
     
       //结束信号     
       P05 = 1;                            //将该引脚电平拉高
       Delay_us(61);                         //延时104us
    }
     

    这里的104us延迟函数,我已经用示波器测试过时间的了,是可以直接使用的。

    因为烧写时候不同的频率也会造成延时函数改变,所以大家有条件的话,也可以自己具体去测量一下的

    接收函数:

     代码:

    void vFn_Uart_Receive()
    {
       unsigned int i; 
       unsigned char uContent = 0x00;        //定义一个用于接收数据变量
     
            //起始信号
       if(P21 == 0)                    //判断是否接收到起始信号
       {
         Delay_us(29);                  //延时52微秒
           if(P21 == 0)                 //再判断一次接收端电平是否被拉低
           {         
           //数据接收     
             for(i=0;i<8;i++)         
             {             
                 uContent = uContent >> 1;   //将值右移一位
                 Delay_us(61);           //延时104微秒
                 if(P21 == 1)           //判断是否为高电平
                 {            
                   uContent |=  0x80;     //若为1则与0x80进行或运算(加上0x80也是一样的道理)
                 }           
             }             
          }              
            Delay_us(61);                //延时104微秒
     
          //结束信号
         if(P21 == 1)                  //判断电平是否被拉高
         {                       
          vFn_Uart_Send(uContent);         //将uContent的值用发送函数发送出来
          Delay_ms(1000);          
          }              
      }                
    }

    这里讲解一下接收函数,我们知道起始信号拉低后,有104us的延时,延时完后就是八个数据位了,如果我们每一次都等完104us再去读取引脚的电平的话可能会不太稳定,所以我们可以在每个电平中间去读取,这个时候是最稳定的。下面为图解

    第四、主函数编写

    因为都把函数放到了其他文件中,这样主函数会看的比较简洁,我们也直接调用相关的函数就行了,主函数使用也没有太多的要求。

    这里的话是需要每写完一个函数就去测试的,不过我是已经是全部测试通过的了,然后大家就还是写完一个测试一个,因为一次性写完所有函数然后马上通过的机率不大,还是要修改很多东西

    然后我用的是下载软件是这个,烧写的时候我们需要将IRC的频率改成12MHz进行烧写

    串口助手的话,我用的是SSCOM,另外因为我这个单片机的主芯片是IAP15W4K48S4,里面的GPIO的波特率也设置为了9600,所以我们也需要将其设置为9600的波特率才能看到数据,不然就是一堆乱码了,再然后就是点击HEX显示和HEX发送了。

    我们来看是已经发送出来了。

    再就是测试接收了

     

    这里是把接收直接放到while(1)里面跑,大家也可以使用定时器的,用中断去跑的话就更好了,这里只是一个小小的示范。

    发送了0x52,也接收了0x52,成功了。

    这样一来,我们也就完成模拟串口的收发了。

    最后再教一下如何用模拟串口发送文字吧,非常简单的一个小函数,

    代码

    void vFn_Send_Word(unsigned char *s)
    {
        while(*s)
        {
            vFn_Uart_Send(*s++);
        }
    }

    然后再在主函数调用就可以实现了。

     

     

    我的关于51单片机模拟串口到这就结束了,谢谢大家。

  • 相关阅读:
    在 Windows 上测试 Redis Cluster的集群填坑笔记
    vmware安装黑苹果教程
    微信支付v3发布到iis时的证书问题
    Linux下安装SQL Server 2016(连接篇SQL Server on linux)
    Linux下安装SQL Server 2016(连接篇SQL Server on linux)
    Linux下安装SQL Server 2016(安装篇SQL Server on linux)
    Linux下安装SQL Server 2016(准备篇SQL Server on linux)
    客服端与服务端APP支付宝支付接口联调的那些坑
    ASP.NET MVC]WebAPI应用支持HTTPS的经验总结
    .net平台下C#socket通信(中)
  • 原文地址:https://www.cnblogs.com/zhenghaoyu/p/10059848.html
Copyright © 2011-2022 走看看