CH573-07-ADC——RISC-V内核BLE MCU快速开发教程

在这里插入图片描述

1.简介

  ch573提供一个 12 位逐次逼近型模拟数字转换器 ADC,提供多达 12 个通道,CH573 支持 10 个外部信号源和 2 个内部信号源,CH571 仅支持前 6 个外部信号源和 2 个内部信号源,支持的引脚为: PA4(AIN0)、PA5(AIN1)、PA12(AIN2)、PA13(AIN3)、PA14(AIN4)、PA15(AIN5)、PB6(AIN9)、PB0(AIN8)、PA8(AIN12)、PA9(AIN13)

2. 新建工程

  复制并粘贴“CH573_01_led”工程,并重命名为“CH573_07_ADC”。


3. ADC初始化与采集

  1) 精简代码

  将与串口无关的LED相关程序删除,如下所示:


  2) 串口1初始化

  复制上一讲的UART1初始化程序,初始化串口1,仅使用PRINT完成串口字符串发送。


    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
    UART1_DefInit();
    PRINT("OK\r\n\r\n");

  3) ADC初始化(单通道)

//ADC初始化
    /* 单通道采样:选择ADC通道0做采样,对应 PA4引脚, 带数据校准功能 */
    GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_Floating);
    ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_0);//3.2M 采样频率,无增益
    RoughCalib_Value = ADC_DataCalib_Rough(); // 用于计算ADC内部偏差,记录到全局变量 RoughCalib_Value中
    ADC_ChannelCfg(0);  //设置ADC采样通道AIN0(PA4)

  除了上述普通单通道方式,还支持中断单通道采样、DMA单通道采样、差分通道采样、TouchKey采样等,详细实现方法可以参考官方资料“\EVT\EXAM\ADC”下的工程文件。

  4) ADC采样

   首先定义ADC采样数据保存的缓冲区:

uint16_t adcBuff[40];
uint32_t adc_get=0;
#define ADC_COUNT 20  //ADC连续采样次数

   连续采样:

// 连续采样ADC_COUNT次
    for(i = 0; i < ADC_COUNT; i++)
    {
        adcBuff[i] = ADC_ExcutSingleConver() + RoughCalib_Value;
        /*注意:由于ADC内部偏差的存在,当采样电压在所选增益范围极限附近的时候
                可能会出现数据溢出的现象,此处采用伪溢出判断*/
        if(adcBuff[i]==65535)   adcBuff[i]=0;
    }

  5) 软件滤波

   在上面完成了连续的ADC采样,将结果进行冒泡排序,然后去掉首尾,即去掉最大和最小值,最后再取平均值使数据更加准确。

 //冒泡排序,去首尾,求平均
    for(i = 0; i < ADC_COUNT; i++)
    {
        PRINT("%d \n", adcBuff[i]);
    }
    PRINT("\r\n\r\n", adcBuff[i]);

    uint32_t mp_temp=0,mp_i=0,mp_j=0;
    for(mp_i = 0; mp_i < ADC_COUNT; mp_i++)
    {
        for(mp_j = 0; mp_j < ADC_COUNT-1-mp_i; mp_j++)
        {
            if(adcBuff[mp_j]>adcBuff[mp_j+1])
            {
                mp_temp=adcBuff[mp_j];
                adcBuff[mp_j]=adcBuff[mp_j+1];
                adcBuff[mp_j+1]=mp_temp;
            }
        }
    }
    //排序后
    PRINT("adc get %d times:",ADC_COUNT);
    for(i = 0; i < ADC_COUNT; i++)
    {
        PRINT("%d \n", adcBuff[i]);
    }
    PRINT("\r\n", adcBuff[i]);

    //去首尾求和
    for(i = 1; i < ADC_COUNT-1; i++)
    {
        adc_get+=adcBuff[i];
    }
    //求平均
    adc_get=adc_get/(ADC_COUNT-2);
    PRINT("adc_get=%d\r\n",adc_get);

4. main.c完整内容

/********************************** (C) COPYRIGHT *******************************
 * File Name          : Main.c
 * Author             : FUNIOT.XYZ
 * Version            : V1.0
 * Date               : 2020/08/06
 * Description        : 实验01-LED闪烁
 * Copyright          : WeChat official accounts "IOT趣制作"
 * SPDX-License-Identifier: Apache-2.0
 *******************************************************************************/

#include "CH57x_common.h"
uint16_t adcBuff[40];
uint32_t adc_get=0;
#define ADC_COUNT 20  //ADC连续采样次数
/*********************************************************************
 * @fn      main
 *
 * @brief   主函数
 *
 * @return  none
 */
int main()
{
    SetSysClock(CLK_SOURCE_PLL_60MHz);
    //串口1初始化
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
    UART1_DefInit();
    PRINT("OK\r\n\r\n");

    signed short RoughCalib_Value = 0; // ADC粗调偏差值
    uint16_t i=0;
    //ADC初始化
    /* 单通道采样:选择ADC通道0做采样,对应 PA4引脚, 带数据校准功能 */
    GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_Floating);
    ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_0);//3.2M 采样频率,无增益
    RoughCalib_Value = ADC_DataCalib_Rough(); // 用于计算ADC内部偏差,记录到全局变量 RoughCalib_Value中
    ADC_ChannelCfg(0);  //设置ADC采样通道AIN0(PA4)
    // 连续采样ADC_COUNT次
    for(i = 0; i < ADC_COUNT; i++)
    {
        adcBuff[i] = ADC_ExcutSingleConver() + RoughCalib_Value;
        /*注意:由于ADC内部偏差的存在,当采样电压在所选增益范围极限附近的时候
                可能会出现数据溢出的现象,此处采用伪溢出判断*/
        if(adcBuff[i]==65535)   adcBuff[i]=0;
    }
    //冒泡排序,去首尾,求平均
//    for(i = 0; i < ADC_COUNT; i++)
//    {
//        PRINT("%d \n", adcBuff[i]);
//    }
//    PRINT("\r\n\r\n", adcBuff[i]);

    uint32_t mp_temp=0,mp_i=0,mp_j=0;
    for(mp_i = 0; mp_i < ADC_COUNT; mp_i++)
    {
        for(mp_j = 0; mp_j < ADC_COUNT-1-mp_i; mp_j++)
        {
            if(adcBuff[mp_j]>adcBuff[mp_j+1])
            {
                mp_temp=adcBuff[mp_j];
                adcBuff[mp_j]=adcBuff[mp_j+1];
                adcBuff[mp_j+1]=mp_temp;
            }
        }
    }
    //排序后
    PRINT("adc get %d times:",ADC_COUNT);
    for(i = 0; i < ADC_COUNT; i++)
    {
        PRINT("%d \n", adcBuff[i]);
    }
    PRINT("\r\n", adcBuff[i]);

    //去首尾求和
    for(i = 1; i < ADC_COUNT-1; i++)
    {
        adc_get+=adcBuff[i];
    }
    //求平均
    adc_get=adc_get/(ADC_COUNT-2);
    PRINT("adc_get=%d\r\n",adc_get);
    while(1)
    {
        DelayMs(1500);
    }
}

5. 编译烧录运行

    完成烧录后,按下复位运行程序,将PA4引脚使用杜邦线分别悬空、连接GND和连接3.3V,并依次按下复位键,完成ADC采集,可以看到ADC读取的具体数据,如下图:
在这里插入图片描述


    如果ADC采集正常,结果与最后截图所示相类似,即达到本实验的目的,如果异常,请检查源代码,如有疑问可关注公众号 “IOT趣制作”,将您遇到的问题描述出来,平台收到您的留言后会第一时间进行解决。