最近在做一个项目,用到的主控芯片是沁恒微的WCH32v003,其中一个功能是多通道采集ADC+DMA运输,在编写代码的时候想找官方的库函数文件,但是找了很久都没有找到,官网只有一个数据手册和应用手册,而应用手册一般是分为库函数应用手册和寄存器应用手册,但是官网上的应用手册是只有寄存器的,而官方的库又用了大量的封装,所以看起来特别的痛苦,于是我结合网上的资料和自己的理解,总结处理一个关于ADC采集的库函数介绍,希望可以帮助到大家。
1.1、void ADC_DeInit(ADC_TypeDef* ADCx)
功 能:将ADCx外围寄存器初始化为其默认重置值。
输 入:ADCx:其中x可以是1以选择ADC外围设备。
1.2、void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct)
功 能:根据ADC_InitStruct中指定的参数初始化ADCx外围设备。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_InitStruct:指向包含指定ADC外围设备的配置信息的ADC_InitTypeDef结构的指针。
1.3、void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct)
功 能:用默认值填充每个ADC_InitStruct成员。
输 入:ADC_InitStruct:指向包含指定ADC外围设备的配置信息的ADC_InitTypeDef结构的指针。
1.4、void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:启用或禁用指定的ADC外围设备。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.5、void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:启用或禁用指定的ADC DMA请求。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.6、void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState)
功 能:启用或禁用指定的ADC中断。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_IT:指定要启用或禁用的ADC中断源。NewState:启用或禁用。
1.7、void ADC_ResetCalibration(ADC_TypeDef* ADCx)
功 能:重置所选ADC校准寄存器。
输 入:ADCx:其中x可以是1以选择ADC外围设备。
1.8、FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx)
功 能:获取所选ADC重置校准寄存器状态。
输 入:ADCx:其中x可以是1以选择ADC外围设备。
1.9、void ADC_StartCalibration(ADC_TypeDef* ADCx)
功 能:启动所选ADC校准过程。
输 入:ADCx:其中x可以是1以选择ADC外围设备。
1.10、FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx)
功 能:获取所选ADC校准状态。
输 入:ADCx:其中x可以是1以选择ADC外围设备。
1.11、void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:启用或禁用所选ADC软件启动转换。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.12、FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx)
功 能:获取所选ADC软件开始转换状态。
输 入:ADCx:其中x可以是1以选择ADC外围设备。
1.13、void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number)
功 能:为所选ADC常规组通道配置不连续模式。
输 入:ADCx:其中x可以是1以选择ADC外围设备;Number:指定不连续模式常规通道计数值。
1.14、void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:为指定的ADC启用或禁用常规组通道上的不连续模式。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.15、void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
功 能:为所选ADC常规通道配置其在序列器中的相应列组及其采样时间。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_Channel:要配置的ADC信道;Rank:常规组序列器中的等级;ADC_SampleTime:要为所选通道设置的采样时间值。
1.16、void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:通过外部触发器启用或禁用ADCx转换。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.17、uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)
功 能:返回常规通道的最后一个ADCx转换结果数据。
输 入:ADCx:其中x可以是1以选择ADC外围设备。
1.18、uint32_t ADC_GetDualModeConversionValue(void)
功 能:以双模式返回最后一个ADC1和ADC2转换结果数据。
输 入:无。
1.19、void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:启用或禁用所选ADC在常规转换后自动注入组转换。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.20、void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:为指定的ADC启用或禁用注入组通道的不连续模式。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.21、void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv)
功 能:为注入通道转换配置ADCx外部触发器。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_ExternalTrigInjecConv:指定开始注入转换的ADC触发器。
1.22、void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:通过外部触发器启用或禁用ADCx注入通道转换。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.23、void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
功 能:启用或禁用注入通道转换的所选ADC启动。
输 入:ADCx:其中x可以是1以选择ADC外围设备;NewState:启用或禁用。
1.24、FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx)
功 能:获取所选ADC软件开始注入转换状态。
输 入:ADCx:其中x可以是1以选择ADC外围设备。
1.25、void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
功 能:为所选ADC注入通道配置其在序列器中的相应秩及其采样时间。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_Channel:要配置的ADC信道;Rank:注入组序列器中的秩;ADC_SampleTime:要为所选通道设置的采样时间值。
1.26、void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length)
功 能:配置注入通道的序列器长度。
输 入:ADCx:其中x可以是1以选择ADC外围设备;Length:序列器的长度。
1.27、void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset)
功 能:设置注入通道转换值偏移。
输 入:ADCx:其中x可以是1以选择ADC外围设备;Offset:所选ADC注入通道的偏移值。
1.28、uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel)
功 能:ADC返回注入通道的结果。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_InjectedChannel:转换后的ADC注入通道。
1.29、void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog)
功 能:启用或禁用单个/所有常规或注入通道上的模拟看门狗。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_AnalogWatchdog:ADC模拟看门狗配置。
1.30、void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold,uint16_t LowThreshold)
功 能:配置模拟看门狗的高阈值和低阈值。
输 入:ADCx:其中x可以是1以选择ADC外围设备;HighThreshold:ADC模拟看门狗高阈值;LowThreshold:ADC模拟看门狗低阈值。
1.31、void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel)
功 能:配置模拟看门狗保护的单通道。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_Channel:为模拟看门狗配置的ADC信道。
1.32、void ADC_TempSensorVrefintCmd(FunctionalState NewState)
功 能:启用或禁用温度传感器和Vrefint通道。
输 入:NewState:启用或禁用。
1.33、FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG)
功 能:检查是否设置了指定的ADC标志。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_FLAG:指定要检查的标志。
1.34、void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG)
功 能:清除ADCx的挂起标志。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_FLAG:指定要清除的标志。
1.35、ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT)
功 能:检查指定的ADC中断是否已发生。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_IT:指定要检查的ADC中断源。
1.36、void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT)
功 能:清除ADCx的中断挂起位。
输 入:ADCx:其中x可以是1以选择ADC外围设备;ADC_IT:指定要清除的ADC中断挂起位。
1.37、s32 TempSensor_Volt_To_Temper(s32 Value)
功 能:内部温度传感器电压与温度之间的关系。
输 入:Value:电压值。
这里是参考wch32v103的,基本上都是一样的,原文地址:十、CH32V103应用教程——ADC - RISC-V技术及应用论坛,开源指令集架构(ISA)论坛 - 21ic电子技术开发论坛
下面的代码部分,是可以直接使用的,具体就不做过多介绍了,对照这上面的库函数介绍都很容易理解。我的代码是3通道采集,大家可以根据自己的实际需求更改。下面是不同封装的引脚定义。
main.c
#include "debug.h" /* Global Variable */ u16 TxBuf[10]; /********************************************************************* * @fn ADC_Function_Init * * @brief Initializes ADC collection. * * @return none */ void ADC_Function_Init(void) { ADC_InitTypeDef ADC_InitStructure = {0}; GPIO_InitTypeDef GPIO_InitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div8); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOD, &GPIO_InitStructure); ADC_DeInit(ADC1); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 3; ADC_Init(ADC1, &ADC_InitStructure); ADC_Calibration_Vol(ADC1, ADC_CALVOL_50PERCENT); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } /********************************************************************* * @fn Get_ADC_Val * * @brief Returns ADCx conversion result data. * * @param ch - ADC channel. * ADC_Channel_0 - ADC Channel0 selected. * ADC_Channel_1 - ADC Channel1 selected. * ADC_Channel_2 - ADC Channel2 selected. * ADC_Channel_3 - ADC Channel3 selected. * ADC_Channel_4 - ADC Channel4 selected. * ADC_Channel_5 - ADC Channel5 selected. * ADC_Channel_6 - ADC Channel6 selected. * ADC_Channel_7 - ADC Channel7 selected. * ADC_Channel_8 - ADC Channel8 selected. * ADC_Channel_9 - ADC Channel9 selected. * * @return none */ u16 Get_ADC_Val(u8 ch) { u16 val; ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_241Cycles); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); val = ADC_GetConversionValue(ADC1); return val; } /********************************************************************* * @fn DMA_Tx_Init * * @brief Initializes the DMAy Channelx configuration. * * @param DMA_CHx - x can be 1 to 7. * ppadr - Peripheral base address. * memadr - Memory base address. * bufsize - DMA channel buffer size. * * @return none */ void DMA_Tx_Init(DMA_Channel_TypeDef *DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize) { DMA_InitTypeDef DMA_InitStructure = {0}; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA_CHx); DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr; DMA_InitStructure.DMA_MemoryBaseAddr = memadr; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = bufsize; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA_CHx, &DMA_InitStructure); } /********************************************************************* * @fn main * * @brief Main program. * * @return none */ int main(void) { u16 i; SystemCoreClockUpdate(); Delay_Init(); #if (SDI_PRINT == SDI_PR_OPEN) SDI_Printf_Enable(); #else USART_Printf_Init(115200); #endif printf("SystemClk:%d\r\n", SystemCoreClock); printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() ); ADC_Function_Init(); DMA_Tx_Init(DMA1_Channel1, (u32)&ADC1->RDATAR, (u32)TxBuf,3); while(1) { ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_241Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_241Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 3, ADC_SampleTime_241Cycles); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_SoftwareStartConvCmd(ADC1, ENABLE); Delay_Ms(5); ADC_SoftwareStartConvCmd(ADC1, DISABLE); DMA_Cmd(DMA1_Channel1, DISABLE); for(i = 0; i < 3; i++) { printf("%04d\r\n", TxBuf[i]); Delay_Ms(10); } Delay_Ms(50); } }