作者:曾Jerry 或 大橙员, 250359225@qq.com
学习KEA之ADC之一:基本介绍
学习KEA之ADC之二:查询方式
学习KEA之ADC之三:中断方式
学习KEA之ADC之四:FIFO
学习KEA之ADC之五:自动比较功能
FIFO的意义
要是不使用FIFO功能的话,在多路采集时,ADC会频繁进入中断,这样对MCU来说是个负担,所以需要开启FIFO功能,这样在所有通道采集完后才进入一次中断,提高了效率。
FIFO有关寄存器
当ADC_SC4[AFDEP]不为0时,便使能了FIFO。 ADC_SC4[AFDEP]也决定了FIFO的深度,其中这个深度最大是8。
FIFO的模拟输入通道 和 结果通道 是由ADC_SC1[ADCH] 决定的:
假如FIFO的深度为3,在初始化ADC_SC1[ADCH]时,依次设置了AD7、AD12和AD14,则最终FIFO转换的结果也是对应了AD7、AD12和AD14。有个要注意的是:若ADC_SC4[ASCANE]=1,则开启了扫描方式,只对第一次设置的通道AD7采样,也就是最终的FIFO转换的3个结果都是AD7的。
当FIFO所有通道转换完成的时候,相应的结果将会存取在FIFO的结果通道,不过最终还是通过ADC_R寄存器来获得。同时,ADC_SC1[COCO]还会置1;如果开启了中断(ADC_SC1[AIEN]=1),还会发生ADC中断。
笔者在调试时,发现寄存器设置的顺序会有影响,建议的顺序如下:
- SIM_SCGC:使能ADC模块
- ADC_APCTL1:把GPIO设置AD管脚
- ADC_SC4:设置FIFO扫描方式、FIFO深度
- ADC_SC3:设置ADC时钟和转换位数
- ADC_SC2:设置软件或硬件启动、参考源
- ADC_SC1:设置单次或连续采样、中断,最后才设置ADC_SC1_ADCH
FIFO的转换时序
FIFO可以由软件或硬件触发,这个由ADC_SC2[ADTRG]决定。
FIFO还有单次采样(Single) 和 连续(Continuous)采样模式,这个由ADC_SC2[ADCO]决定:
- Single: ADC启动后,采样一次就结束了
- Continuous: ADC启动后,会一直地采样
FIFO中断例程
/**
* FIFO, Continuous, AD7, AD12, AD14, interrupt
*
* */
void ADC_Init(void)
{
SIM_SCGC |= SIM_SCGC_ADC_MASK; /* Enable bus clock in ADC*/
ADC_APCTL1 |= ADC_APCTL1_ADPC(1<<7 | 1<<12 | 1<<14); /* Channel selection */
ADC_SC4 |= ADC_SC4_AFDEP(0b010); /* 3-level FIFO is enabled */
ADC_SC3 |= ADC_SC3_ADICLK(0b00); /* Bus clock selected, 20 MHz */
ADC_SC3 |= ADC_SC3_MODE(0b10); /* 12-bit mode operation */
ADC_SC2 |= 0x00; /* Software Conversion trigger, disable compare function*/
ADC_SC2 |= ADC_SC2_REFSEL(0b01); /* Select VDD and VSS as voltage reference source*/
ADC_SC1 |= ADC_SC1_ADCO_MASK; /* Continuous mode operation */
ADC_SC1 |= ADC_SC1_AIEN_MASK; /* ADC Interrupt Enabled */
ADC_SetChannel(7); /* Enable ADC by setting ADCH bits as low*/
ADC_SetChannel(12);
ADC_SetChannel(14);
}
/*****************************************************************************//*!
*
* @brief set ADC channel.
*
* @param[in] u8Channel adc channel to conversion.
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void ADC_SetChannel(uint8_t u8Channel)
{
uint32_t u32temp;
u32temp = ADC_SC1;
u32temp &= ~ADC_SC1_ADCH_MASK;
ADC_SC1 = u32temp | ADC_SC1_ADCH(u8Channel);
}
/***********************************************************************************************
*
* @brief ADC0_IRQHandler - Interrupt for ADC channels, Calls user function.
* @param none
* @return none
* @note 在中断中,不需要查询ADC_SC2_FEMPTY_MASK的
************************************************************************************************/
void ADC0_IRQHandler(void)
{
u16ADC_ConversionBuff[0] = ADC_R;
u16ADC_ConversionBuff[1] = ADC_R;
u16ADC_ConversionBuff[2] = ADC_R;
u8ADC_ConversionFlag = 1;
}
FIFO查询例程
/**
* FIFO, Continuous, AD7, AD12, AD14, no interrupt
*
* */
void ADC_Init(void)
{
SIM_SCGC |= SIM_SCGC_ADC_MASK; /* Enable bus clock in ADC */
ADC_APCTL1 |= ADC_APCTL1_ADPC(1<<7 | 1<<12 | 1<<14); /* Channel selection */
ADC_SC4 &= ~ADC_SC4_ASCANE_MASK; /* FIFO scan mode disabled */
ADC_SC4 |= ADC_SC4_AFDEP(0b010); /* 3-level FIFO is enabled */
ADC_SC3 |= ADC_SC3_ADICLK(0b00); /* Bus clock selected, 20 MHz */
ADC_SC3 |= ADC_SC3_MODE(0b10); /* 12-bit mode operation */
ADC_SC2 |= 0x00; /* Software Conversion trigger, disable compare function*/
ADC_SC2 |= ADC_SC2_REFSEL(0b01); /* Select VDD and VSS as voltage reference source*/
ADC_SC1 |= ADC_SC1_ADCO_MASK; /* Continuous mode operation */
ADC_SC1 &= ~ADC_SC1_AIEN_MASK; /* Disable ADC Interrupt */
ADC_SetChannel(7); /* Enable ADC by setting ADCH bits as low*/
ADC_SetChannel(12);
ADC_SetChannel(14);
}
void ADC_SetChannel(uint8_t u8Channel)
{
uint32_t u32temp;
u32temp = ADC_SC1;
u32temp &= ~ADC_SC1_ADCH_MASK;
ADC_SC1 = u32temp | ADC_SC1_ADCH(u8Channel);
}
/***********************************************************************************************
*
* @brief ADC_FIFO_Poll
* @param none
* @return none
* @note The ADC_SC1[COCO] bit will be set only when all conversions indicated by the analog input channel FIFO complete
* whatever software or hardware trigger is set
************************************************************************************************/
void ADC_FIFO_Poll(uint16_t *buff)
{
while(!(ADC_SC1 & ADC_SC1_COCO_MASK));
buff[0] = ADC_R;
buff[1] = ADC_R;
buff[2] = ADC_R;
}
小结
如果采样次数很多,要求速度比较快的,尽量选择FIFO。
附录
完整代码:
KEAZN64_ADC5_FIFO_POLL.zip
KEAZN64_ADC5_FIFO_Interrupt.zip
OVER~~