聪聪哥哥 发表于 2025-7-29 20:47

【CH32F207VCT6】开发例程+ 05 使用工业级传感器的采集

本帖最后由 聪聪哥哥 于 2025-7-30 20:23 编辑

一:CH32 ADC 的基础知识分享:
ADC 模块包含 2个 12 位的逐次逼近型的模拟数字转换器,最高 14MHz 的输入时钟。支持 16 个外部通道和2个内部信号源采样源。可完成通道的单次转换、连续转换,通道间自动扫描模式、间断模式、外部触发模式、双重采样等功能。可以通过模拟看门狗功能监测通道电压是否在阈值范围内。
二: 基本特征如下所示:
2.1:12 位分辨率
2.2:支持 16 个外部通道和 2个内部信号源采样
2.3多通道的多种采样转换方式:单次、连续、扫描、触发、间断等
2.4数据对齐模式:左对齐、右对齐
2.5采样时间可按通道分别编程
2.6规则转换和注入转换均支持外部触发
2.7模拟看门狗监测通道电压,自校准功能
2.8双重模式
2.9ADC 通道输入范围:0≤V≤VoA
2.10输入增益可调,可实现小信号放大采样

三:软件配置过程:
3.1模块上电:
3.2配置ADC的采样时钟
3.3配置采样的ADC通道配置
3.4使能ADC的自校准功能
3.5设置ADC的采样周期
3.6读取ADC数据及其数据处理

四:软件编写如下所示
这里我是用的PA4 引脚作为ADC的输入引脚
4.1 初始化ADC基本参数
void ADC_Function_Init(void)
{
      ADC_InitTypeDef ADC_InitStructure={0};
      GPIO_InitTypeDef GPIO_InitStructure={0};

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, 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(GPIOA, &GPIO_InitStructure);

      ADC_DeInit(ADC1);
      ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
      ADC_InitStructure.ADC_ScanConvMode = DISABLE;
      ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
      ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC_InitStructure.ADC_NbrOfChannel = 1;
      ADC_Init(ADC1, &ADC_InitStructure);

      ADC_DMACmd(ADC1, ENABLE);
      ADC_Cmd(ADC1, ENABLE);

      ADC_BufferCmd(ADC1, DISABLE);   //disable buffer
      ADC_ResetCalibration(ADC1);
      while(ADC_GetResetCalibrationStatus(ADC1));
      ADC_StartCalibration(ADC1);
      while(ADC_GetCalibrationStatus(ADC1));
      Calibrattion_Val = Get_CalibrationValue(ADC1);      
}4.2 配置DAM方式采集ADC功能
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_Normal;
      DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
      DMA_Init( DMA_CHx, &DMA_InitStructure );
}4.3 :使能ADC的采集功能函数如下所示:
void ADC_INT(void)
{
      ADC_Function_Init();
      
      DMA_Tx_Init( DMA1_Channel1, (u32)&ADC1->RDATAR, (u32)TxBuf, 1024 );
      DMA_Cmd( DMA1_Channel1, ENABLE );

      ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5 );
      ADC_SoftwareStartConvCmd(ADC1, ENABLE);
      Delay_Ms(50);
      ADC_SoftwareStartConvCmd(ADC1, DISABLE);
}4.4 添加 10ms的处理函数如下所示:
//========================================================================
// 函数: void task_10ms(void)
// 描述: 10ms 任务.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2025-07-09
//========================================================================
void task_10ms(void)
{
iAdcData = Get_ADC_Val(4);
}      
五:实物测试如下所示:5.1 传感器实物如下所示:

上图为电阻式的 位移传感器,在工业控制中,常常用来采集位移的变化。
3.2 实物测试如图所示:
实测:使用内部ADC采集工业控制类的位移传感器,可以满足要求。稍后上传视频。

六:和大家分享几种常见的ADC数据处理方法如下所示:

6.1 :一阶互补滤波算法:
取值:k = 0-1,本次取值滤波结果 =(1-K),本次采样值需要加上上次滤波得结果数据
代码如下所示:
int firstdatadeal(int CurrValue, int lastValue, float K)
{    return K * CurrValue + (1-K) * lastValue;}6.2: 采用中值算法滤波
主要是程序在执行的时候,连续采集N次(需要注意下这里下,这里的N必须取值奇数),程序需要按大到小或者从小到达的顺序进行排序,然后取中间数值做为有效值。

int MidValueDeal(int N)
{      
    int value_buf;      int i,j,k,temp;      
    for( i = 0; i < N; ++i)      
    {      
     value_buf = HAL_ADC_GetValue(&hadc1);
    }
      for(j = 0 ; j < N-1; ++j)      
      {         
          for(k = 0; k < N-j-1; ++k)         
          {            //从小到大排序,冒泡法排序            
            if(value_buf > value_buf)            
            {               
                  temp = value_buf;               
                  value_buf = value_buf;               
                  value_buf = temp;            
            }         
          }      
      }
      return value_buf[(N-1)/2];
}可以有效的去除数据因为外界干扰引起的数据的波动,对一些大滞后系统:比如温度、液位等变化缓慢的有良好的滤波效果,上述代码可以有效消除异常数据和平稳变化的采样值效果比较好;
6.3:算术平均数滤波
连续取值N个数据,对所有的数据进行取平均值;
代码如下:
int AverValueDeal(int N)
{   
    int sum = 0;   
    unsinged short i;   
    for(i = 0; i < N; ++i)   
    {      
      sum += HAL_ADC_GetValue(&hadc1);      
    }   
    return sum/N;
}这里取值时候,需要根据被控对象进行选择,N值取值过大,会导致响应过慢,数据的灵敏度过低,所以采用算术平均值滤波时候,需要我们格外的注意;
6.4:滑动滤波算法
把连续取N个采样值看成一个队列,队列的长度固定为N。每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据(先进先出原则)。把队列中的N个数据进行算术平均运算,就可获得新的滤波结果;
#define N 10
int value_buf;
int sum=0; //数据总和
int Num=0; //当前队列中数组下标
int movedataFilter()
{      
    if(Num < N)      
    {         
      value_buf = HAL_ADC_GetValue(&hadc1);         
      sum += value_buf;         
      Num++;         
      return sum/Num;      
    }      
    else      
    {         
       sum -= sum/N;         
       sum += HAL_ADC_GetValue(&hadc1);         
       return sum/N;      
    }
}
页: [1]
查看完整版本: 【CH32F207VCT6】开发例程+ 05 使用工业级传感器的采集