打印
[单片机芯片]

沁恒微WCH32v003多通道ADC采集+DMA

[复制链接]
636|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-3-5 08:20 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
   最近在做一个项目,用到的主控芯片是沁恒微的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);
            Delay_Ms(10);
        }

        Delay_Ms(50);


    }
}

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/abc565846881/article/details/135936553

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1360

主题

13960

帖子

8

粉丝