ADC数模转化器

news2024/11/24 11:07:29

简介

ADC Analog-Digital Converter )模拟 - 数字转换器
ADC 可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
12 位逐次逼近型 ADC 1us 转换时间
(12位:分辨率,12位AD值,表示范围就是0~2^12-1,即量化结果的范围是0~4095,位数越高,量化结果越精细,对应分辨率就越高)
(转换时间:即转换频率,即AD转换开始到产生结果,需要花1us的时间,对应AD转换的频率就是1MHz)
输入电压范围:0~3.3V,转换结果范围:0~4095(输入电压和转换结果一一对应,呈线性关系)
18 个输入通道,可测量 16 个外部和 2 个内部信号源
规则组和注入组两个转换单元
模拟看门狗自动监测输入电压范围
STM32F103C8T6 ADC 资源: ADC1 ADC2 10 个外部输入通道

 逐次逼近型ADC

首先这个ADC有八个输入引脚,通过通道选择开关可以选择IN中其中一个进行下一步,通道选择开关是靠地址锁存和译码控制的,把通道的编号输入ADDA,ADDB,ADDC,然后给一个锁存信号ALE,上面对应的通路开关就可以自动拨好了,相当于一个可以通过模拟信号的数据选择器;因此如果想要转换多路信号,只需要一个AD转换器,加一个多路选择开关,想转换哪路,就选中那个对应通道,然后再开始转换就行了。

接下来会把这个未知编码的电压输出到比较器中,DAC会输出一个已知编码的电压,将两者进行比较,如果未知大于已知,则会增大已知量,如果未知小于已知,则会减小已知量,直到二者近似相等,这样以来,DAC输入的数据就是外部电压的编码数据了,这个电压调节的过程就是这个逐词逼近SAR来完成的。

为了快速找到这个值,我们会使用二分法来寻找,并且这个过程如果使用二进制来表示的话,会发现128、64、32这些值都是二进制每一位的位权,这个判断过程相当于是对二进制从高位到低位依次判断是1还是0的过程。对于8位的ADC,从高位到低位依次判断8次就能找到未知电压的编码了;对于12位的ADC,则需要判断12次。

然后DAC的输入数据就是未知电压的编码,然后通过D0等口进行输出;

EOC(End of Convent):转换结束信号;

START:开始转换,给一个输入脉冲,开始转换;

CLOCK:ADC时钟,每一步都需要时钟的推进

VREF+和VREF-是DAC的参考电压:写入一个数据255,对应5V还是3V由它们决定;

STM32的ADC

 GPIO端口由16个通道,还分为两个通道,第一个是注入通道,第二个是规则通道;

注入通道:至多同时输入四个通道的数据,但是有四个注入通道数据寄存器,可以一次性把四个数据同时展示出来的

规则通道:至多可以同时输入十六个通道的数据,但是只有一个规则通道数据寄存器,会出现数据覆盖,只能把一个通道的数据展示出来;如果想展示多个数据,就需要搭配DMA转运数据。

开始触发(注入组合规则组都有):触发ADC开始转换的信号有两种,一是软件触发,在程序中调用代码启动转换,二是硬件触发,即图中的开始触发(触发源),主要来自定时器;可以使用定时器中断来实现每过一定时间就触发一次ADC,但是频繁进入中断对程序的正常执行有影响;需要定时完成这种简单的任务的情况,一般都会有硬件的支持,比如这里,给TIM3定一个1ms的时间,把TIM3的更新事件选择为TRGO输出,在ADC这,选择开始触发信号为TIM3的TRGO,这样TIM3的更新事件就能通过硬件自动触发ADC转换了。

ADCCLK:即CLK时钟

在RCC时钟树中,ADCCLK最大14MHz,而我们如果选择二分频,即72/2=36,超出范围,而且选择4分频也是超出范围的,只能选择6和8分频

ADC基本结构

还可以布置一个模拟看门狗用于监测转换结果的范围,如果超出所设定的阈值,就会通过中断输出控制,向NVIC申请中断;在AD转换器转换完成之后,还有个EOC信号,它会置一个标志位,然后通向NVIC申请中断。

输入通道

转换模式 

单次转换、非扫描模式

简单的在序列1中指定我们想要转换的通道,然后就可以触发转换,ADC就会对这个通道进行模数转换,过段时间转换完成后,会把转换结果放在数据寄存器中,同时给EOC标志位置1,转换过程就结束了。我们判断这个EOC标志位,如果转换完了,就可以在数据器中读取结果了。

如果还想在启动转换,想要转换其他通道,则就需要把序列1中的通道更改为目标通道,再触发转换。

指定通道在序列1->触发转换->转换结束->给标志位EOC置1->读结果

多次转换,非扫描模式

相比单次转换,多次转换只用触发转换一次,ADC就会一直转换,不用判断结束和不用多次触发转换,想要读取AD值时,就直接从数据寄存器去就可以了。

单次转换,扫描模式

扫描模式下,可以利用多个序列,可以任意指定任意通道,流程依然是触发转换,然后按序列顺序开始给指定通道转换,直到转换完最后一个序列指定的通道,然后给EOC标志位置1。

连续转换,扫描模式

不想解释....

触发控制

数据对齐 

ADC是12位的,但是数据寄存器却是16位的,所以就需要数据对齐;

这里我们常用数据右对齐

转换时间 

AD转换的步骤:采样,保持,量化,编码

(采样保持:量化编码过程需要比较多的时间,在量化编码过程中,如果输入的电压发生变化就很难定位输入电压对应的编码了,所以需要采样保持,在量化编码之前,需要打开采样开关,收集一下外部的电压,比如使用一个小容量的电容存储这个电压,存储好之后,断开采样开关,再进行AD转换,这样就实现了在量化编码过程中,电压始终保持不变) 

STM32 ADC的总转换时间为:

            TCONV = 采样时间 + 12.5ADC周期

例如:当ADCCLK=14MHz,采样时间为1.5ADC周期

            TCONV = 1.5 + 12.5 = 14ADC周期 = 1μs

即最短转换时间为1us(因为ADCCLK最小为14MHz)

校准

ADC 有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码 ( 数字值 ) ,这个码用于消除在随后的转换中每个电容器上产生的误差
建议在每次上电后执行一次校准
启动校准前, ADC 必须处于关电状态超过至少两个 ADC 时钟周期

 硬件电路

图一电位器产生可调电压的电路:可给PA0产生一个0~3.3V的电压,电阻阻值不可太小,一般为10kΩ;

图二传感器输出电压的电路: N1(麦克风,热敏电阻等可变电阻)可以等效为一个可变电阻,其阻值没法直接测量,所以可以通过和一个固定电阻串联分压,来得到一个可以反映电阻值电压的电路;这个固定电阻一般选择和传感器阻值相近的电阻,这样可以得到一个位于中间电压区域比较好的输出;

图三简单的电压转换电路:比如我们想测一个0~5V的Vin电压,但是ADC只能接收最大为3.3V的电压,根据图中两个电阻的分压,可以得到PA2的电压范围就是0~3.3V,就可以进入ADC转换了。输入电压差太多不适合用这个电路。

代码实操

 先介绍相关库函数

ADCCLK的配置函数

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

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

ADC的库函数 

老朋友

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

开关控制

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);

用于开启DMA输出信号

void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);

中断输出控制

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

控制校准的函数 (ADC初始化完成后,依次调用即可)

//复位校准
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);

获取标志位状态(参数写EOC的标志位,判断EOC是否被置1,即转换是否结束)

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

 有关间断的函数

//每隔几个通道间断一次?
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
//是否开启间断
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC规则组通道配置(重要)(ADC号,需要指定的通道,序列几的位置,指定通道的采样的时间)

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

是否允许外部触发转换

void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

ADC获取转换值(重要)即获取AD转换的数据寄存器

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

ADC获取双模式转换值(双ADC获取转换值的函数)

uint32_t ADC_GetDualModeConversionValue(void);

注入组的函数(不讲)

void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);

模拟看门狗 

//是否启用模拟看门狗
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);

ADC温度传感器、内部参考电压控制

void ADC_TempSensorVrefintCmd(FunctionalState NewState);

标志位

//获取标志位状态
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
//清除标志位
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
//获取中断状态
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
//清除中断挂起位
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);


如图所示步骤编写代码

1、开启GPIO和ADC的时钟,还有ADCCLK分频器

	//开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	//6分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);

2、配置GPIO口,配置为模拟输入模式

	//配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	//AIN模拟输入
	//在AIN模式下GPIO口无效,即断开GPIO口
	//防止GPIO输入输出对模拟电压造成干扰(ACD专属模式)
	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);

3、配置多路开关,把左边的通道接入到右边的规则组列表中

	//选择规则组的输入通道
	//参数3:序号数
	//参数4:采样时间的参数,需要更快的转换,选择小点的参数
	//需要稳定的转换,则选择更大的参数
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

4、配置ADC转换器

	//初始化ADC
	ADC_InitTypeDef ADC_InitStructure;
	//ADC工作模式(独立模式)
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	//数据对齐(右对齐)
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	//外部触发转换选择(外部触发源选择)(None,内部软件触发)
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	//连续转换模式(ENABLE-连续模式 or DISABLE-非连续模式)
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	//扫描模式(ENABLE-扫描模式 or DISABLE-非扫描模式)
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	//通道数目(指定在扫描模式下指定用到几个通道0~16)
	//在非扫描模式下,填任何数值都没用
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);

5、开关控制

	//开启ADC电源
	ADC_Cmd(ADC1,ENABLE);

6、还可以对ADC进行校准,可以减小误差

	//校准
	//复位校准
	ADC_ResetCalibration(ADC1);

上列语句是执行复位校准,那应该如何判断复位校准完成了呢?

这个函数是一个返回值,那这个返回值和是否完成校准有什么关系呢?

	//获取复位校准状态	
    ADC_GetResetCalibrationStatus(ADC1);

查看其函数定义 

可以看到其获取的就是CR2寄存器里的RSTCAL标志位

再查看手册查询相关寄存器内容

 则可得

	while(ADC_GetResetCalibrationStatus(ADC1) == SET);

则校准的总代码

	//校准
	//复位校准
	ADC_ResetCalibration(ADC1);
	//获取复位校准状态
	//标志位为1时,表示正在进行复位校准
	//标志位为0时,表示复位校准结束,则我们要保证复位校准成功
	//当复位校准未完成就一直循环等待其完成
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);
	//开始校准
	ADC_StartCalibration(ADC1);
	//获取开始校准状态
	while(ADC_GetCalibrationStatus(ADC1) == SET);

则初始化函数写好了

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	//开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	//6分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	//配置GPIO口
	GPIO_InitTypeDef GPIO_InitStructure;
	//AIN模拟输入
	//在AIN模式下GPIO口无效,即断开GPIO口
	//防止GPIO输入输出对模拟电压造成干扰(ACD专属模式)
	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);
	
	//选择规则组的输入通道
	//参数3:序号数
	//参数4:采样时间的参数,需要更快的转换,选择小点的参数
	//需要稳定的转换,则选择更大的参数
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
	
	//初始化ADC(单次转换,非扫描模式)
	ADC_InitTypeDef ADC_InitStructure;
	//ADC工作模式(独立模式)
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	//数据对齐(右对齐)
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	//外部触发转换选择(外部触发源选择)(None,内部软件触发)
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	//连续转换模式(ENABLE-连续模式 or DISABLE-非连续模式)
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	//扫描模式(ENABLE-扫描模式 or DISABLE-非扫描模式)
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	//通道数目(指定在扫描模式下指定用到几个通道0~16)
	//在非扫描模式下,填任何数值都没用
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	//开启ADC电源
	ADC_Cmd(ADC1,ENABLE);
	
	//校准
	//复位校准
	ADC_ResetCalibration(ADC1);
	//获取复位校准状态
	//标志位为1时,表示正在进行复位校准
	//标志位为0时,表示复位校准结束,则我们要保证复位校准成功
	//当复位校准未完成就一直循环等待其完成
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);
	//开始校准
	ADC_StartCalibration(ADC1);
	//获取开始校准状态
	while(ADC_GetCalibrationStatus(ADC1) == SET);
}

获取结果函数

1、软件触发(启动)

	//软件触发(启动)
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);

2、等待转换完成(EOC置1)(等待)

	//获取EOC标志位状态(等待)
	//与之前的判断复位校准是否完成的操作一致
	//但是与校准有所不同(需要看寄存器描述)
	//0:转换未完成, 1:转换完成
	//在之前我们设置采样周期为55.5,转换周期是固定的12.5
	//加在一起就是68个周期,配置的ADCCLK是72MHz的6分频,即12MHz
	//12MHz进行68个周期转换才能完成,最终时间为1/12M*68=5.6μs
	//即while循环会等待5.6μs
	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

3、读取ADC数据寄存器(读取)

	//获取转换值(读取)
	return ADC_GetConversionValue(ADC1);

整体

//获取转换结果的函数
uint16_t AD_GetValue(void)
{
	//软件触发(启动)
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	
	//获取EOC标志位状态(等待)
	//与之前的判断复位校准是否完成的操作一致
	//但是与校准有所不同(需要看寄存器描述)
	//0:转换未完成, 1:转换完成
	//在之前我们设置采样周期为55.5,转换周期是固定的12.5
	//加在一起就是68个周期,配置的ADCCLK是72MHz的6分频,即12MHz
	//12MHz进行68个周期转换才能完成,最终时间为1/12M*68=5.6μs
	//即while循环会等待5.6μs
	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	
	//获取转换值(读取)
	return ADC_GetConversionValue(ADC1);
}

在主函数中调用

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

uint16_t ADValue;

int main(void)
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1,1,"ADValue");
	while(1)
	{
		ADValue = AD_GetValue();
		OLED_ShowNum(1,9,ADValue,4);
	}
}

然后旋转电位器,可以发现向左拧ADValue增大,向右拧ADValue则减小。

改善

一、数据抖动

我们会发现数据末尾会发生抖动,这是正常现象,当我们想使用这个值进行判断,再执行某些操作,比如光线的AD值小于某阈值就开灯,大于某阈值就关灯,可能会出现假如值在阈值附近抖动,导致我们的操作不稳定(即LED亮灭不稳定),我们可以使用迟滞比较的方法来完成,设置两个阈值,低于下阈值时,开灯,高于上阈值时,关灯,这样就可以避免输出抖动的问题了(施密特触发器同一个原理)。

如果数据跳变来厉害,还可以采用滤波的方法使AD值更平滑点(均值滤波);

或者裁减分辨率,把数据的尾数去掉。

二、显示电压

如之前所说,输入电压和转换结果一一对应,呈线性关系

我们可以利用这个线性关系,输出电压的值(不是完全准确的)

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

uint16_t ADValue;
float Voltage;

int main(void)
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1,1,"ADValue:");
	OLED_ShowString(2,1,"Voltage:0.00V");
	while(1)
	{
		ADValue = AD_GetValue();
		Voltage = (float)ADValue / 4095 * 3.3;
		OLED_ShowNum(1,9,ADValue,4);
		OLED_ShowNum(2,9,Voltage,1);
		OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);
		Delay_ms(100);
	}
}

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

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

相关文章

vue里使用elementui的级联选择器el-cascader进行懒加载的怎么实现数据回显?

需要实现的懒加载回显效果 比如:后端返回数据 广东省/广州市/天河区 :440000000000/440100000000/440106000000,需要我们自动展开到天河区的下一级,效果如下 代码实现 我的实现思路就是拿到 440000000000/440100000000/44010600…

YOLOv5如何训练自己的数据集(生活垃圾数据集为例)

文章目录 前言1、数据标注说明2、定义自己模型文件3、训练模型参考文献 前言 本文主要介绍如何利用YOLOv5训练自己的数据集 1、数据标注说明 以生活垃圾数据集为例子 生活垃圾数据集(YOLO版)点击这里直接下载本文生活垃圾数据集 生活垃圾数据集组成&…

软件测试/测试开发丨利用人工智能ChatGPT自动生成PPT

点此获取更多相关资料 简介 PPT 已经渗透到我们的日常工作中,无论是工作汇报、商务报告、学术演讲、培训材料都常常要求编写一个正式的 PPT,协助完成一次汇报或一次演讲。PPT相比于传统文本的就是有布局、图片、动画效果等,可以给到观众更好…

VSCode 和 CLion

文章目录 一、VSCode1、文档2、插件3、智能编写4、VSCode 与 C(1)安装(2)调试(a)使用 CMake 进行跨平台编译与调试(b)launch.json(c)传参 (3&…

mac有必要用清理软件吗

随着科技的不断进步,我们的计算机硬盘容量也在不断增长。即使是ARM架构的处理器,也可以通过高效的文件系统和技术来充分利用磁盘空间。然而,对于使用Mac OS系统的用户来说,仅仅使用一个盘来存储所有文件可能会导致一些残留文件的问…

深入了解 Docker 容器操作命令:掌握容器化管理的关键

Docker 已经成为现代应用程序开发和部署的行业标准。它借助容器化技术,提供了一种轻量、可移植和可扩展的方式来构建、发布和运行应用程序。然而,最近我在工作中发现,一些家人们对 Docker 容器的操作命令还不太熟悉。因此,本文旨在…

C++之std::function类模板定义函数对象应用总结(二百三十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

PWN基础:从源文件到可执行文件

目录 编译原理 GCC编译过程 Preprocess阶段 File命令 Compile阶段 Assemble阶段 Link阶段 高级语言编写的程序想在操作系统运行,需要被翻译为机器指令,在按照可执行目标文件格式打包并以二进制形式存储在文件中 编译原理 编译器作用:…

php实现分页功能跳转和ajax方式实现

实现效果 准备工作 创建数据表和导入测试数据 CREATE TABLE users ( id int(10) unsigned NOT NULL AUTO_INCREMENT, username varchar(30) DEFAULT NULL COMMENT 账号, email varchar(30) DEFAULT NULL COMMENT 密码, PRIMARY KEY (id) ) ENGINEMyISAM AUTO_INCREM…

Docker 容器编排

是什么 Docker-Compose是 Docker 官方的开源项目,负责实现对Docker容器集群的快速编排。 Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个…

基于微信小程序的医院门诊体检预约管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能:具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

Xcode15下载iOS17一直中断解决办法

1、问题描述 目前的 xcode 15 安装时,跟以前有个差别:以往的 xcode 安装时自带了 ide、sdk 等工具包,安装后即可开始开发,而最新的包则被分开成了不同的包,这里以 ios 开发包为例:Xcode_15.xip 和 iOS_17_…

网络编程-UDP协议(发送数据和接收数据)

需要了解TCP协议的,可以看往期文章 https://blog.csdn.net/weixin_43860634/article/details/133274701 TCP/IP参考模型 通过此图,可以了解UDP所在哪一层级中 代码案例 发送数据 package com.hidata.devops.paas.udp;import java.io.IOException; …

图形处理软件Photoshop Elements 2020 mac中文版 ps简化版

Photoshop Elements 2020 mac是一款非常实用的图形处理工具。ps elements 2020 mac中文版可以帮助您自动生成照片和视频作品的功能,采用Adobe Sensei AI技术可进行图像组织、编辑和创建等。Photoshop Elements 2020 for Mac激活版可以帮助您轻松整理照片和视频&…

【springboot3.x 记录】关于Jakarta包无法引入的问题

最近想将一些项目升级到springboot3.x和java17的时候,发现项目依赖中有Jakarta的包,但是代码标红提示没有相关的类,特此记录一下排查问题和最终解决问题的思路方法 一、发现问题 因为之前有创建过 springboot3.x java17 的项目,…

php导出cvs,excel打开数字超过16变科学计数法

今天使用php导出cvs,在excel中打开,某一个字段是数字,长度高于16位结果就显示科学计数法 超过15位的话从第16位开始就用0代替了 查询了半天总算解决了就是在后面加上"\t" $data[$key][1] " ".$value[1]."\t";…

法规标准-UN R48标准解读

UN R48是做什么的? UN R48全名为关于安装照明和灯光标志装置的车辆认证的统一规定,主要描述了对各类灯具的布置要求及性能要求;其中涉及自动驾驶功能的仅有6.25章节【后方碰撞预警信号】,因此本文仅对此章节进行解读 功能要求 …

Mysql编译安装和yum安装

一、msql数据库介绍 1、什么是sql sql代表结构化查询语言,sql是用于访问数据库的标椎化语言 sql包含三个部分 DDL数据定义语言包含定义数据库及其对象的语言,例如表,视图,触发器,存储过程等 DML数据操作语言包含允许数…

windows 修改hosts映射,可以ping通,但是无法通过http url 路径访问,出现 500 Internal Privoxy Error

问题描述 今天在学习nginx时,想在hosts配置一个nginx的域名映射,但是发现访问nginx服务的ip时可以访问通,在dos命令窗口ping配置的域名映射也可以ping通,但是一旦在浏览器通过http请求访问配置的hosts域名映射时却出现 500 Inter…

学习:原码-反码-补码

文章目录 前提知识原码详解反码补码 二进制负数的运算 前提知识 正数不需要进行原码反码补码一说,正数就是正数,我们原码反码补码是为了针对负数 (按道理来说其实根本不存在什么码,只有二进制机器码,不过是为了方便计…