找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于51的串行通讯原理及协议详解(uart)

  [复制链接]
跳转到指定楼层
楼主
ID:94349 发表于 2015-11-10 02:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
串行与并行通讯方式
并行:控制简单,传输速度快。线多,长距离成本较高且同时接受困难。
串行:将数据字节分成一位一位的行驶在一条传输线上进行传输。如图:
 

同步与异步串行通讯方式
同步串行通讯方式:同步通讯需要建立发送方对接收方时钟的直接控制,是双方达到完全同步。
异步串行通讯方式:通讯的发送和接收设备使用各自的时钟控制数据的发送和接收,为使双方收发协调,要求发送和接收的时钟尽可能一致。如图:


异步通讯方式的特点:
异步通讯以字符构成的帧为单位进行传输,字符与字符之间的间隙是任意的,但每个字符中的各位是以固定的时间传送的。其一帧字符信息由4部分组成:起始位、数据位、奇偶检验位、停止位。在单片机中的通讯一般情况下均使用这种帧格式。如图:


串行通讯的制式
单工:数据传输仅沿一个方向,不能实现反向传输
半双工:数据可以沿两个方向传输,但是需要分时
全双工:数据可以同时进行双向传输

串行通讯三种错误校验:奇偶校验、代码和校验、循环冗余校验

RS232电平与TTL电平的转换
PC使用的串口的电平为RS232的九针串口,MCU使用的电平是TTL电平,要使得PC 和MCU进行通讯,就需要对其电平极性转换。主要的几款电平转换芯片:MAX232、MAX202、HIN232,SIPEX320等

串行通讯速度的定义_波特率
串行通讯的速率用波特率表示,其定义为:
                   每秒钟传送二进制代码的位数,即1波特=1位/秒,单位bps(位/秒)
eg:每秒钟传送240个字符,而每个字符格式包含10位(1起始、8数据、1停止),此时的波特率为:
                   10位*240个/秒=2400bps

串行通讯波特率的计算
单片机的串行口可设定为四种工作方式,其中方式0和方式2波特率固定,方式1和方式3波特率可变,由定时器T1的溢出率来决定。计算公式如下:

其中:fosc为系统晶振频率,通常为12MHz(或者11.0592MHz),SMOD为PCON寄存器的最高位。T1的溢出率即定时器T1溢出的频率。

电源管理寄存器_PCON

SMOD;该位与串通信波特率有关。
SMOD=0;串口方式1、2、3时,波特率正常
SMOD=1;串口方式1、2、3时,波特率加倍
SMOD0,LVDF,P0F,此三位为STC_MCU 所特有的,可查看相关手册。
GF1、GF0;两个通用标志位,可随意使用。
PD;掉电模式设定位,
PD=0;MCU正常工作
PD=1;MCU进入掉电模式
IDL;空闲模式设定位
IDL=0;MCU正常工作
IDL=1;单片机进入空闲模式

单片机的两种模式状态:
掉电模式:进入掉电模式后,晶振停震,CPU,定时器,串行口全部停止工作,只有外部中断继续工作,
可有外部中断低电平触发或下降沿触发或硬件复位模式唤醒。
空闲模式:除CPU不够工作外,其余仍继续工作,在空闲模式下,可由任一个中断或者硬件复位唤醒

T1的溢出率
T1的溢出率就是T1定时器溢出的频率,只要算出T1定时器每一处一次所需的时间T,那么T的倒数即为他的溢出率。

51串行口结构
51单片机串行口是一个可编程全双工的通信接口,具有Uart(通用异步收发器)的全部功能,能同时进行数据的发送与接收,也可作为同步一位寄存器使用。
51_MCU主要由两个独立的串行数据缓冲寄存器SBUF (一个发送,一个接收)和发送控制器、接收控制器,输入移位寄存器及若干控制门电路。如图:


串行口控制寄存器_SCON

SM0,SM1;工作方式选择位,串口有四中工作方式,如下:

SM2;多机通信可控制位,SM2主要用于方式2和方式3,当接收机的SM2=1时,可以利用收的RB8来控制是否激活RI;
RB8=0,不激活RI,收到的信息丢弃
RB8=1,收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走,

当SM2=0时,无论收到的RB8是0还是1,均可以收收到的数据进入SBUF,并激活RI,通过控制SM2可实现多机通信。
在方式0时,SM2必须是0,
在方式1时,若SM2=1,则只有接收到有效停止位时,RI才置1

REN;允许串行接收位
REN=1;允许串行口接收数据
REN=0;禁止串行口接收数据

TB8;方式2、3中发送数据的第九位,可定义其作用,奇偶检验,地址帧标志等,方式0和1中,未使用
RB8;方式2、3中接收数据的第九位,可定义其作用,奇偶检验,地址帧标志等,方式1,若SM2=0,则RB8是接收到的停止位。
TI;发送中断标志位,方式0中,串行发送第8位数据结束时,或者其他方式,串行发送停止位时,由内部硬件置1,向CPU发出中断申请,在中断服务程序中,须用软件清零,取消此中断申请。
RI;接收中断标志位, 方式0中,串行接收第8位数据结束时,或者其他方式,串行接收停止位时,由内部硬件置1,向CPU发出中断申请,在中断服务程序中,须用软件清零,取消此中断申请

串口方式0,串行口为同步移位寄存器的输入输出方式,主要永不扩展并行输入输出接口,数据由RXD(P3.0)引脚输入或者输出,同步移位脉冲由TXD(P3.1)引脚输出,发送和接收均为8位数据,低位在先,高位在后。波特率固定fosc/12

串口方式1;10位数据一步通讯口,1起始,8数据,1停止,TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。其传输波特率可变,对51而言,波特率有定时器1的溢出率而决定,一般而言,在单片基于单片机,单片机与计算机,计算机与计算机串口通讯时,基本都市选择方式1,所以此种方式必须掌握

串口方士2,3;11位数据的异步通讯口,XD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。在这两种方式下,1起始,9数据,1停止,一帧数据11位。方式2的波特率固定为晶晶振频率的1/64或1/32,方式3的波特率由定时器1的溢出率决定。
方式2和方式2的差别仅在于波特率的选取不同,两种方式下,接收到的停止位与SBUF,RB8,RI都无关。

串口方式1的编程实现
方式1数据输出时序图如下:

当数据被写入SBUF寄存器后,单片机自动开始从起始位发送数据,发送到停止位的开始时,
由内部硬件将TI置1,向CPU申请中断,接下来可在中断服务程序中进行相关处理,也可选择不进入中断。

用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,
检测到RXD引脚输入电平发声负跳变时,则说明起始位有效。
将其移入输入移位寄存器并开始接受这一帧信息的其余位。

接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器的最左边,
控制电路进行最后一次移位,当RI=0且SM2=0(或结收到的停止位为1)时,
将接受到的9位数据前8位数据装入接收SBUF,第九位(停止位)进入RB8,并置RI=1,向CPU申请中断,

在进行串口的相关操作之前,需要对单片机的一些特殊寄存器和进行初始化设置
主要是设置产生波特率的定时器1,串行口控制和中断控制,具体步骤如下:
确定T1的工作方式(编程TMOD寄存器)
计算T1的初值,装载TH1和TL1
启动T1(编程TCON中的TR1位)
确定串行口工作方式(编程SCON寄存器)
串行口工作在中断方式时,要进行中断设置(编程IE、IP寄存器)


-----------------------------------------------------------------------------------------------------------------------
//串口方式1
TMOD=0X20;    //T1定时器,工作方式2
TH1=0XFD;    //T1定时器装初值
TL1=0XFD;    //T1定时器装初值
TR1=1;        //启动T1定时器
REN=1;        //允许串口接收
SM0=0;        //设定串口工作方式1
SM1=1;        //设定串口工作方式1
EA=1;        //开总中断
ES=1;        //开串口中断
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
//串口中断服务程序
void ser() interrupt 4
{
    RI=0;           //RI清零;因为收到数据或者或者发送了数据会由硬件置1
    a=SBUF;           //将SBUF中的数据读走给a
    flag=1;           //中断标志位置1
}
-----------------------------------------------------------------------------------------------------------------------

串口方式0
串行口为同步移位寄存器的输入输出方式,主要永不扩展并行输入输出接口,数据由RXD(P3.0)引脚输入或者输出,同步移位脉冲由TXD(P3.1)引脚输出,发送和接收均为8位数据,低位在先,高位在后。波特率固定fosc/12。

在该模式下,串行口的SBUF是作为同步移位寄存器使用的。
在串行口发送时。SBUF相当于一个并行进入,串行输出的移位寄存器,
由单片机的内部总线并行接收八位数据,并从RXD信号线串行输出,在接收操作时,他有相当于一个串行输入、并行输出的移位寄存器。该模式下,SM2,RB8,TB8不起作用。
方式0数据输出时序图如下:

发送操作在TI=0时进行,CPU将数据移入SBUF后,RXD线上即可发出8位数据,TXD上发送同步脉冲,
8位数据发送完后,TI由硬件置位,并在中断允许的情况下向CPU申请中断,
CPU相应中断后,先用软件是TI清零,然后再给SBUF送下一个需要发送的字符,如此重复上述过程。

方式0数据输入时序图如下:

接收过程在REN=1和RI=0的条件下启动,为此串行数据由RXD线输入,TXD线输出同步脉冲,
接收电路接收到8位数据后,RI自动置位并在中断允许的条件下向CPU发出中断请求,
CPU 查询到RI为1或者相应中断以后便将SBUF中的数据送到累加器,RI需要由软件复位,

需要注意的是:
串行口工作模式0并不是一个同步通讯串口通讯方式,
它的主要用途是与外面的同步移位寄存器相连已达到扩展单片机输入并行口和输出并行口的目的。
其可以通过芯片(74LS164)把串口数据转化成并口数据,通过芯片(74LS165)把并行输出的数据转换成串口输出

-----------------------------------------------------------------------------------------------------------------------
使用串口工作模式0间隔发送数据0XAA
void main()
{
    SCON=0;               //串行口工作方式0
    EA=1;            //开总中断
    ES=1;            //允许串口中断
    TI=0;            //发送中断标志位
    while(1)
    {
        SBUF=0XAA;   
        delay();
    }
}
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
void ser0() interrupt 4
{
    TI=0;        //清楚发送中断标志位
}
-----------------------------------------------------------------------------------------------------------------------

串口方式2和方式3
均为11位数据的异步通信口,唯一的区别在于传输速率的不同。
TXD数据发送引脚,RXD数据接收引脚,1起始,
9数据(含1位附加第9位,发送时为SCON中的TB8,接收时为RB8),1停止,一帧数据11位。
方式2的波特率固定为晶晶振频率的1/64或1/32,方式3的波特率由定时器1的溢出率决定。

串口方式2和方式3一帧数据传送格式,如图:


串口方式2和方式3输出时序图:

发送开始时,先把起始位0输出到TXD管脚,然后发送移位寄存器的的输出位(D0)到TXD引脚
每一个移位脉冲都使输出移位寄存器的各位右移一位,并由TXD引脚输出,
第一次移位时,停止位1移入输出移位寄存器的第9位,以后每次移位,左边都输入0
当停止移位至输出位时,左边其余位全为零,检测电路检测到这一条件时,使控制电路进行最后一次移位,并置TI=1;向CPU请求中断。

串口方式2和方式3输入时序图:

接受时,数据从右边移入输入移位寄存器,在起始位0移到最左边时,控制电路进行最后一次移位。
当RI=0且SM2=0(或接收到第9位数据位1)时,接收到的数据装入接收缓冲器SBUF和RB8(接收数据的第9位),置RI=1,向CPU申请中断,如果条件不满足,则数据丢失,且不置位RI,继续搜索RXD引脚的负跳变。

在方式2和方式3中,要用到SCON寄存器中的TB8位和RB8位,TB8为数据发送的第9位,用于方式2和方式3,由软件更改,RB8为数据接收的第9位,用于方式2和方式3,在方式1中,如果SM2=0,则RB8用于存放接收到的停止位,在方式0下不适用该位。

-----------------------------------------------------------------------------------------------------------------------
使用串口工作方式2发送0XAA
void main()
{
    SM0=1;            //SMOSM1为10,串行工作方式2
    SM1=0;            //11位异步收发(9位数据)
    TB8=0;            //数据发送的第9位
    EA=1;            //开总中断
    ES=1;            //允许串口中断
    TI=0;            //发送中断标志位
    while(1)
    {
        SBUF=0XAA;   
        delay();
    }
}
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
void ser0() interrupt 4
{
    TI=0;        //清楚发送中断标志位
}
-----------------------------------------------------------------------------------------------------------------------

单片机双机通信
通常单片机通信有以下四种实现方式:
TTL电平通信
RS-232C通信
RS-422A通信
RS-485通信

TTL电平通信:


RS-232C通信:


RS-422A通信
RS-422A驱动器为双端驱动器,其中一条线的逻辑为1,另一条线就为0,
具抗干扰型,能够200mv以上的电位差,
传输速率90Kbps,传输距离可达1200m,接口电路如下:(全双工)


RS-485通信
RS-485是RS-422A的变种,422A是全双工,485为半双工,
最多可使用32对差分器。如在一个网络中连接超过32个,还可使用中继器。
引起传输线采用差动信号,所以抗干扰性好,传输速率可达1Mbps,接口如下:


多机通信
采用主从结构,在整个系统中,有且仅有一个主机,其余全是从机,多机通信所应遵循的原则如下:
A.所有从机的SM2=1;处于接收地址帧状态
B.主机发送一地址帧,其中8位是地址,第9位是地址/数据区分标志,该位置1表示地址帧。
所有从机收到地址帧后,与本季的地址比较,对于地址相符的从机,
是自己的SM2置0(已接收主机随后发来的数据帧),并把本机地址发回主机作为应答,
对于地址不符的,仍保持SM2=1,对主机随后发来的数据帧不予理睬.

C.从机发送数据结束后,要发送一帧校验和,并置第9位(TB8)为1,作为从机数据结束的标志。
D.主机验证数据时,先判断数据接收标志(RB8),若RB8=1;表示数据传送结束,并比较此帧校验和,
若正确则会送正确信号00H,命令该从机复位(即重新等待地址帧)。
若校验和出错,则发送0FFH,命令该从机重发数据。
若接受侦的RB8=0;则将数据存到缓存区,并准备接收下一帧信息。

E.主机接到从机应答地址后,确认地址是否相符,如果地址不符,
则发复位信号(数据帧中TB8=1),如果地址相符,则TB8清0,开始发送数据。

从机收到复位命令后,会到监听地址状态(SM2=1),否则开始接收数据和命令。
编程时,可按以下方式操作:
主机发送的地址联络信号为00H,01H,02H,...(即从机设备地址);地址FFH为命令各从机复位,即回复SM2=1;
主机命令编码如下:
01H:主机命令从机接收数据;
02H:主机命令从机发送数句;
若有其他数据,则都按02H对待。

从机状态字格式如图:

若ERR =1;从机收到非法命令。
若TRDY=1;从机发送准备就绪
若RRDY=1;从机接收准备就绪

通常,从机以中断方式控制和主机通讯。

多机通信主机流程图如下:


程序代码如下:
-----------------------------------------------------------------------------------------------------------------------
#include
#define  uchar unsigned char
#define uint unsigned int
#define SLAVE 0X02   //从机地址
#define  NB 16

uchar rbuf[16];
uchar code tbuf[16]={"master transmit"};

void err()
{
    SBUF=0XFF;
    while(!TI=1);
    TI=0;
}
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
uchar master(uchar add,uchar com)
{
    while(1)
    {
        SBUF=SLAVE;            //发呼叫地址
        while(!TI=1);
        TI=0;
        while(!RI=1);
        RI=0;                //等待从机应答
        if(SBUF!=add)
        {
            err();            //地址错误,发复位信号
               
        else                //地址相符
        {
            TB8=0;            //清地址标志
            SBUF=cmd;        //发命令
            while(!TI=1);
            TI=0;
            while(!RI=1);
            RI=0;
            aa=SBUF;        //接收状态
            if(aa&0x08==0x08)        //若命令未被接收,发复位信号
            {
                TB8=1;
                err();
            }
            else
            {
                if(cmd==0X01)          //发送命令
                {
                    if(aa&0x01==0x01)     //从机准备好接受
                    {
                        do
                        {
                            p=0;              //清校验和
                            for(i=0;i
                            {
                                SBUF=tbuf[i];    //发送一数据
                                p+=tbuf[i];
                                while(!TI=1);
                                TI=0;
                            }
                            SBUF=p;            //发送检验和
                            while(!TI=1);
                            TI=0;
                            while(!RI=1);
                            RI=0;
                        }
                        while(SBUF!=0);        //接收不正确,重新发送
                        TB8=1;                //置地址标志
                        return(0);
                    }
                    else
                    if(aa&0x02==0x02)        //是接收命令,从机准备好发送
                    {
                        while(1)
                        {
                            p=0;        //清检验和
                            for(i=0;i
                            {
                                while(!RI=1);
                                RI=0;
                                rbuf[i]=SBUF;        //接收一数据
                                p+=rbuf[i];
                            }
                            while(!RI=1);
                            RI=0;
                            if(SBUF==p)
                            {
                                SBUF=0x00;            //校验和相同发0X00
                                while(!TI=1);
                                TI=0;
                                break;
                            }
                            else
                            {
                                SBUF=0xFF;
                                while(!TI=1);
                                TI=0;
                            }
                        }
                        TB8=1;              //置地址标志
                        return(0);
                    }
                }

            }
        }
    }

}
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
void main()
{
    TMOD=0x20;    //T/C1定义为方式2
    TL1=0XFD;    //置初值
    TH1=0XFD;
    PCON=0X00;
    TR1=1;
    SCON=0XF0;    //串行口方式3
    master(SLAVE,0x01);
    master(SLAVE,0X02);
    while(1);
}
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
多机通信从机流程图:


程序如下:
-----------------------------------------------------------------------------------------------------------------------
#include
#define uchar unsigned char
#define uint unsigned int
#define  SLAVE 0X02
#define BN  16

uchar trbuf[16];
uchar rebuf[16];
bit tready;
bit rready;

void str(void);
void sre(void);

void main()
{
     TMOD=0x20;            //T/C1定义为方式2
    TH1=0XFD;
    TL1=0XFD;
    PCON=0X00;
    TR1=1;
    SCON=0XF0;
    ES=1;     //开串行口中断
    EA=1;     //开总中断

    while(1)
    {
        tready=1;
        rready=1;   
           //假定准备好发送和接受
}
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
void ssio(void) interrupt 4
{
    uchar a;
    RI=0;
    ES=0;
    if(SBUF!=SLAVE)
    {
        ES=1;
        goto reti;
                        //非本机地址继续监听
    SM2=0;                //取消监听状态
    SBUF=SLAVE;            //从本地址发回
    while(!TI=1);
    TI=0;
    while(!RI=1);
    RI=0;
    if(RB8=1)
    {
        SM2=1;
        ES=1;
        goto reti;
                        //是复位信号,恢复监听
    a=SBUF;                //接收命令
    if(a==0X01)
    {
        if(rready=1)
            SBUF=0X01;        //接收准备好发状体
        else
            SBUF=0X00;
        while(!TI=1);
        TI=0;
        while(!RI=1);
        RI=0;
        if(RB8==1)
        {
            SM2=1;
            ES=1;
            goto reti;
        }
        sre();            //接收数据
    }
    else
    {
        if(a==0X02)            //从机向主机发送数据
        {
            if(tready=1)
                SBUF=0X02;        //发送准备好发状体
            else
                SBUF=0X00;
            while(!TI=1);
            TI=0;
            while(!RI=1);
            RI=0;
            if(RB8==1)
            {
                SM2=1;
                ES=1;
                goto reti;
            }
            str();            //发送数据
        }
        else
        {
            SBUF=0X80;            //命令非法,发状态
            while(!TI=1);
            TI=0;
            SM2=1;
            ES=1;             //恢复监听
         
    }
    reti;
}
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
void str(void)            //发送数据块
{
    uchr p,i;
    tready=0;
    do
    {
        p=0;        //清校验和
        for(i=0;i
        {
            SBUF=trbuf[i];            //发送一数据
            p+=trbuf[i];
            while(!TI=1);
            TI=0;
        }
        SBUF=p;             //发送校验和
        while(!TI=1);
        TI=0;
        while(!RI=1);
        RI=0;
    }while(SBUF!=0);        //主机接收不正确,从新发送
    SM2=1;
    ES=1;   
}
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
void sre(void)                  //接收数据块
{
    uchr p,i;
    rready=0;
    while(1)
    {
        p=0;        //清校验和
        for(i=0;i
        {
            while(!RI=1);
            RI=0;
            rebuf[i]=SBUF;        //接收数据
            p+=rebuf[i];
        }
        while(!RI=1);
        RI=0;
        if(SBUF==p)
        {
            SBUF=0X00;
            break;
                //校验和相同发00
        else
        {
            SBUF=0XFF;           //校验值不同发0FF,重新接收
            while(!TI=1);
            TI=0;
        }
    }
    SM2=1;
    ES=1;       
}
-----------------------------------------------------------------------------------------------------------------------

以上是51串口的通讯的协议内容,也可以说是串口通讯协议。其与Uart等具有相同的传输性质:双向传输,全双工!



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏17 分享淘帖 顶 踩
回复

使用道具 举报

来自 2#
ID:235664 发表于 2018-5-11 07:45 | 只看该作者
楼主您好, 问您个问题, STC15W204S单片机,初始化如下:
void UartInit(void)//9600bps@11.0592MHz
{
        SCON = 0x50;//8位数据,可变波特率  REN = 1
        AUXR |= 0x15;//定时器2时钟为Fosc,即1T          // 定时器T2运行, 定时器T2作为波特率发生器,
        T2L = 0xE0;//设定定时初值
        T2H = 0xFE;//设定定时初值
        TI = 1;
        ES = 1;
        EA=1;
}
我在interrupt 4 里面接受数据并将数据发给上位机, 数据没问题, 但是在其他函数里面发送,那么接受到的数据是一个固定值,请问这是怎么回事? 还望楼主和管理员赐教
回复

使用道具 举报

板凳
ID:235562 发表于 2017-11-3 20:54 | 只看该作者
楼主很棒,最近写了一个51单片机双机通信,
回复

使用道具 举报

地板
ID:286552 发表于 2018-3-1 11:17 | 只看该作者
你好!
回复

使用道具 举报

5#
ID:311817 发表于 2018-4-19 17:05 | 只看该作者
有没有word
回复

使用道具 举报

6#
ID:20672 发表于 2018-7-26 14:03 | 只看该作者
楼主很棒,太棒了。。。。
回复

使用道具 举报

7#
ID:367948 发表于 2018-8-3 11:40 | 只看该作者
非常详细,谢谢
回复

使用道具 举报

8#
ID:528308 发表于 2019-5-10 19:29 | 只看该作者
太好了,谢谢楼主
回复

使用道具 举报

9#
ID:85480 发表于 2019-7-31 15:31 | 只看该作者
详细,感谢分享!
回复

使用道具 举报

10#
ID:718536 发表于 2021-1-22 02:59 | 只看该作者
多机通讯这段代码很眼熟呀,是老郭的那段?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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