这次的实验和上一个ADC实验不同的是,采用扫描模式采样通道13和通道16。因为规则通道转换的值储存在一个仅有的数据寄存器中,所以当转换多个规则通道时需要使用DMA,这可以避免丢失已经存储在ADC_DR寄存器中的数据。 只有在规则通道的转换结束时才产生DMA请求,并将转换的数据从ADC_DR寄存器传输到用户指定的目的地址。因此这样也能体验一下GD32的DMA功能。
void AdcInit() { GPIO_InitTypeDef GPIO_InitStruct; ADC_InitTypeDef ADC_InitStruct; DMA_InitTypeDef DMA_InitStruct; RCC_AHBPeriphClockCmd (RCC_AHBPeriph_DMA1 ,ENABLE ); RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC1, ENABLE); RCC_ADCCLKConfig (RCC_PCLK2_Div6); RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN ; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz ; GPIO_Init (GPIOC,&GPIO_InitStruct); ADC_InitStruct.ADC_ContinuousConvMode = ENABLE ; ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; ADC_InitStruct.ADC_NbrOfChannel = 2; ADC_InitStruct.ADC_ScanConvMode = ENABLE ; ADC_Init (ADC1,&ADC_InitStruct); ADC_RegularChannelConfig(ADC1,ADC_Channel_13,1,ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_16,2,ADC_SampleTime_239Cycles5); ADC_DMACmd (ADC1,ENABLE); ADC_Cmd (ADC1,ENABLE); ADC_TempSensorVrefintCmd (ENABLE ); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1) == SET) { ; } ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1) == SET) { ; } DMA_InitStruct.DMA_BufferSize = 2; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC ; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_InitStruct.DMA_MemoryBaseAddr = (u32)gAdcVal; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR)); DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_Init (DMA1_Channel1 ,&DMA_InitStruct); DMA_Cmd (DMA1_Channel1,ENABLE); ADC_SoftwareStartConvCmd (ADC1,ENABLE); }
这次代码没有在中断服务函数里去获取AD采样的值,在这里是通过建立一个数组,通过DMA来直接将ADC1的数据寄存器的值传到数组中。那么再主函数里就可以直接使用:
float gVoltage = 0.01; float gTemperate = 0.01; int main() { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); LedPinInit(); SysTickInit(); TimerInit(99,7199); AdcInit(); GUI_Init(); GUI_SetBkColor(GUI_RED); GUI_SetColor(GUI_WHITE); GUI_Clear(); GUI_DispStringAt("liklon--->GD32107C-EVAL",1,40); GUI_DispStringAt("www.eepw.com.cn",40,60); GUI_DispStringAt("ADC:",80,80); GUI_DispStringAt("VOLTAGE:",48,120); GUI_DispStringAt("TEMPERATE:",48,160); while(1) { if(gLedRunFlag > 10) { gVoltage = gAdcVal[0] * 3.3 / 4096.0; gTemperate = gAdcVal[1] * 3.3 / 4096.0; gTemperate = (1.43 - gTemperate) / 0.0043 + 25; GUI_DispDecAt(gAdcVal[0],100,100,4); GUI_GotoXY(100,140); GUI_DispFloat(gVoltage,3); GUI_GotoXY(100,180); GUI_DispFloat(gTemperate,5); gLedRunFlag = 0; } } }
计算温度误差比较大,下面是效果图:
这次体验的是DMA功能在ADC中的应用,这样以后如果需要多个通道采集时,便方便许多了。GD32的内部资源丰富而且都非常实用。这个温度误差有点大,不知道是不是自己换算的过程中有问题,一眼看出道道的童鞋希望可以指点指点。