5.串口通信

文章目录

  • 串口的介绍
    • TTL
    • RS-232
    • RS-485
  • 分类方式
    • 串口并口
    • 同步异步
  • 相关寄存器
    • SCON
    • PCON
    • TMOD
    • SBUF
    • IE
  • 中断处理函数
  • 代码编写
    • main.c
    • delay.c
    • delay.h
    • Uart.c
    • Uart.h
    • main.h
    • 回环
  • 继电器
  • ESP8266
    • AT指令
    • 代码编写
      • main.c
      • define.c
      • define.h
      • send.c
      • send.h
      • receive.c
      • delay.c
      • delay.h

串口的介绍

UART(通用异步收发器)是一种双向、串行、异步的通信总线,仅用一根数据接收线(RX)和一根数据发送线(TX)就能实现全双工通信

R:Receiver(接收),T:Transmit(发送)

数据组成

UART 在发送或接收过程中的一帧数据由4部分组成,起始位、数据位、奇偶校验位和停止位

如图所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束,数据位是一帧数据中的有效数据,校验位分为奇校验和偶校验,用于检验数据在传输过程中是否出错。(奇校验时,发送方应使数据位中1的个数与校验位中1的个数之和为奇数;接收方在接收数据时, 对1的个数进行检查,若不为奇数,则说明数据在传输过程中出了差错。同样,偶校验则检查1的个数是否为偶数)

UART通信过程中的数据格式及传输速率是可设置的,为了正确的通信,收发双方应约定并遵循同样的设置。数据位可选择为5、6、7、8位,其中8位数据位是最常用的,在实际应用中一般都选择8位数据位;校验位可选择奇校验、偶校验或者无校验位;停止位可选择1位(默认), 1.5或2位

串口通信的速率用波特率表示,它表示每秒传输二进制数据的位数,单位是bps(位 /秒),常用的波特率有9600、19200、38400、57600以及115200等

如波特率9600则代表每秒传输9600bit数据,以串口发送1个字节10bit算(起始位1bit+数据8bit+停止位1bit+NO校验位),则传输1个字节需要的时间是1*10/9600秒

USART:通用同步/异步串行接收/发送器

TTL

一般单片机产生的都是TTL电平。无论是51、32、还是各种跑Linux的ARM芯片,TTL满足绝大多数调试需求

TTL串口采用的是单一的信号线 (TX线和RX线) 进行数据传输,其中TX线用于单片机发送数据,RX线用于单片机接收数据。数据传输速率通常可以达到几-kbps至上百kbps的速率,传输距离较短,一般不超过数十米

TTL转USB
例图


传输方向

TTL的逻辑电平通常是0V和5V,其中0V表示逻辑“0”,5V表示逻辑“1”

RS-232

RS-232转USB

规定逻辑“1”的电平为-5V~-15 V,逻辑“0”的电平为+5 V~+15 V

由于RS -232采用串行传送方式,并且将TTL电平(某芯片)转换为RS-232C电平,其传送距离一般可达30 m。若采用光电隔离20 mA的电流环进行传送,其传送距离可以达到1000 m

公母头接法

RS-485

传输速度可以达到10Mb/s以上,传输距离可以达到3000米左右

传输方式为:差分方式

分类方式

串口并口

图解

同步异步

异步:通信双方各自约定通信速率

UART:TX、RX

1 Wire

同步:通信双方靠一根时钟线来约定通信速率

IIC:SDA、SCL

SPI:MOSI、MISO、SCK、CS

单工:指消息只能单方向传输的工作方式

半双工:指信息即可从A到B,也可以从B到A,任一时刻只能有一个方向上的传输存在

全双工:指在任意时刻线路上存在A到B和B到A的双向信号传输

相关寄存器

SCON

工作模式:01(8位UART波特率可变)其他不用为0

详细1

REN = 1,接收信息,一开始发送中断标志位、接收中断标志位置0

TB8:发送校验位,RB8:接收校验位,TI:发送中断,RI:接收中断

详细2

则SCON = 0x50

详细3

PCON

PCON解释图

TMOD

模式(M1、M0):这里选10(8位自动重装载定时器),其他在定时器有讲解

TMOD解释图

SBUF

接收和发送的数据都存在SBUF
SBUF图解

IE

中断允许寄存器
允许寄存器分析

中断处理函数

中断源中断处理函数
UARTUART_Routine(void) interrupt 4

代码编写

为何需要使用定时器观看链接讲解(9.34):波特率发生器

main.c

#include <reg52.h>
#include "delay.h"	//声明头文件,可在此文件使用头文件声明的函数、变量等
#include "Uart.h"uchar recv;	//全局变量用于接收数据void main()
{UART_Init();while(1){Delay1000ms();UART_send_str("i am xingzai");	//发送字符}
}
//串口中断处理函数
UART_Routine(void)         interrupt 4
{if(1 == RI){RI = 0;	//接收中断请求标志位软件复位recv = SBUF;	//接收数据赋值给变量switch(recv){case 0x1: LED1 = 0;break;   case 0x2: LED2 = 0;break;case 0x3: LED3 = 0;break;case 0x4: LED4 = 0;break;case 0x5: P1  |= 0x0F;break;	//这里采用或等于,目的不让P1.6蜂鸣器为0,保留高位原数据case 0x6: BEEP = 0;break;case 0x7: BEEP = 1;break;case 0x8: JDQ1 = 0;break;case 0x9: JDQ1 = 1;break;}}
}

delay.c

#include "delay.h"	//声明对应头文件,用于声明里面此文件函数、变量等
#include <intrins.h>
#include "main.h"
//延时函数
void Delay1000ms()		//@11.0592MHz
{uchar data i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}

delay.h

//头文件固定格式,防止头文件重复包含
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay1000ms();#endif

Uart.c

#include <reg52.h>
#include "Uart.h"void UART_Init()
{//配置相关寄存器SCON = 0x50;	//配置串口寄存器PCON=0x00;TMOD |= 0x20;	//配置时间寄存器定时器1//定时器初值TH1 = 0xFD;TL1 = 0xFD;EA = 1;	//打开中断总允许位ES = 1;	//打开串口中断允许位TR1 = 1;	//打开定时器1运行控制位
}//字符发送函数
void UART_send_char(uchar send_char)
{//将字符赋值给数据缓存寄存器SBUF = send_char;while(!TI);	//发送时为0,发送完触发发送中断时为1,为1时则数据发送完TI = 0;	//发送中断请求标志位软件复位
}
//接收传过来的字符串
void UART_send_str(uchar *send_str)
{//判断字符到最后'\0'则停止发送while(*send_str != '\0')UART_send_char(*send_str++);	//将字符逐个传给这个函数发送
}

Uart.h

#ifndef __UART_H__
#define __UART_H__
//因为main.c中已经声明了Uart.h,在Uart.h声明了main.h则main.c中也可以使用mian.h
#include "main.h"		void UART_Init();
void UART_send_char(unsigned char send_char);
void UART_send_str(unsigned char *send_str);#endif

main.h

#ifndef __MAIN_H__
#define __MAIN_H__
#include "reg52.h"typedef unsigned char uchar;	//给unsigned char取别名uchar
//定义对应元器件引脚
sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
sbit BEEP = P1^6;
sbit JDQ1 = P1^7;#endif

回环

#include "reg52.h"
#include <intrins.h>unsigned char recv;
unsigned char send_buf[20];sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
sbit BEEP = P1^6;
sbit JDQ1 = P1^7;void Delay1000ms()    //@11.0592MHz
{unsigned char data i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}void UART_send_byte(unsigned char send_byte)
{SBUF = send_byte;while(!TI);TI=0;
}void UART_send_str(unsigned char *send_str)
{	while(*send_str != '\0'){UART_send_byte(*send_str++);	}	
}void main()
{SCON = 0x50;PCON=0x00;TMOD |= 0x20;TH1 = 0xFD;TL1 = 0xFD;EA = 1;ES = 1;TR1 = 1;while(1){Delay1000ms();
//		UART_send_str("i am wfeng!\r\n");}
}UART_Routine(void)    interrupt 4
{if(1 == RI) //if(RI){RI=0;recv = SBUF;SBUF = recv;while(!TI);TI=0;}
}

继电器

继电器动态原理图

继电器模块的基本工作原理:

电磁线圈: 继电器内部包含一个电磁线圈,通常由绕制在绝缘芯片上的细导线组成。当通过线圈通电时,产生电磁场。

磁性吸引: 电磁场会使继电器中的铁芯(或磁性材料)受到磁性吸引,导致铁芯在电磁力的作用下移动。

触点操作: 铁芯的移动会导致机械部分的运动,最终使触点(开关)发生动作。继电器通常有常开(Normally Open,NO)和常闭(Normally Closed,NC)两组触点。

常开触点: 在继电器未通电时处于闭合状态,当电磁线圈通电时,触点打开。

常闭触点: 在继电器未通电时处于打开状态,当电磁线圈通电时,触点闭合。

电气隔离: 继电器的主要作用之一是提供电气隔离。通过电磁原理,可以在控制信号与被控制电路之间提供隔离,从而使得不同电路之间的电流不会相互影响。继电器模块常用于控制高电流或高电压的电路。

ESP8266

AP模式:无线接入点,它是一个无线网络的中心节点,可以看成是一个服务器。它作为一个网络的中心节点,提供无线接入服务,其他的无线设备允许接入该节点,所有接入该节点设备的无线信号数据都要通过它才能进行交换和互相访问。一般的无线路由器、网关、热点就是工作在AP模式下,AP节点和AP节点之间允许相互连接。

STA模式:无线网络中的一个终端站点设备,可以看成是一个客户端,一般来说,处在STA模式下的设备本身不接受无线的接入,该设备连接到AP节点进行网络访问,STA模式下的设备之间的通信可以通过AP进行转发实现

AT指令

可在官网寻找对应的指令集:安信可科技

配置 WiFi 模式:AT+CWMODE=3	//模式3:STA+AP
连接路由器:AT+CWJAP="wfeng","wf05430543"
查询 ESP8266的IP 地址: AT+CIFSR
//PC端使用网络调试工具,建⽴一个 TCP 服务器器
ESP8266 作为Client 连接到服务器:AT+CIPSTART="TCP","192.168.31.118",8090
发送数据:AT+CIPSEND=4

代码编写

电脑当服务端,单片机当客户端,电脑发指令控制单片机(接收),单片机发送字符给电脑

main.c

#include "define.h"
#include "send.h"
#include "delay.h"void main()
{define_bl();do{send_str("AT+CWMODE=3\r\n");	//发送AT指令配置ESP8266模块,选择模式3Delay1000ms();}while(Esp_Ok_flag);Esp_Ok_flag = 1;do{send_str("AT+CWJAP=\"qiji\",\"12345678\"\r\n");	//连接WiFiDelay1000ms();}while(Esp_Ok_flag);Esp_Ok_flag = 1;do{send_str("AT+CIPSTART=\"TCP\",\"192.168.43.10\",8085\r\n");	//连接服务器Delay1000ms();}while(Esp_Ok_flag);do{send_str("AT+CIPSEND=4\r\n");	//发送4个字节数据Delay1000ms();}while(Esp_Ok_flag);send_str("xinz\r\n");	//发送的数据Esp_Ok_flag = 1;while(1){Delay1000ms();}
}

define.c

#include <define.h>
int Esp_Ok_flag = 1;
void define_bl()
{SCON = 0x50;PCON = 0x00;TMOD = 0x20;TH1 = 0xFD;TL1 = 0xFD;TR1 = 1;ES = 1;EA = 1;
}

define.h

#ifndef __DELAY_H__
#define __DELAY_H__#include "reg52.h"void define_bl();typedef unsigned char uchar;	//取别名
extern int Esp_Ok_flag;	//定义一个全局变量方便不同.c文件使用
//定义对应元器件引脚
sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
sbit BEEP = P1^6;
sbit JDQ1 = P1^7;#endif

send.c

#include <send.h>
//接收需要发送的字符
void send_str(uchar *send_s)
{while(*send_s != '\0')	//当字符串!='\0'时把字符一个个传给send_char函数发送{send_char(*send_s++);	//将每个字符逐一发送}
}void send_char(uchar send_c)
{SBUF = send_c;	//将单个字符赋值给SBUF则发送while(!TI);	//当TI为0,则发送未完成,当发送完成为1,取反为0跳出循环TI = 0;	//复位,发送请求中断标志位为0
}

send.h

#ifndef __SEND_H__
#define __SEND_H__#include "define.h"
//声明两个发送函数
void send_str(uchar *send_s);
void send_char(uchar send_c);#endif

receive.c

#include <define.h>
uchar Recv_Buf[20];
char recv;
//串口中断函数
UART_Routine(void) interrupt 4
{static int i = 0;  //static:全局使用不重新char Recv;if(1 == RI) //if(RI){RI=0;Recv=SBUF;if(Recv == 'O'|| Recv == '+'){i = 0;Recv_Buf[i] = Recv;Recv_Buf[i+1] = Recv;			}else{i++;Recv_Buf[i] = Recv;		}if(Recv_Buf[0] == 'O'&&Recv_Buf[1] == 'K')	//收到回复OK则说明指令执行成功{Esp_Ok_flag = 0;	//让标志为0跳出循环,执行下一个指令i = 0;	//重置数组指向位数}//接收到服务器,接收到的指令会以 +IPD 开头,以及第七个是接收的指令开始,判断接收到哪个指令执行下方的操作if(Recv_Buf[0] == '+'&&Recv_Buf[1] == 'I'&&Recv_Buf[2] == 'P'&&Recv_Buf[3] == 'D'){if(Recv_Buf[7] == 'L'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'D'&&Recv_Buf[10] == '1'&&Recv_Buf[11] == '1')LED1 = 1;if(Recv_Buf[7] == 'L'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'D'&&Recv_Buf[10] == '1'&&Recv_Buf[11] == '0')LED1 = 0;			if(Recv_Buf[7] == 'L'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'D'&&Recv_Buf[10] == '2'&&Recv_Buf[11] == '1')LED2 = 1;if(Recv_Buf[7] == 'L'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'D'&&Recv_Buf[10] == '2'&&Recv_Buf[11] == '0')LED2 = 0;				if(Recv_Buf[7] == 'L'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'D'&&Recv_Buf[10] == '3'&&Recv_Buf[11] == '1')LED3 = 1;if(Recv_Buf[7] == 'L'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'D'&&Recv_Buf[10] == '3'&&Recv_Buf[11] == '0')LED3 = 0;				if(Recv_Buf[7] == 'L'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'D'&&Recv_Buf[10] == '4'&&Recv_Buf[11] == '1')LED4 = 1;if(Recv_Buf[7] == 'L'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'D'&&Recv_Buf[10] == '4'&&Recv_Buf[11] == '0')LED4 = 0;				if(Recv_Buf[7] == 'B'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'E'&&Recv_Buf[10] == 'P'&&Recv_Buf[11] == '1')BEEP = 1;if(Recv_Buf[7] == 'B'&&Recv_Buf[8] == 'E'&&Recv_Buf[9] == 'E'&&Recv_Buf[10] == 'P'&&Recv_Buf[11] == '0')BEEP = 0;			if(Recv_Buf[7] == 'J'&&Recv_Buf[8] == 'D'&&Recv_Buf[9] == 'Q'&&Recv_Buf[10] == '1'&&Recv_Buf[11] == '1')JDQ1 = 1;if(Recv_Buf[7] == 'J'&&Recv_Buf[8] == 'D'&&Recv_Buf[9] == 'Q'&&Recv_Buf[10] == '1'&&Recv_Buf[11] == '0')JDQ1 = 0;								}	if(i>18)i=18;}
}

delay.c

#include <delay.h>
#include <intrins.h>
//延时函数
void Delay1000ms()    //@11.0592MHz
{unsigned char data i, j, k;_nop_();i = 8;j = 1;k = 243;do{do{while (--k);} while (--j);} while (--i);
}

delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
//声明延时函数
void Delay1000ms();#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3245346.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Spark的动态资源分配算法

文章目录 前言基于任务需求进行资源请求的整体过程资源申请的生成过程详解资源申请的生成过程的简单例子资源调度算法的代码解析 申请资源以后的处理&#xff1a;Executor的启动或者结束对于新启动的Container的处理对于结束的Container的处理 基于资源分配结果进行任务调度Pen…

R语言实现SVM算法——分类与回归

### 11.6 基于支持向量机进行类别预测 ### # 构建数据子集 X <- iris[iris$Species! virginica,2:3] # 自变量&#xff1a;Sepal.Width, Petal.Length y <- iris[iris$Species ! virginica,Species] # 因变量 plot(X,col y,pch as.numeric(y)15,cex 1.5) # 绘制散点图…

【Java--数据结构】二叉树oj题(上)

前言 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 判断是否是相同的树 oj链接 要判断树是否一样&#xff0c;要满足3个条件 根的 结构 和 值 一样左子树的结构和值一样右子树的结构和值一样 所以就可以总结以下思路…

十五、C++11常用新特性—Lambda表达式

1.基本 这个好像是很好用的&#xff0c;其有以下有点&#xff1a; 声明式的编程风格&#xff1a;直接匿名定义目标函数或函数对象&#xff0c;不需要额外写一个命名函数或函数对象。简洁&#xff1a;避免了代码膨胀和功能分散&#xff0c;让开发更加高效。在需要的时间和地点…

Rust编程-crates.io

发布配置和开发配置&#xff1a; [profile.dev]: > cargo build opt-level0 [profile.release]: > cargo build --release opt-level3 发布到crates.io 文档注释&#xff1a; 三斜线&#xff08;///&#xff09;&#xff0c;使用markdown语法来格式化内容 可以为函数…

MySQL-事务、日志

事务 特性 原子性 是指事务开始后&#xff0c;必须成功执行完所有的操作才会结束&#xff0c;否则会回滚到事务刚开始前。 拿转账来说&#xff0c;一个成功的 A向B转账100元的过程 会涉及如下过程&#xff1a; A&#xff1a;从数据库读取A的余额&#xff1b;A的余额-100&am…

防火墙双机热备和带宽管理练习

目录 实验拓扑 实验需求 实验思路 实验步骤 需求12 需求13 需求14 需求15 需求16 实验拓扑 实验需求 12&#xff0c;对现有网络进行改造升级&#xff0c;将当个防火墙组网改成双机热备的组网形式&#xff0c;做负载分担模式&#xff0c;游客区和DMZ区走FW3&#xff0c…

网络原理(上)

前言&#x1f440;~ 上一章我们介绍了网络的一些基础知识&#xff0c;今天来讲解一下网络原理相关的知识点&#xff0c;分三篇进行阐述内容有点多​​​​​​​ 再谈协议分层 应用层 传输层&#xff08;重点&#xff09; UDP协议 TCP协议 TCP如何完成可靠传输&#xff…

Windows系统中MySQL的安装和卸载(详细包含msi和zip下载方式,以及完全卸载方法,易出现问题及解决方案等)

MySQL的安装: 第一种:msi安装(交简单,但是不能自定义安装路径) 下载地址:https://dev.mysql.com/downloads/installer/ 选择历史版本 选择安装版本,这里我选择的是8.0.37的版本,然后点击Download下载离线安装包 如下图即为下载好的版本,双击打开安装 出现如下情况,…

设计模式-领域逻辑模式-事务脚本(Transaction Script)

事务脚本的特点 多数应用可看成由多个事务组成事务脚本将多个业务逻辑组织成单个过程事务间相互修改各自产生的数据 事务脚本的运行机制 使用事务脚本时&#xff0c;领域逻辑主要通过系统所执行的事务来组织。例如&#xff1a;预定酒店过程。 事务脚本的组织 将整个事务脚本放…

Qt 多语言

记录Qt多语言的实现过程 目录 1.项目配置文件.pro配置 2.程序中的字符串用tr()封装 3.生成翻译文件 4.使用Qt语言家修改翻译文件 4.1使用Qt语言家打开 4.2 .更改文件配置 5. 生成qm文件 6.代码执行切换语言 6.1入口处 6.2 事件执行 0.效果 1.项目配置文件.pro配置 T…

Redis-基础概念

目录 概念 Redis是什么 Redis 和 MySQL 的区别&#xff1f; Redis单线程有什么极端场景的瓶颈 Redis为什么快? 为什么Redis是单线程? Redis是单线程还是多线程 Redis为什么选择单线程做核心处理 Redis6.0之后引入了多线程&#xff0c;你知道为什么吗? 瓶颈是内存和I…

jmeter之变量随机参数化以及解决多线程不会随机变化

参考链接&#xff1a; https://www.cnblogs.com/Testing1105/p/12743475.html jmeter 使用random函数多线程运行时数据不会随机变化&#xff1f;_jmeter 线程组循环执行时 变量不变-CSDN博客 1、如下图所示&#xff0c;需要对请求参数 autor 和phone进行随机参数化 2、目前有…

基于用户非兴趣/非偏好/非习惯的推荐

基于用户非兴趣、非偏好、非习惯的推荐是一种个性化推荐技术&#xff0c;旨在为用户提供与其日常行为和兴趣模式不同的推荐内容。这种推荐方法的目的是打破用户的信息过滤和习惯&#xff0c;发现新的、潜在的兴趣点&#xff0c;从而提供更广泛和多样化的推荐结果。 通过收集和分…

Qt6 OpenCV4视频监控系统项目源码解析——附源码及编译运行步骤

很多刚毕业&#xff0c;或者想着转行到C Qt方向的小伙伴&#xff0c;平时可能拿不出比较像样的项目。这里你可要好好收藏啦。自己拿回去好好改改&#xff0c;就可以成为自己的项目经历了。祝各位找工作顺利呀。 好了。废话不多说。 这个项目架构采用的是MVC架构&#xff0c;结…

Qt 使用发布工具 windeployqt 来release

本文记录使用qt进行release文件 目录 1. windeployqt 常用选项 2. 创建release文件夹&#xff0c;并将exe文件拷贝进来 3.使用命令 1. windeployqt 常用选项 选项 意义 --release --no-quick-import --translations <languages> --no-translations --no-virtualkeyb…

PTA - 嵌套列表求和

使用递归函数对嵌套列表求和 函数接口定义&#xff1a; def sumtree(L) L是输入的嵌套列表。 裁判测试程序样例&#xff1a; /* 请在这里填写答案 */L eval(input()) print(sumtree(L)) # 调用函数 输入样例&#xff1a; 在这里给出一组输入。例如&#xff1a; [1,[2…

2024华为数通HCIP-datacom最新题库(变题更新⑥)

请注意&#xff0c;华为HCIP-Datacom考试831已变题 请注意&#xff0c;华为HCIP-Datacom考试831已变题 请注意&#xff0c;华为HCIP-Datacom考试831已变题 近期打算考HCIP的朋友注意了&#xff0c;如果你准备去考试&#xff0c;还是用的之前的题库&#xff0c;切记暂缓。 1、…

六边形动态特效404单页HTML源码

源码介绍 动态悬浮的六边形,旁边404文字以及跳转按钮,整体看着像科技二次元画风,页面简约美观,可以做网站错误页或者丢失页面,将下面的代码放到空白的HTML里面,然后上传到服务器里面,设置好重定向即可 效果预览 完整源码 <!DOCTYPE html> <html><head…

图——图的应用02最短路径(Dijkstra算法与Floyd算法详解),拓扑排序及关键路径

前面介绍了图的应用——01最小生成树章节&#xff0c;大家可以通过下面的链接学习&#xff1a; 图——图的应用01最小生成树&#xff08;Prim算法与Kruskal算法详解&#xff09; 今天就讲一下图的其他应用——最短路径&#xff0c;拓扑排序及关键路径。 目录 一&#xff0c…