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. 【SpringBoot】条件装配 @profile

    profile 使用说明: @profile注解的作用是指定类或方法在特定的 Profile 环境生效,任何@Component或@Configuration注解的类都可以使用@Profile注解. ...

  2. Java面试题全集(一)

    JDK.JRE.JVM之间的区别 JDK(Java SE Development Kit),Java标准开发包,它提供了编译.运⾏Java程序所需的各种⼯具和资源,包括Java编译器.Java运⾏时环 ...

  3. PTA 21级数据结构与算法实验5—树和二叉树

    目录 7-1 还原二叉树 7-2 朋友圈 7-3 修理牧场 7-4 玩转二叉树 7-5 根据后序和中序遍历输出先序遍历 7-6 完全二叉树的层序遍历 7-7 列出叶结点 7-8 部落 7-9 建立与遍 ...

  4. Avalonia项目打包安装包

    Avalonia项目打包安装包 要将 Avalonia 项目打包成安装包,你可以使用 Avalonia 发布工具来完成 1.创建一个发布配置文件 在你的 Avalonia 项目中,创建一个发布配置文件 ...

  5. 介绍一个简易的MAUI安卓打包工具

    介绍一个简易的MAUI安卓打包工具 它可以帮助进行MAUI安卓的打包. 虽然也是用MAUI写的,但是只考虑了Windows版本,mac还不太会. 没什么高级的功能,甚至很简陋,它能做的,只是节省你从M ...

  6. Unity UGUI的PhysicsRaycaster (物理射线检测)组件的介绍及使用

    Unity UGUI的PhysicsRaycaster (物理射线检测)组件的介绍及使用 1. 什么是PhysicsRaycaster组件? PhysicsRaycaster是Unity UGUI中的 ...

  7. while(1) ; CPU 会一直等下去吗

    标题答疑 不会,计算机从外部设备读取数据到存储器,每读取1word的数据,CPU对外设状态进行一次检查. 可能有小伙伴看到这就要退出了,别急,看下去或许会有收获. 首先解决第一个问题:一个字是多少字节 ...

  8. 零基础入门——从零开始学习PHP反序列化笔记(一)

    靶场环境搭建 方法一:PHPstudy搭建 GitHub地址 https://github.com/mcc0624/php_ser_Class 方法二:Docker部署 pull镜像文件 docker ...

  9. vim 配色调整

    ~/.vimrc " Configuration file for vim set modelines=0 " CVE-2007-2438 set number " se ...

  10. npm install 下载依赖的过程

    首先检查.npmrc文件,项目级.npmrc文件>用户级的.npmrc文件>全局性的.npmrc文件>npm内置的.npmrc文件 是否有lock文件 没有lock文件 从npm远程 ...