【51单片机】串口通信与单片机交互详解

单片机与串口通信

  • 一、任务目标
  • 二、理论基础
  • 三、实现过程
  • 3.1 串口传送流水灯数据
  • 3.1.1 仿真图
  • 3.1.2 甲机代码
  • 3.1.3 乙机代码
  • 3.2 串口通信
  • 3.2.1 仿真图
  • 3.2.2 实现代码
  • 四、实验总结
  • 一、任务目标

    1.甲、乙两单片机进行 方式3(或方式2)串行通信。甲机把控制8个流水灯点亮的数据发送给乙机并点亮其P1口的8个LED。方式3比方式1多了1个可编程位TB8,该位一般作奇偶校验位。乙机接收到的8位二进制数据有可能出错,需进行奇偶校验,其方法是将乙机的RB8和PSW的奇偶校验位P进行比较,如果相同,接收数据;否则拒绝接收。

    2.将单片机串口与笔记本电脑串口模块相连,单片机每隔2秒发送“Hello C51”,笔记本电脑用串口助手软件接收。 如果串口助手发送字符“0" 给单片机,则单片机停止发送; 如果单片机收到“1”,则继续每隔2秒发送“Hello C51”。

    二、理论基础

    串行口的内部结构如下:
    串行口的内部结构
    想要利用串行口通信,发送端TXD单向导向RXD。
    半双工
    单工

    全双工
    串行口控制寄存器SCON,字节地址98H,可位寻址,位地址为98H~9FH,即SCON的所有位都可用软件来进行位操作清“0”或置“1”。

    三、实现过程

    3.1 串口传送流水灯数据

    3.1.1 仿真图

    3.1.2 甲机代码

    #include <reg51.h>  
    void Send(unsigned char dat);
    int i,j;
    sbit P_x=PSW^0; 
    unsigned char Tab[8] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f}; // 控制流水灯显示数据数组  
    
    void delay(void) // 延时函数,这里假设晶振为12MHz,大约延时200ms  
    {  
        unsigned char m, n;  
        for (m = 200; m > 0; m--) // 调整循环次数以达到约200ms的延时效果  
        {  
            for (n = 248; n > 0; n--); // 内层循环同样需要调整  
        }  
    }
    
    void main(void)  
    {  
        unsigned char i;  
        TMOD = 0x20; // 设置定时器T1为方式2
        SCON = 0x50; // 设置串口为方式1,8位可变波特率,允许接收。方式3通常用于多机通信。  
        TH1 = 0xfd; // 波特率设置需要根据晶振频率来确定,这里假设晶振为11.0592MHz。  
        TL1 = 0xfd;  
        TR1 = 1; // 启动定时器T1  
        while (1)  
        {  
            for(i = 0; i < 8; i++)  
            {  
                Send(Tab[i]);  
                delay(); // 延时函数应根据实际晶振频率调整以达到约200ms的效果。  
            }  
        }  
    }  
      
    void Send(unsigned char dat) // 发送1字节数据的函数  
    {  
        unsigned char temp;  
        temp = dat; // 保存原始数据以便后面计算偶校验位  
        TB8 = 0; // 初始设置为0,之后根据数据计算偶校验位  
        for(j = 0; j < 8; j++) // 计算偶校验位  
        {  
            if ((temp & 0x01) ^ TB8) // 如果当前位和TB8不同,则TB8取反  
            {  
                TB8 = ~TB8;  
            }  
            temp >>= 1; // 右移一位处理下一位  
        }  
        SBUF = dat; // 发送数据  
        while (!TI); // 等待发送完成  
        TI = 0; // 清除发送完成标志  
    }  
      
    

    3.1.3 乙机代码

    #include <reg51.h>
    sbit P_x=PSW^0;		// P位为PSW 寄存器的第0位,即奇偶校验位
    void main(void) 		//主函数
    {	
     TMOD=0x20;		//设置定时器T1为方式2
     SCON=0xd0;		//设置串口为方式3,允许接收REN=1
     PCON=0x00;  		// SMOD=0  
     TH1=0xfd;		//给定时器T1赋初值,波特率为9600
     TL1=0xfd;
     TR1=1;			//接通定时器T1
     REN=1; 			//允许接收
     while(1)
     {	
      P1=Receive();			//将接收到的数据送P1口显示
     }
    }
      
    unsigned char Receive(void)		//接收1字节数据的函数
    {	
     unsigned char dat;
     while(RI==0); 		//检测RI,RI=0,未接收完,则循环等待
     ;
     RI=0;			//已接收一帧数据,将RI清0
     ACC=SBUF;			//将接收缓冲器的数据存于ACC
     if(RB8==P_x) 			//只有偶校验成功才能往下执行,接收数据
     {	
      dat=ACC;		//将接收缓冲器的数据存于dat
      return dat;		//将接收的数据返回
     }
    }    
    
    

    3.2 串口通信

    3.2.1 仿真图

    3.2.2 实现代码

    #include <reg51.h>
    #include <stdio.h>
    #include <string.h>
    char send_flag = 0;
    char received_char;
    // 假设波特率设置为9600,根据实际情况调整
    void serial_init() {
        SCON = 0x50; // 设置为模式1,8位数据,可变波特率
        TMOD &= 0x0F; // 清除定时器1模式位
        TMOD |= 0x20; // 设置定时器1为8位自动重装模式
        TH1 = TL1 = 256 - 12; // 定时器初值,根据波特率调整
        TR1 = 1; // 启动定时器1
        ES = 1; // 开启串口中断
        EA = 1; // 开启总中断
    }
    
    // 发送字符串函数
    void serial_send_string(char *str) {
        while (*str) {
            while (!TI); // 等待上一次发送完成
            SBUF = *str++; // 发送当前字符
            TI = 0; // 清除发送完成标志
        }
    }
    
    // 串口中断服务程序
    void serial_ISR() interrupt 4 using 1 {
        if (RI) {
            RI = 0; // 清除接收标志
            received_char = SBUF; // 读取接收到的字符
            if (received_char == '0') {
                // 如果接收到字符'0',停止发送
            } else if (received_char == '1') {
                // 如果接收到字符'1',继续发送
            }
        }
    }
    
    // 主函数
    void main() {
        serial_init(); // 初始化串口
        send_flag = 1; // 发送标志
    
        while (1) {
            if (send_flag) {
                serial_send_string("Hello C51"); // 发送字符串
                // 延时2秒,可以使用定时器中断实现
            }
        }
    }
    

    四、实验总结

    通过本次实验,我深刻体会到了理论与实践相结合的重要性。在实验过程中,我不仅加深了对相关理论知识的理解,还提高了自己的实践操作能力。同时,我也学会了如何分析和解决实验中遇到的问题,这对我的学习和工作都具有重要的意义。

    以上则是我此次的实验内容,如有错漏请各位大佬多多指教!

    作者:双料毒狼_s

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【51单片机】串口通信与单片机交互详解

    发表回复