找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1227|回复: 16
收起左侧

51单片机UART通信-不理解接收程序 求分析

[复制链接]
ID:1078938 发表于 2023-6-4 20:16 | 显示全部楼层 |阅读模式
不理解逻辑。
单片机是通过010101这种的高低电平模拟二级制记录数据的,这里是接收数据部分,PIN_RXD引脚的高低电平这里是如何控制的?

#include <reg52.h>

sbit PIN_RXD = P3^0;
sbit PIN_TXD = P3^1;

bit RxdEnd = 0;  //接收数据完成标记位
bit RxdOrTxd = 0;   //发送 和接收状态标记位
unsigned char RxdBuf = 0;//接收数据缓冲区
unsigned char TxdBuf = 0;//发送数据缓冲区

void ConfigUART(unsigned int baud);
void StartRXD();
void StartTXD(unsigned char dat);

void main()
{
     EA = 1;
           ConfigUART(9600);
        
           while(1)
                 {
                   while(PIN_RXD);
                         StartRXD();
                         while(!RxdEnd);
                         StartTXD(RxdBuf+1);
                         while(!TxdEnd);
                 }
}

void ConfigUART(unsigned int baud)
{

   TMOD &= 0XF0;
         TMOD |= 0X02; //模式2 ,自动重装模式
         TH0 = 256 - 11059200 / 12 / baud ;
         
}

void StartRXD()
{
   TL0 = 256 - ((256 - TH0)>>1);
         ET0 = 1;
         TR0 = 1;
         RxdEnd = 0;
         RxdOrTxd = 0;
}

void StartTXD(unsigned  char dat)
{

   TxdBuf = dat;
         TL0 = TH0; //发送整个数据
         ET0 = 1;
         TR0 = 1;
         PIN_TXD = 0;
         TxdEnd = 0;
         RxdOrTxd = 1;
}

void InterruptTimer0() interrupt 1
{
   static unsigned char cnt = 0;
        
         if(RxdOrTxd)
         {
            cnt ++ ;
                  if(cnt <= 8)
                        {
                           PIN _TXD = TxdBuf & 0x01;
                                 TxdBuf >>= 1;
                                 
                        }
                        else if(cnt == 9)
                        {
                          PIN _ TXD = 1;// STOP BIT
                        }
                        else
                        {
                           cnt = 0;
                                 TR0 = 0;
                                 TxdEnd = 1;
                        }
         }
         else //接收状态
         {
            if(cnt == 0)
                        {
                           if(!PIN_RXD) // 确认是起始位
                                 {
                                    RxdBuf = 0; //接收RxdBuf清空
                                          cnt++;
                                 }
                                 else // 不是低电平,是干扰信号
                                 {
                                    TR0 = 0; //关中断
                                 }
                        }
                        else if(cnt <= 8)
                        {
                            RxdBuf >>= 1; //接收数据是一位一位的接收
                                  if(PIN_RXD)
                                        {
                                          RxdBuf |= 0x80;
                                        }
                                        cnt ++;
                        }
      else
                        {
                            cnt = 0;
                                  TR0 = 0;
                                  if(PIN_RXD)
                                        {
                                          RxdEnd = 1;            
                                        }
                        }                                
         }

}

对于如下的:              RxdBuf >>= 1;
                                  if(PIN_RXD)
                                        {
                                          RxdBuf |= 0x80;
                                        }
                                        cnt ++;
回复

使用道具 举报

ID:1078938 发表于 2023-6-4 20:36 | 显示全部楼层
沙发,详情见下面回复
回复

使用道具 举报

ID:1078938 发表于 2023-6-4 20:48 | 显示全部楼层
我理解如下:
PIN_RXD是接收数据的引脚,1就是高,0就是低。
以接收 1010 0101为例子举例。
1 . 数据确定是从起始位开始后,RxdBuf  = 0;
2.1  RxdBuf = 0 ,
       PIN_RXD这时候接收为高电平,RxdBuf |= 1000 0000 ===> RxdBuf = 1000 0000
2.2 PIN_RXD 接收低电平 ,RxdBuf = 0100 0000 (右移了一位)
2.3 PIN_Rxd接收高电平  , RxdBuff >>=  0010 0000  ==>1010 0000
2.4 PIN_Rxd低, RxdBuf  ==> 0101 0000
2.5 Pin_Rxd为低 , RxdBuf ==> 0010 1000
2.6 Pin_Rxd高, Rxdbuf ===>1001 0100
2.7 Pin_Rxd低,RxdBuf ===> 0100 1010
2.8 Pin_Rxd高, RxdBuf ==> 1010 0101

3.发送停止位
回复

使用道具 举报

ID:1078938 发表于 2023-6-4 21:18 | 显示全部楼层
为何串口发送1 ,接收81??
Snipaste_2023-06-04_21-17-35.jpg
回复

使用道具 举报

ID:1078938 发表于 2023-6-4 22:16 | 显示全部楼层
用逻辑分析仪抓波形,数据传输是对的,不理解为何是81?

Snipaste_2023-06-04_22-16-04.jpg
回复

使用道具 举报

ID:624769 发表于 2023-6-5 00:13 | 显示全部楼层
你接收程序有问题, 接收到起始位后,要 错位 半个时间位才能 正确收到数据,即要在收到起始位后,经过1.3~ 1.5个位 的时间后 才开始接收 第一位数据。所以,广泛会用 3分波特率 或4分波特率方式。
回复

使用道具 举报

ID:1078938 发表于 2023-6-5 00:16 | 显示全部楼层
但是如果使用51单片机的串口模块,发送数据和接收数据是正确的。
#include <reg52.h>

void ConfigUART(unsigned int baud);

void main()
{
         EA = 1;
   ConfigUART(9600);
       
         while(1)
         {
          
         }
}

void ConfigUART(unsigned int baud)
{
   SCON = 0X50; //模式1  REN = 1 ,允许软件接收
         TMOD &= 0X0F; //定时器1
         TMOD |= 0X20;//模式2
         TH1 = 256 - (11059200/12/32)/baud;
         TL1 = TH1;
         ET1 = 0; //T1只能做波特率发生器,关闭定时器1中断
         TR1 = 1;
         ES = 1; //打开串口中断
}

void InterruptUART() interrupt 4
{
   if(RI)
         {
           RI = 0;
                 SBUF = SBUF + 1;
         }
         if(TI)
         {
           TI = 0;
         }
}
Snipaste_2023-06-05_00-16-12.jpg
回复

使用道具 举报

ID:1078938 发表于 2023-6-5 01:30 | 显示全部楼层
188610329 发表于 2023-6-5 00:13
你接收程序有问题, 接收到起始位后,要 错位 半个时间位才能 正确收到数据,即要在收到起始位后,经过1.3~ ...

接收部分,是从每个比特位的中间部分接收的,不太理解如何从1.3-1.5接收
回复

使用道具 举报

ID:213173 发表于 2023-6-5 06:05 | 显示全部楼层
哈兰德 发表于 2023-6-4 20:48
我理解如下:
PIN_RXD是接收数据的引脚,1就是高,0就是低。
以接收 1010 0101为例子举例。

软件模拟串口示例
  1. #include "reg51.h"

  2. typedef unsigned char uchar;
  3. typedef unsigned int uint;

  4. sbit RXB = P3^0;         //定义UART TX/RX端口
  5. sbit TXB = P3^1;

  6. uchar TBUF,RBUF;
  7. uchar TDAT,RDAT;
  8. uchar TCNT,RCNT;
  9. uchar TBIT,RBIT;
  10. bit TING,RING;
  11. bit TEND,REND;
  12. uchar t, r;
  13. uchar buf[16];

  14. //初始UART模块
  15. void UART_INIT()
  16. {
  17.         TING = 0;
  18.         RING = 0;
  19.         TEND = 1;
  20.         REND = 0;
  21.         TCNT = 0;
  22.         RCNT = 0;
  23.         TMOD = 0x02;   //8位自动重载12T模式
  24.         TL1 = 0xE8;                //设定定时初值(波特率1200)
  25.         TH1 = 0xE8;                //设定定时器重装值
  26. //        TMOD = 0x00;   // 16位自动重载模式中的Time0
  27. //        AUXR = 0x80;   // 1T工作模式
  28. //        TL0 = BAUD;
  29. //        TH0 = BAUD>>8; // 初始Time0和设置重载值
  30.         TR0  = 1;      // tiemr0开始运行
  31.         ET0  = 1;      // 启用Time0中断
  32.         PT0  = 1;      // 提高定时中断优先级
  33.         EA   = 1;      // 打开全局中断开关
  34. }
  35. //
  36. void main()
  37. {
  38.         UART_INIT();   //初始UART模块
  39.         while (1)
  40.         {              //用户功能
  41.                 if (REND)   //接收完成标志为真
  42.                 {
  43.                         REND = 0;//接收完成标志清0
  44.                         buf[r++ & 0x0f] = RBUF;//保存在缓存中
  45.                 }
  46.                 if (TEND)
  47.                 {
  48.                         if (t != r)
  49.                         {
  50.                                 TEND = 0;
  51.                                 TBUF = buf[t++ & 0x0f];//发送缓存中数据
  52.                                 TING = 1;
  53.                         }
  54.                 }
  55.         }
  56. }
  57. //UART定时器中断例程
  58. void tm0() interrupt 1 using 1
  59. {
  60.         if (RING)
  61.         {
  62.                 if (--RCNT == 0)
  63.                 {
  64.                         RCNT = 3;                   //重置发送波特率计数器
  65.                         if (--RBIT == 0)
  66.                         {
  67.                                 RBUF = RDAT;            //将数据保存到RBUF
  68.                                 RING = 0;               //停止接收
  69.                                 REND = 1;               //设置接收完成标志
  70.                         }
  71.                         else
  72.                         {
  73.                                 RDAT >>= 1;
  74.                                 if (RXB) RDAT |= 0x80;  //将RX数据转换为RX缓冲区
  75.                         }
  76.                 }
  77.         }
  78.         else if (!RXB)
  79.         {
  80.                 RING = 1;                       //设置开始接收标志
  81.                 RCNT = 4;                       //初始接收波特率计数器
  82.                 RBIT = 9;                       //initial receive bit number (8 data bits + 1 stop bit)
  83.         }                                                                                          //初始接收比特数(8个数据位+ 1个停止位)
  84.         if (--TCNT == 0)
  85.         {
  86.                 TCNT = 3;                       //重置发送波特率计数器
  87.                 if (TING)                       //判断是否发送
  88.                 {
  89.                         if (TBIT == 0)
  90.                         {
  91.                                 TXB = 0;                //发送起始位
  92.                                 TDAT = TBUF;            //加载数据 TBUF 到 TDAT
  93.                                 TBIT = 9;               //initial send bit number (8 data bits + 1 stop bit)
  94.                         }                                                                        //初始发送比特数(8个数据位+ 1个停止位)
  95.                         else
  96.                         {
  97.                                 TDAT >>= 1;             //将数据转换到CY
  98.                                 if (--TBIT == 0)
  99.                                 {
  100.                                         TXB = 1;
  101.                                         TING = 0;           //停止发送
  102.                                         TEND = 1;           //设置发送完成标志
  103.                                 }
  104.                                 else
  105.                                 {
  106.                                         TXB = CY;           //将CY写入TX端口
  107.                                 }
  108.                         }
  109.                 }
  110.         }
  111. }
复制代码
回复

使用道具 举报

ID:195496 发表于 2023-6-5 09:25 | 显示全部楼层
用硬件接收,看你的状态,还没有完全搞明白串口通信与接收的采样位关系。先用硬件串口吧,软件要实现一时半会你可能调试不出结果。
回复

使用道具 举报

ID:1064915 发表于 2023-6-5 10:16 | 显示全部楼层
有逻辑分析仪,厉害
回复

使用道具 举报

ID:1078938 发表于 2023-6-5 10:32 | 显示全部楼层
大漠落日 发表于 2023-6-5 09:25
用硬件接收,看你的状态,还没有完全搞明白串口通信与接收的采样位关系。先用硬件串口吧,软件要实现一时半 ...

就是接收部分的    TL0 = 256 - ((256 - TH0)>>1);  不理解怎么改
回复

使用道具 举报

ID:1064915 发表于 2023-6-5 10:35 | 显示全部楼层
wulin 发表于 2023-6-5 06:05
软件模拟串口示例

TL1 = 0xE8; T0可以用吗
回复

使用道具 举报

ID:1078938 发表于 2023-6-5 10:39 | 显示全部楼层
wulin 发表于 2023-6-5 06:05
软件模拟串口示例

确实可以,把波特率改为1200就可以。
Snipaste_2023-06-05_14-51-58.jpg
回复

使用道具 举报

ID:123289 发表于 2023-6-5 10:43 | 显示全部楼层
【PIN_RXD引脚的高低电平这里是如何控制的?】
由发送方进行控制。
控制的逻辑依据串行协议。
接收方由单片机内部嵌入的UART硬件完成,当然也会按照同样的协议进行解码。
回复

使用道具 举报

ID:624769 发表于 2023-6-5 11:26 来自手机 | 显示全部楼层
哈兰德 发表于 2023-6-5 01:30
接收部分,是从每个比特位的中间部分接收的,不太理解如何从1.3-1.5接收

参考9楼给你的代码,这是典型的3分波特率,每个位的间隔为3次中断,收到起始信号时为4个时间中断,就是从1.333的位置开始接受。
回复

使用道具 举报

ID:1078938 发表于 2023-6-6 09:43 | 显示全部楼层
wulin 发表于 2023-6-5 06:05
软件模拟串口示例
  1.   if (RING)
  2.         {
  3.                 if (--RCNT == 0)
  4.                 {
  5.                         RCNT = 3;                   //重置发送波特率计数器
  6.                         if (--RBIT == 0)
  7.                         {
  8.                                 RBUF = RDAT;            //将数据保存到RBUF
  9.                                 RING = 0;               //停止接收
  10.                                 REND = 1;               //设置接收完成标志
  11.                         }
  12.                         else
  13.                         {
  14.                                 RDAT >>= 1;
  15.                                 if (RXB) RDAT |= 0x80;  //将RX数据转换为RX缓冲区
  16.                         }
  17.                 }
  18.         }
  19.         else if (!RXB)
  20.         {
  21.                 RING = 1;                       //设置开始接收标志
  22.                 RCNT = 4;                       //初始接收波特率计数器
  23.                 RBIT = 9;                       //initial receive bit number (8 data bits + 1 stop bit)
  24.         }                                                                                          //初始接收比特数(8个数据位+ 1个停止位)
复制代码

我的理解:         波特率就是传输二进制的速率,这里选用的是1200,每秒传送1200个比特位,1 / 1200 = 833 us,833us传输一个比特位。每次溢出后进入中断,代表已经时间已经达到一个码元位,如果向下面理解那么传输的比特不应该是对的????

接收代码的理解:
    1.当遇到低电平RXB的时候,代表UART通信开始接收,先把RING = 1 , 比特计数器RCNT = 4 , 比特数RBIT = 9。
    2.下次再进入中断,RCNT自动减1,经过4次中断进入后,直到RCNT = 0,然后赋值RCNT = 3,比特数RBT减少一位,这时候认为数据是有效的,把RXB电平的数据记录到RDAT中。
    3. 每个比特位都需要RCNT减3次后才把RXB的数据赋值给RDAT。同时,把RBIT数据也减1,直到等于0就代表接收完毕,然后恢复RING = 0。








回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表