news 2026/9/12 10:37:12

STM32C5A3R ADC电压采集全流程:从CubeMX配置到DMA滤波校准

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32C5A3R ADC电压采集全流程:从CubeMX配置到DMA滤波校准

做嵌入式开发绕不开ADC,这次拿到STM32C5A3R这颗料,我第一件事就是把它的ADC电压采集完整跑一遍。从CubeMX配置、HAL库代码、多通道DMA、软件滤波到校准补偿,我会把每个环节的细节和踩坑记录都整理出来,让同样在用这颗芯片的人少走弯路。

STM32C5A3R属于ST新一代Cortex-M33内核的MCU,ADC外设相比老一代F1/F4有了明显升级,支持可配置分辨率、更高采样率和更灵活的触发方式。这次项目用的是单ADC多通道采集,外加DMA搬运数据,实测下来稳定性不错,但有几个细节如果没注意,还真容易翻车:采样周期设太短导致数据跳动、多通道DMA缓冲区对不齐、基准电压噪声引入误差等等。这篇文章把这些坑都总结清楚。

不管你是刚上手STM32C5A3R,还是以前用F103想快速迁移过来,又或者单纯想把ADC采集做得更规范,这篇内容都适合你。先说结论:STM32C5A3R的ADC采集链路本身不复杂,复杂的是在使用之前把原理吃透、把参数选对、把数据处理好。

1. 项目概述与ADC外设初体验

1.1 开发环境与硬件准备

这次开发我用了STM32CubeIDE + STM32CubeMX的组合,HAL库版本跟着官方最新走。板子是自己画的最小系统板,电源部分用了一颗低压差线性稳压器单独给模拟部分供电,主控芯片就是STM32C5A3R。其实环境这东西没啥好纠结的,Keil MDK、IAR、STM32CubeIDE随便哪一个都行,关键是HAL库的API基本一致,换了IDE代码迁移成本很低。

硬件上需要注意的几点列出来:

  • 模拟供电VDDA和数字供电VDD必须分开走,STM32C5A3R的ADC参考电压范围一般直接接VDDA,如果VDDA噪声大,采集结果会直接反映出来。
  • 输入引脚尽量不要复用做数字输出,即便复用也要等ADC采样完成后切换,否则切换瞬间的毛刺会串进采样值。
  • 采样保持电容的充电电荷来自输入源,如果输入源阻抗太高,采样时间不够就会产生电压跌落,这个后面会详细算。

我这次采集的电压范围是0到3.3V,直接用电阻分压把被测电压降到ADC量程内,输出端并了一个100nF电容做低通滤波,其实这就是最简单的ADC前端电路。

1.2 STM32C5A3R的ADC特性梳理

STM32C5A3R这一代MCU的ADC最大变化在于位数可配置,不再像F1系列那样固定12位。它支持在较高位数和较低位数之间做取舍,位数越高单次转换时间越长,但分辨率更好。实际项目中如果只是监测电池电压,没必要开最高位数,反而低位数配合更短的采样周期、更高的采样率,效果更好。

另外值得强调的是,这颗芯片拥有多个ADC实例,可以各自独立工作,也可以配合起来形成双重或者三重模式。如果后续有高频采样需求,比如同时采集三相电流,完全可以把负载分摊到不同ADC上。不过这次电压采集只是一路主ADC加一个备用通道,属于杀鸡用牛刀了。

1.3 ADC相关的几个高频关键词解读

很多刚接触ADC的人会被一堆名词吓到,我在这里直接把这次会用到的概念梳理一遍:

  • 采样周期:ADC内部采样开关闭合的时间长度,以ADC模块时钟周期为单位计算。采样周期越长,采样电容充电越充分,结果越准确,但转换率会下降。
  • 建立时间:输入信号从跳变到稳定所需的时间。如果被测信号本身波动剧烈,ADC采到的是某一瞬间的值,不能反应真实电平。
  • 过采样:通过提高采样率并做数字平均,等效提升分辨率。STM32C5A3R带硬件过采样单元,也支持软件过采样。
  • 校准:因为芯片制造和实际使用环境的差异,ADC转换结果会存在增益误差和偏移误差,通过一个或多个参考点做修正,能明显提高精度。
  • DMA:直接把ADC转换结果搬运到内存,不需要CPU介入,适合多通道连续采集。

记住这些关键词后,后面读代码和调参数都会顺畅很多。

2. ADC采样的核心原理与关键参数

2.1 SAR型ADC逐次逼近到底怎么工作

STM32C5A3R内部用的是SAR型ADC,全称是逐次逼近寄存器型。原理可以拿天平称重来类比:你有一堆砝码,从大到小逐个尝试,每次判断"当前砝码加上去之后是不是超重",超了就取下,没超就保留,把所有砝码试一遍,最后剩下的总重量就是被测物体的质量。

ADC内部也是这样,用比较器做判断,用一个电容阵列充当砝码。第一步先判断输入电压是否高于满量程的一半,第二步判断是否高于四分之三或者四分之一,以此类推,每一位都是靠这种二分法逼近下来的。

位数越高,需要的比较次数就越多,这就是为什么16位分辨率下转换时间会比12位长。理解了这个原理,就能明白为什么输入信号在采样保持阶段必须"冻结"——如果比较过程中输入电压还在变化,那比较器的判断就失去意义了,最终结果可能是乱的。所以ADC内部一定有采样保持电路,这就是所谓track-and-hold。

2.2 采样周期的选择逻辑与计算过程

采样周期设定的本质,是决定内部采样电容充电时间长短。STM32C5A3R的ADC内部有一个采样电容,典型值在几皮法到十几皮法之间,充电电阻也有一定阻值。如果要让电容电压在采样结束后足够接近输入电压,时间常数RC必须远小于采样窗口。

总转换时间可以用下面这个公式估算:

总转换时间 = 采样时间 + 转换时间

其中采样时间 = 采样周期数 x ADC时钟周期。转换时间一般等于(分辨率 + 若干额外周期)x ADC时钟周期。举个例子,假如ADC时钟频率为12.5MHz,采样周期数设为13.5个周期:

采样时间 = 13.5 x (1 / 12.5MHz) = 1.08μs

如果分辨率配置为12位,加上固定开销的周期数(通常约8到12个周期),总周期数大约在25个ADC时钟周期左右:

总转换时间 ≈ 25 x 80ns = 2μs

对应采样率就是500kHz。这个速度对电压采集绰绰有余。真正要注意的是,如果你外接的传感器输出阻抗很高,比如10kΩ以上,那13.5个周期的采样时间可能不够,需要适当调大采样周期,不让就让采样电容充不满,采出来的电压会比实际值低。

我这次外接信号源输出阻抗在1kΩ以内,又并了100nF电容,所以直接把采样周期设成了一个保守值,实测数据很稳定。

2.3 分辨率与量程的配合

很多人在代码里直接读出原始ADC值然后算电压,但容易忽略一点:ADC原始值的满量程并不一定等于参考电压。如果一个12位ADC的参考电压是3.3V,那么理论上代码里读到的4095对应3.3V,0对应0V。但注意,STM32C5A3R的ADC可能不是严格的二进制度数对应电压,比如手册上会写明偏移误差(OFFSET)和增益误差(GAIN)的存在。

电压换算公式很朴素:

电压 = 原始ADC值 x LSB大小

其中LSB大小 = 参考电压 / 2^分辨率。12位分辨率下,3.3V参考:

LSB = 3.3 / 4096 ≈ 0.8057mV

也就是说,每个ADC码值对应的电压量级是0.8mV左右。如果不校准,出厂时芯片内部的不一致性可能导致满量程处的实际电压偏差达到正负几毫伏甚至十几毫伏,这在小信号精密测量场景下是致命的。后续我会专门讲怎么通过校准把这个误差修掉。

3. 硬件设计:ADC精准采样的三条生命线

3.1 PCB布局核心要点一:电源与地平面的噪声隔离

热词里提到的"ADC/DAC电路设计:规避时钟抖动与电源噪声的3个PCB布局要点",我这次深有体会。ADC的模拟部分对电源噪声极其敏感,尤其是参考电压引脚。如果VDDA和VDD走的是一个网络,芯片内部的数字翻转噪声会直接干扰比较结果。

我的做法是:模拟电源从主电源经过磁珠隔离,再加一个10μF钽电容和一个100nF陶瓷电容并联滤波,ADC的参考电压引脚就近再放一个1μF电容。还有就是地平面一定要完整,不要在ADC输入引脚下方走数字信号线,否则高速信号切换会在参考平面上产生噪声。

有人觉得这是强迫症,但实测过:没有做电源隔离的板子,ADC读数低端跳动幅度能达到正负5个LSB,做了隔离之后降到正负1个LSB以内,效果立竿见影。

3.2 PCB布局核心要点二:时钟与模拟信号的物理隔离

STM32C5A3R的主频可以跑到很高,芯片内部和板上的SPI、UART、PWM这些数字信号上升沿很陡峭,谐波丰富。这些信号如果跟ADC输入走线靠得太近,会通过寄生电容耦合到模拟输入端。

这里有一个非常实在的经验:ADC输入走线两侧一定要有完整的GND跟随,就像给信号线围了一道墙。另外,任何高频时钟线(比如晶振引线、SPI时钟)都不要和ADC输入线平行走线,如果必须交叉,最好垂直交叉,减少耦合面积。

PCB Layout的时候还有一个被忽略的点:ADC输入回路的面积要尽可能小。信号源通过输入引脚进入芯片,最终要从GND引脚返回源端,这个回路围住的面积越小,吸收空间电磁干扰的能力就越弱。简单说就是输入线旁边加地线,让回流路径在一块儿。

3.3 PCB布局核心要点三:参考电压与输入端的RC滤波

很多开发板直接拿VDDA作为ADC参考电压,其实精度要求高的场合应该单独布置参考源芯片。哪怕是成本受限,至少也要保证VREF+引脚上的电容足够靠近引脚,走线不要过长,否则参考电压在转换过程中的跌落会影响高位判断。

输入端加RC滤波的取值也需要章法。RC滤波器的截止频率公式:

f_c = 1 / (2 x π x R x C)

我这次后端接了电阻分压,等效源阻抗不高,所以R取值100Ω、C取100nF,算下来截止频率约16kHz,用于滤除高频噪声绰绰有余。如果被测信号本身很快(比如音频信号的ADC采集),RC截止频率就要提高,否则会把有用的高频分量滤掉。

还有一个注意点:RC滤波电路中的C会储存电荷,如果ADC每次采样周期内都要从C抽取电荷,那么只要C足够大并且充电时间足够,ADC读数就会比较稳。但如果R太大,采完一次后C上的电荷来不及补充,第二次测量就会偏低。这种现象可以通过连续转换模式观察到一条缓慢下降的曲线,遇到这种情况要么减小R要么增加采样时间。

4. 软件配置与代码实现全流程

4.1 CubeMX图形化配置步骤

STM32CubeMX配置ADC非常直观,我建议所有人在手写寄存器之前先把它跑通。步骤如下:

  1. 打开CubeMX,选择STM32C5A3R这颗料,初始化时钟。我一般把ADC时钟配置在最高允许频率之下,留一点裕量。
  2. 在Pinout视图里找到ADC1,把要用的通道引脚设置为ADC模式,比如ADC1_IN0对应PA0。
  3. Parameter Settings里选择分辨率,我选了12位作为平衡点;选择扫描模式为Enable(多通道时必选),连续转换模式根据需求开启。
  4. 配置采样周期,我把共用的采样周期设为13.5个周期。
  5. 如果要用DMA,在DMA Settings里添加ADC1请求,选择循环模式Circular,数据宽度设为Half Word(16位)。
  6. 生成工程前检查一下中断优先级,DMA中断优先级不要高于系统关键的实时中断,否则可能影响主循环时序。

CubeMX生成代码后,main函数里会自动出现MX_ADC1_Init(),但注意默认生成的代码不会直接开始转换,你要自己调用启动函数。

4.2 单通道单次采集的代码骨架

单通道单次采集是最基础的ADC用法,适合低频轮询场景,比如每秒测一次电池电压。核心代码极其简单:

uint32_t adc_raw; float voltage; HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); adc_raw = HAL_ADC_GetValue(&hadc1); HAL_ADC_Stop(&hadc1); voltage = ((float)adc_raw / 4096.0f) * 3.3f;

这段代码每次采样前启动ADC、等待转换结束、读取结果、然后关闭。有一个小的性能隐患:每次HAL_ADC_Start都会重新校准内部电容阵列的初始状态,频繁调用会浪费一些时间。如果采样频率要求比较高,更好的做法是启动一次后连续转换,需要时直接取值。

4.3 多通道DMA采集的配置与实施细节

多通道采集时,如果继续用轮询逐个通道处理,CPU会被频繁打断。正确做法是利用ADC扫描模式和DMA自动搬运数据。整个配置的核心逻辑是:ADC按通道顺序依次转换,DMA把转换结果依次写入缓冲区,缓冲区满后产生中断,你在中断里处理数据。

CubeMX里把扫描模式打开,然后配置转化通道顺序顺序。我在ADC1上开了3个通道:IN0、IN1、IN2,对应PA0到PA2。DMA缓冲数组定义示例如下:

#define ADC_CHANNEL_COUNT 3 uint16_t adc_buffer[ADC_CHANNEL_COUNT]; HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_buffer, ADC_CHANNEL_COUNT);

启动后,每轮三个通道的转换结果会自动填入adc_buffer[0]、adc_buffer[1]、adc_buffer[2]。这里有个至关重要的问题:如何知道哪一批数据是完整的一轮?在循环模式下,DMA是连续覆盖写的,如果你不知道当前写入的位置,拿到的一半是上一轮的数据、一半是这一轮的数据。

解决办法是在DMA转换完成中断里处理数据。HAL库提供了回调函数:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc->Instance == ADC1) { // 此时adc_buffer里是完整的一轮三个通道数据 process_adc_data(adc_buffer); } }

因为DMA设置了循环模式,每次传输完成都会触发这个回调,三轮数据之间不会出现交叉错位。我之前曾见过有人在主循环里直接读缓冲区,结果因为时序错位,通道0的数据偶尔跑到通道1的位置上,排查了很久才发现是读取时机问题。

4.4 ADC按键的简单扩展思路

如果改天你想做按键输入,又不愿意占用多个GPIO,完全可以用ADC按键方案。原理很简单:多个按键通过不同阻值的电阻串联分压,按下不同的键会在ADC输入脚产生不同的电压,MCU根据ADC值判断是哪一个键被按下。

但这里有个坑:机械按键存在抖动,按下瞬间ADC值会在两个电压档位之间快速跳变。所以ADC按键软件上必须做消抖,我的做法是连续采集三次,如果三次值落在同一个分档区域内并且维持了一段时间,才认为按键有效。另外还要注意不同按键档位之间的电压间隔要足够大,至少大于PCB噪声引起的ADC波动范围,否则容易误判。

5. 数据后处理:滤波与校准是精度的一半

5.1 为什么ADC原始数据不能直接用

ADC原始数据从原理上就包含误差:电源噪声、参考电压波动、输入源阻抗导致的充电不完全、芯片本身的偏移和增益误差。还有一个容易被忽视的问题是量化噪声——ADC输出是离散台阶,实际电压在两个台阶之间时,转换结果会落到其中一个台阶上,这就引入了量化误差。

如果直接把这样的数据用于控制环或者仪表显示,轻则数值抖动,重则系统误判。比如一个12位ADC在3.3V参考下,一个LSB是0.8mV,看起来很小,但如果你采集的是一个高阻抗信号,噪声可能达到正负10mV的幅度,换算成ADC码值就是正负12个LSB的抖动。你不滤波,界面上的数字就像心电图一样跳。

滤波的目的不是抹掉真实信号,而是把真实信号附近的噪声分量消除掉。选择哪种滤波算法,取决于你关注的是响应速度还是稳定精度。

5.2 C语言实现三大ADC滤波函数

我项目里用了三种滤波算法,按场景切换,直接贴代码给大家参考。

第一种是限幅滤波,适合剔除突变干扰。比如传感器偶尔受到尖峰脉冲干扰,一次采样值突然飙到满量程:

#define ADC_MAX_DEVIATION 50 uint16_t amplitude_limit_filter(uint16_t new_sample, uint16_t last_valid) { if ((new_sample > last_valid + ADC_MAX_DEVIATION) || (new_sample < last_valid - ADC_MAX_DEVIATION)) { return last_valid; } return new_sample; }

第二种是中值滤波,适合消除偶尔的脉冲噪声。做法是连续采N次,排序后取中间值。注意经典中值滤波的窗口不能太大,不然响应太慢:

#define MEDIAN_WINDOW 5 uint16_t median_filter(uint16_t *samples, uint8_t len) { uint16_t buf[MEDIAN_WINDOW]; uint8_t i, j; uint16_t temp; for (i = 0; i < len; i++) { buf[i] = samples[i]; } for (i = 0; i < len - 1; i++) { for (j = i + 1; j < len; j++) { if (buf[j] < buf[i]) { temp = buf[i]; buf[i] = buf[j]; buf[j] = temp; } } } return buf[len / 2]; }

第三种是滑动平均滤波(带去极值),适合精度要求高的场合。先去掉最大最小值,再对剩余值求平均,兼顾了抗脉冲干扰和平滑效果:

#define AVG_WINDOW 8 uint16_t moving_average_deglitch(uint16_t *samples, uint8_t len) { uint32_t sum = 0; uint16_t min_v = samples[0]; uint16_t max_v = samples[0]; uint8_t i; for (i = 0; i < len; i++) { if (samples[i] < min_v) min_v = samples[i]; if (samples[i] > max_v) max_v = samples[i]; sum += samples[i]; } sum = sum - min_v - max_v; return (uint16_t)(sum / (len - 2)); }

实际使用中,我把滑动平均去极值放在循环DMA回调函数里,对三个通道都做处理,输出的数据稳定度明显改善,而且滤波后的数值跟随负载变化的响应时间完全可以接受。

5.3 外部ADC三点校准原理与实施步骤

先解释为什么需要校准。每个芯片的ADC都存在偏移误差和增益误差,前者指输入电压为0时ADC读数不为0,后者指满量程处读数偏离理想值。两点校准能解决线性的偏移和增益问题,但ADC内部电容阵列的非线性误差在高位段更为明显,这时候就需要三点校准来分段修正。

热词里"外部ADC三点校准"问的人特别多,我详细说一下操作步骤:

第一步,准备一个精密电压源。如果手头没有,可以用高精度基准芯片比如TL431搭一个简单的电压基准,但要先确认基准本身的精度。

第二步,选取三个校准点。我一般选满量程的10%、50%、90%三个点,比如3.3V量程下选0.33V、1.65V和2.97V。

第三步,对每个校准点采集N次数据取平均,得到三个对应的ADC码值。

第四步,用线性分段方法建立电压映射关系。比如在0.33V这个点附近,使用(电压1 = 0.33V,ADC码值1 = 实际读数)这个点来修正靠近低端的读数;在1.65V附近用第二个点修正中段读数。实际计算公式:

修正后电压 = V_ref_low + (raw - adc_low) x (V_ref_high - V_ref_low) / (adc_high - adc_low)

每个分段区间套用这个公式即可。

我这次实测,不做校准时,3.3V输入条件下读数只有3.278V左右,误差约0.7%。做了三点校准之后,三个校准点的误差都降到0.05%以内,效果相当明显。如果你的应用对绝对电压精度要求不高,这个校准步骤可以跳过,但如果你做的是电池电量计、模拟量采集模块之类的产品,校准会极大提升你的产品一致性。注意校准参数要保存在非易失存储区,比如Flash或者EEPROM,出厂前烧录一次,运行时直接调用。

6. 常见问题与排查技巧实录

6.1 数据跳动大,大概率是采样时间不够或噪声耦合

现象:ADC读数在某个范围内来回跳动,尤其输入电压越靠近满量程时跳动越明显。

排查步骤我按优先级排序:

  1. 先增大采样周期,把采样周期从1.5周期改成13.5周期甚至28.5周期,看跳动幅度有没有明显下降。如果是,说明内部采样电容没充饱。
  2. 检查输入前端RC的R值是不是太大,100kΩ以上的电阻会大幅增加源阻抗,降压明显。
  3. 用示波器测量ADC输入引脚的信号波形,看是否有高频干扰叠加。
  4. 如果是用面包板搭的电路,尝试改成杜邦线短接或者直接焊在洞洞板上,面包板寄生电容和接触电阻会带来很大麻烦。

6.2 DMA多通道数据错位怎么办

多通道DMA数据错位非常经典,症状是通道一和通道二的值偶尔互换,或者某一次数据中混入了上一个周期的值。

常见的三种原因和对策:

原因表现对策
DMA缓冲区大小小于通道数乘2字节数据越界覆盖缓冲区长度设为通道数,每个元素为uint16_t(2字节)
在DMA传输一半时读取缓冲区读到半轮新旧混合数据只在转换完成回调里处理整轮数据
扫描顺序配置与缓冲区地址顺序不匹配固定的错位映射检查CubeMX中Rank顺序,与硬件期望对应

另外还有一个容易被忽略的:STM32C5A3R的ADC数据寄存器是16位有效数据,如果DMA数据宽度配置错误(比如配置成了8位),高字节和低字节会被拆成两个字节,最终数据完全错乱。所以DMA数据宽度和缓冲区元素宽度必须都是Half Word。

6.3 电压计算结果永远偏低或者偏高

这种情况基本不是软件计算问题,而是参考电压不准。HAL库里的电压转换公式如果硬编码用了3.3V,但实际VDDA是3.29V,那结果自然偏低。最好的解决办法是不要直接信任数学公式里的参考电压,而是实测一下VDDA,把实测值代入公式。

另外一个来源是芯片出厂校准值没有使能。STM32很多系列在出厂时会在芯片内部存储校准数据(校准时序),HAL库也提供了校准API。调用一下校准函数再启动ADC,很多偏移误差可以直接消除:

HAL_ADCEx_Calibration_Start(&hadc1);

注意校准需要在ADC上电之后、开始转换之前调用,并且校准过程不能被打断,否则结果可能无效。我这次实际调用校准后,零输入条件下读到的值从原来的8个LSB偏移降到了1个LSB以内,效果立竿见影。

6.4 读数呈阶梯状跳跃

如果电压缓慢变化时,ADC读数不是平滑变化,而是偶尔跳一大段,随后又回到原有趋势上,很可能是信号源阻抗过高导致采样电容前一次采样的残余电荷影响了本次采样。这种情况下加大采样周期或者降低输入源阻抗都能改善。

如果被测信号自身就带有高频分量,而你的采样率相对较低,那么可能出现混叠效应,表现为读数随机跳动且滤波无效。这时候需要在ADC输入前端增加抗混叠低通滤波器,把截止频率设置在采样率的一半以下,也就是满足奈奎斯特条件。我经常使用的经验公式是:

RC截止频率 ≤ Fs / 2

同时在软件层面配合一定的过采样和平均,双重保险,数据就干净了。

6.5 高级进阶思路:PWM中心对齐模式与ADC采样时刻配合

如果你后续做电机控制、开关电源这类项目,热词里提到的"高级定时器PWM中心对齐模式和ADC采样时刻点设置"一定会遇到。原理很简单:PWM载波周期内,电流或电压信号会在开关动作的产生尖峰干扰,如果在开关边沿附近采样,读到的数据会被毛刺污染;如果延迟到载波中心点采样,此时开关状态已经稳定,采样值最能反映真正有效值。

实现方式是利用高级定时器的更新事件或触发输出事件来启动ADC转换。CubeMX里把定时器的主输出模式配置为PWM中心对齐模式,触发事件选择更新事件,然后ADC触发源选定时器触发,这样就把采样点精确锁定了。我在这颗芯片上跑过一版双向Buck电路的电流采样,用这个方式后电流环的稳定裕度明显改善,采样数据噪声也比自由运行ADC小不少。

写在后面的一点体会

这次STM32C5A3R的ADC电压采集项目做下来,我最深的感触是:ADC项目能不能做好,其实前半程看硬件、后半程看数据。很多人在CubeMX里点几下就开始调代码,遇到数据不稳就不断改软件,折腾半天最后发现是板上VDDA纹波太大,这种弯路我真的替大家心疼。

如果只让我说一条经验,那就是先把采样周期和参考电压搞定,再谈滤波和校准。采样周期是ADC准确度的根基,参考电压是精度天花板。这两个根基没打好,后面软件做得再花哨都是空中楼阁。这也是我后来做任何模拟量采集项目都必须先写的两份检查清单:一份是检查VDDA噪声,一份是实测参考电压。

最后再分享一个写代码的小技巧:ADC数据处理的代码最好独立成一个模块,输入是三个通道的原始ADC值,输出是三个通道修正后的物理量。这样做的好处是后续换芯片、换采样频率、改校准参数,只需要动一个文件,不用在整个工程里到处搜魔法数字。我就是靠这个方法,把这次C5A3R的ADC驱动从一个测试Demo逐步整理成了可以直接复用到产品项目里的通用模块。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 10:35:22

Linux自学指南:从入门到实战的12天学习路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 10:33:04

二叉树算法实战:从递归到迭代的C++实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 10:32:32

SpringBoot+Vue3美食分享平台架构设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 10:31:13

HJ212解析器实战:Java实现TCP粘包拆包与CRC校验

简介&#xff1a;面向环保数据通信开发者的HJ212协议Java解析器示例&#xff0c;聚焦环境监测数据采集传输协议&#xff08;HJ212&#xff09;的报文解析与数据处理&#xff0c;适合需要对接环保数采仪、搭建数据接入平台或学习自定义协议解析的程序员。压缩包共112个文件&…

作者头像 李华
网站建设 2026/9/12 10:30:25

Rust驱动的具身智能边缘运行时:MicroDuck设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 10:30:24

Flutter在鸿蒙平台的errno库适配与优化实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华