STM32单片机ADC
STM32单片机ADCADC转换模式单次转换模式Single Conversion ModeADC在每次触发时只进行一次转换。适用于低速、低功耗的应用。连续转换模式Continuous Conversion ModeADC持续进行转换适用于需要实时监测的应用如信号处理和实时数据采集。扫描模式Scan ModeADC可以在多个通道间进行扫描每个通道依次进行转换适合多通道数据采集。触发模式Triggered Mode转换过程由外部信号触发可以是定时器、GPIO引脚等适合需要同步数据采集的场景。差分模式Differential ModeADC测量两个输入信号的差值提供更高的噪声抗性适用于高精度测量。伪差分模式Pseudo-Differential Mode其中一个输入端连接到地另一端测量信号适合简单的差分测量。在ADC模数转换器的应用中通道组可以分为规则通道组Regular Channel Group和注入通道组Injected Channel Group。这两种通道组的主要区别在于它们的工作方式、优先级以及使用场景。规则通道组Regular Channel Group定义规则通道组是ADC的主要通道组用于常规的信号采集。它通常用于周期性采集的传感器信号。特点持续转换在连续转换模式下规则通道组可以在多个通道间进行循环采样。优先级低相较于注入通道组规则通道组的优先级较低通常用于常规数据的采集。数据存储转换结果通常存储在一个数据寄存器中等待主程序读取。触发方式可以通过定时器、外部事件等方式触发采样。适用场景适用于需要实时采集且对响应时间要求不高的应用如环境监测、温度传感器等。注入通道组Injected Channel Group定义注入通道组用于优先级更高的信号采集通常用于突发事件或特定条件下的快速采样。特点高优先级注入通道组具有较高的优先级能够在任何时候中断规则通道组的采样进行数据采集。快速响应适合快速响应的应用如检测瞬时信号变化、故障检测等。独立触发可以独立于规则通道组进行触发支持多种触发源如外部引脚、内部事件等。多个通道通常可以配置多个注入通道进行快速的信号采样。适用场景适用于需要在特定条件下迅速采集信号的应用如运动控制、脉冲信号采集等。采样时间配置STM32F103 的 ADC 允许用户根据输入信号的特性选择不同的采样时间。可选的采样时间设置包括1.5 个 ADC 时钟周期7.5 个 ADC 时钟周期13.5 个 ADC 时钟周期28.5 个 ADC 时钟周期41.5 个 ADC 时钟周期55.5 个 ADC 时钟周期71.5 个 ADC 时钟周期239.5 个 ADC 时钟周期通过设置 ADC 寄存器中的采样时间字段可以选择合适的采样时间。例如对于快速变化的信号可能选择较短的采样时间而对于慢变化的信号较长的采样时间可以提高测量的准确性。采样时间与转换时间的关系采样时间加上转换时间组成了每次 ADC 转换的总时间。转换时间对于 STM32F103 的 ADC 是固定的大约为1.5 个 ADC 时钟周期。因此总的转换时间公式可以表示为总时间采样时间1.5xADC时钟周期STM32CubeMXModeADC_Mode_Independent独立模式模式下双ADC不能同步每个ADC接口独立工作。所以如果不需要ADC同步或者只是用了一个ADC的时候应该设成独立模式多个ADC同时使用时会有其他模式如双重ADC同步模式两个ADC同时采集一个或多个通道可以提高采样率Data Alignment(数据对齐方式)右对齐/左对齐Scan Conversion Mode( 扫描模式 )DISABLE / ENABLE如果只是用了一个通道的话DISABLE就可以了(也只能DISABLE)如果使用了多个通道的话会自动设置为ENABLE。 就是是否开启扫描模式Number OF Conversion(转换通道数)1用到几个通道就设置为几多个通道自动使能扫描模式。Extenal Trigger Conversion SourceRegular Conversion launched by software规则的软件触发调用函数触发即可Timer X Capture Compare X event外部引脚触发Timer X Trigger Out event定时器通道输出触发需要设置相应的定时器设置Rank多个通道时会有多个Rank可以设定每个通道的转换顺序ADC总转换时间如下计算TCONV 采样时间 12.5个周期当ADCCLK14MHz(最大)采样时间为1.5周期(最快)时TCONV 1.512.514周期1μs。因此ADC的最小采样时间1usADC时钟14MHz采样周期为1.5周期下得到定时器触发ADC采样首先设置定时器的计时参数这里设置为1s可以不开启定时器中断ADC的设置中要关闭连续转换模式并且设置为定时器触发这里就是设置定时器触发就是定时器时间一够就触发adc会掉函数这里如果连续转换不关闭会自动连续运行不受定时器触发的控制。所以要disable。最后还要开启ADC中断。在keil中打开工程重写ADC中断的回调函数以指示ADC转换好main函数中添加如下代码检测是否转换好并读取AD值回传下载到板子运行可以看到每1s输出一个ad值说明实现了定时器触发adc转换的功能。ADC的DMA多通道转换如下图选择IN0和IN1两个通道并启用DMA循环模式由于ad值为12位所以这里DMA传输半字就可以了当然也可以传输整个字。然后设置ADC的通道如下图解释一下需要修改的地方scan conversion mode是使能扫描模式因为我们开了两个通道IN0和IN1两个通道都要有转换continuous conversion mode是设置连续转换即一次完成以后自动进行下一次转换Number of conversion设置为2因为我们有两个通道两个Rank下面设置通道号因为我们有两个通道IN0和IN1所以一个rank下选通道0另一个rank下选择通道1。Sampling time采样时间如果资源允许可以选长一点的时间转换结果更准确。然后就可以生成工程代码了。在keil中打开工程主函数中添加代码如下注意这里的HAL_ADC_Start_DMA(hadc1, ADC_Value, 16); 最后这个参数16表示的是DMA搬移数据的次数向ADC_Value及其之后的地址搬移16个数据我们这里设置了2个通道所以从首地址开始填入的是交替的两个通道的数据ADC0、ADC1、ADC0、ADC1…一共16个数。这里设置为16是因为太小的数值很快就会执行完一个循环产生DMA传输中断时间太短的话会频繁产生中断导致一直在中断中执行没有时间执行主循环中的语句。这里是增加搬移数据的次数也可以设置AD采样时间长一些那么每次的转换时间变长也不会产生过多的中断。另外这里的校准函数一定要放在启动ADC、DMA之前否则会占用一个通道之后的AD通道顺序会有问题。ADC中断用法在主循环前启动一次中断转换然后在主循环中检查标志位是否已经完成转换ADC转换完成中断如果已经转换完成则读取结果上传再启动下一次中断转换回调函数中只修改标志位使得主循环中可以检测到已发生了转换完成中断注意上面的主函数里使用了一个100ms的延时主要是因为stm32的ADC转换是很快的如果不使用延时会有大量数据通过串口上传不方便观察。逻辑程序启动转换后CPU 可以去干别的事比如处理其他逻辑、延时当 ADC 转换完成时硬件会发送一个中断信号CPU 自动跳转到 HAL_ADC_IRQHandler(hadc1) 函数HAL 库封装的中断入口该入口函数会清除中断标志并调用回调函数HAL_ADC_ConvCpltCallback。ADC轮询的用法在keil中打开我们先试验轮询模式即软件开始ADC转换后一直等到转换完成后才向后执行代码如下这个代码在初始化ADC之后执行一次校准不执行这一步也可以但精度可能会低一些然后就可以使用ADC轮询转换了只需要三步启动转换、等待转换完成、读取转换数据即可完成一次ADC转换。这里将转换结果通过串口发出来了可以看到右下角的串口调试助手的结果显示。Stm32的adc是12位这里拆成两个字节发送。轮询模式用通俗的例子理解轮询轮询方式你把水壶放到灶上点火后就一直站在旁边盯着水壶不做任何其他事不刷手机、不做饭直到水开了看到冒泡 / 听到响声才关火去做下一步。对比非轮询中断你点火后就去做别的事水壶上装个报警器水开了报警器响触发中断你听到后再回来关火。具体执行逻辑CPU 执行HAL_ADC_Start(hadcl)启动 ADC 转换后立刻执行HAL_ADC_PollForConversion这个函数会让 CPU 停在这里阻塞不断检查 ADC 的 “转换完成标志位”相当于你不断看水壶有没有开只有两种情况会退出这个等待检测到 “转换完成”水开了返回HAL_OKCPU 继续执行后面的 “读取数据、串口发送” 操作等待超过 50ms 还没完成超时比如 ADC 硬件故障返回错误CPU 也会退出等待。轮训方式的多通道采集间断模式扫描模式我开启了通道0、1、2以及内部温度读取通道一共四个通道如果想使用轮训方式并且不使用DMA的多通道采集那么就要配置为【单次模式间断模式】并且将Number Of Discontinuous Conversions为1也就是每个通道分成了一个组配置如下图由于我这里设置间断数为1也就是将4个通道分成了4组那么我每次采集的时候都需要手动去触发ADC采集也就是调用一次HAL_ADC_Start函数完整代码如下我将通道0分别接到3.3V和GND上4通道采集运行效果如下方式二完全轮训完全使用轮训的方式不能使用扫描模式理论上来说多通道需要使用扫描模式而不是完全轮训但是使用STM32CUBEMX配置多通道扫描模式不无法被关闭的所以我们先用STM32CUBEMX配置成一个通道然后读取ADC采集数值的函数是这样uint16_t ADC_Read(uint32_t Channel) { ADC_ChannelConfTypeDef sConfig {0}; sConfig.Channel Channel; /* 通道 */ sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; /* 采样时间 */ if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, HAL_MAX_DELAY); return (uint16_t)HAL_ADC_GetValue(hadc1); } /* uint16_t ADC_Value[5]; ADC_Value[0] ADC_Read(ADC_CHANNEL_1); // 采集并读取通道1 ADC_Value[1] ADC_Read(ADC_CHANNEL_4); ADC_Value[2] ADC_Read(ADC_CHANNEL_5); ADC_Value[3] ADC_Read(ADC_CHANNEL_6); ADC_Value[4] ADC_Read(ADC_CHANNEL_7); */TIMDMA实现多通道采集在不使用DMA的情况下定时器控制ADC进行数据采集只能是单通道如果开启了多通道读取到的ADC采集值只会是最后一个通道的值所以要想使用定时器控制ADC采集多通道必须使用DMACubeMX配置如下使能ADC的DMAADC的触发方式设置为定时器3的触发事件采样时间设置为了55.5个周期对应采样频率为176.47KHz所以定时器3的频率设置要低于176.47KHz。设置定时器3分频系数为72重载值为10得到72MHz / 72分频 / 10 100KHz的定时器3代码如下运行结果如下当然也可以选择进行一组数据例如将32个点为一组数据进行采集设置如下运行结果如下