找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1015|回复: 9
打印 上一主题 下一主题
收起左侧

单片机任意I/O口模拟串口的程序,有一句代码不明白

  [复制链接]
跳转到指定楼层
楼主
ID:384954 发表于 2023-12-23 23:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
请高人帮忙指点,小弟胜感激
/****************《51单片机轻松入门-基于STC15W4K系列》配套例程 *************
/*  任意I/O口模拟串口,22.1184MHZ, 内部R/C时钟,9600bps  */

#include "STC15W4K.H"            // 包含 "STC15W4K.H"寄存器定义头文件  
#define RECEIVE_MAX_BYTES  1     // 最大接收字节数

unsigned char RecvBuf[16];       // 接收数据缓冲区
unsigned char RecvCount=0;       // 接收数据计数器

sbit T_TXD=P3^2;                 // 发送数据的引脚
sbit R_RXD=P3^3;                 // 接收数据的引脚
bit RXD_OK;                         // 数据接收完成标志,1(接收正确),0(接收错误)
//******************************************/
void delay104uS()
{
  unsigned char i,j,k;
  for(i=1;i>0;i--)         // 注意后面没分号
  for(j=3;j>0;j--)         // 注意后面没分号
  for(k=189;k>0;k--);      // 注意后面有分号  
}
void delay52uS()               // 起始位结束后52uS采样数据
{
  unsigned char i,j,k;
  for(i=1;i>0;i--)         // 注意后面没分号
  for(j=3;j>0;j--)         // 注意后面没分号
  for(k=93;k>0;k--);       // 注意后面有分号  
}
void SendByte(unsigned char Dat)
{
       unsignedchar i=8;      // 发送8 位数据
       T_TXD=0;                        // 发送起始位
       delay104uS();
       while(i--)
       {
              if(Dat&1)T_TXD=1;
              elseT_TXD=0;
              delay104uS();
              Dat>>=1;
       }
       T_TXD=1;                        // 发送停止位
       delay104uS();           // 延时   
}

unsigned char RecvByte()
{
       unsignedchar i;      
       unsignedchar Dat=0;            // 接收到的数据
       RXD_OK=0;                              // 字节数据接收正常标志,0——错误,1——正常
       delay52uS();                   // 数据位中心位置读数据   
       if(R_RXD==0)                     // 确认起始位正常
       {   
              delay104uS();               // 起始位宽度            
              for(i=0;i<8;i++)
              {
                     if(R_RXD)     Dat|=(1<<i);  /这一句不懂,求高人讲解。
                     delay104uS();
              }   
              if(R_RXD==1)                // 确认停止位正常
              {
                     RXD_OK=1;
              }
       }  
       returnDat;
}

//功能:串口打印字符串
//*****************************************/
void PrintfStr(char * pstr)
{
       while(*pstr)   
       {
              SendByte(*pstr++);
       }
}

//功能:函数主体
//******************************************/
void main(void)
{  
       unsignedchar i;     
       PrintfStr("模拟串口:STC15\r\n");
       while(1)                  
       {
              if(R_RXD==0)      // 死循环不断检测R_RXD是否有起始位出现
              {
                     RecvBuf[RecvCount]=RecvByte();
                     if(RXD_OK==1)                                     // 一个字节接收正常
                     {  
                            RecvCount++;
                            if(RecvCount>=RECEIVE_MAX_BYTES)
                            {
                                   RecvCount=0;
                                   for(i=0;i<RECEIVE_MAX_BYTES;i++)
                                   {
                                          SendByte(RecvBuf[ i]+1);        // 接收到得数据+1后发回
                                   }
                            }
                     }            
              }
       }
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:366877 发表于 2023-12-24 01:19 | 只看该作者
这里要实现的是把串行收到的数一位一位地接收下来转成并行的8位数,这里只考虑收到是1的情况,没考虑收到0的情况,应该是少了一句程序。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

板凳
ID:213173 发表于 2023-12-24 07:30 | 只看该作者
Dat变量初始为0,用2进制表示:00000000 8位都是0
当for循环,if(R_RXD)判断R_RXD为真,也就是1,
Dat|=(1<<i); 等同Dat=Dat|(1<<i),结果一样写法不同,
这段代码就是把由低到高收到的1按位插入Dat。
例如:
Dat初始=0000 0000
收到字节1010 0101
逐次按位相或后Dat=1010 0101=0xa5
回复

使用道具 举报

地板
ID:384109 发表于 2023-12-24 08:32 | 只看该作者
功能如楼上所说,不过DAT初始化为0,所以不考虑接收0的情况
回复

使用道具 举报

5#
ID:1105954 发表于 2023-12-24 09:52 | 只看该作者
表示接收的数据或等于1右移i位
回复

使用道具 举报

6#
ID:1105893 发表于 2023-12-24 10:49 | 只看该作者
这段代码是使用单片机STC15W4K模拟串口通信的程序。它通过模拟IO口实现了串口的发送和接收功能。  代码中定义了一个接收数据缓冲区RecvBuf和一个接收数据计数器RecvCount。接收到的数据存储在RecvBuf数组中,并根据接收计数器进行处理。  在主函数main中,先发送一条初始化信息"模拟串口:STC15\r\n",然后进入死循环不断检测R_RXD引脚是否有起始位出现。如果检测到起始位,则调用RecvByte函数接收一字节数据,并判断接收是否正常。  如果接收正常,将接收到的数据存储在RecvBuf数组中,并递增接收计数器RecvCount。当接收计数器达到最大接收字节数RECEIVE_MAX_BYTES时,将接收到的数据加1后通过SendByte函数发送回去。  整个程序的功能是模拟串口通信,接收到的数据加1后再发送回去。  需要注意的是,这段代码只是单片机的程序,无法在此环境中直接运行。如果需要运行,请将代码下载到STC15W4K单片机开发板上,并根据硬件连接情况进行相应的配置。
回复

使用道具 举报

7#
ID:517951 发表于 2023-12-24 11:16 | 只看该作者
如果R_RXD=1, 就把Dat=Dat第0 到7 bit(根据i的循环置0-7)置1.
回复

使用道具 举报

8#
ID:384954 发表于 2023-12-24 19:00 | 只看该作者
wulin 发表于 2023-12-24 07:30
Dat变量初始为0,用2进制表示:00000000 8位都是0
当for循环,if(R_RXD)判断R_RXD为真,也就是1,
Dat|=( ...

非常感谢这位老师的回复!
只是我感觉这句代码有问题,如果改动一下就对了,也好理解。
if(R_RXD)
Dat |=(i<<1);
回复

使用道具 举报

9#
ID:584814 发表于 2023-12-25 08:16 | 只看该作者
1017038201 发表于 2023-12-24 19:00
非常感谢这位老师的回复!
只是我感觉这句代码有问题,如果改动一下就对了,也好理解。
if(R_RXD)

没有任何改动哈,回车和缩进对机器可有可无只是方便人类阅读罢了。
将多行放在一行是可行的,只要多行能正常运行放在同一行也一样行。
回复

使用道具 举报

10#
ID:192020 发表于 2023-12-28 13:55 | 只看该作者
1017038201 发表于 2023-12-24 19:00
非常感谢这位老师的回复!
只是我感觉这句代码有问题,如果改动一下就对了,也好理解。
if(R_RXD)

不知道是你复制错了还是故意改的,Dat |=(i<<1);不能这样改,逻辑上错了,还得原本的Dat |=(1<<i);
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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