简介
在S32K中,不同的芯片型号支持的ADC通道不同,S32K144UAVLL有两个ADC,每个ADC有12位、10位、8位和6位可选,每个ADC有16个外部通道。学习ADC的第一步是要掌握ADC的功能框图,对ADC的工作过程和编程过程有个整体的了解。
ADC功能框图
对ADC的配置主要涉及三种寄存器,控制状态寄存器、触发寄存器和数据寄存器。控制状态寄存器主要有SC2
、SC3
、CFG1
和CFG2
;触发寄存器主要有SC1
和SC2
;数据寄存器主要有Rn
。
电压输入范围
ADC的输入电压范围为:,ADC的输入范围取决于4个参考电源 。
ADC的电压输入范围取决于4个参考电源,我们在设计原理图的时候一般把 和 接地,把 和 接3.3V,可以得到ADC的输入范围是0~3.3V。在设计原理图时,应该把ADC设置为可以配置成外用输入电压参考源,以备不时之需,如下图所示。
如上图所示,有三个选项。
- 焊接上R103,拆掉R99,R109和D7,电压参考源为VDD_MCU,一般为3.3V
- 焊接上D7和R99,拆掉R103和R109,R99进行分压之后为3V
- 焊接上R109,拆掉R103,R99和D7。这里的是外部输入电压引脚,可以配置为外部电压参考源
时钟配置
可以选择4个时钟源ALTCLKx
之一来作为ADC模块的时钟源。ADC具有多个时钟源。 选择取决于配置PCC_ADCn[PCS]
。 分频器的配置应使ADC转换时钟频率在ADC要求的有效范围内(请参见数据手册)。如下图所示为ADC的时钟分配图。
如图所示,ADC的时钟源输入通过PCC_ADCn[PCS]
来选择SOSCDIV2_CLK
、SIRCDIV2_CLK
、FIRCDIV2_CLK
和SPLLDIV2_CLK
四种,然后经过ADC_CFG1[ADIV]
来时钟分频,最后产生ADC的输入时钟ADCK
,ADCK
由数据手册可得,最大50MHZ,最小2MHZ,典型值为40MHZ,如果超过最大频率,ADC的转换结果会变得不可靠。ADC时钟设置流程如下:
- 设置
PCC_ADCn[PCS]
:选择时钟源 - 设置
ADC_CFG1[ADICLK]
:选择时钟输入 - 设置
ADC_CFG1[ADIV]
:选择时钟分频
转换时间
数据手册显示,ADC的转换时间取决于:
ADC_CFG2[SAMPLTS]
确定的采样时间- MCU的Bus总线时钟频率
ADC_CFG1[MODE]
确定的转换模式- 即ADC的转换时钟频率
由数据手册可得,ADC的总转换时间=采样相位时间(SMPLTS设置的再+1)+保持相位(1个ADC周期)+比较相位时间(8位模式=20个ADC周期,10位模式=24个ADC周期,12位模式=28个ADC周期)+单个或第一个连续时间加法器(5个ADC周期+5个总线时钟周期)
例:设置BUS时钟为40MHZ,ADC时钟选择40MHZ,12位ADC,采样周期选择255个ADC周期,计算ADC的一次转换时间为:
触发设置
ADC触发设置主要包括寄存器SC2
和SC1
。ADC支持软件触发和硬件触发两种,软件触发就是在ADC转换完毕之后产生中断;在硬件触发方面,ADC模块具有可选的异步硬件转换触发器ADHWT
,主要通过PDB来触发。触发设置可见PDB触发ADC。设置ADC_SC2[ADTRG]
来选择是硬件触发还是软件触发。触发方式的设置流程如下:
- 设置
ADC_SC2[ADTRG]
:选择触发方式 - 设置
ADC_SC1n[ADCH]
:选择ADC通道 - 如果上一步使用了具有硬件交错功能的通道,则需要设置
SIM_CHIPCTL[ADC_INTERLEAVE_EN]
位 - 设置
ADC_SC1n[AIEN]
:开启中断触发(软件触发模式下)
获得ADC数据
最后转换成功后,ADC的转换结果会被存放在ADC_Rn
寄存器,ADC_Rn
寄存器对应的是ADC_SC1n
寄存器,比如ADC_SC1A
的数据会存放在ADC_RA
,ADC_SC1B
的数据会存放在ADC_RB
,以此类推。
在不同的转换位数下,ADC_Rn
寄存器的数据位数也不同,如下图所示。
注:ADC_Rn
寄存器是只读的
电压转换
模拟电压经过ADC转换后,是一个相对精度的数字值,如果通过串口以16进制打印出来的话,可读性比较差,故需要把数字电压转换为模拟电压,也可以根据实际的模拟电压(用万用表测)对比,看看转换是否准确。
在设计原理图时,一般会把ADC的输入电压范围定在0~3.3V,若设置的ADC为12位,那么12位满量程对应的就是3.3V,12位满量程对应的数字值是: 。数值0对应的就是0V。如果转换后的数值为X,X对应的模拟电压为Y,那么:
实例:ADC触发中断
功能概述
- 平台:S32K144
现在使用S32K144的ADC0通道8,软件触发模式下,转换结束后触发中断。
编程顺序
- 初始化ADC0的时钟
- 初始化ADC0的位数
- 选择ADC0的通道,开启中断
- 如果该通道有硬件交错功能,需要选择是哪个ADC通道
- 选择软件触发
- NVIC开启ADC中断
// ADC初始化函数
void ADC0_Init(void)
{
PCC->PCCn[PCC_PORTA_INDEX] |= PCC_PCCn_CGC_MASK; /* Enable clock for PORTA */
SIM->CHIPCTL |= (1 << 2); /* 具有硬件交错功能,选择PTB13 */
PCC->PCCn[PCC_ADC0_INDEX] &= ~PCC_PCCn_CGC_MASK;
PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_PCS(6); /* PCS=6: 选择内核时钟80MHZ */
PCC->PCCn[PCC_ADC0_INDEX] |= PCC_PCCn_CGC_MASK;
ADC0->CFG1 = ADC_CFG1_ADIV(2) | /* ADIV=2:输入内核时钟两分频=40MHZ */
ADC_CFG1_MODE(1) | /* MODE=1: 12位ADC */
ADC_CFG1_ADICLK(0); /* ADICLK=0: 默认选择PCC分配的时钟 */
ADC0->SC1[0] = ADC_SC1_AIEN_MASK | /* AIEN=1: 开启中断触发 */
ADC_SC1_ADCH(8); /* ADCH=8: 序号0选择通道8 */
ADC0->SC2 |= ADC_SC2_ADTRG(0); /* ADTRG=0: 开启软件触发 */
ADC0->SC3 = 0;
S32_NVIC->ICPR[1] = 1 << (39 % 32); /* 注册ADC0中断 */
S32_NVIC->ISER[1] = 1 << (39 % 32); /* 使能ADC0中断 */
S32_NVIC->IP[39] = 0xA0; /* 优先级为10 */
}
/*
* \brief adcChan通道开启一次ADC转换
*
* \param adcChan 需要进行ADC转换的通道
*
*/
void convertAdcChan(uint16_t adcChan)
{
ADC0->SC1[0] &= ~ADC_SC1_ADCH_MASK; /* Clear prior ADCH bits */
ADC0->SC1[0] = ADC_SC1_ADCH(adcChan); /* Initiate Conversion*/
}
/*
* \brief ADC转换判断函数
*
* \return >0 转换已完成
* \return =0 转换未完成
*
*/
uint8_t adc_complete(void)
{
return((ADC0->SC1[0] & ADC_SC1_COCO_MASK) >> ADC_SC1_COCO_SHIFT);
}
/*
* \brief ADC值转换函数
*
* \return 返回转换后的ADC电压值
*
*/
uint32_t read_adc_chx(uint8_t ChanIndex)
{
uint16_t adc_result = 0;
adc_result = ADC0->R[ChanIndex];
/* For SW trigger mode, R[0] is used */
return(uint32_t)((5000 * adc_result) / 0xFFF);
/* Convert result to mv for 0-5V range */
}
void ADC0_IRQHandler(void)
{
adcRawValue1 = read_adc_chx(0);
adcRawValue2 = read_adc_chx(1);
adcConvDone = true;
}