搞懂收发模式(Transmit、Receive、IT、DMA、ToIdle、Abort、Callback)

news2024/11/24 13:56:56

搞懂收发模式(Transmit、Receive、IT、DMA、ToIdle、Abort)

文章目录

  • `搞懂收发模式(Transmit、Receive、IT、DMA、ToIdle、Abort)`
    • `1、阻塞模式(阻塞轮询)`
    • `2、非阻塞模式( IT )`
    • `3、直接内存访问模式( DMA )`
    • `4、扩展接收模式( ToIdle )`
    • `5、中止收发( Abort )`
    • `6、中断服务函数的回调函数(Callback)`
    • `PS:阻塞、非阻塞、轮询和中断的关系`
      • `阻塞(Blocking)`
      • `非阻塞(Non-blocking)`
      • `轮询(Polling)`
        • `轮询的定义`
        • `阻塞轮询`
        • `非阻塞轮询`
      • `中断(Interrupt)`
      • `四者关系`
  • `如果对你有帮助,就点赞收藏把!(。・ω・。)ノ♡`


截取了一段<<stm32f1xx_hal_uart.h>>里面的代码

/** @addtogroup UART_Exported_Functions_Group2 IO operation functions
  * @{
  */

/* IO operation functions *******************************************************/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart);

HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, 
                                           uint16_t *RxLen, uint32_t Timeout);
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

HAL_UART_RxEventTypeTypeDef HAL_UARTEx_GetRxEventType(UART_HandleTypeDef *huart);

/* Transfer Abort functions */
HAL_StatusTypeDef HAL_UART_Abort(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortTransmit(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_Abort_IT(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortTransmit_IT(UART_HandleTypeDef *huart);
HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart);

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart);

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);

大致可以分成几类:
1、阻塞模式(普通模式)
2、非阻塞模式( IT )
3、直接内存访问模式( DMA )
4、扩展接收模式( ToIdle )
5、中止收发( Abort )
6、中断服务函数的回调函数(Callback)
接下来一一讲解,这里以串口为例,其他外设触类旁通


1、阻塞模式(阻塞轮询)

在这里插入图片描述
阻塞式函数
用于进行UART通信的,会等待操作完成,直到数据传输或接收指定数量的字节。

  • HAL_UART_Transmit:使用阻塞轮询方式通过UART发送数据,函数会一直等待直到所有数据发送完成或超时。
  • HAL_UART_Receive:使用阻塞轮询方式通过UART接收数据,函数会一直等待直到所有数据接收完成或超时。

缺点:阻塞模式可能会导致CPU资源的浪费
优点:就是避免数据大量涌入,导致服务器崩溃

在这里插入图片描述


2、非阻塞模式( IT )

在这里插入图片描述

基于中断的非阻塞式函数
启动传输或接收过程后立即返回,当操作完成时会触发中断,并在相应的回调函数中处理完成事件。

  • HAL_UART_Transmit_IT:通过中断非阻塞方式发送数据,不阻塞调用线程,当数据发送完成后,会触发相应的中断服务例程。
  • HAL_UART_Receive_IT:通过中断非阻塞方式接收数据,不阻塞调用线程,当数据接收完成后,会触发相应的中断服务例程。

中断非阻塞方式,可以在等待I/O操作完成的同时,执行其他任务,提高了效率


3、直接内存访问模式( DMA )


通过/控制DMA(直接内存访问)进行UART传输和接收的函数

  • HAL_UART_Transmit_DMA:启动一个DMA传输,用于通过UART发送数据。
  • HAL_UART_Receive_DMA:启动一个DMA传输,用于通过UART接收数据。
  • HAL_UART_DMAPause:暂停当前正在进行的DMA传输。
  • HAL_UART_DMAResume:恢复之前暂停的DMA传输。
  • HAL_UART_DMAStop:停止当前正在进行的DMA传输。

这些函数允许用户更灵活地控制UART的DMA传输过程
可以在需要时 暂停恢复停止 传输,而 不需要等待传输自然完成
利用DMA控制器在后台处理数据传输,不需要CPU的持续干预,可以在传输或接收过程中执行其他任务。


4、扩展接收模式( ToIdle )

在这里插入图片描述

UART扩展功能,提供了额外的接收模式
用于在 接收到指定数量的数据发生IDLE事件 时停止接收 。

  • HAL_UARTEx_ReceiveToIdle:阻塞接收模式,当接收到指定数量的数据或发生IDLE事件时,停止接收。
  • HAL_UARTEx_ReceiveToIdle_DMA:DMA接收模式,当接收到指定数量的数据或发生IDLE事件时,DMA传输结束。
  • HAL_UARTEx_ReceiveToIdle_IT:中断接收模式,当接收到指定数量的数据或发生IDLE事件时,触发中断并调用中断服务函数

这些函数适用于需要在特定条件下停止接收数据的情况
例如,当UART线路空闲时或者接收到一定数量的数据后,可以停止接收,
这在处理特定长度的数据包或者在数据接收完成后立即停止接收时非常有用。

PS:IDLE事件
通常指接收缓冲区中的数据已接收完毕,没有数据可以接收,此时UART线路变为空闲


5、中止收发( Abort )

用于中止当前的UART传输或接收操作
使用这些函数可以确保UART操作能够被及时终止,释放相关资源,并且可以防止数据丢失或乱序。

  • HAL_UART_Abort:中止UART的所有传输和接收操作。
  • HAL_UART_AbortTransmit:中止UART的发送操作。
  • HAL_UART_AbortReceive:中止UART的接收操作。

用于中止UART的传输或接收操作。
是阻塞函数,程序会被停止,直到传输或接收操作完全中止。
在调用函数时,UART的中断会被禁用,并且UART的状态会被重置。

  • HAL_UART_Abort_IT:通过中断方式中止UART的传输和接收操作。
  • HAL_UART_AbortTransmit_IT:通过中断方式中止UART的发送操作。
  • HAL_UART_AbortReceive_IT:通过中断方式中止UART的接收操作。

同样用于中止UART的传输或接收操作。
是非阻塞函数,它会立即返回,而实际的终止操作会在UART中断服务例程(ISR)中异步执行。
调用此函数后,UART的中断不会被立即禁用,而是在中断中处理中止操作。

应用场景:
1.当需要提前结束一个正在执行的传输或接收操作时。
2.当检测到错误或异常情况,需要立即停止UART通信时。
3.在传输或接收过程中,如果系统需要资源回收或者有更高优先级的任务需要处理时。


6、中断服务函数的回调函数(Callback)

在这里插入图片描述

HAL_UART_IRQHandler 是UART中断服务例程,用于处理UART中断事件。

这些是UART操作完成时的回调函数,用于在操作完成后执行用户定义的代码。
这些回调函数都是用__weak修饰(弱定义),程序员可以重写这些函数
HAL_UART_IRQHandler 会自动调用这些函数,并清除部分标志位(建议主动清标志位)

HAL_UART_TxCpltCallback				//发送完成回调函数。当UART发送完成时,会被调用。
HAL_UART_TxHalfCpltCallback			//发送一半回调函数。当UART发送一半数据时,会被调用。
HAL_UART_RxCpltCallback				//接收完成回调函数。当UART接收完成时,会被调用。
HAL_UART_RxHalfCpltCallback			//接收一半回调函数。当UART接收一半数据时,会被调用。
HAL_UART_ErrorCallback				//出现错误回调函数。当UART操作中发生错误时,会被调用。
HAL_UART_AbortCpltCallback			//中止完成回调函数。当UART操作被中止时,会被调用。
HAL_UART_AbortTransmitCpltCallback	//发送中止回调函数。当中止发送时,会被调用。
HAL_UART_AbortReceiveCpltCallback	//接收中止回调函数。当中止接收时,会被调用。
HAL_UARTEx_RxEventCallback			//扩展接收事件回调函数。当特定的接收事件发生时,此函数会被调用
									//例如接收到指定数量的数据或UART线路变为空闲。

PS:阻塞、非阻塞、轮询和中断的关系


阻塞(Blocking)

在这里插入图片描述

阻塞:程序在等待某个操作完成时暂时停止执行,直到该操作完成或发生超时。

在阻塞操作期间,进程的执行流程被中断,直到等待的事件完成或发生超时
阻塞可能导致CPU资源浪费,进程在等待期间不做任何有用的工作
阻塞操作完成后,进程才会从挂起状态恢复,继续执行后续指令。

非阻塞(Non-blocking)

在这里插入图片描述

非阻塞:程序在等待某任务完成期间,能继续执行其他任务

在非阻塞操作中,程序不会停止执行,而是会立即返回,可能返回操作的结果或状态。
非阻塞操作通常需要通过回调函数、状态标志或事件来通知操作完成。

如果数据还没有准备好,它会立即返回一个错误或者特定的值,而不是等待。
进程可以利用这个返回值来决定是否需要重试操作,或者执行其他任务


轮询(Polling)

在这里插入图片描述

轮询是一种 检查条件是否满足 的技术
阻塞轮询: 会导致进程在等待事件时挂起,不执行其他任务
非阻塞轮询: 允许进程在等待事件时继续执行其他任务,提高了CPU的利用率

轮询是否阻塞通常可以 通过代码设置 ,轮询可以用于实现 阻塞非阻塞 I/O操作
在许多操作系统中和编程环境中,可以通过特定的API或设置来控制I/O操作是阻塞还是非阻塞。

轮询的定义

轮询是一种编程技术,它涉及程序定期检查某个条件或资源的状态,以确定是否可以进行下一步操作
在轮询过程中,程序会周期性地查询一个或多个状态标志或硬件寄存器,直到期望的事件发生

阻塞轮询
  • 是指程序在检查条件时,如果条件不满足,程序会持续检查,直到条件满足 / 超时为止
  • 在这个过程中,程序的执行被暂停,在条件成立之前 / 超时,不执行其他任务,程序是阻塞的
  • 阻塞轮询会占用CPU资源,涉及到重复的检查操作,在条件长时间不改变时可能导致效率低下
非阻塞轮询
  • 是指程序在检查条件时,如果条件不满足,程序会立即返回并执行其他任务,稍后再回来检查条件
  • 在这个过程中,程序不会因为条件未满足而被暂停,会继续执行其他操作,并在适当的时机再次检查条件
  • 非阻塞轮询不会长时间占用CPU资源,条件未满足时程序执行其他任务,提高了CPU的利用率和程序的效率

中断(Interrupt)

中断机制是一种硬件或软件机制
在特定事件发生时,能够暂停当前程序的执行,并转而跳转到一个预定义的处理程序(中断服务例程ISR)。
中断通常用于处理异步事件,如硬件信号或计时器溢出。
通过中断,可以实现非阻塞操作,使得CPU在处理I/O操作等事件的同时,主程序能够继续执行其他任务。
虽然中断是实现非阻塞I/O的常见方式,但非阻塞操作也可以通过轮询等其他方法来完成。


四者关系

  • 阻塞与轮询
    轮询通常是阻塞的,但阻塞操作不一定是通过轮询实现的
    阻塞通常是指程序在等待I/O操作完成时挂起,而轮询是一种不断检查条件的方法。
    轮询可以是阻塞的,如果它在检查条件时暂停其他操作。

  • 非阻塞与轮询
    非阻塞轮询是一种特殊的轮询方式 ,它允许程序在条件不满足时继续执行其他任务,而不是等待。
    轮询是一种实现非阻塞I/O的方式,通过不断地检查某个条件是否满足来实现对I/O操作的监控。
    非阻塞I/O通常与轮询一起使用,进程会不断地尝试I/O操作,直到数据准备好。

  • 中断与轮询
    轮询和中断是两种不同的处理异步事件的方法。
    轮询需要程序主动检查
    中断则是事件驱动的,由硬件或软件条件触发。

  • 中断与非阻塞
    非阻塞操作可以允许程序在等待某个条件时继续执行,而中断是处理异步事件的一种机制
    中断是一种实现非阻塞I/O的机制,因为它允许CPU在事件发生时立即响应,而无需程序主动检查。
    非阻塞操作不一定是通过中断实现的,但中断是实现非阻塞操作的一种常见方式。


虽然本文只是讲解串口的这些函数
但是其他外设的函数也是一样的,取名都异曲同工
要学会触类旁通,比如

_IT结尾:非阻塞
_DMA结尾:直接内存
_ToIdle结尾:拓展函数
_Abort结尾:中止函数
_Callback结尾:回调函数

当然,还有一些拓展知识,比如IDLE,以及阻塞,非阻塞,轮询和中断的关系
这么多干货,你是怎么忍住不 点赞 + 收藏 的啊,赶紧动起手 (。・ω・。)ノ♡


┈┈┈┈▕▔╲┈┈┈┈┈┈┈ ┈┈┈┈▕▔╲┈┈┈┈┈┈┈ ┈┈┈┈▕▔╲┈┈┈┈┈┈┈┈
┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈┈┈┈┈▏▕┈┈┈┈┈┈┈ ┈
┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈┈┈┈┈▏ ▕▂▂▂▂▂┈┈┈
▂▂▂▂╱┈┈▕▂▂▂▂▏┈ ▂▂▂▂╱┈┈▕▂▂▂▂▏┈ ▂▂▂▂╱┈┈▕▂▂▂▂▏┈┈
▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈
▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈ ▉▉▉┈┈┈┈▕▂▂▂▂▏ ┈
▔▔▔▔╲▂▂▕▂▂▂▂▏┈ ▔▔▔▔╲▂▂▕▂▂▂▂▏┈ ▔▔▔▔╲▂▂▕▂▂▂▂▏┈┈

如果对你有帮助,就点赞收藏把!(。・ω・。)ノ♡

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

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

相关文章

D盘根目录莫名出现 *.scratch 文件夹

不知道从什么时候开始&#xff0c;突然发现D盘根目录出现奇怪的空文件夹&#xff08;图一&#xff09;&#xff0c;一开始因为需求紧张没时间管&#xff0c;但是没几天就发现这个空文件夹越来越多&#xff0c;多到上百个了。 要是几个那还能忍忍&#xff0c;这种程度已经严重影…

IDEA优化配置,提高启动和运行速度

一、修改配置参数 IDEA默认启动配置主要考虑低配置用户&#xff0c;参数不高&#xff0c;导致 启动慢&#xff0c;然后运行也不流畅&#xff0c;这里我们需要优化下启动和运行配置&#xff1b; 找到idea安装的bin目录&#xff1b; 你的按照目录\IntelliJ IDEA 2018.2.2\bin …

客户现场电脑卡死

最近遇到一个很奇怪的现象,客户现场机台运行过程中,出现不规律的卡顿或假死蓝屏情况,软件分析显得异常重要. 首先我们从软件的运行状态,内存,cpu利用率等性能方面排查,通过观察,我们发现内存没有暴涨的情况,cpu利用率也不是很高,表现的现象就是不定时的出现软件假死,卡顿现象.…

SQL插入、更新和删除数据

SQL插入、更新和删除数据 一、直接向表插入数据 1.1、插入完整的行 这里所说的完整行指的是包含表内所有字段的数据行&#xff1b;假设表中有n个字段&#xff0c;则插入完整行的语法&#xff1a; INSERT INTO 表名或视图名 VALUES(字段1的值,字段2的值,字段3的值,...,字段n的…

JSONP跨域

1 概述 定义 json存在的意义&#xff1a; 不同类型的语言&#xff0c;都能识别json JSONP(JSON with Padding)是JSON的一种“使用模式”&#xff0c;可用于解决主流浏览器的跨域数据访问的问题。由于同源策略&#xff0c;一般来说位于 server1.example.com 的网页无法与不是 s…

MCU单片机GPIO初始化该按什么顺序配置?为什么初始化时有电平跳变?

GPIO初始化时有时钟配置、模式配置、输出配置、复用配置&#xff0c;那么在编写初始化代码时&#xff0c;到底该按什么顺序执行呢&#xff1f;如果顺序不当那初始化过程可能会出现短暂的电平跳变。 第一步&#xff0c;初始化MCU外设时&#xff0c;一般都需要先打开对应寄存器的…

Multi-Head Mixture-of-Experts笔记

这篇文章&#xff08;还是校友&#xff09;&#xff0c;也是和dot product本身没什么关系。讲一讲核心思想 文章在背景中介绍了Sparse Mixture of Experts&#xff0c;因为MH-MoE也是在S-MoE基础上做的&#xff0c;个人感觉其实变动并不大&#xff0c;但我觉得写的很清楚&…

优化 Spring Boot 项目启动速度:高效管理大量 Bean 注入

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119@qq.com] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? 专栏导…

卷积神经网络 - 卷积运算篇

序言 在探索深度学习尤其是计算机视觉领域的奥秘时&#xff0c;卷积神经网络&#xff08; Convolutional Neural Networks, CNNs \text{Convolutional Neural Networks, CNNs} Convolutional Neural Networks, CNNs&#xff09;无疑占据了核心地位。而卷积运算&#xff0c;作为…

书生大模型基础岛-第二关:8G 显存玩转书生大模型 Demo

1.来源 https://github.com/InternLM/Tutorial/blob/camp3/docs/L1/Demo/task.md 2.过程 在 /root/share/pre_envs 中配置好了预置环境 icamp3_demo conda activate /root/share/pre_envs/icamp3_demo创建一个目录&#xff0c;用于存放我们的代码。并创建一个 cli_demo.py …

【JVM基础09】——垃圾回收-对象什么时候可以被垃圾回收器回收?

目录 1- 引言&#xff1a;垃圾回收1-1 什么是垃圾回收&#xff1f;(What)1-2 为什么要进行垃圾回收&#xff1f;(Why) 2- ⭐核心&#xff1a;对象什么时候可以被垃圾回收器回收&#xff1f;(How)2-1 对象什么时候可以被回收&#xff1f;2-2 引用计数法引用计数法存在的问题&…

误删文件大救星!4款必备数据恢复软件,轻松恢复各类文档照片

在数字化的时代信息就是王道&#xff0c;很多时候丢失了信息就以为着丢失了资源。这时候就需要失易得数据恢复这样的数据恢复工具来帮我们守护信息的安全。 1.福昕数据恢复 https://www.pdf365.cn/foxit-restore/链接直达&#xff1a;https://www.pdf365.cn/foxit-restore/ …

设计模式-创建型模式-单例设计模式

创建型模式提供创建对象的机制&#xff0c;能够提升已有代码的灵活性和复用性&#xff1b; 常用的有&#xff1a;单例模式、工厂模式、建造设模式&#xff1b;不常用的&#xff1a;原型模式&#xff1b; 1.概述 单例模式是最简单的模式之一&#xff0c;其保证了某个类在运行期…

Ubuntu22 下 Docker 安装,VS Code Docker配置

1. Docker 安装 1. 卸载旧版本的 Docker&#xff08;如果有&#xff09;&#xff1a; sudo apt-get remove docker docker-engine docker.io containerd runc 2. 更新软件包&#xff1a; sudo apt-get update sudo apt-get upgrade 3. 安装 Docker 依赖&#xff1a; sudo apt-…

苹果手机通讯录恢复教程?3招速成指南

随着科技的不断进步&#xff0c;手机丢失、系统崩溃等意外情况也时有发生&#xff0c;一旦这些情况发生&#xff0c;我们宝贵的通讯录资料很可能会付诸东流。对此&#xff0c;本文为广大苹果手机用户提供一份简洁明了的通讯录恢复教程&#xff0c;让你轻松掌握苹果手机通讯录恢…

接了一个2000块的小活,大家进来看看值不值,附源码

如题&#xff0c;上周的一天&#xff0c;朋友圈的一个旧友找到了我&#xff0c;说让我帮他开发一个小工具&#xff0c;虽然活不大&#xff0c;但没个几年的全栈经验还不一定能接下来&#xff0c;因为麻雀虽小&#xff0c;涉及的内容可不少&#xff1a; 需求分析 原型设计 详细…

Halcon 边缘提取(像素)

传统提取边缘的方法即通过图像中的明暗进行过滤&#xff0c;其左右就是根据明暗区域找到像素边界。从数学角度&#xff0c;滤波器决定图像剃度&#xff0c;该图像剃度通常作为边缘幅度和边缘方法返回。通过选取所有边缘幅值高的像素点&#xff0c;可以提取区域间的轮廓。另一个…

G1简介、各种GC总结

概述 G1首次出现是在JDK 6u14版本里作为体验版&#xff0c;JDK 7u4版本被正式推出&#xff0c;JDK 9中被设置为默认垃圾收集器&#xff08;参考JEP 248&#xff09;。 G1全称是Garbage First&#xff0c;目标&#xff1a;延迟可控的情况下&#xff0c;尽可能高的吞吐量。一款…

怎么使用Element ui来做一个前端登录页面

找到Layout 布局 他通过基础的 24 分栏&#xff0c;迅速简便地创建布局。 找一个对齐方式 这个就不错,找到对应的代码 这个 复制进入idea 引入我们的图片和文字 我这里图片有点问题 然后我再添加一条分割线 加入表单校验 把里面的代码同上加入idea 结果 对表单内容进行调整 …