No.9 ADC的说明
或许还有很多人会有跟我一样的疑惑,那我来说说这些问题吧。
1.我们到底要配置那些东西啊?
2.我们常用的是软件触发还是硬件触发?
3.硬件触发都有哪些触发源?
4.FIFO到底怎么用,怎么设置?
5.中断不同情况下怎么产生的?
6.APCTL1这个引脚控制寄存器到底干吗用?
7.多个通道能一次配置吗?
这些问题或许和你想的不一样?但是下面的解答或许能给你提供一些灵感,解决你的疑惑。
答:问题的解答并不是一个一个的,接下来的唠叨就涵盖了所有的问题答案。
我们需要配置的东西有很多。
那我们从一个配置ADC_Init()来分析吧。
- /*************************************************************************************************
- * Function Name : AdcInit
- * Description : ADC初始化
- * Input : None
- * Output : None
- * Return : None
- ***********************************************************************************Author:liming*/
- void AdcInit(void)
- {
- ADC_ConfigType ADC_ConfigStructure={0};
- PMC->SPMSC1 |= 0X01; // 开启bandgap
- ADC_ConfigStructure.sSetting.bCompareAndEn =0; // 比较模式关闭
- ADC_ConfigStructure.sSetting.bCompareEn = 0; // 比较模式关闭
- ADC_ConfigStructure.sSetting.bCompareGreaterEn =0; // 比较模式关闭
- ADC_ConfigStructure.sSetting.bContinuousEn =0; // 连续转换模式
- ADC_ConfigStructure.sSetting.bFiFoScanModeEn =0; // FIFO扫描模式关闭
- ADC_ConfigStructure.sSetting.bHardwareTriggerEn =0; // 硬件触发模式关闭
- ADC_ConfigStructure.sSetting.bLongSampleEn =0; // 长采样模式
- ADC_ConfigStructure.sSetting.bLowPowerEn = 0; // 高速度
- ADC_ConfigStructure.sSetting.bIntEn =1; // 中断使能
-
- ADC_ConfigStructure.u16PinControl =0X01; // AD0 端口PA0禁止端口控制器控制
- ADC_ConfigStructure.u8ClockSource =CLOCK_SOURCE_BUS_CLOCK_divIDE_2; // 总线2分频时钟
- ADC_ConfigStructure.u8ClockDiv =ADC_Adiv_divIDE_8; // 8分频
- ADC_ConfigStructure.u8FiFoLevel =ADC_FIFO_LEVEL3; // fifo深度3
- ADC_ConfigStructure.u8Mode = ADC_MODE_8BIT; // 8bit模式
- ADC_SetCallBack(ADC_IRQHandler); // 设置中断回调函数
- ADC_Init(ADC,&ADC_ConfigStructure); //
- }
可以看到有比较模式,连续转换,FIFO扫描,触发方式,转换速度,采样模式,中断开关。
下面还有什么端口屏蔽,时钟选择和时钟分频,FIFO深度,采样精度。
或许有些人一看到这些就蒙了,这么多的配置都有什么关系啊!头大。
然而还有更多官方说明书1.12版本在这个模块都没写出来的配置。
首先默认情况下bandgap是没有开起来的。
刚开始不知道的时候,我要测试ADC,想想也就对比bandgap和温度最容易了,外部什么都不用接,如果bandgap正确,那么获取的温度也没问题。
结果,发现bandgap是0.5V这有点奇怪,哪有这么低的bandgap?问Navota说是1.12v,那问题来了,我的怎么不对呢?这个时候我就去接了变阻器测试端口PA0,结果发现测量值和实际用表测的相差不大,说明我的ADC程序没问题,那为什么bandgap获取的电压就不对呢。好久之后另外一为Navota告诉要用bandgap需要打开它。在PMC里面。我去!这,ADC模块这里怎么只字未提?
好吧,按照他说的我找到了这个寄存器,并进行设置,PMC->SPMSC1 |= 0X01; OK,bandgap稳定在1.15V左右。
其次如果你使用了硬件触发模式,还有一个寄存器(ADHWT),你只看本模块是怎么也找不到它在哪里的,实际上它在SIM->SOPT寄存器。
原本你只知道可以使用硬件触发,都不知道哪些是可以触发的硬件源,找到这个寄存器这些都清楚了。
上面的一段回答了问题1和问题3。
FIFO 怎么用?是我最开始迷茫的东西。奇怪输入通道FIFO只有8个输出FIFO却有12个。这不是对应关系啊!
是这样的,如果我们要转换单个通道,比如只要bandgap,那可以用软件触发和硬件触发,软件 触发就是我们写入一次通道号,触发一次转换。然后就会得到一个转换完成的中断(ADC中断开启的情况下)。这个时候我们就可以拿转换完成后的值使用了。硬件就是上面的那些触发源产生的。也可以说基本都是定时产生的硬件中断。
只要一个通道我们就可以不使用FIFO,直接
ADC_ConfigStructure.u8FiFoLevel =ADC_FIFO_DISABLE;
这个时候每当我们 设置一次通道
ADC_SetChannel(ADC,ADC_CHANNEL_AD23_BANDGAP);
就会得到一个中断,我们就能从转换结果寄存器把结果读出来了。这个时候的中断是一个转换完成产生了。
那如果我要转换三个通道呢?
一个方法就像上面一样,一个通道一个通道的setchannel 然后一个一个的等待中断的到来。
另外还有一个方法就是使用FIFO我们一次告诉ADC我要转换三个通道。
例如我要转换bandgap,tempsensor和PA0。
那我就要设置 FIFO 的深度是3
ADC_ConfigStructure.u8FiFoLevel =ADC_FIFO_LEVEL3;
在初始化的地方
AdcInit(); // ADC初始化里面有开启我们的ADC中断ADC_SetChannel(ADC,ADC_CHANNEL_AD23_BANDGAP);//第一个通道
ADC_SetChannel(ADC,ADC_CHANNEL_AD22_TEMPSENSOR);//第二个通道
ADC_SetChannel(ADC,ADC_CHANNEL_AD0);//第三个通道
这样它会在三个都转换完成后产生一次中断。
那有疑问了,一次中断我们的三个结果都放哪里去了?很好想到了转换结果FIFO。对就是在里面。只需要按次序去读转换结果寄存器,FIFO里面的值就会一个一个的读出来了。
这里就牵扯到了实际的外部端口PA0,因为bandgap和tempsensor都是内部通道。PA0是我们的一个GPIO我们要使用的它的模拟输入你会想到去配置GPIO的相关寄存器配置成输入,NONONO,这里它是复用了,我们可以直接配置。就是那个APCTL1,16个外部ADC端口都可以用它来控制,当响应的引脚寄存器配置为1时,这个引脚我们就只供给我们ADC使用了,你去读取它的逻辑值或者置位清零对应引脚的输出寄存器时它都处于高阻态。也就是说我们要使用这些端口作为ADC的输入时最好把它普通端口的功能给禁掉以免影响我们的采样。
上面回答了问题 4,5,6。
中断在我们使用FIFO多个通道的时候它是各个通道都转换完才产生一次,中间的单个通道转换完成会自动放在结果FIFO中。我们不使用FIFO进行单个通道转换就会每转换完一次产生一次中断,记得及时取出转换结果啊。
上面都没讲过循环连续采样啊!
不是说了吗,连续采样其实就是一个定时器到了采样一次,产生一次中断,我们要在中断里把结果及时取出,要不然就会被下次转换结果覆盖。
当然硬件触发也有好玩的地方,就是当你是多通道时肯定是要用FIFO了,结果和软触发一样去结果FIFO读;
单通道就好玩了,一次触发如果不适用FIFO,中断后你只能读到一个值,如果使用了FIFO你就可以从结果FIFO连续读出来12个。也就是说单通道采用FIFO是获取了12次的转换结果才产生的中断。
到这里我们回答第二个问题,常用的是软触发还是硬触发呢?我觉得这个多余了问题。
如果我都是多通道,每次想要的时候获取一次,可以使用软触发,就能得到了。当然可以使用硬触发只是我不要的时候,结果我就不读了,让它一直去覆盖吧。
如果我是单通道,或许硬触发一次的12个结果便于做平均呢!
最后一个问题,能一次设置多个通道吗?呵呵了,都讲到这里了,你还不知道吗?
你要多通道就要用FIFO,用FIFO就要一个一个按顺序的往通道FIFO写入通道号,这样结果也是按照你的顺序出来的。所以一次不能设置多个通道。
下一篇再讲我的ADC使用吧。这里只是一个说明。
还有一个我没搞懂的问题就是FIFO扫描模式是什么意思,知道的说一声吧。