打印
[经验分享]

51单片机双机通信

[复制链接]
31|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
晓伍|  楼主 | 2025-3-11 07:19 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
对于这个51单片机双机通信,之前无聊做的玩的,但是既然写了一篇51单片机串行口通信的博客,那就顺便出来供大家学习,希望能够帮助到一些刚刚接触51单片机的朋友。废话不多讲,直接上正题。

1、实习任务
1.1 任务目的
通过单片机之间的双机通信设计,进一步学习定时器的功能和编程使用,理解穿行通信与并行通信两种通信方式的异同,掌握串行通信的重要指标:字符帧和波特率,初步了解MCS-51系列单片机串行口的使用方法。

1.2 任务要求
本任务是建立一个简单的单片机串行口双机通信测试系统。系统中,发射与接收各用一套STC89C51单片机电路,成为甲机和乙机。编制程序,使甲、乙双方能够进行串行通信。要求:将甲机内的多个数据(例如1,3,4,6,7,5共六个数据)发送个乙机,并在乙机的六个数码管上显示出来。

2、系统总体设计
2.1 设计思路
STC89C52单片机双机通信可以采用串口通信的方式。首先要确定串口通信的参数,包括波特率、数据位、停止位和校验位。编写发送程序和接收程序,可以使用C语言编写程序,在发送端将要传输的数据存储在发送缓冲区中,然后根据协议依次发送每个字节。在接收端收到数据后,根据协议依次读取每个字节并存储到接收缓冲区中。使用定时器或者外部终端等方式实现异步通信。可以在发送端通过定时器产生中断来发送数据,而在接收端通过外部中断的方式接收数据。实现数据的校验,为保证数据的完整性和正确性,可以使用校验位、CRC等方式实现数据校验。进行调试和测试,设计完成后,可以通过实际测试来验证通信的可靠性和稳定性,针对不同情况进行调整和优化。需要注意的是,在进行STC89C52单片机双机通信时,应根据具体实际情况进行选择和调整,比如要考虑到硬件电路的设计和外界干扰等因素,保证通信的稳定和可靠性。

2.2 设计结构框图



3、51单片机双机通信原理图、仿真图及实物图
3.1 原理图



原理图的组成是:两个51单片机最小系统,还有一个按键及一个数码管显示。至于51最小系统的知识,我已经在前面的博客讲解过了,不懂得朋友可以翻看我之前的博客的。这里没有画USB转TTL下载模块,由于资源有限,就只能在开发板上下载好程序之后再把芯片拿出来放到自己制作的手工电路板了。

3.2 仿真图
没有允许仿真如下图:



仿真图也是很简单的。



开始的时候乙机数码管初始化为0。按一下按键就送发1,后面相应的发送2、3、4、5、6、7、8、9,然后又从0开始发。



3.3 实物图



上图是发送数据0的现象。



上图是发送数据9的现象。

4、程序
甲机(主机)是属于发送机,按键发送数据;乙机(从机)属于接收机,接收后数码管显示出甲机(主机)发送个数据。 甲机(主机)只发不接,乙机(从机)只接不发。

甲机(主机)

main.c

#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
sbit KEY = P1^7;//按键口
unsigned char flag;
unsigned char count;
unsigned char DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void main()
{
        P2=0xc0;
        UartInit();               
        while(1)
        {       
                P2=DSY_CODE[count];       
                if(KEY==0)
                {
                        Delay(20);
                        if(KEY==0)
                        {
                                flag=1;
                                count++;
                        }
                        while(!KEY);
                }
                if(count>9)count=0;
        if(flag)
        {
            flag=0;
             switch(count)
            {
                case 0:UART_SendByte(0);break;
                case 1:UART_SendByte(1);break;
                case 2:UART_SendByte(2);break;
                case 3:UART_SendByte(3);break;
                case 4:UART_SendByte(4);break;
                case 5:UART_SendByte(5);break;
                case 6:UART_SendByte(6);break;
                case 7:UART_SendByte(7);break;
                case 8:UART_SendByte(8);break;
                case 9:UART_SendByte(9);break;        
            }
        }

        }
}


void TR_process(void) interrupt 4
{
        if(RI)
        {
                RI = 0;               
        }
}


Delay.c


void Delay(unsigned int xms)
{
        unsigned char i, j;
        while(xms--)
        {
                i = 2;
                j = 239;
                do
                {
                        while (--j);
                } while (--i);
        }
}

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif
UART.c

#include <REGX52.H>

void UartInit(void)                //9600bps@11.0592MHz
{
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                        //8位数据,可变波特率
        TMOD &= 0x0F;                //清除定时器1模式位
        TMOD |= 0x20;                //设定定时器1为8位自动重装方式
        TL1 = 0xFD;                //设定定时初值
        TH1 = 0xFD;                //设定定时器重装值
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
        ES=1;                //串口中断允许控制位
        EA=1;                //中断允许总控制位
}


void UART_SendByte(unsigned char Byte)
{
        SBUF=Byte;
        while(TI==0);
        TI=0;
}

UART.h

#ifndef __UART_H__
#define __UART_H__

void UartInit();
void UART_SendByte(unsigned char Byte);

#endif
乙机(从机)

main.c

#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
unsigned char DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void main()
{
        P2=0xc0;
        UartInit();                //串口初始化
        while(1);
}

void UART_Routine() interrupt 4
{
        if(RI)
        {
            RI=0;               
            switch(SBUF)
            {
                case 0x00: P2=DSY_CODE[0];break;
                case 0x01: P2=DSY_CODE[1];break;
                case 0x02: P2=DSY_CODE[2];break;
                case 0x03: P2=DSY_CODE[3];break;
                case 0x04: P2=DSY_CODE[4];break;
                case 0x05: P2=DSY_CODE[5];break;
                case 0x06: P2=DSY_CODE[6];break;
                case 0x07: P2=DSY_CODE[7];break;
                case 0x08: P2=DSY_CODE[8];break;
                case 0x09: P2=DSY_CODE[9];break;
            }
        }
        if(TI)
        {
            TI=0;
        }
}

Delay.c


void Delay(unsigned int xms)
{
        unsigned char i, j;
        while(xms--)
        {
                i = 2;
                j = 239;
                do
                {
                        while (--j);
                } while (--i);
        }
}

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif
UART.c

#include <REGX52.H>


void UartInit(void)                //9600bps@11.0592MHz
{
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                        //8位数据,可变波特率
        TMOD &= 0x0F;                //清除定时器1模式位
        TMOD |= 0x20;                //设定定时器1为8位自动重装方式
        TL1 = 0xFD;                //设定定时初值
        TH1 = 0xFD;                //设定定时器重装值
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
        ES=1;                //串口中断允许控制位
        EA=1;                //中断允许总控制位
}


void UART_SendByte(unsigned char Byte)
{
        SBUF=Byte;
        while(TI==0);
        TI=0;
}

/*
void UART_Routine() interrupt 4
{
        if(RI==1)
        {
               
                RI=0;
        }
}
*/

UART.h

#ifndef __UART_H__
#define __UART_H__

void UartInit();
void UART_SendByte(unsigned char Byte);

#endif
最后提醒一下,这里我使用的数码管是共阳数码管的,如果使用共阴数码管的朋友则是不符合我的代码、原理图、仿真图的,因为共阴数码管和共阳数码管的公共端的接法是不一样的,这里就不多说关于数码管的知识了,感兴趣的朋友可以自己去了解。

上面是通过一个按键进行通信控制的,但是感觉还是过于死板,于是,在上面的基础上,我们可以进行举一反三,通过一个矩阵键盘进行控制,这里我采用的是4x4的矩阵键盘进行控制,可以发从0~f的值,每个按键对应一个值;但是这个修改后,对应的代码和仿真,都是需要在上面代码的基础上进行修改的,我这里只是提供一个思路,方便大家自由发挥;如下图:





这里我只是进行第一个值和最后一个值进行截图,其他图就不做过多的放置了;
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_65980796/article/details/131995444

使用特权

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

本版积分规则

78

主题

4221

帖子

1

粉丝