STM32 ADC模数转换

目录

  • ADC简介
  • 逐次逼近型ADC
  • STM32的ADC
  • 输入通道
  • 规则组的转换模式
    • 单次转换、非扫描模式
    • 连续转换、非扫描模式
    • 单次转换、扫描模式
    • 连续转换、扫描模式
    • 间断模式
  • 数据对齐
  • 转换时间
  • 校准
  • 代码
    • 软件触发单次转换非扫描模式

ADC简介

  • ADC(Analog-Digital Converter)模拟-数字转换器

  • ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁

  • 12位逐次逼近型ADC,1us转换时间。12位是分辨率,1us是转换频率,就是1MHz。

  • 输入电压范围:0 ~ 3.3V,转换结果范围:0~4095

  • 18个输入通道,可测量16个外部和2个内部信号源。2个内部的是温度传感器和内部参考电压。温度传感器可以测量CPU温度。内部参考电压是一个1.2V左右的基准电压。这个基准电压是不随外部供电电压变化而变化的。

  • 规则组和注入组两个转换单元

  • 模拟看门狗自动监测输入电压范围

  • STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道,没有DAC转换

存在ADC当然也存在DAC,数字电路到模拟电路的桥梁。使用DAC可以将数字信号转化为模拟信号,其实之前学习的PWM就是数字到模拟的桥梁,这种方式也完成了数字信号输出模拟信号。因为PWM只有完全导通和完全断开两种状态,这两种状态都没有功率损耗,所以在直流电机调速这种大功率的应用场景使用PWM来等效模拟量比DAC本身更好用。并且PWM更加简单常用。DAC的应用主要是在波形生成等领域,比如信号发生器,音频解码芯片。

STM32F103C8T6只有两个ADC资源和10个外部引脚的模拟信号,上面说的16个外部信号源是这个系列最多有16个外部信号源。但是C8T6引脚较少,所以其他信号源没有。

逐次逼近型ADC

在这里插入图片描述
上图是ADC0809芯片的原理图,这个芯片是逐次逼近型的ADC转换和C8T6是一样的原理。

ADC0809是一个独立的8位逐次逼近型ADC,单片机内部没有集成ADC时需要外挂ADC芯片,ADC0809就是这么一款经典的ADC芯片。现在很多单片机内部已经集成了ADC外设,就不需要外挂芯片,可以直接测量电压。

IN7~IN0:8路模拟输入。
ADDA、ADDB、ADDC、ALE:地址锁存,选择当前的模拟输入引脚。相当于38译码器。
CLOCK:ADC时钟线,ADC需要时钟来推动这个过程。
START:开始AD转换。
EOC:转换结束标志位。
内部DAC:加权电阻网络,用于产生和输入模拟信号进行比较的模拟信号。
OE:输出使能,控制三态门输出。
D7~D0:输出的8位数字信号。
VREF(+)、VREF(-):参考电压。

内部存在一个电压比较器,可以判断两个输入信号电压的大小关系。左侧接入的通道是待测电压,下面DAC是电压输出端,输出到比较器。DAC的电压我们知道,通过这个电压和待测电压的比较,然后再调节DAC,逐次逼近待测电压。这样DAC的电压就是待测电压了。DAC电压调节的过程就是图中SAR来完成的。通常使用二分法来完成。最终电压通过锁存器输出,输出的值就是待测的值。图中输出的是8位,就有8根线,C8T6是12位就有12根线。
上面EOC是End Of Convert,转化结束信号。START是开始转换,给一个输入脉冲,开始转换。
CLOCK是ADC时钟线,,因为ADC内部是一步一步进行判断的,所以需要时钟来推动这个过程。VREF(+)和VREF(-)是DAC的参考电压。255对应是5V还是3.3V就由这个参考电压决定。这个电压也决定了ADC的输入范围,所以也是ADC的参考电压。
VCC和GND是整个芯片的供电,通常参考电压的正极和VCC是一样的,参考电压的负极和GND是一样的。

STM32的ADC

在这里插入图片描述

上图是ADC的结构图。
最左边是ADC的输入通道,包括16个GPIO口,IN0 ~ IN15,稍右边还有两个内部的通道,一个内部温度传感器,另一个是VREFINT(V Reference Internal),内部参考电压。总共是18个输入通道。
然后通过模拟多路开关指定我们想要选择的通道,然后输出到模数转换器。这里就没有给内部细节执行流程了,大致和上面说的转换流程是一样的。转换结果直接放到上面的数据寄存器中。读取寄存器就可以知道ADC转换的结果了。
普通的ADC转换只能转换一路ADC,这里可以转换多路。分为两组,规则通道组和注入通道组,规则通道组一次性最多选中16个通道,注入通道组最多选中4个通道。

注入通道【使用不多】:最多一次性选4路通道,配合4个16位寄存器,就可以一次性转换4路模拟数据。
规则通道【常用】:最多一次性选16路通道,但只有1个16位寄存器,存在新来的数据覆盖上一个数据的问题,此时要么尽快将数据取走,要是使用DMA帮助转运数据,进而可以实现一次性转换16路模拟数据。当然,一次就选一个通道,就是普通的ADC功能。

左下角是触发转化的部分,就是上面说的START信号。对于STM32,触发方式有两种。

软件触发:在程序中手动调一句代码。
硬件触发:上图所示的就是硬件触发源,分为注入组的触发源和规则组的触发源。主要来自于定时器TIMx,定时器TRGO主模式的输出,也可以外部中断引脚EXTI。
正常思路是:定时器每隔1ms产生一次中断 --> 中断函数中开启触发转换信号 --> ADC完成一次转换。缺点是需要频繁进入中断,消耗软件资源。但是得益于上图的硬件电路设计,stm32可以直接使用定时器主模式触发ADC转换,硬件全自动无需申请中断,可以极大地减轻CPU负担。

左上部分有VREF(+)和VREF(-)是ADC的参考电压,VDDA和VSSA是ADC的供电引脚,一般VREF(+)要接VDDA,VREF(-)要接VSSA

VDDA和VSSA在引脚定义中也可以看到
在这里插入图片描述
VDDA和VSSA是内部模拟部分的电源,如ADC,RC振荡器,锁相环等。这里的VDDA接了3.3V,VSSA接GND。

接着看框图,转换器右边的ADCCLK是ADC的时钟。
来自ADC的预分频器,这个ADC的预分频器则来自于“RCC时钟树”。具体可以查看时钟树的电路,APB2时钟输出72MHz然后通过ADC预分频器进行预分频得到ADCCLK,由于ADCCLK最大14MHz,所以只能选择6分频/8分频
在这里插入图片描述

接着看框图,ADCCLK上面是DMA请求,这个是用于触发DMA进行数据转运的。

模拟看门狗:一旦高于上阈值或低于下阈值,就会申请模拟看门狗的中断,最终进入NVIC。
EOC:规则或注入通道转换完成信号。
JEOC:注入通道转换完成信号。
这两个信号会在状态寄存器里置一个标志位,通过读取这个标志位就能知道是不是转换结束。同时这两个标志位也可以去到NVIC申请中断。

在这里插入图片描述

输入通道

STM32有16个外部通道,这些通道对应的GPIO口如下
在这里插入图片描述
只有ADC1存在内部的两个ADC,其他两个不存在。c8t6不存在ADC3。

通过引脚定义表也可以知道对应哪些引脚,但是写的是ADC12,这表示ADC1和ADC2复用的一个引脚,为什么还要ADC2呢?
对于c8t6这个型号来说,ADC1和ADC2共用引脚,不仅可以单独使用,可以组成更加复杂的双ADC模式。双ADC模式通过配合可以组成同步模式、交叉模式(ADC1和ADC2交叉对同一个通道进行采样,以提高采样率)等。

规则组的转换模式

stm32的ADC最多同时支持16个通道,那么ADC每次扫描1个通道还是多个通道,便是选择非扫描模式/扫描模式;而对于单个通道的ADC转换来说,触发一次ADC是只转换一次,还是自动的进行连续转换,便是选择 单次转换/连续转换 。上面这两种选择进行组合,便产生了规则组的4种转换模式:

单次转换、非扫描模式

触发一次仅转换一次;仅序列1有效,但可以任意指定需要转换的通道。此时ADC选择一组的方式退化成只能选择一个。读取数据时,需要等待EOC标志位置1,然后从数据寄存器读取结果。如要再进行转换,就需要再次触发转换。
在这里插入图片描述

连续转换、非扫描模式

相比于上一个模式,仅需要一次触发,ADC就会在一次转换完成后立刻进入下一次转换,实现不断地自动进行转换。此时就不需要读EOC看转换是否完成,直接想读数据的时候就读。
在这里插入图片描述

单次转换、扫描模式

相比于第一种模式,可以一次性转换多个通道,不过还是触发一次、所有通道只转换一次。此时需要指定多少个序列,每个序列用的哪个通道。因为数据寄存器只有一个,所以此时需要DMA配合转运数据。n个通道转化完成后产生EOC信号就标志转换结束。
在这里插入图片描述

连续转换、扫描模式

不仅可以一次性转换多个通道,还可以实现触发一次、自动不间断转换。
在这里插入图片描述
上面所说的序列其实就是DMA模式下,ADC的采集顺序。

间断模式

每几次转换就暂停一下,需要再次触发才可以继续……

数据对齐

在这里插入图片描述
因为ADC是12位的,而寄存器宽度为16位,所有便有了数据对齐方式的选择。

右对齐【常用】:读出的值就是实际值。
左对齐:有时候不需要太大的分辨率,便将12位ADC的转换数据左对齐,然后只取高8位。

转换时间

在这里插入图片描述
低速采样可以忽略转换频率,高速采样必须考虑转换时间 的损耗。AD转换的步骤主要为:采样,保持,量化,编码。“采样”时间越长,越可以消除一些毛刺信号的干扰;而“量化、编码”是逐次比较的过程,消耗的时间则比“采样、保持”更长。“采样、保持”主要是因为“量化、编码”需要一段时间,所以“采样、保持”需要维持自己一段时间电压,不让这个电压不停的变化。

12.5个ADC周期因为是12位的ADC,这个周期就是ADCCLK。多出的0.5个周期在做其他事情。

校准

ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差

建议在每次上电后执行一次校准

启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期
校准过程的代码是固定的,只需要在ADC初始化之后加几句代码即可。

代码

第一步,开启RCC时钟,包括ADC和GPIO的时钟。ADCCLK的配置
第二部,配置GPIO,将需要用到的GPIO配置为模拟输入模式
第三步,配置多路开关,将左边的通道接入到右边的规则组列表中
第四步,配置ADC转换器,在库函数在用结构体就可以配置好,可以配置AD转换器和AD数据寄存器。ADC的单次还是连续转换,扫描还是非扫描,有几个通道,触发源,数据对齐方式等。
第五步,如果需要配置模拟看门狗,有几个函数用来配置阈值和监测通道的。
第六步,开关控制没开启ADC。开启之后可以进行一下ADC校准。

库函数:

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

用来配置ADCCLK分频器的,可以对APB2的72MHz时钟选择2,4,6,8分频输入到ADCCLK。

void ADC_DeInit(ADC_TypeDef* ADCx);
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);

ADC_DeInit恢复缺省配置,ADC_Init初始化,ADC_StructInit结构体初始化。

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

用来给ADC上电,就是ADC的开关控制。

void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);

开启DMA输出信号,如果使用DMA转运数据就需要调用这个函数。

void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);

中断输出控制

void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);

分别是复位校准,获取复位校准状态,开始校准,获取开始校准状态

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC软件开始转换控制,这个是用于软件触发的函数

FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);

ADC获取软件开始转换状态,功能是给SWSTART位置1,以开始转换。返回SWSTART的状态,但是手册上说,在置1后立刻由硬件置0。这个函数大多数情况下没用,而是用下面的。

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

获取标志位状态,参数给EOC的标志位,判断EOC标志位是不是置1,如果置1,那么转换结束。

void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

用来配置间断模式。

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);

ADC规则组通道配置,给序列的每个位置填写指定的通道

void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC外部触发转换控制,就是是否允许外部触发转换。

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

ADC获取转换值,获取AD转化的数据寄存器,读取转换结果就要调用这个函数。

uint32_t ADC_GetDualModeConversionValue(void);

ADC获取双模式转换值,这是双ADC模式读取转换结果的函数。

void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);

上面三个函数都是对模拟看门口进行配置的。是否启动模拟看门狗,配置高低阈值,配置看门的通道。

void ADC_TempSensorVrefintCmd(FunctionalState NewState);

ADC温度传感器内部参考电压控制,用来开启内部的两个通道,如果要使用这两个通道,就要调用这个函数。

软件触发单次转换非扫描模式

#include "Config.h"
void AD_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//哪个ADC,用通道几,使用第几个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_13Cycles5);//ADC规则组通道配置,给序列的每个位置填写指定的通道
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式还是双ADC模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据对齐方式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//外部触发转换选择,即触发控制的触发源,这里选择软件触发
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//连续转换模式,选择连续转换还是单次转换
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//扫描转换模式,选择扫描模式还是非扫描模式
	ADC_InitStructure.ADC_NbrOfChannel = 1;//通道数目,在扫描模式下用到几个通道
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);//复位校准
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成
	ADC_StartCalibration(ADC1);//开始校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);//等待校准完成
}


uint16_t AD_GetValue()
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Facebook 的历史与发展:从校园网站到全球社交平台

引言 Facebook,这个全球最大的社交网络平台之一,其发展历程充满了创新和变革。从最初的校园网站到如今的全球社交平台,Facebook 不仅改变了人们的沟通方式,也重塑了信息传播和社交互动的模式。 起源:校园内的点子 Fa…

自然语言转SQL之Vanna.ai:AI集成数据库

自然语言转SQL之Vanna.ai:AI集成数据库 一、Vanna.ai是什么二、落地步骤:实现三层需求2.1 官方示例看效果2.2 对接自己的数据库2.3 完全本地化之路 三、构建自己的产品3.1 提问转SQL3.2 执行SQL查询实例2 要实现的功能就是:用中文语言同数据库…

Android 平台架构系统启动流程详解

目录 一、平台架构模块 1.1 Linux 内核 1.2 硬件抽象层 (HAL) 1.3 Android 运行时 1.4 原生 C/C 库 1.5 Java API 框架 1.6 系统应用 二、系统启动流程 2.1 Bootloader阶段 2.2 内核启动 2.3 Init进程(PID 1) 2.4 Zygote与System Serv…

QT 作业 C++ day5

作业 代码 MyQThread.h class MyThread : public QThread {Q_OBJECT public:MyThread(QObject *parent nullptr); protected:void run() override; signals://向ui界面发送的 "复制进度" 的信号void copy_process_signal(int index); public slots:// "复…

24、如何在C++中创建和管理线程?【中高频】 -

创建线程对象: //无参构造,该线程对象没有关联任何线程函数,也就是它没有启动任何线程:thread t1;//... t1 thread(func, 10);//移动构造(调用移动赋值函数)t1.join();//含参构造thread t1(func1, 1, 10);//thread 提…

【Altium】22.11版本后如何导出Gerber镜像层

1、 文档目标 解决 22.11 版本后如何导出 Gerber 镜像层的问题 2、 问题场景 Gerber 导出旧版本,在 AD 22.11 之前的 Gerber 导出中是存在镜像层的选择。 图 1 软件更新至 AD22.11 及之后版本,在 Gerber 导出设置中无法选择层镜像进行导出。 图 2 3、…

配置 Thunderbird 以使用 QQ 邮箱

配置 Thunderbird 以使用 QQ 邮箱 本片文章的操作系统为 windws 10 ,thunder bird 客户端版本为 128.7.1esr(64位)。注意到其他文章的图片中 thunder bird 的 ui 界面和我这个不一样,导致看起来不太方便,所以这里写一篇博客。不同版本的 thu…

wxWidgets GUI 跨平台 入门学习笔记

准备 参考 https://wiki.wxwidgets.org/Microsoft_Visual_C_NuGethttps://wiki.wxwidgets.org/Tools#Rapid_Application_Development_.2F_GUI_Buildershttps://docs.wxwidgets.org/3.2/https://docs.wxwidgets.org/latest/overview_helloworld.htmlhttps://wizardforcel.gitb…

DeepSeek系列模型技术报告的阅读笔记

DeepSeek系列模型技术报告的阅读笔记 之前仔细阅读了DeepSeek系列模型的主要技术方面内容与发展脉络,以下是DeepSeek系列模型技术报告的笔记,有错误的地方欢迎指正! 文章目录 DeepSeek系列模型技术报告的阅读笔记GQADeepseek MoEAbstractIn…

海思Hi3516DV300交叉编译opencv

OpenCV是一个开源的跨平台计算机视觉库,支持C、Python等多种语言,适用于图像处理、目标检测、机器学习等任务。其核心由C编写,高效轻量,提供实时视觉处理功能,广泛应用于工业自动化、医疗影像等领域。 1 环境准备 1…

React + React-intl @3.xx + TypeScript

声明:此篇文章使用的版本是 "react-intl": "^3.12.0"。 因为react-intl3.xx版本相较于react-intl2.xx版本差别较大,有些API是break change, 所以这篇文章的实现方式,不适用于react-intl2.xx版本。 一: 安装react-intl np…

(二 十 二)趣学设计模式 之 备忘录模式!

目录 一、 啥是备忘录模式?二、 为什么要用备忘录模式?三、 备忘录模式的实现方式四、 备忘录模式的优缺点五、 备忘录模式的应用场景六、 总结 🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,…

20250307确认荣品PRO-RK3566开发板在Android13下的以太网络共享功能

20250307确认荣品PRO-RK3566开发板在Android13下的以太网络共享功能 2025/3/7 13:56 缘起:我司地面站需要实现“太网络共享功能”功能。电脑PC要像连接WIFI热点一样连接在Android设备/平板电脑上来实现上网功能/数据传输。 Android设备/平板电脑通过4G/WIFI来上网。…

HMC7043和HMC7044芯片配置使用

一,HMC7043芯片 MC7043独特的特性是对14个通道分别进行独立灵活的相位管理。所有14个通道均支持频率和相位调整。这些输出还可针对50 Ω或100 Ω内部和外部端接选项进行编程。HMC7043器件具有RF SYNC功能,支持确定性同步多个HMC7043器件,即确保所有时钟输出从同一时钟沿开始…

RSA的理解运用与Pycharm组装Cryptodome库

1、RSA的来源 RSA通常指基于RSA算法的密码系统,令我没想到的是,其名字的来源竟然不是某个含有特别意义的单词缩写而成(比如PHP:Hypertext Preprocessor(超文本预处理器)),而是由1977年提出该算法的三个歪果…

嵌入式 ARM Linux 系统构成(3):根文件系统(Root File System)

目录 一、根文件系统的原理与重要性 二、根文件系统的构成 2.1. 基本目录结构 2.2. 核心组件 2.3. 设备驱动 2.4. 网络工具和协议 2.5. 调试工具 三、根文件系统的制作方法 四、根文件系统的测试 五、构建根文件系统的关键技术 5.1. 最小化构建工具 5.2. 关键配置文…

SpringBoot知识点及其源码解析(1)

自动配置 以web启动器为例,在spring-boot-starter-test-3.4.3.pom文件整合了一系列的依赖,那么当启动程序后会不会进行自动配置?当获取到这个容器后,可以从容器中获取所有bean的名字,此时就可以在控制台发现很多bean的…

网络安全配置截图 网络安全i

网络安全概念及规范 1.网络安全定义 网络安全的概述和发展历史 网络安全 广义的网络安全:Cyber Security(网络空间安全) 网络空间有独立且相互依存的信息基础设施和网络组成,包括互联网、电信网、计算机系统、嵌入式处理器和控…

【ThreeJS Basics 09】Debug

文章目录 简介从 dat.GUI 到 lil-gui例子安装 lil-gui 并实例化不同类型的调整改变位置针对非属性的调整复选框颜色 功能/按钮调整几何形状文件夹调整 GUI宽度标题关闭文件夹隐藏按键切换 结论 简介 每一个创意项目的一个基本方面是能够轻松调整。开发人员和参与项目的其他参与…

第六课:数据存储三剑客:CSV/JSON/MySQL

在Python的数据存储与处理领域,CSV、JSON和MySQL被广大开发者誉为“数据存储三剑客”。它们各自在不同的场景下发挥着重要作用,无论是简单的数据交换、轻量级的数据存储,还是复杂的关系型数据库管理,都能找到它们的身影。本文将详…