STM32F3系列 ADC 单端采样(基于LL库)

  • 芯片型号:STM32f303RBT6
  • 开发软件:MDK5 & CubeMX & VS Code

目录

引言

STM32F303系列单片机一般具有多个12位逐次逼近型(Successive approximatio)模数转换器(ADC,analog-to-digital converter)。STM32的ADC功能很多:单端采样、差分采样、主从模式、双ADC模式、注入模式等。本文作为学习笔记,记录最简单的单端(single-end)模式.

1 基础知识

1.1ADC转换基本流程



上图是STM32ADC的框图,黑色箭头我自己加的开关。其转换流程大概可以简略为:

  1. 接收到触发信号,摁下开关
  2. 外部电压经过外部电阻(\(R_{AIN}\)),杂散电容(\(C_{parastitic}\))、ADC内部电阻(\(R_{ADC}\)),给采样电容\(C_{ADC}\)充电。
  3. 充电完成,松开开关,转换核心开始将电容上的电压值转为数字信号。
  4. 转换完成,转换结果存入ADC的数据寄存器中。

1.2 时钟树

STM32F3系列的单片机的ADC时钟有两路,一路为同步时钟(黑色),一路为异步时钟(蓝色)。异步时钟除了比同步时钟具有更多的分频选择,其他没有大的区别,其时钟最高频率也是相同的。

但是建议采用同步时钟,使用异步时钟时或许可能转换会出现问题,我也不知道什么原因。

1.3 关键参数

1.3.1 位数

ADC一般可以分为10bit、12bit、16bit等,这个bit就是指的位数。位数的含义就是能把参考电平分为2的多少次方份。

比如:10bit的ADC可以把参考电平分为1024份; 12bit的ADC可以把参考电平分为4096份。若是参考电压为3.3V,则10bitADC可以分辨的最小电压为\(3.3/(2^{10}) = 3.22mV\),12bitADC可以分辨的最小电压为\(3.3/(2^{12}) = 0.806mV\)。

由此可见,ADC位数越大,其分辨率越高,采集到的电压相对越准确。

1.3.2 触发信号

触发信号对于ADC转换流程中的第一步,即告诉ADC什么时候开始转换。触发信号有很多种,常用的有:软件触发、定时器信号触发和外部触发等。

1.3.3 采样时间

采样时间对应ADC转换流程中的第二步,即开关摁下多久,外部信号对\(C_{ADC}\)充电多长时间。一般来说采样时间以ADC时钟周期\(T_{ADC}\)的倍数,如:\(1.5T_{ADC}\)、\(2.5T_{ADC}\)、\(19.5T_{ADC}\)等。一般来说采样时间越长,信号采样越准确,一般是根据外电阻的大小来选择采样时间,具体采样时间选择可以参照下表:



例如:外电阻为5k,外电阻介入2.7k~8.2k之间,则可以选择的采样时间为\(61.5T_{ADC}\)

1.3.4 转换时间

转换时间指的是ADC将制定电压转为为数字信号所用的时间,这个时间一般不可以控制,与ADC的时钟周期有关,时钟周期越长则转换时间越小。

2 CubeMx 配置步骤

2.1 确定输入通道



选取ADC1-IN1通道作为检测通道,选择单端模式Single-ended。

2.2 配置ADC



重要参数介绍:

  • Mode:independence即独立模式;
  • Clock Prescale:选取同步时钟最为ADC的时钟,分频系数为1,即ADC时钟为72M
  • Resolution(分辨率):选取12bit
  • Data Alignment(数据对其):一般选右对齐
  • End of Conversion selection(转换完成信号):这个参数指定了何时ADC触发DMA和中断,有两个参数End of single conversion(EOC) 与 End of sequence of conversion(EOS),即单次转换完成和顺序转换完成,由于我们只有一个通道选择这两个一样的,本次选择EOC。
  • OverRun behavior(覆写行为):若使能这个功能,则在ADC上次数据还没有读取的时候,新的输出产生时,会直接覆写上次数据。
  • Lower Power Auto Wait(低功耗自动等待):用于低功耗的功能。
  • Enable Regular Conversations(使能常规转换组):字面意思,使能常规组转换。
  • Number of Conversion(转换数量):需要转换的信号有几个。
  • External Trigger Conversion Source(外部触发源):触发信号是什么?软件、或定时器等。
  • External Trigger Conversion Edge(外部触发边沿):指定触发类型,上升沿触发、或下降沿触发等
  • Rank 1:
    • Channal(通道号):对应Channel1
    • Sampling Time(采样时间):对应上文的采样时间;
    • Offset Number(通道偏移):指定那个通道需要数据偏移。
    • Offset(数值偏移):即在采集到的数据减去一个数字偏置。
  • ADC_Injected Conversions(ADC注入模式):暂时不需要。
  • Analog Watchdog1~3():看门狗功能,暂时不需要。

2.3 输出设置

使用LL库,剩下的按照常规配置就行。

2.4 MD5 设置

勾选Reset and Run,否则下载程序后单片机不会自动运行,复位后才会运行。

3 程序解读

3.1 ADC初始化

void MX_ADC1_Init(void)
{ /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; /* Peripheral clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12); // 使能ADC时钟 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA); // 使能GPIOA时钟
/**ADC1 GPIO Configuration
PA0 ------> ADC1_IN1
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Common config
*/
ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B; // 12bit分辨率
ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;// 数据右对齐
ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;// 不使用低功耗模式
LL_ADC_Init(ADC1, &ADC_InitStruct);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;// 软件触发
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;// 不使用扫描模式
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;// 不使用断续模式
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;// 单次触发单次转换
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_LIMITED;// 不使用DMA
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN; // 数据覆写使能
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_SYNC_PCLK_DIV1;// 使能内部时钟1分频作为ADC时钟
ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;// ADC采取独立模式
LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct); /* Enable ADC internal voltage regulator *//*使能ADC内部的稳压器*/
LL_ADC_EnableInternalRegulator(ADC1);
/* Delay for ADC internal voltage regulator stabilization. */
/* Compute number of CPU cycles to wait for, from delay in us. */
/* Note: Variable divided by 2 to compensate partially */
/* CPU processing cycles (depends on compilation optimization). */
/* Note: If system core clock frequency is below 200kHz, wait time */
/* is only a few CPU processing cycles. */
uint32_t wait_loop_index;
wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
while(wait_loop_index != 0)
{
wait_loop_index--;
} /** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_1); // 设置通道1转换次序为1
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_1, LL_ADC_SAMPLINGTIME_181CYCLES_5);// 采样时间为181.5个ADC周期
LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_1, LL_ADC_SINGLE_ENDED);// 采样模式为单端采样
/* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ }

3.2 校准和启动ADC

上述配置完后,使用LL库还需要一些额外的代码,ADC才可以正常工作。

void Mx_ADC_Start(void)
{
uint8_t TimeDelta = LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES; LL_ADC_StartCalibration(ADC1,LL_ADC_SINGLE_ENDED); // 开始校准
while(LL_ADC_IsCalibrationOnGoing(ADC1)) // 等待校准完成
;
LL_ADC_SetCalibrationFactor(ADC1,LL_ADC_SINGLE_ENDED LL_ADC_GetCalibrationFactor(ADC1,LL_ADC_SINGLE_ENDED));// 将校准向量写 ADC1中 while(TimeDelta > 0) // 校准后延时
{
TimeDelta--;
}
LL_ADC_Enable(ADC1); // 使能ADC
}

3.3 主函数配置

主函数就比较简单,使用软件触发ADC转换,待ADC转换完成后,使用窗口将转换数据经串口上传到上位机。串口程序用的为匿名上位机。

while (1)
{
LL_ADC_REG_StartConversion(ADC1); // 用软件触发ADC转换
while(LL_ADC_REG_IsConversionOngoing(ADC1)) // 等待ADC转换完成
;
sent_data(LL_ADC_REG_ReadConversionData12(ADC1),0,0,0);// 使用匿名上机 ADC数据发送到电脑
while(count) // 适当延迟
{
count--;
}
}

3.4 匿名上位机程序

uint8_t BUFF[30];

void sent_data(uint16_t A,uint16_t B,uint16_t C,uint16_t D)
{
int i;
uint8_t sumcheck = 0;
uint8_t addcheck = 0;
uint8_t _cnt=0;
BUFF[_cnt++]=0xAA;//帧头
BUFF[_cnt++]=0xFF;//目标地址
BUFF[_cnt++]=0XF1;//功能码
BUFF[_cnt++]=0x08;//数据长度
BUFF[_cnt++]=(A&0x00ff);//数据内容,小段模式,低位在前
BUFF[_cnt++]=(A&0xff00)>>8;//需要将字节进行拆分,调用上面的宏定义即可。
BUFF[_cnt++]=(B&0x00ff);
BUFF[_cnt++]=(B&0xff00)>>8;
BUFF[_cnt++]=(C&0x00ff);//数据内容,小段模式,低位在前
BUFF[_cnt++]=(C&0xff00)>>8;//需要将字节进行拆分,调用上面的宏定义即可。
BUFF[_cnt++]=(D&0x00ff);
BUFF[_cnt++]=(D&0xff00)>>8;
//SC和AC的校验直接抄最上面上面简介的即可
for(i=0;i<BUFF[3]+4;i++)
{
sumcheck+=BUFF[i];
addcheck+=sumcheck;
}
BUFF[_cnt++]=sumcheck;
BUFF[_cnt++]=addcheck; for(i=0;i<_cnt;i++)
{
while ((USART1->ISR & 0X40) == 0)
; /* 等待上一个字符发送完成 */
USART1->TDR=BUFF[i];
}//串口逐个发送数据
}

4 实验波形

使用函数信号发生器,产生频率为1kHz,幅值为3V的正弦波,经两个2k电阻分压后传入ADC采集通道,电路图如图:



实验波形在匿名上位机上显示如图:



可以看到:

  • 波形为正弦波
  • 最高值 1863 对应 1.501V

    证明ADC采集正确。

5 总结

至此完成了STM32最简单的ADC单端采样,STM32的ADC还有很多其他功能,待之后有时间再记录。本文记录难免有错误,如有错误,欢迎指出。

STM32F3系列 ADC采样单端采样模式(基于LL库)的更多相关文章

  1. 差分ADC到单端ADC

    单片机可以处理单端ADC(不在电压范围内要进行分压),也可以处理差分ADC(但需要双路输入).差分信号在传输过程中抗共模干扰能力很强,所以传输中都用差分传输,到ADC时可以差分也可以单端(需要放大器处 ...

  2. STM32 ADC基础与多通道采样

    12位ADC是一种逐次逼近型模拟数字数字转换器.它有多达18个通道,可测量16个外部和2个内部信号源.ADC的输入时钟不得超过14MHZ,它是由PCLK2经分频产生.如果被ADC转换的模拟电压低于低阀 ...

  3. STM32 ADC多通道规则采样和注入采样

    layout: post tags: [STM32] comments: true 文章目录 layout: post tags: [STM32] comments: true 什么是ADC? STM ...

  4. 详解APM数据采样与端到端

    高驰涛 云智慧首席架构师 据云智慧统计,APM从客户端采集的性能数据可能占到业务数据的50%,而企业要做到从Request到Response整个链路中涉及到的所有数据的准确采集,并进行有效串接,进而实 ...

  5. 《动手学深度学习》系列笔记 —— 语言模型(n元语法、随机采样、连续采样)

    目录 1. 语言模型 2. n元语法 3. 语言模型数据集 4. 时序数据的采样 4.1 随机采样 4.2 相邻采样 一段自然语言文本可以看作是一个离散时间序列,给定一个长度为\(T\)的词的序列\( ...

  6. webpack4 系列教程(十五):开发模式与webpack-dev-server

    作者按:因为教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步<webpack4 系列教程(十五):开发模式与 webpack-dev-server>原文地址.更欢迎来我的 ...

  7. SEPIC 单端初级电感转换器 稳压器 -- Zeta 转换器

    single ended primary inductor converter 单端初级电感转换器 SEPIC(single ended primary inductor converter) 是一种 ...

  8. 单端通用ISM频段接收器 Si4313

    Si4313芯片是单端通用ISM频段接收器,工作频率为240-960MHz,可编程接收频率带宽为2.6-260kHz,接收灵敏度为-118dBm,数据速率为0.2-128kb/s,采用FSK.GFSK ...

  9. hive单用户多点模式配置

    简介 单用户多点模式也称远程服务模式,用户非java客户端访问元数据库,在服务端启动MetaStoreServer,客户端利用Thrift协议通过MetaStoreServer访问元数据库. mysq ...

  10. docker启动单节点server模式的consul | Bitdoom

    原文:docker启动单节点server模式的consul | Bitdoom docker启动单节点server模式的consul 2017-09-07 环境:MacOSX, consul_0.9. ...

随机推荐

  1. python的jsonpath 提取器

    jsonpath 解析 接下来讲一个非常强大并且方便的 jsonpath 专门用于 json 解析,解决路径深的老大难问题!先安装依赖包 pip install jsonpath 学习jsonpath ...

  2. mysql高级进阶(存储过程、游标、触发器)

    废话不多说,直接进入正题... 一.存储过程 a.概述 存储过程可以看成是对一系列 SQL 操作的批处理: 使用存储过程的好处 代码封装,保证了一定的安全性: 代码复用: 由于是预先编译,因此具有很高 ...

  3. 使用LaTex添加公式到Hexo博客里

    代码编辑器,强烈推荐使用微软的 VS code,相比Atom开启迅速,使用方便,扩展丰富 第一步: 安装Kramed hexo 默认的渲染引擎是 marked,但是 marked 不支持 mathja ...

  4. REST API 设计最佳实践:为什么不要在URI中使用动词?

    总的来说,HTTP协议出现以来Web服务也就存在了.但是,自从云计算出现后,才成为实现客户端与服务和数据交互的普遍方法. 作为一名开发者,我很幸运能够在工作中使用一些仍然存在的SOAP服务.但是,我主 ...

  5. PlayWright(二十)- Pytest之conftest文件

    1.介绍与使用场景 conftest.py 这个是什么呢?   顾名思义,他就是一个文件,那这个文件是干什么用的呢?   在我们上文中,用了fixture函数是直接在用例的文件里定义的,那不能我们所有 ...

  6. 2023年郑州轻工业大学校赛邀请赛yy

    这也是第一次参加几个人以组队的形式来进行答题.评比,而且这是一场线下赛,收获更是很多.题目一共有十二道,一共五个小时,我们上来也是没有头绪先做哪个,可能三个人的思路不太一样,我们最终先写了第一题,写出 ...

  7. 【ElasticSearch】大数据量情况下的前缀、中缀实时搜索方案

    简述 业务开发中经常会遇到这样一种情况,用户在搜索框输入时要实时展示搜索相关的结果.要实现这个场景常用的方案有Completion Suggester.search_as_you_type.那么这两种 ...

  8. jquery解决跨域问题

    在Ajax请求的url不是本地或者同一个服务器下面的URI,最后虽然请求显示为200,但是不会返回任何数据,事实上简单来说请求同一个域名下的url或者说用不带http的绝对路径和相对路径请求是没有任何 ...

  9. 最全面的JAVA多线程知识总结

    ​ 背景: 2023年经营惨淡,经历了裁员就业跳槽再就业,在找工作过程中对于知识的梳理和总结,本文总结JAVA多线程. 应用场景: 需要同时执行多个任务或处理大量并发请求时, 目前常用的场景有: We ...

  10. .net通用RSA加密工具类

    目前最流行的加密算法莫过于RSA了,以下是我们.net/.net core C#生成环境用的RSA加密工具类,在此分享给大家. using System; using System.IO; using ...