串口多机通信

串口多机通信学习

一、51单片机的主从模式,首先要设定工作方式3:(主从模式+波特率可变)
这里写图片描述
SCON串口功能寄存器:SM0=1;SM1=1(工作方式3)

注:主机和从机都要为工作方式3。

工作方式2 (SM0 SM1 :1 0):串行口为11位异步通信接口。发送或接收一帧信息包括1位起始位“0”、8位数据位、1位可编程位、1位停止位“1”。发送数据:发送前,先根据通信协议由软件设置TB8为“奇偶校验位”或“数据标识位”,然后将要发送的数据写入SBUF,即能启动发送器。发送过程是由执行任何一条以SBUF为目的寄存器的指令而启动的,把8位数据装入SBUF,同时还把TB8装到发送移位寄存器的第9位上,然后从TXD(P3.1)端口输出一帧数据。接收数据:先置REN=1,使串行口为允许接收状态,同时还要将RI清“0”。然后再根据SM2的状态和所接收到的RB8的状态决定此串行口在信息到来后是否置R1=1,并申请中断,通知CPU接收数据。当SM2=0时,不管RB8为“0”还是为“1”,都置RI=1,此串行口将接收发送来的信息。当SM2=1时,且RB8=1,表示在多机通信情况下,接收的信息为“地址帧”, 此时置RI=1,串行口将接收发来的地址。当SM2=1时,且RB8=0,表示在多机通信情况下,接收的信息为“数据帧”, 但不是发给本从机的,此时RI不置为“1”,因而SBUF中接收的数据帧将丢失。

工作方式3 (SM0 SM1 :1 1):为波特率可变的11位异步通信方式,除了波特率有所区别之外,其余方式都与方式2相同。【以上内容摘自网络】

参见网址:http://blog.sina.com.cn/s/blog_9ffa22710102w8oa.html

主机

1.主机的配置发送“地址”时,把TB8设定为1,发送数据时TB8设定为0;

2.主机在配置SCON寄存器时,不需要配置SM2=1;该位主要用于从机接收地址和数据时的区分;

3.其发送帧结构为:
这里写图片描述
主机的配置,及相关程序为:

//主机为STC12C5A60S2单片机,下面是初始化程序
void UART_init()
{
    TMOD =0x20; //定时器1,工作方式2:8位、自动重装
    PCON=0x00;//波特率不加倍
    TH1 =  0xfd; //fd: 9600bps @ 11.0592M
    TL1 =  0xfd; //e8: 1200bps @ 11.0592M
    SCON|=  0xd8;   //串行口工作方式3        主机模式,不需设置SM2=1
    TR1 = 1; //启动定时器1
    ES =  1; //开串口中断
    EA =  1; //中断 总开关
}
//主机端发送程序,使用为串口多机通信
void TXdata(unsigned char addr,unsigned char *str)
{
    TB8 = 1; //发送地址
    SBUF = addr; //把地址发送出去
    while(!TI); //判断是否发送成功(发送成功后TI会置1,需手动清0)
    TI = 0;
    TB8 = 0; //发送数据
    while(*str != '\0') //发送数组
    {
        SBUF = (*str);
        while(!TI);
        TI = 0;
        str++;
    }
}
//中断程序
void UartReceive() interrupt 4 //串口中断服务函数
{
    ES = 0; //关闭串口中断
    if(RI) //再次判断,是否接收到数据(接收到数据后,RI会置1,需手动清0)
    {
        RXData = SBUF;
            if(RXData== '*') //判断是否接收到数据结束标志 $
            {
                LCD_Write_String(0,0,ReceiveData);
                j_yang=0;
            }
            else if(RXData=='#')
            {
                LCD_Write_String(0,1,ReceiveData);
                j_yang=0;
            }
            else //接收到 结束标志 $
            {
                ReceiveData[j_yang] = RXData; //没有接收到结束标志,正常保存数据至数组
                j_yang++;
            }
    }
    RI = 0; //清除接收标志位
    ES = 1; //重新开启串口中断
}

从机

1.从机接收时,首先串口初始化时,使SM2=1(接收地址模式,即只能接收到TB8=1的数据,才触发中断),主机发送TB8=0的数据,被认为是总线上的主机发送给别机的通信数据,本机丢弃,不产生中断。

2.接收的地址与本机地址相符后,使SM2=0(接收数据模式,接收数据正常触发中断)

从机的配置及相关程序:

//使用的单片机是STC15W4K48S4,该单片机设置独立定时器为波特率发生器,配置程序,若是不使用此种单片机或者是此种波特率发生器,则除了SM2设置不一样之外,其他设置与主机是一致的。
void Serial_Init()
{
    SCON = 0xf8;            //8位数据,可变波特率
    AUXR = 0x14;            //允许独立波特率发生器运行,独立波特发生器每1个时钟周期记一次数
    AUXR |= 0x01;           // 独立波特率发生器作为串口1的波特率发生器,此时定时器1得到释放,可以作为独立定时器使用
    T2L = (65536 - (FOSC/4/BAUD));   //设置波特率重装值,其中FOSC为外部晶振的频率,BAUD为定义的波特率,此处为9600
    T2H = (65536 - (FOSC/4/BAUD))>>8;
    ES = 1;                            //使能串口中断
    EA = 1;
}

//中断服务程序
void Uart(void) interrupt 4
{
    ES = 0; //关闭串口中断
    if(RI) //再次判断,是否接收到数据(接收到数据后,RI会置1,需手动清0)
    {
        RXData = SBUF;
        if(RXstart) //判断是否接收到过本地址
        {
            if(RXData != '*') //判断是否接收到数据结束标志*
            {
                ReceiveData[j_yang] = RXData; //没有接收到结束标志,正常保存数据至数组
                j_yang++;
            }
            else //接收到 结束标志*
            {
                RXstart= 0; //本次接收结束
                UartSends(ReceiveData);//将接受的数据反过来发送回去
                UartSendChar('#');//默认接收以#结束
                SM2 = 1; //重新 配置为:只接收地址模式,下次发送TB8=1才中断
                j_yang = 0;
                Uart_flag1=1;
            }
        }
        if(RXData == 2) //判断是否呼叫本机,地址范围:000– 254(00 - FE)
        {
            RXstart = 1; //开始接收数据
            SM2 = 0; //配置为:接收数据 模式
        }
    }
    RI = 0; //清除接收标志位
    ES = 1; //重新开启串口中断
}

遇到问题记录

1.在写主机程序时,发现如果不写中断服务程序,单片机会默认一直发送第一个字节,最后发现应该是串口中断程序影响的,没有串口中断就会一直发送第一个字节,究其原因是数据发送完成后TI会置1,这将导致中断的产生,一旦没有中断服务程序,默认不产生中断,就一直发不清零。

2.主机程序配置时,不需要配置SM2,这样从机不管是谁发送数据,主机都可以接收的到,但是是在通信的时候做区分,比如主机给从机1发消息,发送完成后,从机1立马给主机发送请求的数据,发送完成之后,从机再配置SM2=1,只接收地址的模式。

3.波特率一定要设置的一致,否则无法正常通信。

4.硬件连接方式为:
这里写图片描述

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页