STC51-串口通信

2023-05-16

1 并行与串行基本通信方式

        随着单片机系统的广泛应用和计算机网络技术的普及,单片机的通信功能愈来愈显得重要。单片机通信是指单片机与计算机或单片机与单片机之间的信息交换,通常单片机与计算机之间的通信我们用的较多。
        通信有并行和串行两种方式。在单片机系统以及现代单片机测控系统中,信息的交换多采用串行通信方式。

1.1 并行通信方式

        并行通信通常是将数据字节的各位用多条数据线同时进行传送,每一位数据都需要一条传输线,如下图所示,8位数据总线的通信系统,一次传送8位数据(1个字节),将需要8条数据线。此外,还需要一条信号线和若干控制信号线,这种方式仅适合于短距离的数据传输,如比较老式的打印机就是通过并口方式与计算机连接,现在都用传输速度非常快的USB2.0接口通信了。由于并口通信已经用得较少,因此我们在这里也仅做简单介绍,大家只需了解即可。

在这里插入图片描述

        并行通信控制简单、相对传输速度快,但由于传输线较多,长距离传送时成本高且收、 发方的各位同时接收存在困难。

1.2 串行通信方式

        串行通信是将数据字节分成一位一位的形式在一条传输线上逐个地传送,此时只需要一条数据线,外加一条公共信号地线和若干控制信号线。因为一次只能传送一位,所以对于一个字节的数据,至少要分8位才能传送完毕,如下图所示。

在这里插入图片描述

        串行通信的必要过程是:发送时,要把并行数据变成串行数据发送到线路上去,接收时,要把串行信号再变成并行数据,这样才能被计算机及其他设备处理。
        串行通信传输线少,长距离传送时成本低,且可以利用电话网等现成的设备,但数据的传送控制比并行通信复杂。
        串行通信又有两种方式:异步串行通信和同步串行通信。
        异步串行通信方式:
        异步串行通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方收、发协调,要求发送和接收设备的时钟尽可能一致,如下图所示。

在这里插入图片描述

        异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时间间隔) 是任意的,但每个字符中的各位是以固定的时间传送的,即字符之间不一定有“位间隔"的整数倍关系,但同一字符内的各位之间的距离均为“位间隔"的整数倍。
        异步通信一帧字符信息由4部分组成:起始位、数据位、奇偶校验位和停止位,如下图所示。有的字符信息也有带空闲位形式, 即在字符之间有空闲字符。

在这里插入图片描述

        异步通信的特点:不要求收发双方时钟的严格一致,实现容易,设备开销较小,但每个字符要附加2~3位,用于起止位、校验位和停止位,各帧之间还有间隔,因此传输效率不高。
        在单片机与单片机之间,单片机与计算机之间通信时,通常采用异步串行通信方式。
        同步串行通信方式:
        同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。此时,传输数据的位之间的距离均为"位间隔"的整数倍,同时传送的字符间不留间隙,即保持位同步关系,也保持字符同步关系。发送方对接收方的同步可以通过外同步和自同步两种方法实现,分别如下图左和下图右所示。

在这里插入图片描述

        面向字符的同步格式如下图所示。

在这里插入图片描述

        此时,传送的数据和控制信息都必须由规定的字符集(如ASCII码)中的字符所组成。上图中帧头为1个或2个同步字符SYN(ASCII码为16H)。SOH为序始字符(ASCII码为OlH),表示标题的开始,标题中包含源地址、目标地址和路由指示等信息。STX为文始字符(ASCII码为02H),表示传送的数据块开始。数据块是传送的正文内容,由多个字符组成,数据块后面是组终字符ETB(ASCII码为17H)或文终字符ETX(ASCII码为03H),然后是校验码,典型的面向字符的同步规程如IBM的二进制同步规程BSC。
        面向位的同步格式如下图所示。

在这里插入图片描述

        此时,将数据块看做数据流,并用序列01111110作为开始和结束标志。为了避免在数据流中出现序列01111110时引起的混乱,发送方总是在其发送的数据流中每出现5个连续的1就插入一个附加的0;接收方则每检测到5个连续的1并且其后有一个0时,就删除该0。
        典型的面向位的同步协议如ISO的高级数据链路控制规程HDLC和IBM的同步数据链路控制规程SDLC。
        面向位的同步通信的特点是以特定的位组合01111110作为帧的开始和结束标志,所传输的一帧数据可以是任意位。它传输的效率较高,但实现的硬件设备比异步通信复杂。

1.3 串行通信的制式

        1)单工。单工是指数据传输仅能沿一个方向,不能实现反向传输。
        2)半双工。半双工是指数据传输可以沿两个方向,但需要分时进行
        3)全双工。全双工是指数据可以同时进行双向传输。三种制式分别如下图左、下图中和下图右所示。

在这里插入图片描述

1.4 串行通信的错误校验

        1)奇偶校验
        在发送数据时,数据位尾随的1位为奇偶校验位(1或0)。奇校验时,数据中1的个数与校验位1的个数之和应为奇数;偶校验时,数据中1的个数与校验位1的个数之和应为偶数。接收字符时,对1的个数进行校验,若发现不一致,则说明传输数据过程中出现了差错。
        2)代码和校验
        代码和校验是发送方将所发数据块求和(或各字节异或),产生一个字节的校验字符(校验和)附加到数据块末尾。接收方接收数据时同时对数据块(除校验字节外)求和(或各字节异或),将所得的结果与发送方的“校验和“进行比较,相符则无差错,否则即认为传送过程中出现了差错。
        3)循环冗余校验
        这种校验是通过某种数学运算实现有效信息与校验位之间的循环校验,常用于对磁盘信息的传输、存储区的完整性校验等。这种校验方法纠错能力强,广泛应用于同步通信中。

2 RS-232 电平与TTL 电平的转换

        关于RS-232电平与TTL电平的特性在前面已经讲过,本节主要讲解使用较多的计算机RS-232电平与单片机TTL电平之间的转换方式。早期的MC1488、75188等芯片可实现TTL电平到RS-232电平的转换;MC1489、75189等芯片可实现RS-232电平到TTL电平的转换。但是现在用的较多的是MAX232, MAX202, HIN232等芯片,它们同时集成了RS-232电平和TTL电平之间的互转。为丰富大家的知识,下面首先讲解在没有M心(232这种现成电平转换芯片时,如何用二极管、三极管、电阻、电容等分立元件搭建一个简单的RS-232电平与TTL电平之间的转换电路。

2.1 分立元件实现RS-232电平与TTL电平转换电路

        集成芯片内部都是由最基本电子元件组成,如电阻、电容、二极管、三极管等元件,为了方便用户使用,制造商把这些具有一定功能的分立元件封装到一个芯片内,这样就制成了我们使用的各种芯片。学会本电路后,我们也就基本搞清了MAX232芯片内部的大致结构。
        MAX232是把TTL电平从0V和5V转换到3V、15V或-3V、-15 V之间。分析图下图,首先TTL电平TXD发送数据时,若发送低电平0,这时Q3导通,PCRXD由空闲时的低电平变高电平(如PC用中断接收的话会产生中断),满足条件。发送高电平1时,TXD为高电平,Q3截止,由于PCRXD内部高阻,而PCTXD平时是-3~-15V,通过D1和R7将其拉低PCRXD至-3-15V,此时计算机接收到的就是1。下面再反过来,PC发送信号,由单片机来接收信号。当PCTXD为低电平-3-(-15V)时,Q4截止,单片机端的RXD被R9拉到5V高电平;当PCTXD变高时,Q4导通,RXD被Q4拉到低电平,这样便实现的双向转换,这是一个很好的电路,值得大家学习。

在这里插入图片描述

2.2 MAX232芯片实现RS-232电平与TTL电平转换

        MAX232芯片是MAXIM公司生产的、包含两路接收器和驱动器的IC芯片,它的内部有一个电源电压变换器,可以把输入的+5V电源电压变换成为RS-232输出电平所需的+10V电压。所以,采用此芯片接口的串行通信系统只需单一的+5V电源就可以了。对千没有+12V电源的场合,其适应性更强,加之其价格适中,硬件接口简单,所以被广泛采用。
        MAX232芯片实物如左上图和右上图所示,其引脚结构和外围连接分别如左下图和右下图所示。

        右下图中上半部分电容C1、C2、C3、C4及V+、V-是电源变换电路部分。在实际应用中,器件对电源噪声很敏感,因此Vee必须要对地加去耦电容Cs,其值为0.1µF。按芯片手册中介绍,电容C1、C2、C3、C4应取1.0µF/16V的电解电容,经大量实验及实际应用,这4个电容都可以选用0.1µF的非极性瓷片电容代替1.0µF/16V的电解电容,在具体设计电路时,这4个电容要尽量靠近MAX232芯片,以提高抗干扰能力。
        右下图下半部分为发送和接收部分。实际应用中,T1IN、T2IN可直接连接TTL/CMOS电平的51单片机串行发送端TXD;R10UT。R20UT可直接连接TTL/CMOS电平的51单片机的串行接收端RXD;T10UT,T20UT可直接连接PC机的RS-232串口的接收端RXD;R1IN,R2IN可直接连接PC机的RS-232串口的发送端TXD。
        现从MAX232芯片中两路发送、接收中任选一路作为接口。要注意其发送、接收的引脚要对应。如使T1IN连接单片机的发送端TXD,则PC机的RS-232接收端RXD一定要对应接
T10UT引脚。同时,R10UT连接单片机的RXD引脚,PC机的RS-232发送端TXD对应接R1 IN引脚。
        实验板串口部分原理图如下左图所示,实验板上实物如下右图所示。
        其数据传输过程如下:MAX232的11脚T1IN接单片机TXD端P3.1,TTL电平从单片机的TXD端发出,经过MAX232转换为RS-232电平后从MAX232的14脚T1OUT发出,再连接到实验板上串口座的第3脚,再经过随板配送的交叉串口线后,连接至PC机的串口座的第2脚RXD端,至此计算机接收到数据。PC机发送数据时从PC机串口座第3脚TXD端发出数据,再逆向流向单片机的RXD端P3.0接收数据。

在这里插入图片描述

        这里需要注意的是,MAX232与串口座连接时,无论是数据输出端,还是数据输入端,连接串口座的第2引脚或第3引脚都可以,选用不同的连接方法时,单片机与计算机之间的串口线都要谨慎选择,是选择平行串口线还是交叉串口线、是选择母头对母头串口线还是母头对公头串口线这些都要非常注意,每种选择都有对应的电路,但无论哪种搭配方式,大家必须要明白,在单片机与计算机之间必须要有一条数据能互相传输的回路,只要把握好每个交接点就一定能通信成功。

3 波特率与定时器初值的关系

3.1 波特率

        单片机或计算机在串口通信时的速率用波特率表示,它定义为每秒传输二进制代码的位数,即1波特=1位/秒,单位是bps(位/秒)。如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的波特率为10位X240个/秒=2400bps。
        串行接口或终端直接传送串行信息位流的最大距离与传输速率及传输线的电气特性也有关。当传输线使用每0.3m(约1英尺)有50pF电容的非平衡屏蔽双绞线时,传输距离随传输速率的增加而减小。当比特率超过1000bps时,最大传输距离迅速下降,如9600bps时最大距离下降到只有76m(约250英尺)。因此我们在做串口通信实验选择较高速率传输数据时,尽量缩短数据线的长度,为了能使数据安全传输,即使是在较低传输速率下也不要使用太长的数据线。

3.2 波特率的计算

        在串行通信中,收、发双方对发送或接收数据的速率要有约定。通过编程可对单片机串行口设定为4种工作方式,其中方式0和方式2的波特率是固定的,而方式1和方式3的波特率是可变的,由定时器T1的溢出率来决定。
        串行口的4种工作方式对应三种波特率。由于输入的移位时钟的来源不同,所以各种方式的波特率计算公式也不相同,以下是4种方式波特率的计算公式。
                方式0的波特率=fos/12。
                方式1的波特率=(2^SMOD/32) x(T1溢出率)。
                方式2的波特率=(2^SMOD/64)Xfoc。
                方式3的波特率=(2SMOD/32)x(Tl溢出率)。
        式中,fosc为系统晶振频率,通常为12MHz或11.0592MHz; SMOD是PCON寄存器的最高位(关于PCON寄存器请看下一个知识点);T1溢出率即定时器Tl溢出的频率。

3.3 电源管理寄存器PCON

        电源管理寄存器在特殊功能寄存器中,字节地址为87H,不能位寻址,PCON用来管理单片机的电源部分,包括上电复位检测、掉电模式、空闲模式等。单片机复位时PCON全部被清0。其各位的定义如下表所示。

在这里插入图片描述

        SMOD—该位与串口通信波特率有关。
                SMOD=0:串口方式1、2、3时,波特率正常。
                SMOD=1:串口方式1、2、3时,波特率加倍。
        (SMOD0),(LVDF),(P0F)—这三位是STC单片机特有的功能,请查看相关手册,其他单片机保留未使用。
        GF1,GF0—两个通用工作标志位,用户可以自由使用。
        PD—掉电模式设定位。
                PD=0:单片机处于正常工作状态。
                PD=1:单片机进入掉电(PowerDown)模式,可由外部中断低电平触发或由下降沿触发或者硬件复位模式唤醒,进入掉电模式后,外部晶振停振,CPU、定时器、串行口全部停止工作,只有外部中断继续工作。
        IDL—空闲模式设定位。
                IDL=0:单片机处于正常工作状态。
                IDL=1:单片机进入空闲(Idle)模式,除CPU不工作外,其余仍继续工作,在空闲模式下可由任一个中断或硬件复位唤醒。
        T1溢出率就是T1定时器溢出的频率,只要算出T1定时器每溢出一次所需的时间T,那么T的倒数1/T就是它的溢出率。这个问题还是比较容易理解的,在第3章讲解过定时器T0和T1方式1的操作方法,若我们设定定时器T1每50ms溢出一次,那么其溢出率就为20Hz,再将20代入串口波特率计算公式中即可求出相应的波特率,当然也可根据波特率反推出定时器的溢出率,进而计算出定时器的初值。通常单片机在通信时,波特率都较高,因此T1溢出率也必定很高,如果我们使用定时器1的工作方式1在中断中装初值的方法来求T1溢出率的话,在进入中断、装值、出中断这个过程中很容易产生时间上微小的误差,当多次操作时微小的误差不断累积,终会产生错误。有效的解决办法是,使用T1定时器的工作方式2,8位初值自动重装的8位定时器/计数器,定时器方式2逻辑结构图如下图所示。

在这里插入图片描述

        在学习定时器方式2时可参考定时器方式1,在方式1中,当定时器计满溢出时,自动进入中断服务程序,然后我们需要手动再次给定时器装初值,而在方式2中,当定时器计满溢出后,单片机会自动为其装初值,并且无须进入中断服务程序进行任何处理,这样定时器溢出的速率就会绝对稳定。方式2的工作过程是:先设定M0M1选择定时器方式2,在TLX和THX中装入计算好的初值,启动定时器,然后TLX寄存器便在时钟的作用下开始加1计数,当TLX计满溢出后,CPU会自动将THX中的数装入TLX中,继续计数。因此我们在启动定时器之前必须先将TLX和THX中装好合适的数值,以让定时器输出产生的溢出率,这里TLX和THX中装的数值必须是一样的,因为每次计数溢出后TLX中装入的新值是从THX中取出的。
        下面我们举一个例子来讲解根据已知波特率,如何计算定时器1 方式2下计数寄存器中的初值。
        例如:已知串口通信在串口方式1下,波特率为9600bps, 系统晶振频率为11.0592MHz,求TL1和TH1中装入的数值是多少?
        解:设所求的数为X,则定时器每计256-X个数溢出一次,每计一个数的时间为一个机器周期,一个机器周期等于12个时钟周期,所以计一个数的时间为12/11.0592MHz(s),那么定时器溢出一次的时间为[256-X]x12/11.0592MHz(s),T1的溢出率就是它的倒数,方式1的波特率=[(2SMOD)/32]x(T1溢出率),这里我们取SMOD=0,则2SMOD=1,将已知的数代入公式后得9600=(1/32)x11059200/[256-X]x12,求得X=253,转换成十六进制为0xFD。上面若将SMOD置1的话,那么X的值就变成250了。可见,在不变化X值的状态下,SMOD由0变1后,波特率便增加一倍。
        大家一定要搞明白上面这段由波特率计算定时器初值的方法,通常波特率都是固定的一些数据,如1200、2400、4800、9600等,所以都是根据所要使用的波特率来求定时器初值,而没有说根据定时器初值来求波特率的,以后大家若要使用不同的波特率来做单片机和单片机之间或单片机与计算机之间的通信实验时,可参考上面的计算方法来求定时器初值。
        大家可能会有疑惑,为什么单片机系统的晶振要选11.0592MHz 呢?通过上面的计算可能有些人已经明白了,我们用一个小知识点来为大家解答这个疑惑。

3.4 为什么51系列单片机常用11.0592MHz的晶振设计

        常用波特率通常按规范取为1200、2400、4800、9600…,若采用晶振12MHz或6MHz,计算得出的T1定时初值将不是一个整数,这样通信时便会产生积累误差,进而产生波特率误差,影响串行通信的同步性能。解决的方法只有调整单片机的时钟频率fosc,通常采用11.0592MHz晶振。因为用它能够非常准确地计算出T1定时初值,即使对于较高的波特率(19600、19200),不管多么古怪的值,只要是标准通信速率,使用11.0592MHz的晶振可以得到非常准确的数值。
        下表列出了串口方式1定时器1方式2产生常用波特率时,TL0和TH0中所装入的值。

在这里插入图片描述

4 51单片机串行口结构描述

4.1 串行口结构

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

在这里插入图片描述

        51单片机可以通过特殊功能寄存器SBUF对串行接收或串行发送寄存器进行访问,两个寄存器共用一个地址99H,但在物理上是两个独立的寄存器,由指令操作决定访问哪一个寄存器。执行写指令时,访问串行发送寄存器;执行读指令时,访问串行接收寄存器。接收器具有双缓冲结构,即在从接收寄存器中读出前一个已收到的字节之前,便能接收第二个字节,如果第二个字节已经接收完毕,第一个字节还没有读出,则将丢失其中一个字节,编程时应引起注意。对于发送器,因为数据是由CPU控制和发送的,所以不需要考虑。
        与串行口紧密相关的一个特殊功能寄存器是串行口控制寄存器SCON,它用来设定串行口的工作方式、接收/发送控制以及设置状态标志等。

4.2 串行口控制寄存器SCON

        串行口控制寄存器SCON在特殊功能寄存器中,字节地址为98H,可位寻址,SCON用以设定串行口的工作方式、接收/发送控制以及设置状态标志等。单片机复位时SCON全部被清0。其各位的定义如下表所示。

在这里插入图片描述

        SM2—多机通信控制位。
                SM2主要用于方式2和方式3。当接收机的SM2=1时,可以利用收到的RB8来控制是否激活RI(RB8=0时不激活RI,收到的信息丢弃;RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走)。当SM2=0时,不论收到的RB8是0还是1,均可以使收到的数据进入SBUF,并激活RI(即此时RB8不具有控制RI激活的功能)。通过控制SM2,可以实现多机通信。在方式0时,SM2必须是0。在方式1时,若SM2=1,则只有接收到有效停止位时,RI才置1。
        REN—允许串行接收位。
                REN=1:允许串行口接收数据;
                REN=0:禁止串行口接收数据。
        TBS—方式2,3中发送数据的笫9位。
                在方式2或方式3中,是发送数据的笫9位,可以用软件规定其作用。可以用做数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。在方式0和方式1中,该位未用。
        RBS—方式2,3中接收数据的笫9位。
                在方式2或方式3中,是接收数据的笫9位,可作为奇偶校验位或地址帧/数据帧的标志位。在方式1时,若SM2=0,则RBS是接收到的停止位。
        TI—发送中断标志位。
                在方式0时,当串行发送笫8位数据结束时,或在其他方式,串行发送停止位的开始时,由内部硬件使TI置1,向CPU发出中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请。
        RI—接收中断标志位。
                在方式0时,当串行接收笫8位数据结束时,或在其他方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发出中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。

4.3 串口方式简介

        在这里对串口4种方式仅做简单介绍,在下一节将重点介绍串口方式1,在后面的篇章对其他几种方式再做详细介绍。
        1)方式0。方式0时,串行口为同步移位寄存器的输入/输出方式,主要用于扩展并行输入或输出口。数据由RXD(P3.0)引脚输入或输出,同步移位脉冲由TXD(P3.1)引脚输出。发送和接收均为8位数据,低位在先,高位在后,波特率固定为fosc/12。
        2)方式1。方式1是10位数据的异步通信口,其中1位起始位,8 位数据位,1位停止位。TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。其传输波特率是可变的,对于51单片机,波特率由定时器1的溢出率决定。通常我们在做单片机与单片机串口通信、单片机与计算机串口通信、计算机与计算机串口通信时,基本都选择方式1,因此这种方式大家务必要完全掌握。
        3)方式2、3。方式2、3时为11位数据的异步通信口。TXD(P3.1)为数据发送引脚,RXD(P3.0)为数据接收引脚。这两种方式下,起始位1位,数据9位(含1位附加的第9位,发送时为SCON中的TBS,接收时为RBS),停止位1位,一帧数据为11位。方式2的波特率固定为晶振频率的1/64或1/32,方式3的波特率由定时器Tl的溢出率决定。
        方式2和方式3的差别仅在于波特率的选取方式不同,在两种方式下,接收到的停止位与SBUF、RBS及RI都无关。

5 串行口方式1编程与实现

        串行口方式1是最常用的通信方式,其传送一帧数据的格式如下图所示。

在这里插入图片描述

        串行口方式1传送一帧数据共10位,1位起始位(0),8位数据位,最低位在前,高位在后,1位停止位(1),帧与帧之间可以有空闲,也可以无空闲。方式1数据输出时序图和数据输入时序图分别如下图和下下图所示。

在这里插入图片描述

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

在这里插入图片描述

        用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。当Rl=0,且SM2=0(或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置Rl=1,向CPU请求中断。
        在具体操作串行口之前,需要对单片机的一些与串口有关的特殊功能寄存器进行初始化设置,主要是设置产生波特率的定时器1、串行口控制和中断控制。具体步骤如下:
                ①确定T1的工作方式(编程TMOD寄存器);
                ②计算T1的初值,装载TH1、TL1;
                ③启动T1(编程TCON中的TR1位);
                ④确定串行口工作方式(编程SCON寄存器);
                ⑤串行口工作在中断方式时,要进行中断设置(编程IE, IP寄存器)。
        下面我们用一个实例讲解串口方式1的具体使用方法和操作流程,在TX-IC实验板上实现如下功能。
        例如:在上位机上用串口调试助手发送一个字符X,单片机收到字符后返回给上位机"I get X",串口波特率设为9600bps。新建文件Temp.c,程序代码如下:

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
uchar flag,a,i;
uchar code table[]="I get";
void init()
{
  TMOD=0x20;
  TH1=0xfd;
  TL1=0xfd;
  TR1=1;
  REN=1;
  SM0=0;
  SM1=1;
  EA=1;
  ES=1;
  }
void main()
{
  init();
  while(1)
  {
    if(flag==1)
	{
	  ES=0;
	  for(i=0;i<6;i++)
	  {
	    SBUF=table[i];
		while(!TI);
		TI=0;
		}
	   SBUF=a;
	   while(!TI);
	   TI=0;
	   ES=1;
	   flag=0;
	   }
	}
}
void ser() interrupt 4
{
   RI=0;
   a=SBUF;
   flag=1;
}

在这里插入图片描述

        分析如下:
        1)"uchar code table[]=“I get”;"定义了一个字符类型的编码数组,数组中的元素为字符串时,用双撇号将字符串引起来,空格也算一个字符。字符串由一个一个字符组成,因此也可写成另外一种方式"uchar code table[]={‘I’,’’,‘g’,‘e’,‘t’,’’};”,这里的每个字符用两个单撇号引起来,元素之间要用逗号隔开,空格也算一个字符。为叙述简便,建议大家选择第一种方式。
        2)初始化函数"void init()"中各句解释如下:

                TMOD=0x20; //设定Tl定时器工作方式2
                TH1=0xfd; //定时器装初值
                TL1=0xfd; //定时器装初值
                TR1=1; //启动Tl定时器
                REN=1; //允许串口接收
                SM0=0; //设定串口工作方式1
                SM1=1; //同上
                EA=1; //开总中断
                ES=1; //开串口中断

        这里我们没有看到开定时器1中断的语旬,因为定时器1工作在方式2时为8位自动重装方式,我们进中断后无事可做,因此无须打开定时器1的中断,更无须写定时器1的中断服务程序。
        3)"void ser () interrupt 4"为串口中断服务程序,在本程序中完成三件事:RI清0,因为程序既然产生了串口中断,那么肯定是收到或发送了数据,在开始时没有发送任何数据,那必然是收到了数据,此时RI会被硬件置1,进入串口中断服务程序后必须由软件清0,这样才能产生下一次中断;将SBUF中的数据读走给a,这才是进入中断服务程序中最重要的目的;将标志位flag置1,以方便在主程序中查询判断是否已经收到数据。
        4)进入大循环while()语句后,一直在检测标志位flag是否为1,当检测到为1时,说明程序已经执行过串口中断服务程序,即收到了数据,否则始终检测flag的状态。当检测到flag置1后,先是将ES清0,原因是接下来要发送数据,若不关闭串口中断,当发送完数据后,单片机同样会申请串口中断,便再次进入中断服务程序,flag又被置1,主程序检测到flag为1,又回到这里再次发送,如此重复下去,程序便成了死循环,造成错误的现象,因此我们在发送数据前把串口中断关闭,等发送完数据后再打开串口中断,这样便可以安全地发送数据了。大家可亲自做实验,不要关闭串口,观察实验结果。
        5)在发送数据时,当发送前面6个固定的字符时,使用了一个for循环语句,将前面数组中的字符依次发送出去,后面再接着发送从中断服务程序中读回来的SBUF中的数据时,当向SBUF中写入一个数据后,使用"while(!TI);"等待是否发送完毕,因为当发送完毕后TI会由硬件置1,然后才退出"while(!TI);"接下来我们再将TI手动清0。
        6)当接收数据时,我们写"a=SBUF;"语句,单片机便会自动将串口接收寄存器中的数据取走给a;当发送数据时,我们写"SBUF=a;“语句,程序执行完这条语句便自动开始将串口发送寄存器中的数据一位位从串口发送出去。很多初学者搞不明白,在这里再强调一下,SBUF是共用一个地址的两个独立的寄存器,单片机识别操作哪个寄存器的关键语句就是
“a=SBUF”和"SBUF=a”。
        串口调试助手设置及实验实拍照片如下图所示。

在这里插入图片描述

6 串行口打印在调试程序中的应用

        串行口打印功能通常用在程序调试中,举个例子说明它的用途:我们正在用单片机调试一个A/D芯片,单片机的外围只接了A/D芯片和串行口,当我们写好单片机程序下载后让其运行,可是我们根本不知道这个A/D芯片工作了没有?更不知道A/D芯片采集回来的数值对不对?这时如果我们使用串口打印功能,将单片机采集回来的A/D值经过处理后,发送到上位机上,在上位机上用一个简单的串口工具就可看见数据,这样我们在调试程序时便会方便许多。其次我们在调试其他程序时,在整个程序的不同地方,或是关键地方使用串口打印功能输出给上位机一个关键数据,我们就可知道程序中某些变量的实时数值,进一步得知程序运行的状况。
        上面的事例中我们将"I get"放在一个数组中,通过一个for循环连续发送给上位机,这实际上也算是串口打印功能的应用,但我们还有更方便的方法来运用它,本节我们将为大家介绍几个C51库函数中自带的与串口有关的非常有用的函数。
        下面通过一个实例完整讲述串口打印功能的用法及相关注意事项,利用上位机与实验板实现如下功能。
        实例:单片机上电后等待从上位机串口发送来的命令,同时在数码管的前三位以十进制方式显示A/D采集的数值,在未收到上位机发送来的启动A/D转换命令之前数码管始终显示000。
        当收到上位机以十六进制发送来的01后,向上位机发送字符串"Turn on ad!",同时间隔一秒读取一次A/D的值,然后把A/D采集回来的8位二进制数转换成十进制数表示的实际电压浮点数,并且从串口发送给上位机,形式如"The voltage is 3.398438V",发送周期也是一秒一次,同时在数码管上也要每秒刷新显示的数值。
        当收到上位机以十六进制发送来的02后,向上位机发送字符串"Turn off ad!",然后停止发送电压值,数码管上显示上次结束时保持的值。
        当收到上位机发来的其他任何数时,向上位机发送字符串"Error!"。

        下面是实现上述功能的完整例程,在调试本程序的时候遇到了许多很奇怪的错误现象,我在经过大量反复实验后总结出了一些非常重要的知识点,在例程的后面将一一描述,我们先来看例程,新建文件Temp.c,程序代码如下:

#include <reg52.h> 
#include <intrins.h> 
#include <stdio.h>	
#define uchar unsigned char
#define uint unsigned int
sbit dula=P2^6;		//申明U1锁存器的锁存端
sbit wela=P2^7;		//申明U2锁存器的锁存端
sbit adwr=P3^6;		//定义AD的WR端口
sbit adrd=P3^7;		//定义AD的RD端口
uchar flag,a;
unsigned char flag_uart,flag_time,flag_on,a,i,t0_num,ad_val;
float ad_vo;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void delayms(uint xms)				
{
	uint i,j;
	for(i=xms;i>0;i--)		      //i=xms即延时约xms毫秒
		for(j=110;j>0;j--);
}
void init()
{
	TMOD=0x21;
//	SCON=0x50;
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	TH1=0xfd;
	TL1=0xfd;
	TR1=1;
	ET0=1;
	SM0=0;
	SM1=1;
	REN=1;
	EA=1;
	ES=1;

}
void display(uchar value)  //显示子函数
{
	uchar bai,shi,ge;
	bai=value/100;		//分出百,十,和个位
	shi=value%100/10;
	ge=value%10;
	dula=1;
	P0=table[bai];    //送段选数据
	dula=0;
	P0=0xff;		//送位选数据前关闭所有显示,防止打开位选锁存时
	wela=1;			//原来段选数据通过位选锁存器造成混乱
	P0=0x7e;		//送位选数据
	wela=0;
	delayms(5);	    //延时
	dula=1;
	P0=table[shi];
	dula=0;
	P0=0xff;
	wela=1;
	P0=0x7d;
	wela=0;
	delayms(5);
	dula=1;
	P0=table[ge];
	dula=0;
	P0=0xff;
	wela=1;
	P0=0x7b;
	wela=0;
	delayms(5);
}
uchar get_ad()		
{
 	uchar adval;
	adwr=1;
	_nop_();
	adwr=0;			//启动AD转换
	_nop_();
	adwr=1;
	P1=0xff;                    //读取P1口之前先给其写全1 
	adrd=1;                   
	_nop_();	
	adrd=0;                     //AD读使能
	_nop_();
	adval=P1;			//AD数据读取
	adrd=1;
	return adval;
} 
void main()
{
	init();
	wela=1;
	P0=0x7f;           //置CSAD为0,选通ADCS 以后不必再管ADCS
	wela=0;
	while(1)
	{
		if(flag_uart==1)
		{
			flag_uart=0;
			ES=0;
			TI=1;
			switch(flag_on)
			{
				case 0: puts("Turn on ad!\n");
						TR0=1;
						break;
				case 1: printf("Turn off ad!\n");
						TR0=0;
						break;
				case 2: puts("Error!\n");
						break;
			}
			while(!TI);//必须要加
			TI=0;
			ES=1;
		}
		if(flag_time==1)
		{
			flag_time=0;
			ad_val=get_ad();
			ad_vo=(float)ad_val*5.0/256.0;
			ES=0;
			TI=1;
			printf("The voltage is %fV\n",ad_vo);
			while(!TI);
			TI=0;
			ES=1;
		}
		display(ad_val);
	}
}
void timer0() interrupt 1
{
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	t0_num++;
	if(t0_num==20)
	{
		t0_num=0;
		flag_time=1;
	}
}
void ser() interrupt 4
{
	RI=0;
	a=SBUF;
	flag_uart=1;
	if(a==1)
		flag_on=0;
 	else if(a==2)
			flag_on=1;
		else
			flag_on=2;
}

        编译程序下载到实验板,打开串口调试助手,分别发送01、02、03,当开启A/D转换后,适当调节实验板上A/D电压调节电位器,可看到返回的电压实际值在变化,最终界面显示如下图所示。

在这里插入图片描述

        分析如下:在分析本节例程之前,先来看上一节的例程。其实在上节串口测试程序中有个小问题:如果我们先打开串口调试助手软件,再打开实验板上电源的话,会看到上位机软件会在实验板刚一上电的时候收到一串字符’'I get",可是这时我们并没有向单片机发送任何命令,而单片机为何为主动发数据呢?也许大多数人并没有注意到这个现象,如果作为一个产品的话,这样的系统肯定不能算稳定工作的,上节的问题若没有解决,本节的例程将不可能调试成功,因此我们必须解决掉任何一个不正常的问题。
        1)先来解决上节的问题。我们在串口初始化函数中有这样几条语句:

REN=1;
SM0=0;
SM1=1;

        这三位都是串行口控制寄存器SCON里面的,单片机刚上电时SCON被清0,因为串口方式为方式0,串行口为同步移位寄存器的输入/输出方式,当执行完REN置1这条语句后,它便直接开始从RXD引脚接收数据,并不管与它连接的系统有无发送数据,这时SM0和SM1还未被操作,可单片机串口寄存器已经收到数据,并且已经产生了串口中断,因此串口中断中的标志位flag将被置1,当运行完下面两条指令后,串口方式才被设置为方式1,这时才终止串口接收数据。当程序运行到while(1)大循环中时,因为串口中断服务程序中的标志位flag已经被置1,所以接下来将发送里面的"I get",至于后面的a被发送到上位机之后为什么变成了一个空格,这个由大家自己来研究。
        本问题解决办法如下:
                ①将上面三条语句顺序改为:

SM0=0;
SM1=1;
REN=1;

                先设置串口模式,再允许串口接收,这样就会避开串口方式0接收数据。
                ②不要对SCON寄存器进行位操作,而是直接对整个寄存器进行设置,如SCON=0x50。大家可亲自做实验体检各种现象,若将本节实验中这三句改回原样后实验,产生的错误便不会像上节一样简单了,将会影响整个系统的正常运行,大家务必尝试一下。像这种看似很小的问题,在没有解决之前可能需要花费很长的时间才能找到问题的根源,我也不隐讳地告诉大家,我在调试本例程时,花了近3个小时才将它调试成功,无论如何也没有想到错误的原因竟然是因为把"REN=1;“这条语句提前写了两行,当然每解决一个问题,我们学到的知识都将更进一步,甚至更多,单片机是硬件,必须要经过大量的实验方可掌握,像这种现象光靠学书本上的理论,是永远都学不到的。
        2)#include头文件中包含有我们要使用的函数printf()和puts()。我们到Keil\C51\INC文件夹下打开STDIO.H,可看到里面申明了一些外部函数,内容如下:

extern char _getkey(void);
extern char getchar(void);
extern char ungetchar(char);
extern char putchar(char);
extern int printf(const char*,…);
extern int sprintf(char*,const char*,…);
extern int vprintf(const char*,char*);
extern int vsprinf(char*,const char*,char*);
extern chargets(char,int n);
extern int scanf(const char*,…);
extern int sscanf(char*,const char*,…);
extern int puts(const char*);

        extern表示在这里申明的是一个外部函数,外部函数的函数体不在本文件中,而是在其他某个文件中写有这个函数的实现部分。
        在本例中用到的printf()和puts()函数,在它内部都是由putchar()这个函数实现的,关于这两个函数的用法大家请看C51的帮助文件。在Keil\C5l\LIB文件夹下打开PUTCHAR.C文件可看到内容如下:

char putchar (char c)  {

  if (c == '\n')  {
    if (RI)  {
      if (SBUF == XOFF)  {
        do  {
          RI = 0;
          while (!RI);
        }
        while (SBUF != XON);
        RI = 0; 
      }
    }
    while (!TI);
    TI = 0;
    SBUF = 0x0d;                         /* output CR  */
  }
  if (RI)  {
    if (SBUF == XOFF)  {
      do  {
        RI = 0;
        while (!RI);
      }
      while (SBUF != XON);
      RI = 0; 
    }
  }
  while (!TI);
  TI = 0;
  return (SBUF = c);
}

        这个函数的主要作用是通过串口发送一个字符,在代码的最后我们看到有等待TI为1才将字符发送出去,否则一直等待下去,这也就是我们在本节例程中看到的每次在调用printf()和puts()函数之前先要手动将TI置1的原因,这一点至关重要,大家可改变例程亲自做实验,体验去掉TI=1后的现象。
        3)printf()和puts()的区别:从串口调试助手收到的数据我们可以看出,两个函数在参数中都加有”\n",即回车的意思。而puts()函数输出到上位机后还多了一个换行,这是区别之一;区别之二是,printf()可以在后面追加要输出的变量,而puts()只能输出字符串。
        4)在使用stdio.h这个头文件中的函数之前,必须将串口部分初始化完毕,最好将串口设置为方式1,波特率与上位机一致。
        5)在每次调用完printf()和puts()函数后,必须检测是否发送完毕,即检测TI是否为1,当发送完毕后要把TI清0,否则程序会出错,大家可自行验证。
        6)每次调用printf()和puts()函数之前,必须将串口中断先关闭。若不关闭串口中断,每发送一个字节,程序就会申请进入串口中断,从而导致程序出错。
        7)“ad_val=get_ad();“是将A/D采集回来的8位二进制数赋给ad_val,"(float)ad_val"的意思是将字符型变量ad_val的值强制转换成浮点型,然后经过"(float)ad_val*5.0/256.0"运算得出以浮点数表示的A/D实际采集到的电压标准值。注意:在浮点数运算中,原来是整数的常量后面需要加".0变成浮点数,原来是整数的变量需要强制转换成浮点数再进行运算。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STC51-串口通信 的相关文章

  • C51单片机串口工作的四种方式总结

    方式0 同步移位寄存器输入输出方式 1 利用移位寄存器实现串行 并行的转换 功能 2 波特率 fosc 12 3 RXD P3 0 用于串行数据的输入和输出 TXD P3 1 充当输出的移位时钟 4 数据大小 8位 5 方式0发送 串口接口
  • labview串口打开之后visaclose不起作用关闭不了老是占用的问题

    labview串口打开之后visaclose不起作用关闭不了老是占用的问题 最近在做一个数据接收的上位机 用串口发送接收数据 之前有用过labview 整体操作相当简单 于是就打算用labview做一个 但是之前做labview的时候就有一
  • SPI协议代码

    软件模拟SPI程序代码 文章目录 SPI协议简介 SPI接口介绍 SPI数据传输方向 SPI传输模式 通过两个单片机模拟SPI来加深理解 硬件连接方式 SPI模式 程序思路 主机C代码 波形 从机C代码 波形 概述 通过两个MCU STM3
  • Qt 串口发送0x00

    应用场景 大恒光电的平移台 GCD 040101M 先看看要发什么东西 这是串口监听软件截取的结果 绿色的字 串口协议主要包括三个部分 前面是固定的 后面是key 后面是 0x00 最后面是数据 错误版本1 bool MoveStage w
  • STM32使用USART串口调试ULN2003驱动步进电机

    传送门 STM32控制ULN2003驱动步进电机28BYJ 48最基础版 使用串口调试步进电机28BYJ 48获得需要转速 当使用STM32控制ULN2003驱动步进电机28BYJ 48时 步进电机转速变化缓慢 想要得到合适的控制速度 需要
  • 可靠传输的基本概念

    可靠传输的基本概念 使用差错检错技术 接受方的数据链路层就可以检测出真在传输过程中是否出现误码 这取决于数据链路层向上层提供的服务类型 不可靠传输 仅仅丢弃有误码的帧 其他的什么也不做 可靠传输 想方法实现发送端发送什么 接收端就收到什么
  • 蓝桥杯单片机学习过程记录(二十八)第五届国赛串口通信相关代码补充

    蓝桥杯单片机学习过程记录 二十八 第五届国赛串口通信相关代码补充 UART串口通信 第五届国赛uart串口内容相关补充 设置数组存储输入输入字符 并与设定的密码相判断 include
  • LabVIEW串口通信实际操作

    理论基础 LabVIEW串口通信基础知识 读取串口字节 我们新建一个空白 VI 借助串口调试助手和虚拟串口 在 LabVIEW 中编写的一个最简单的例子 写一个基本的读取串口字节的程序 在程序框图中编程如下 注意这里 串口配置放到循环外 不
  • CSerialPort教程4.3.x (1) - CSerialPort项目简介

    CSerialPort教程4 3 x 1 CSerialPort项目简介 前言 CSerialPort项目是一个基于C C 的轻量级开源跨平台串口类库 可以轻松实现跨平台多操作系统的串口读写 同时还支持C Java Python Node
  • STM32双串口

    STM32双串口的使用 最近老是需要stm32通过串口去跟WiFi模块 蓝牙模块 openmv进行数据交互 然后需要用到stm32的串口调试 就把这个程序整理成一个工程 方便调试 实验目的 外设模块 WiFi模块 蓝牙模块 openmv 发
  • C#串口通信三步走

    第一步 实例化串口通讯类 SerialPort sp new SerialPort 第二步 设置串口信息并打开串口 串口设置 public void SetSP string PortName string BaudRate string
  • 串口接收数据分包问题处理(QT上位机/单片机等)

    串口数据出现分包如何正确完整接收 提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 设计思路 二 代码参考 总结 前言 串口通信在QT上位机以及单片机或者安卓串口等使用情况下 经常容易出现一包数据分成几包
  • 硬件设计——外围电路(晶振电路)

    硬件设计之晶振电路 为什么要用晶振 晶振电路由何组成 晶振电路中其电容的作用 在日常的电路设计中 我们经常会用到晶振电路 所以我们就要首先先提一下什么是晶振 这样才能理解晶振电路 为什么要用晶振 晶振的作用是为系统提供基本的时钟信号 通常一
  • 九.ARM裸机学习之串口通信详解1(串口通信接口及原理框图详解)

    一 串口通信的基本概念及原理理解 2017 11 12 22 52 1 同步通信和异步通信 异步通信 指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程 为使双方的收发协调 要求发送和接收设备的时钟尽可能一致 即发送方和接收方没有
  • CSerialPort教程4.3.x (6) - CSerialPort作为第三方库的使用

    CSerialPort教程4 3 x 6 CSerialPort作为第三方库的使用 环境 系统 windows 10 CentOS 7 cmake 3 22 1 前言 CSerialPort项目是一个基于C C 的轻量级开源跨平台串口类库
  • OUT指令时,就进入了I/O端口读写周期

    1 译码电路的输入信号 每当CPU执行IN或者OUT指令时 就进入了I O端口读写周期 此时首先是端口地址有效 然后是I O读写控制信号 IOR和 IOW有效 把对端口地址译码而产生的译码信号同 IOR和 IOW结合起来一同控制对I O端口
  • FPGA笔记8——串口通信(回环实验)

    目录 串口通信原理 串行通信基础知识 处理器与外部设备通信的两种方式 串行通信的通信方式 串行通信的传输方向 常见的串行通信接口 异步串口通信UART基础知识 数据格式 传输速率 接口标准 RS232接口 串口通信实验RS 232 实验任务
  • 串口通信——接收串口数据并处理(C语言)

    本文主要内容包含 1 接收串口数据程序的编程逻辑示意图 2 接收串口数据程序要用到的通用函数模块 可直接引用 无需更改 3 接收串口数据程序的示例 1 接收串口数据程序的编程逻辑示意图 2 与串口有关的函数模块及数组 可直接引用到自己的程序
  • QT串口助手的实现

    serial c include serial h include ui serial h serial serial QWidget parent QWidget parent ui new Ui serial ui gt setupUi
  • HMI智能串口屏——在STM32开发板上的实战应用及其详解

    HMI智能串口屏 在STM32开发板上的实战应用及其详解 一 HMI智能串口屏使用步骤 二 附录 一 HMI智能串口屏使用步骤 安装USART HMI软件 一般买的串口屏里面 商家送的资料里面都有改该软件 打开软件 并点击左上角的 新建 选

随机推荐

  • C++常用标准库

    STL是Standard Template Library的简称 xff0c 中文名标准模板库 从根本上说 xff0c STL是一些 容器 的集合 xff0c 这些 容器 有list vector set map等 xff0c STL也是算
  • 如何轻松写出正确的链表代码

    如何轻松写出正确的链表代码 xff1f 1 理解指针或引用的含义 将某个变量赋值给指针 xff0c 实际上就是将这个变量的地址赋值给指针 xff0c 或者反过来说 xff0c 指针中存储了这个变量的内存地址 xff0c 指向了这个变量 xf
  • JVM之虚拟机栈详细讲解

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域 这些区域有各自的用途 xff0c 以及创建和销毁的时间 xff0c 有的区域随着虚拟机进程的启动而一直存在 xff0c 有些区域则是依赖用户线程的启动和结
  • 【图像处理】特征点算法整理总结

    特征点检测 1 Susan SUSA xff08 Smallest Univalue Segment Assimilating Nucleus xff09 算子是一种高效的边缘和角点检测算子 xff0c 并且具有结构保留的降噪功能 原理 用
  • 图像特征点匹配算法

    sift https blog csdn net weixin 38404120 article details 73740612 https blog csdn net abcjennifer article details 763968
  • 算法目标检测面经

    1 自我介绍 2 简历上的项目 网易雷火 AI研究员 1 ResNet FCN Fasterrcnn 2 膨胀腐蚀的原理 3 均值滤波的原理 时间复杂度 怎么优化 4 第k大的数 topK个数 网易互娱预研 深度学习计算机视觉 1 语义分割
  • 图像配准(Image Registration)简介

    图像配准在目标检测 模型重建 运动估计 特征匹配 xff0c 肿瘤检测 病变定位 血管造影 地质勘探 航空侦察等领域都有广泛的应用 每一种配准方法通常都针对某个具体问题而设计的 xff0c 众多方法中 xff0c 唯一的共性就是每个配准问题
  • SSD算法详解

    转载 xff1a https blog csdn net ytusdc article details 86577939 SSD github https github com weiliu89 caffe tree ssd SSD pap
  • 深度学习-目标检测评估指标P-R曲线、AP、mAP

    基本概念 P R曲线中 xff0c P为图中precision xff0c 即精准度 xff0c R为图中recall xff0c 即召回率 Example 下面通过具体例子说明 首先用训练好的模型得到所有测试样本的confidence s
  • 使用gitlab初次上传代码

    提要 项目开发中需要使用gitlab来管理代码 xff0c 将自己开发的模块上传到gitlab 第一次使用这个代码管理仓库 xff0c 记录一下 方法 1 首先注册gitlab的账号 这个在百度上搜一下gitlab的官网 xff0c 进去后
  • Keil5添加.c文件与.h文件的方法-导入支持库-新大陆物联网竞赛-Lora模块&NBIOT模块例程-添加导入文件

    一 概述 在某些情况下 xff0c 我们使用现用的物联网开发例程 xff0c 例如新大陆物联网的Lora与NBIOT的例程 xff0c 我们对其例程内目前所有的库不满意 xff0c 不足以实现开发需要的功能 xff0c 我们需要在原有工程上
  • 初探DSO-SLAM并运行dso_ros

    最近在做SLAM相关的工作 xff0c 用思岚的A2激光雷达在turtlebot3上测试SLAM建图效果 xff0c 感觉还是不错的 由于项目在方案上还没有确定选择哪种作为SLAM的最终方案 xff0c 在我测试奥比中光ASTRA mini
  • 虚拟机中安装CMake工具

    https www cnblogs com yanqingyang p 12731855 html
  • 寻路系统:动态障碍物

    寻路的相关参数 需要先勾选 游戏场景中所有需要烘焙路径信息的游戏对象状态为 static 然后点开windos菜单下的navigation窗口进行烘培 Navigation Static xff1b 表示该游戏对象是否参与导航网格的烘培 G
  • Ubuntu18.04下使用cmake编译一个OpenCV程序(编写CMakeLists.txt文件)

    导航 1 安装OpenCV1 1首先安装OpenCV 1 2定位OpenCV 2 创建一个项目3 编写一个基础OpenCV程序4 编写CMakeLists txt文件 为了记录以及防止遗忘 xff0c 备份一个大致能满足运行的CMakeLi
  • linux下最全curl命令使用方式学习和拓展

    为什么要使用curl命令 xff1f curl命令可以帮助我们在linux服务内部通讯 xff0c 排查接口是否能够正确调用 xff0c 外网的接口是否有防火墙限制 xff0c 内网的请求可以快速帮我们获取接口参数返回 xff0c 并且调试
  • 【传感器标定】kalibr 标定工具箱问题汇总

    文章目录 写在前面一 运行一段时间报错 96 Spline Coefficient Buffer Exceeded Set larger buffer margins 96 的解决方法1 问题描述2 解决方法参考链接 写在前面 kalibr
  • C++中的Vector存放指针的清空问题

    C 43 43 中的Vector存放指针的清空问题 一 写在前面二 参考做法参考链接 这两个链接写得挺好 xff0c 可以参考下 一 写在前面 C 43 43 很难的一个重要原因就是内存管理的问题 xff0c 因为你既要管理申请内存 xff
  • find_package(xxxx REQUIRED)找不到路径的全平台通用解决办法

    相信刚学cmake c 43 43 的朋友们在编译的时候一定被这个问题折磨许久哈 然后怎么搜怎么添加都有问题 xff0c 仔细研究了我才发现这个地方不同的索引机制 xff0c 但是表面上都是 find package xxxx REQUIR
  • STC51-串口通信

    1 并行与串行基本通信方式 随着单片机系统的广泛应用和计算机网络技术的普及 xff0c 单片机的通信功能愈来愈显得重要 单片机通信是指单片机与计算机或单片机与单片机之间的信息交换 xff0c 通常单片机与计算机之间的通信我们用的较多 通信有