注入通道转换时任意事件转换通道发生时序图
使用触发开始注入通道转换,必须保证触发事件的间隔长与注入序列,注入通道转换期间发生注入事件将被忽略。
触发信号
DC转换的触发源包括软件触发、定时器和外部事件。
在触发信号产生后,延时N个PCLK2的
时钟周期再开始采样。如果是触发扫描模式,只有第一个通道采样被延时,其余通道是在上一个采样结束后立即开始。
设置ADC_ANY_CR寄存器的JTRGEN位可以使用外部事件触发注入通道转换。设置ADC_ANY_CR寄存器的JTRGSEL位可以选择注入通道外部触发源。
具体的外部触发源选择情况,可以参考AD控制寄存器(ADC_ADCR.TRGSEL 或ADC_ANY_CR.JTRGSEL)相关位的描述。外部触发可设置延时控制,具体参考AD控制寄存器(ADC_ADCR.TRGSH
IFT 或 ADC_ANY_CR.J TRGSHIFT)相关位的描述。
实验
本次实验使用ADC的注入通道:将ADC1的通道0配置为规则通道模式,通过软件触发,并使用DMA
传输数据。将ADC1的通道1配置为注入通道模式,通过外部事件触发,并使用中断,在中断服务子程序中,就可以获取AD值。
开始只有ADC1的通道0进行AD转换,通道1不进行AD转换。当外部事件发生后,通道0当前转换结束后停止,通道1开始进行转换直至结束,通道0继续进行AD转换,经MCU处理将电压数据打印出来。
程序设计
ADC1 配置初始化
void ADC1BasicConfigWithParameter(void)
{
ADC_InitTypeDef ADC_InitStruct;
ADC_TypeDef* ADCn;
ADCn = ADC1;
ADC_Struc
tinit(&ADC_InitStruct);
ADCx
clockSet(ADCn, ENABLE);
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_PRESCARE = ADC_PCLK2_PRESCARE_16;
ADC_InitStruct.ADC_Mode = ADC_Mode_Continue;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_Init(ADCn, &ADC_InitStruct);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 0, ADC_SMPR1_SAMCTL0_240_5);
ADC_InjectedSequencerConfig(ADC1, ADC_ANY_CR_JTRGSEL_EXTI12, ADC_ANY_CR_JTRGSHIFT_64);
ADC_InjectedSequencerLengthConfig(ADC1, ADC_Inject_Seqen_Len1);
ADC_InjectedSequencerChannelConfig(ADC1, ADC_InjectedChannel_1, ADC_Channel_1);
ADC1->ANYCR |= (1<<4);
DMAInit();
ADC_DMACmd(ADCn, ENABLE);
ADC_Cmd(ADCn, ENABLE);
}
外部事件初始化
ADC触发源选择外部事件触发方式,配置EXTI_Line12下降沿触发
外部中断,通过PB12复用为外部中断/事件线。void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_SYSCFG, ENABLE);
//Set to pull-up input
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//GPIOB.12
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource12);
EXTI_StructInit(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = EXTI_Line12;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;
//Falling edge
trigger
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
ADC1中断服务函数
外部事件触发ADC注入通道采样,转换完成便会触发ADC中断,在中断服务子程序中获取AD值。void ADC1_2_IRQHandler(void)
{
if(RESET != ADC_SREXT_JEOSIF)
{
ADC1->SREXT |= (1 << 20); //Clear the bit by writing about 1
ADCVAL = ADC_GetInjectedCurrentConvertedValue(ADC1);
Flag_InjectConvert = 1;
if(RESET != EXTI_GetFlagStatus(EXTI_Line12)) {
EXTI_ClearITPendingBit(EXTI_Line12);
}
}
}DMA中断服务函数规则通道使用DMA中断进行数据传输,在DMA中断服务函数中调用ADCFilter()函数对获取的AD值做滤波处理。void DMA1_Channel1_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_IT_TC1)) {
DMA_ClearITPendingBit(DMA1_IT_TC1);
ADCFilter();
}
}
主函数
示例中将获取的AD值与3.3V比对,转换为ADC输入通道的电压,并间隔300ms打印。s32 main(void)
{
DELAY_Init();
CONSOLE_Init(115200);
ADC1_ConfigInit();
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(1)
{
if(Flag_InjectConvert)
{
Flag_InjectConvert = 0;
fValue = ((float)ADCVAL / 4095) * 3.3;
// ADC injection channel
printf("ADC1_CH_1 = %fV\r\n\n", fValue);
}
if(Flag_ADCFilter)
{
Flag_ADCFilter = 0;
//Convert the filtered value to voltage
ADCVolatge = ((float)ADCFilterValue / 4095) * 3.3;
//ADC regular channels
printf("ADC1_CH_0 = %fV\r\n\n", ADCVolatge);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
DELAY_Ms(300);
}
}
演示
在
开发板上将PA0(ADC1通道0)连接板上GND,将PA1(ADC1通道1)连接板上3.3V。
运行程序,开始时只有ADC1通道0(规则通道)进行AD转换。给PB12一个下降沿信号,此时外部事件触发ADC1通道1(注入通道)进行AD转换,通道0当前转换完成后停止AD转换,通道1进行转换直到结束,通道0进行AD转换。串口调试助手显示如下:
各通道输出数据和采样电压一致,与预期相符。在一些ADC应用场合中,通常将注入通道和规则通道混合使用,在规则通道转换的过程中立刻进行注入通道采样,充分发挥ADC外设的特性。
0