1.前言
刚刚研究ADC的时候发现芯片里面还有应该mrt 16位的定时器没有搞,那回头补上吧。下午研究了一下ADC的使用,我也只是能用上,这里我只是抛砖引玉一下吧,有需要的还请各位自行深入探究,我这里讲解的是软件触发模式。
2.初始化
初始化程序如下
cpp
#define ADC_SAMPLE_CHANNEL_NUMBER 7
adc_result_info_t ADCResult;
void init_adc(void)
{
adc_config_t adcConfigStruct;
adc_conv_seq_config_t adcConvSeqConfigStruct;
/* Enables clock for IOCON.: enable */
CLOCK_EnableClock(kCLOCK_Iocon);
/* Enables clock for switch matrix.: enable */
CLOCK_EnableClock(kCLOCK_Swm);
const uint32_t IOCON_INDEX_PIO0_10_config = (/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Enable hysteresis */
IOCON_PIO_HYS_EN |
/* Input not invert */
IOCON_PIO_INV_DI |
/* Disables Open-drain function */
IOCON_PIO_OD_DI);
/* PIO0 PIN10 (coords: 11) is configured as ADC0, CH, 7. */
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_10, IOCON_INDEX_PIO0_10_config);
/* ADC_CHN7 connect to P0_10 */
SWM_SetFixedPinSelect(SWM0, kSWM_ADC_CHN7, true);
/* Disable clock for switch matrix. */
CLOCK_DisableClock(kCLOCK_Swm);
/* Attach FRO clock to ADC0. */
CLOCK_Select(kADC_Clk_From_Fro);
CLOCK_SetClkDivider(kCLOCK_DivAdcClk, 1U);
/* Power on ADC. */
POWER_DisablePD(kPDRUNCFG_PD_ADC0);
adcConfigStruct.clockDividerNumber = 1;
adcConfigStruct.enableLowPowerMode = false;
ADC_Init(ADC, &adcConfigStruct);
adcConvSeqConfigStruct.channelMask =(1U << ADC_SAMPLE_CHANNEL_NUMBER); /* Includes channel DEMO_ADC_SAMPLE_CHANNEL_NUMBER. */
adcConvSeqConfigStruct.triggerMask = 0U;//选择硬件触发源
adcConvSeqConfigStruct.triggerPolarity = kADC_TriggerPolarityPositiveEdge;//上升还是下降沿触发
adcConvSeqConfigStruct.enableSingleStep = false;//单次触发模式
adcConvSeqConfigStruct.enableSyncBypass = true;//启用此功能允许硬件触发输入绕过同步触发器阶段,从而缩短触发输入信号和转换开始之间的时间。
adcConvSeqConfigStruct.interruptMode = kADC_InterruptForEachSequence;//设置中断模式
ADC_SetConvSeqAConfig(ADC, &adcConvSeqConfigStruct);
ADC_EnableConvSeqA(ADC, true); /* Enable the conversion sequence A. */
/* Clear the result register. */
ADC_DoSoftwareTriggerConvSeqA(ADC);
while (!ADC_GetChannelConversionResult(ADC, ADC_SAMPLE_CHANNEL_NUMBER, &ADCResult))
{
}
ADC_GetConvSeqAGlobalConversionResult(ADC, &ADCResult);
}
前面几行比较简单,先申请几个配置的结构体
然后是设置引脚,这里我们可以看到这里会多出几行,在模拟引脚我们都需要这样设置,就是配置管脚的速度,默认上下拉,保证是模拟模式,然后关联到相应通道
然后是设置时钟和分频系数,设置完毕后就开通电源
这一部分是设置ADC的分频和低功耗模式
这个结构体里,也只有这两个参数可以设置,在804这里比较鸡肋
这一块是重头戏,我来一个个介绍
第一句话是选择通道,这里我是通道7
第2~4句要连着一起用,常见的示波器都有外部触发功能,这里也可以设置,你可以让ADC的通道2作为外部触发源,你接上方波后对内部ADC进行触发,然后是设置方波极性,上升沿还是下降沿触发,最后一句是设置硬件触发模式,因为这里是软件触发不用硬件所以我直接跳过同步了。
然后是设置中断,因为是软件触发,我就跟着例程走了
配置完毕后就可以使能了,两句话要一起使用
然后是进行一次转换,官方给的说法是清除寄存器里的数据
3.软件触发
程序如下
cpp
void ReadADC(void)
{
/* Get the input from terminal and trigger the converter by software. */
ADC_DoSoftwareTriggerConvSeqA(ADC);
/* Wait for the converter to be done. */
while (!ADC_GetChannelConversionResult(ADC, ADC_SAMPLE_CHANNEL_NUMBER, &ADCResult)){}
}
这里主要介绍一下我们的通道是这个参数,如何改通道就要改这里,当然初始化部分也要改
我们的结果是放在这个结构体内
这个结构体原型如下
result就是我们的读到的数据,是最重要的。中间两是检测ADC的状态,我不怎么常用就没读了。chanelnumber是通道,比如我们这里是通道7,这个数字就是7了。overrunflag是可以检测ADC数据是否存在覆盖的情况,因为芯片内部没有DMA,所以搬运还是依靠CPU来搞,可以通过这个参数查看是否有丢失数据情况。
4.测试
我这里输入是0.8V直流信号
我在程序内部也有进行转换,上面985就是实际读取的值,下面是计算后的电压值,可以看到基本是准的。