【STM32】ADC模数转换器
1 ADC简介
ADC(Analog-Digital Converter)模拟-数字转换器
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
STM32是数字电路,只有高低电平,没有几V电压的概念,想读取电压值,就需要借助ADC模数转换器了。DAC则是相反的功能。
12位逐次逼近型ADC,1us转换时间
分辨率:一般用多少位来表示,0 ~ 2 ^ 12 - 1(量化结果0~4095)
转换时间:也是转换频率,从转换开始到产生结果需要花1us时间,即转换频率是1MHz
输入电压范围:0~3.3V,转换结果范围:0~4095
线性对应
18个输入通道,可测量16个外部和2个内部信号源
16个GPIO口、内部温度传感器(测量CPU的温度)和内部参考电压(1.2V的基准电压)
规则组和注入组两个转换单元
模拟看门狗自动监测输入电压范围
STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道
1.1 逐次逼近型ADC
ADC0809的内部结构图,独立的8位逐次逼近型ADC芯片。
左边是8路输入通道,通过通道选择开关,选中一路,输入到比较器前进行转换;下面是地址锁存和译码(想选中哪个通道,就把通道号放在这三个引脚上,再给一个锁存信号,上面对应的通路开关就可以自动拨好了,相当于38译码器)
比较器有两个输入端,一个是待测电压,另一个是DAC(数模转换器)的电压输出端;如果DAC输出的电压比较大,就调小DAC数据;如果DAC输出的电压比较小,就增大DAC数据;直到DAC输出的电压和外部通道输入的电压近似相等,这样DAC输入的数据就是外部电压的编码数据了,这就是DAC的实现原理。一般使用二分法调节。
1.2 ADC框图
具体的
有温度传感器、内部参考电压,总共18个输入通道,接到模拟多路开关,其输出接到模数转换器,即逐次比较,转换结果放在数据寄存器里。
普通的的流程是:多路开关选中某一个通道,开始转换,等待转换完成,取出结果。
这里比较高级,可以同时选中多个,而且在转换的时候,还分成了两个组,规则通道组和注入通道组,其中规则组可以一次性最多选择16个通道,注入组一次最多选择4个通道。规则组的数据寄存器只能存储一个结果,如果不想之前的结果被覆盖,那在转换完成之后,要尽快把结果拿走(使用DMA转运数据);注入组可以存4个结果,不用担心数据覆盖。
左下角是触发转换部分,对于STM32的ADC,触发ADC开始转换的信号有两种:一种是软件触发,程序中调用一条代码;另一种是硬件触发,就是这些触发源。上面是注入组触发源,下面是规则组触发源。这些触发源主要来自定时器,有定时器的各个通道,还有TRGO定时器主模式的输出。定时器可以通向ADC、DAC这些外设,用于触发转换。因为ADC经常需要过一个固定的时间段转换一次,正常的思路是:用定时器,每隔1ms申请一次中断,在中断里手动开始一次转换;但是频繁进中断对程序是有影响的,所以对这种需要频繁进中断,并且在中断里只完成简单的工作的情况,一般都会有硬件的支持。还可以选择外部中断引脚来触发转换。
VREF+、VREF-是ADC的参考电压,决定了ADC的输入电压范围,VDDA、VSSA是ADC的供电引脚,一般情况下VREF+接VDDA,VREF-接VSSA。
右边这里是ADCCLK是ADC的时钟,是用于驱动内部逐次比较的时钟,这个时钟来自ADC的预分频器,而ADC预分频器来自RCC的。
模拟看门狗里面可以存储阈值高限和阈值底限,如果指定了模拟看门狗,并且指定了看门的通道,越限之后,它就会乱叫,在上面申请一个模拟看门狗中断,最后通向NVIC。
对于规则组和注入组,转换完成之后,也会有一个EOC转换完成的信号,EOC是规则组的完成信号,JEOC是注入组完成的信号,这两个信号会在状态寄存器里置一个标志位,读取这个标志位就可以知道是不是转换完成了;同时这两个标志位也可以去到NVIC,申请中断,如果开启了NVIC对应的通道,它们就会触发中断。
1.3 ADC基本结构
左边是输入通道,16个GPIO口外加两个内部通道,然后进入AD转换器。AD转换器里有两个组,一个是规则组,一个是注入组,规则组最多选择16个通道,注入组最多选择4个通道,然后转换的结果存在AD数据寄存器里,其中规则组只有一个数据寄存器,而注入组有4个数据寄存器。下面有触发控制,触发控制可以选择软件触发和硬件触发,硬件触发主要是来自定时器,当然也可以选择外部中断的引脚;右边是来自RCC的ADC时钟CLOCK,ADC逐次比较的功能就是这个时钟推动的。然后上面可以布置一个模拟看门狗用于检测转换结果的范围,如果超出设定的阈值,就通过中断输出控制,向NVIC申请中断。另外规则组和注入组完成之后会有个EOC信号,它会置一个标志位,当然也可以通向NVIC。右下角有个开关控制,在库函数中就是ADC_Cmd,用于给ADC上电的。
1.4 输入通道
通道 | ADC1 | ADC2 | ADC3 |
通道0 | PA0 | PA0 | PA0 |
通道1 | PA1 | PA1 | PA1 |
通道2 | PA2 | PA2 | PA2 |
通道3 | PA3 | PA3 | PA3 |
通道4 | PA4 | PA4 | PF6 |
通道5 | PA5 | PA5 | PF7 |
通道6 | PA6 | PA6 | PF8 |
通道7 | PA7 | PA7 | PF9 |
通道8 | PB0 | PB0 | PF10 |
通道9 | PB1 | PB1 | |
通道10 | PC0 | PC0 | PC0 |
通道11 | PC1 | PC1 | PC1 |
通道12 | PC2 | PC2 | PC2 |
通道13 | PC3 | PC3 | PC3 |
通道14 | PC4 | PC4 | |
通道15 | PC5 | PC5 | |
通道16 | 温度传感器 | ||
通道17 | 内部参考电压 |
ADC通道和引脚复用的关系。
ADC12_IN0的意思是ADC1和ADC2的IN0都是在PA0上的。以此类推。双ADC模式。
1.5 规则组的转换模式
在ADC初始化中会有两个参数,一个是选择单次转换还是连续转换;另一个是扫描模式还是非扫描
1.5.1 单次转换,非扫描模式
这个列表就是规则组里面的菜单,有16个空位。可以在这里写入要转换的通道,比如通道2,在非扫描的模式下,这个菜单就只有第一个序列1的位置有效。这时菜单同时选中一组的方式就退化成简单地选中一个的方式了,在这里可以在序列1的位置指定想转换的通道,比如通道2,然后触发转换,ADC就会对通道2进行模数转换,过一小段时间后,转换完成,转换结果放在数据寄存器里,同时给EOC标志位置1,整个转换过程就结束了。判断EOC标志位来确定转换是否完成。如果想再启动一次转换,那就需要再触发一次,转换结束,置EOC标志位,读结果。如果想换一个通道转换,那就在转换之前把第一个位置的通道2改成其他通道,再启动转换就可以了。这就是单次转换、非扫描的转换模式。
1.5.2 连续转换,非扫描模式
首先还是非扫描模式。所以菜单列表就只用第一个,然后与上一个单次转换不同的是它在一次转换结束后不会停止,而是立刻开始下一轮的转换,然后一直持续下去。只触发一次就可以转换了。
好处是:开始转换之后不需要等待一段时间,因为一直在转换,所以也不需要手动开始转换,也不用判断是否结束,想要读AD值的时候,直接从寄存器取就是了。
1.5.3 单次转换,扫描模式
单次转换,每触发一次,转换结束后,就会停下来。扫描模式会用到菜单列表,选择通道,可以任意指定,可以重复,初始化结构体中有个参数指定通道数目。这里为了防止数据被覆盖,就需要用DMA及时将数据挪走,7个通道转换完成之后,产生EOC信号,转换结束。再触发下一次,开始新的转换。
1.5.4 连续转换,扫描模式
在上一个模式的基础上变了,就是一次转换完成后,立刻开始下一次转换。
还有间断模式,每隔几个转换,暂停一次需要再次触发才能继续。
1.6 触发控制
这个表是规则组的触发源,有来自定时器的信号,也有来自外部引脚/片上外设的信号,具体需要AFIO重映射。还有软件触发。这些触发信号通过右边寄存器的位来完成。
1.7 数据对齐
ADC是12位的,但是数据寄存器是16位的,因此存在一个数据对齐的问题
数据右对齐(一般是这个)
数据左对齐
有点像大端模式,小端模式
1.8 转换时间
AD转换的步骤:采样,保持,量化,编码
STM32 ADC的总转换时间为:TCONV = 采样时间 + 12.5个ADC周期(12位)
例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs
1.9 校准
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
建议在每次上电后执行一次校准
启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期
1.10 硬件电路
第一个是电位器产生一个可调的电压,这里电位器的两个固定端,一个接3.3,一个接GND,这样中间的滑动端就可以输出一个0~3.3的可调电压输出了。这里可以接ADC的输入通道,比如PA0口;滑动端往上滑时,电压增大,往下滑时,电压减小。阻值不宜太小。
第二个是传感器输出电压的电路,一般是光敏电阻、热敏电阻、红外接收管、麦克风等。串联分压,当传感器阻值变小时,下拉作用变强,输出端电压就下降;反之,输出端电压增大。
第三个是电压转换电路,比如想测0~5V的VIN电压,但是ADC只能接收0~3.3V的电压,分压。
手册
2 AD单通道
2.1 接线图
2.2 模块封装
按这个初始化
相关库函数
// 在rcc.h中
// 配置ADCCLK分频器,2/4/6/8分频
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);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); // 给ADC上电的// 中断输出控制,用于某个中断,能不能通往NVIC
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);// ADC软件开始转换控制,软件触发
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);// 配置间断模式
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number); // 每隔几个通道间断一次
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState); // 是否启用间断模式// ADC规则组通道配置
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获取双模式转换值
uint32_t ADC_GetDualModeConversionValue(void);// 获取标志位状态/清除标志位状态/获取中断状态/清除中断挂起位
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);// 带Injected是注入组的函数
版本1:单次转换非扫描
AD.c
#include "stm32f10x.h" // Device header// AD初始化函数
void AD_Init(void)
{// 1开启RCC时钟,ADC、GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 72M / 6 = 12M// 2配置GPIO模拟输入模式GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_Init(GPIOA, &GPIO_InitStructure);// 3配置多路开关,选择规则组的输入通道,指定通道/规则组序列器的次序/通道采样时间ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);// 4配置ADC转换器ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 外部触发选择,不使用外部触发ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 工作模式(独立/双ADC)ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次/连续转换ADC_InitStructure.ADC_NbrOfChannel = 1; // 通道数目ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 扫描/非扫描转换// 单次转换非扫描模式// 单次转换/连续转换 扫描/非扫描ADC_Init(ADC1, &ADC_InitStructure);// 5开关控制ADC_Cmd(ADC1, ENABLE);// 6校准ADC_ResetCalibration(ADC1); // 复位校准while(ADC_GetResetCalibrationStatus(ADC1) == SET); // 等待复位校准完成ADC_StartCalibration(ADC1); // 开始校准while(ADC_GetCalibrationStatus(ADC1) == SET); // 等待校准完成
}// 获取转换结果
uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 软件触发转换while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换完成return ADC_GetConversionValue(ADC1); // 返回转换值
}
版本2:连续转换非扫描
#include "stm32f10x.h" // Device header// AD初始化函数
void AD_Init(void)
{// 1开启RCC时钟,ADC、GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 72M / 6 = 12M// 2配置GPIO模拟输入模式GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_Init(GPIOA, &GPIO_InitStructure);// 3配置多路开关,选择规则组的输入通道,指定通道/规则组序列器的次序/通道采样时间ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);// 4配置ADC转换器ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 外部触发选择,不使用外部触发ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 工作模式(独立/双ADC)
// ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次/连续转换ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 单次/连续转换ADC_InitStructure.ADC_NbrOfChannel = 1; // 通道数目ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 扫描/非扫描转换// 单次转换非扫描模式// 单次转换/连续转换 扫描/非扫描ADC_Init(ADC1, &ADC_InitStructure);// 5开关控制ADC_Cmd(ADC1, ENABLE);// 6校准ADC_ResetCalibration(ADC1); // 复位校准while(ADC_GetResetCalibrationStatus(ADC1) == SET); // 等待复位校准完成ADC_StartCalibration(ADC1); // 开始校准while(ADC_GetCalibrationStatus(ADC1) == SET); // 等待校准完成// 加到这里触发一次ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 软件触发转换
}// 获取转换结果
uint16_t AD_GetValue(void)
{
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 软件触发转换
// while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换完成return ADC_GetConversionValue(ADC1); // 返回转换值
}
2.3 主函数
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t ADValue;
float voltage;int main()
{OLED_Init(); // 初始化OLEDAD_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);}
}
3 AD多通道
3.1 接线图
使用了4个通道
3.2 模块封装
单次转换非扫描
#include "stm32f10x.h" // Device header// AD初始化函数
void AD_Init(void)
{// 1开启RCC时钟,ADC、GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 72M / 6 = 12M// 2配置GPIO模拟输入模式GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_Init(GPIOA, &GPIO_InitStructure);// 3配置多路开关,选择规则组的输入通道,指定通道/规则组序列器的次序/通道采样时间ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);// 4配置ADC转换器ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 外部触发选择,不使用外部触发ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 工作模式(独立/双ADC)ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换ADC_InitStructure.ADC_NbrOfChannel = 1; // 通道数目ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 非扫描转换// 单次转换非扫描模式// 单次转换/连续转换 扫描/非扫描ADC_Init(ADC1, &ADC_InitStructure);// 5开关控制ADC_Cmd(ADC1, ENABLE);// 6校准ADC_ResetCalibration(ADC1); // 复位校准while(ADC_GetResetCalibrationStatus(ADC1) == SET); // 等待复位校准完成ADC_StartCalibration(ADC1); // 开始校准while(ADC_GetCalibrationStatus(ADC1) == SET); // 等待校准完成
}// 获取转换结果
uint16_t AD_GetValue(uint8_t ADC_Channel)
{// 3配置多路开关,选择规则组的输入通道,指定通道/规则组序列器的次序/通道采样时间// 填充通道ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 软件触发转换while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换完成return ADC_GetConversionValue(ADC1); // 返回转换值
}
3.3 主函数
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t AD0, AD1, AD2, AD3;int main()
{OLED_Init(); // 初始化AD_Init();OLED_ShowString(1, 1, "AD0:");OLED_ShowString(2, 1, "AD1:");OLED_ShowString(3, 1, "AD2:");OLED_ShowString(4, 1, "AD3:");while (1){AD0 = AD_GetValue(ADC_Channel_0);AD1 = AD_GetValue(ADC_Channel_1);AD2 = AD_GetValue(ADC_Channel_2);AD3 = AD_GetValue(ADC_Channel_3);OLED_ShowNum(1, 5, AD0, 4);OLED_ShowNum(2, 5, AD1, 4);OLED_ShowNum(3, 5, AD2, 4);OLED_ShowNum(4, 5, AD3, 4);Delay_ms(100);}
}
相关文章:

【STM32】ADC模数转换器
1 ADC简介 ADC(Analog-Digital Converter)模拟-数字转换器 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁 STM32是数字电路,只有高低电平,没有几V电压的概念ÿ…...

Git篇---第九篇
系列文章目录 文章目录 系列文章目录前言一、使用过git merge和git rebase吗?它们之间有什么区别?二、使用过git cherry-pick,有什么作用?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看…...

Paper Reading: (ACRST) 基于自适应类再平衡自训练的半监督目标检测
目录 简介工作重点方法CropBankFBRAFFRTwo-stage Pseudo-label Filtering 实验与SOTA比较消融实验 简介 题目:《Semi-Supervised Object Detection with Adaptive Class-Rebalancing Self-Training》,AAAI’22, 基于自适应类再平衡自训练的半…...

2023年贺岁电影:一眼多,二眼好多
如果从11月末开始统计,今年贺岁档共有72部贺岁片,平均一天就有2部电影上映,看完总计需要花费7400分钟。 这个数量几乎快赶上2021年到2022年贺岁片的总和。 今年电影市场快速回暖以来,多部爆款作品接力上映,持续刺激市…...
软件测试面试中基础与功能的问题
一、 你们的测试流程是怎么样的? 答:1.项目开始阶段, BA (需求分析师) 从用户方收集需求并将需求转化为规格说明书,接 下来在 项目组领导 会组织需求评审。 2.需求评审通过后,BA 会组织 项目…...

map|二分查找|离线查询|LeetCode:2736最大和查询
本文涉及的基础知识点 二分查找算法合集 题目 给你两个长度为 n 、下标从 0 开始的整数数组 nums1 和 nums2 ,另给你一个下标从 1 开始的二维数组 queries ,其中 queries[i] [xi, yi] 。 对于第 i 个查询,在所有满足 nums1[j] > xi 且…...

你知道Java中的BigInteger类和BigDecimal类吗?
BigInteger和BigDecimal: 我们在学习JavaSE基础的时候学习过int和double,前者是整形,后者是双精度浮点数,但它们是有最大值的,也就是说,他两并不支持无限大的数字。 其范围如下所示: 因此对于…...
33.搜索旋转排序数组
题目来源: leetcode题目,网址:33. 搜索旋转排序数组 - 力扣(LeetCode) 解题思路: 在二分查找时,分情况讨论即可。通过与第一个元素和最后一个元素的比较来获得 mid 处于第一个序列中还是第…...

【unity】【WebRTC】从0开始创建一个Unity远程媒体流app-设置输入设备
【项目源码】 包括本篇需要的脚本都打包在项目源码中,可以通过下面链接下载: https://download.csdn.net/download/weixin_41697242/88623091 【背景】 目前我们能投射到远端浏览器(或者任何其它Peer)的媒体流只有默认的MainCamera画面,其实我们还可以通过配置输入来传…...

Redis持久化AOF详解
基础面试题 什么是AOF AOF(Append-Only File)用于将Redis服务器收到的写操作追加到日志文件,通过该机制可以保证服务器重启后依然可以依靠日志文件恢复数据。 它的工作过程大抵分为以下几步: 收到客户端的写入命令(例如SET、DE…...

基于ssm网络安全宣传网站设计论文
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本网络安全宣传网站就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息…...

机器人行业数据闭环实践:从对象存储到 JuiceFS
JuiceFS 社区聚集了来自各行各业的前沿科技用户。本次分享的案例来源于刻行,一家商用服务机器人领域科技企业。 商用服务机器人指的是我们日常生活中常见的清洁机器人、送餐机器人、仓库机器人等。刻行采用 JuiceFS 来弥补对象存储性能不足等问题。 值得一提的是&am…...

墒情监测FDS-400 土壤温湿电导率盐分传感器
墒情监测FDS-400 土壤温湿电导率盐分传感器产品概述 土壤温度部分是由精密铂电阻和高精度变送器两部分组成。变送器部分由电源模块、温度传感模块、变送模块、温度补偿模块及数据处理模块等组成,解决铂电阻因自身特点导入的测量误差,变送器内有零漂电路…...

QT -CloudViewer工具
QT -CloudViewer工具 一、演示效果二、关键程序三、程序下载 一、演示效果 二、关键程序 void CloudViewer::doOpen(const QStringList& filePathList) {// Open point cloud file one by onefor (int i 0; i ! filePathList.size(); i) {timeStart(); // time startmycl…...

GoLong的学习之路,进阶,微服务之使用,RPC包(包括源码分析)
今天这篇是接上上篇RPC原理之后这篇是讲如何使用go本身自带的标准库RPC。这篇篇幅会比较短。重点在于上一章对的补充。 文章目录 RPC包的概念使用RPC包服务器代码分析如何实现的?总结Server还提供了两个注册服务的方法 客户端代码分析如何实现的?如何异步…...

uniapp x 相比于其他的开发系统框架怎么样?
首先我们要知道niapp这是一种基于Vue.js开发的跨平台应用框架,可以将同一套代码同时运行在多个平台上,包括iOS、Android、H5等。相比其他开发系统框架,他有什么优点呢?让我们共同探讨一下吧! 图片来源:unia…...

2024最新独立站建站教程!WordPress 搭建独立站的方法和步骤
不知道大家是否听说过 WordPress ?最近有个国外博主分享,她60岁的奶奶居然用WordPress建了个关于她宠物日常的小博客,看来 WordPress 在国外真的是很普及。其实,国外很多商家还利用 WordPress 搭建自己的电商网站,那说…...
深入React Flow Renderer(二):构建拖动操作栏
在上一篇博客中,我们介绍了如何启动React Flow Renderer并创建一个基本的工作流界面。本文将进一步深入,着重讨论如何构建一个可拖动的操作栏,它是用户与工作流交互的入口之一。 引言 操作栏是工作流界面的一部分,通常位于界面的…...

Java项目学生管理系统六后端补充
班级管理 1 班级列表:后端 编写JavaBean【已有】编写Mapper【已有】编写Service编写controller 编写Service 接口 package com.czxy.service;import com.czxy.domain.Classes;import java.util.List;/*** author 桐叔* email liangtongitcast.cn* description*/ p…...

PDF控件Spire.PDF for .NET【转换】演示:将 PDF 转换为线性化
PDF 线性化,也称为“快速 Web 查看”,是一种优化 PDF 文件的方法。通常,只有当用户的网络浏览器从服务器下载了所有页面后,用户才能在线查看多页 PDF 文件。然而,如果 PDF 文件是线性化的,即使完整下载尚未…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...

Tauri2学习笔记
教程地址:https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引:https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多,我按照Tauri1的教程来学习&…...
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候,显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...