ADC——电压采集
25.1. ADC简介
ADC即模拟数字转换器,ADC英文全称(Analog-to-digital converter), 是一种用于将模拟电压的连续信号转换为离散的数字信号。 就比如我们可以将我们生活中的温度、压力、声音这样的模拟信号通过ADC转化为我们可以通过单片机处理的数字信号。
RA6M5 有2个ADC单元,每个ADC单元有12位、10位、8位读取数据的格式可以选择,在单元0上有13个ADC通道,而在单元1上有16个ADC通道。 ADC单元具有三种扫描方式分别为:单次描模式、连续扫描模式和分组扫描模式, 对于RA6M5来说ADC单元具有强大的功能,具体我们可以通过ADC特性和ADC的结构框图中分析每个部分的功能。
25.1.1. ADC特性
- 2 个ADC转换单元。
- 可以进行TrustZone安全设置。
- 支持内部温度检测,内部参考电压。
- 逐次逼近型ADC,支持的分辨率:12-bit, 10-bit, 8-bit。
- 转换时间短:0.4 μs/每通道(12-bit ADC、时钟PCLKC (ADCLK)等于50 MHz的条件下)。
- 可启用A/D 数据存储缓冲区是一个环形缓冲区,由16个缓冲区组成,用于顺序存储A/D转换后的数据。
- 自诊断在每次扫描开始时执行一次,在ADC执行生成中的三个参考电压值中选择一个A/D转换值。
25.2. ADC的结构框图
### 25.2.1. 电压输入范围
ADC输入范围为:VREFL- ≤ VIN ≤ VREFH+。 RA6M5的参考电压是由VREFL、VREFH 、AVCC0 、AVSS0 这四个外部引脚决定,且每个单元可以设置不同的参考电压,具体我们可以通过设置不同通道的VREFL、VREFH进行改变。
我们在设计原理图的时候一般把AVSS0和VREFL接地,把AVCC0和VREFH接3V3,得到ADC的输入电压范围为:0-3.3V。 如果我们想让输入的电压范围变宽,可以测试负电压或者更高的正电压,我们可以在外部加一个电压调理电路, 把需要转换的电压抬升或者降压到0~3.3V,这样ADC就可以测量了,为了测量的准确性我们还可以加上磁珠进行滤波。
25.2.2. 工作模式
在ADC单元0中有多达13个模拟输入通道,而在ADC单元1中有多达16个模拟输入通道以及内部的温度传感器输出, 两个ADC单元加起来总共就拥有了29个ADC通道,这么多的ADC通道我们该如何使用它们呢? 在这里我们就可以引入工作模式的概念, 我的单片机上的ADC处在什么样的工作模式进行ADC转换以及我们该如何进行设置。
- 单次扫描模式:在单次扫描下,一次扫描一个或多个指定通道。
- 连续扫描模式:在连续扫描下,一个或多个指定的通道被重复扫描,直到软件设置寄存器ADCSR.ADST位为0。
- 分组扫描模式:将所选择的模拟输入通道上分为A组和b组,然后按组对所选择的模拟输入通道进行一次A/D转换。 A、B组可独立选择扫描启动条件,可独立启动A、B组的A/D转换。
在单次扫描模式下和在连续扫描模式下,都会从最小的扫描通道开始从低到高进行A/D转换。 如果开启了自诊断模式,在每次扫描开始时执行一次, 并转换三个参考电压中选择一个。 每一种转换都有着它的优点和缺点,但具体使用什么模式进行ADC转换,就需要通过我们的项目的需求需要什么样的效果来决定。
25.2.3. 转换过程顺序
有三种扫描转换模式分别为:单次扫描模式、连续扫描模式、组扫描模式。 在扫描中,A/D转换是按顺序对指定通道的模拟输入进行的。
单次扫描模式 :
在单次扫描模式转换期间,我们可以通过ADST为来判断ADC是否处在工作状态,在ADC转换的期间ADST为将一直保持为1,当所有选定通道的ADST转换完成时,将自动设置为0。 然后ADC将进入一个等待状态。
- 当ADCSR.ADST位通过软件触发器、同步触发器输入(ELC)和异步触发器输入被置1的时候,ADC转换开始。 对在ADANSA0和ADANSA1寄存器中选择的ANn通道进行A/D转换,从编号最小的n的通道开始。
- 每当单个信道的A/D转换完成时,A/D转换结果都被存储在关联的A/D数据寄存器(ADDRy)中。
- 当所有选定通道的A/D转换完成时,将生成一个ADC12i_ADI(i = 0,1)中断请求。
连续扫描模式 :
在连续扫描模式下,对指定信道的模拟输入重复执行A/D转换。 这里的ADCSR.ADST位不会自动清除,只要ADCSR.ADST位保持1时就会一直的重复步骤2、步骤3、步骤4,直到ADCSR.ADST位通过软件被置0时ADC单元转换才会停止,之后ADC单元进入等待状态。
- 当ADCSR.ADST位通过软件触发器、同步触发器输入(ELC)和异步触发器输入被置1的时候,ADC转换开始。 对在ADANSA0和ADANSA1寄存器中选择的ANn通道进行A/D转换,从编号最小的n的通道开始。
- 每当单个信道的A/D转换完成时,A/D转换结果都被存储在关联的A/D数据寄存器(ADDRy)中。
- 当所有选定通道的A/D转换完成时,将生成一个ADC12i_ADI(i = 0,1)中断请求。
- 对在ADANSA0和ADANSA1寄存器中选择的ANn通道进行A/D转换,从编号最小的n的通道开始。
组扫描模式 :
在群组扫描模式下,请选择A、B两组,分别选择A、B两组的开始扫描条件,并在不同的时间开始扫描。 另外我们还可以设置优先级,假设我们设置A组优先级高于B组优先级操作时,就可以在B组A/D转换时打断它, 使得A组进行A/D转换,而B组暂停A/D转换。
我们以ELC为列例子:使用GPT作为A组的触发源,并使用A组作为B组的触发源。
- 当ELC0上的GPT触发ELC_ADC(A组)时,A组的ADC开始转换。
- 当组A扫描完成时,将生成一个ADC12i_ADI(i = 0,1)中断。
- B组的扫描由ELC_ADC(A组)开始。
- 当B组扫描完成时,如果ADCSR.GBADIE位为1时将生成一个ADC12i_GBADI(i = 0,1)中断。
25.2.4. 触发源
通道选好了,工作模式也设置好了,那么接下来就需要设置我们的触发源了。 我们可以设置软件来触发ADC、或者通过使用ELC进行触发、甚至我们还可以使用外部中断进行触发。 最终我们的目的是为了使得ADCSR.ADST位被置1,以至于我们可以使用不同的方式进行触发。
下图为我们可以在FSP里选择的模式:
25.2.5. ADC转换时间
25.2.5.1. ADC时钟
ADC输入时钟(转换时钟)ADCLK由PCLKC经过分频产生,最大值是四分频50MHz,ADC允许的最大值是50MHz,当我们使用50 MHz的时候12-bit转换时间为0.4 μs。 PCLKA 和 PCLKC (ADCLK) 的分频比可以设置为 1:1, 2:1, 4:1, 8:1, 1:2, 1:4。
25.2.5.2. 采样时间
扫描转换时间(tSCAN)包括:扫描开始时间(tD)、断开检测辅助处理时间(tDIS)*1、自诊断A/D转换处理时间(tDIAG和tDSD)*2、A/D转换处理时间(tCONV)、扫描结束时间(tED)。
A/D转换处理时间(tCONV)由输入采样时间(tSPL)和逐次逼近转换时间(tSAM)组成。 采样时间(tSPL)用于在A/D转换器中对采样和保持电路充电。 如果由于模拟输入信号源的高阻抗而没有足够的采样时间,或者如果A/ D转换时钟(ADCLK)很慢,可以使用ADSSTRn寄存器来调整采样时间。
由逐次逼近(tSAM)转换的时间如下
- 12位精度需要13个ADCLK
- 状态10位精度需要11个ADCLK
- 状态8位精度需要9ADCLK
选择通道数为n的单次描模式下的扫描转换时间(tSCAN)可确定为:
连续扫描模式下第一个周期的扫描转换时间为单次扫描减去tED的tSCAN。 连续扫描模式下第二次及后续周期的扫描转换时间固定如下:
25.2.6. 数据寄存器
在RA6M5的ADC中的数据寄存器有很多种,用来保存不同描模式下的数据 比如:ADDRn寄存器是16位只读寄存器(n=0~15),用来存储A/D转换结果、ADTSDR寄存器用来保存内部的温度传感器数据寄存器、 ADRD寄存器是用来自动诊断数据寄存器、ADOCDR寄存器是ADC内部参考电压数据寄存器。
我们还可以通过一些寄存器来设置数据的格式比如: ADC转换精度选择由ADCER.ADPRC[1:0]位设置(12位、10位、8位可选)、 ADC数据寄存器格式选择位ADCER.ADRFMT位设置(左对齐或右对齐)
25.2.7. 电压转换
模拟电压经过ADC转换后,是一个12位的数字值,如果通过串口以16进制打印出来的话,可读性比较差,那么有时候我们就需要把数字电压转换成模拟电压,也可以跟实际的模拟电压(用万用表测)对比,看看转换是否准确。
我们一般在设计原理图的时候会把ADC的输入电压范围设定在:0~3.3v,因为ADC是12位的,那么12位满量程对应的就是3.3V,12位满量程对应的数字值是:2^12。 数值0对应的就是0V。 如果转换后的数值为 X ,X对应的模拟电压为Y,那么会有这么一个等式成立: 2^12 / 3.3 = X / Y,=> Y = (3.3 * X ) / 2^12。
25.3. ADC程序设计
25.3.1. 硬件设计
ADC引脚 [](https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter25/chapter25.html#id22 "永久链接至表格")| ADC引脚 | P000 |
| ----------------- | ------ |
25.3.2. 软件设计
25.3.2.1. 新建工程
因为本章节的 ADC 相关实验例程需要用到板子上的串口功能,因此我们可以直接以前面的“19_UART_Receive_Send”工程为基础进行修改。
对于 e2 studio 开发环境:拷贝一份我们之前的 e2s 工程模板 “19_UART_Receive_Send” , 然后将工程文件夹重命名为 “25_ADC” ,最后再将它导入到我们的 e2 studio 工作空间中。
对于 Keil 开发环境:拷贝一份我们之前的 Keil 工程模板 “19_UART_Receive_Send” , 然后将工程文件夹重命名为 “25_ADC” ,并进入该文件夹里面双击 Keil 工程文件, 打开该工程。
25.3.2.2. FSP配置
我们先打开e2 studio软件里面的 Smart Configurator 配置FSP。
双击 configuration.xml 打开配置界面: 然后点开依次点击 Stacks -> New Stack -> Analog -> ADC(r_adc) 来配置ADC模块。
ADC页面的属性介绍
ADC 属性介绍 [](https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter25/chapter25.html#id23 "永久链接至表格")| ADC属性 | 描述 |
| - | - |
| ----------------------------- |
乌因特 | 指定要使用的ADC单元 |
---|---|
再接 | 指定转换分辨率 |
对准 | 指定转换结果对齐方式 |
阅读后清除 | 读取转换结果后自动清除 |
模式 | 模式 |
双扳机装置 | 双触发 |
正常/A 组触发器 | A的触发模式 |
回调 | 回调函数 |
扫描结束中断优先级 | 扫描完成中断优先级 |
模数转换器环形缓冲器 | ADC环形缓冲区 |
配置完成之后可以按下快捷键“Ctrl + S”保存, 最后点右上角的 “Generate Project Content” 按钮,让软件自动生成配置代码即可。
25.3.2.3. ADC初始化
void adc_Init(void)
{
fsp_err_t err;
err = R_ADC_Open(&g_adc0_ctrl, &g_adc0_cfg);
err = R_ADC_ScanCfg(&g_adc0_ctrl, &g_adc0_channel_cfg);
assert(FSP_SUCCESS == err);
}
- R_ADC_Open()为整个外设设置操作模式、触发源、中断优先级和配置。 如果启用了中断,该函数将注册一个回调函数指针,以便在扫描完成时通知用户。
- R_ADC_ScanCfg()配置ADC扫描参数。 通道特定设置是在这个函数中设置的。
25.3.2.4. ADC回调函数
volatile bool scan_complete_flag = false;
void adc_callback(adc_callback_args_t * p_args)
{
FSP_PARAMETER_NOT_USED(p_args);
scan_complete_flag = true;
}
在FSP配置页面注册回调函数以及优先级,我们就可以使用来自ADC的中断回调函数了。
注解
我们通过ADC的中断回调函数来判断ADC是否转换完成。 我们需要定义了一个布尔类型的数据scan_complete_flag来当做ADC读取完成的标志位。 当没有转换完成的时候scan_complete_flag的值一直为false,单ADC触发中断的时候将scan_complete_flag的值变为true。
25.3.2.5. 如果未启用中断
如果未启用中断,则可使用R_ADC_StatusGet() API 用于轮询 ADC 以确定扫描何时完成。 读取 API 函数用于访问转换后的 ADC 结果。 这适用于支持校准的MCU的普通扫描和校准扫描。
25.3.2.6. ADC读取转换后的数值
ADC读取思路,我们在这里调用R_ADC_ScanStart触发相应的adc通道转换,当ADC转换完成之后会将scan_complete_flag标志位变为true。 当我们判断到标志位变为true后我们使用R_ADC_Read()或R_ADC_Read32()读取转换完成的数值。
double adc_read(void)
{
uint16_t adc_data;
double a0;
(void)R_ADC_ScanStart(&g_adc0_ctrl);
scan_complete_flag = false;
while (!scan_complete_flag)
{
;
}
R_ADC_Read(&g_adc0_ctrl, ADC_CHANNEL_0, &adc_data);
a0 = (double)(adc_data*3.3/4095);
return a0;
}
- R_ADC_ScanStart()启动软件扫描或启用扫描的硬件触发器,具体取决于触发器在R_ADC_Open调用中的配置方式。 如果该单元被配置为ELC或外部硬件触发,那么该功能允许触发信号到达ADC单元。 该函数不能控制触发器本身的生成。 如果该单元被配置为软件触发,则该功能启动软件触发扫描。
- R_ADC_Read()从单通道或传感器寄存器读取转换结果,返回的数据为uint16_t型。
- R_ADC_Read32()从单通道或传感器寄存器读取转换结果,返回的数据为uint32_t型。
25.3.2.7. hal_entry函数
void hal_entry(void)
{
err = R_SCI_UART_Open(&g_uart4_ctrl, &g_uart4_cfg);
printf("开始读取ADC的数值\\r\\n");
adc_Init();
while(1){
printf("a0=%f\\r\\n",adc_read());
R_BSP_SoftwareDelay(1000,BSP_DELAY_UNITS_MILLISECONDS); //大概1秒钟读取一次
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
25.3.3. 下载验证
用USB线连接开发板“USB TO UART”接口跟电脑,在电脑端打开串口调试助手,把编译好的程序下载到开发板。 在串口调试助手可看到ADC引脚读出的模拟数值。
评论
查看更多