52832 3通道ADC笔记

因为业务需要, 需要在52832上, 采集3个pin的电压.
52832的ADC, 分为什么single, 连续, 扫描模式
single就是只有一个通道并采集一次, 连续就是不停的扫描, 如果要捕捉声音之类, 就配合DMA, 连续不停的采集, 转换就行了.
扫描模式就是如果是多通道, 就一开始初始化多个通道, 存放数据的数组, 以及采样次数, 然后全扫, 扫完回调中去拿数据即可.

初始化:

// 初始化SAADC,配置使用的SAADC通道的参数和缓存
void saadc_3c_init(void) {
    ret_code_t err_code;
    // 使用NRF_SAADC_INPUT_AIN7通道,即P0.31引脚, 生成一个通道配置结构体
    nrf_saadc_channel_config_t channel_config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);

    // 初始化ADC通道0
    err_code = nrfx_saadc_channel_init(0, &channel_config);
    APP_ERROR_CHECK(err_code);
    
    // 为NRF_SAADC_INPUT_AIN5, 初始化ADC 通道1
    channel_config.pin_p = NRF_SAADC_INPUT_AIN5;
    err_code = nrfx_saadc_channel_init(1, &channel_config);
    
    // 为NRF_SAADC_INPUT_AIN6, 初始化ADC 通道2
    APP_ERROR_CHECK(err_code);
    channel_config.pin_p = NRF_SAADC_INPUT_AIN6;
    err_code = nrfx_saadc_channel_init(2, &channel_config);
    APP_ERROR_CHECK(err_code);

    // 双缓存模式
    err_code = nrfx_saadc_buffer_convert(m_buffer_pool[0], ADC_SAMPLES_BUFFER_LEN);
    APP_ERROR_CHECK(err_code);
    err_code = nrfx_saadc_buffer_convert(m_buffer_pool[1], ADC_SAMPLES_BUFFER_LEN);
    APP_ERROR_CHECK(err_code);

}

这里使用的是双缓存模式, 采样的数据量为ADC_SAMPLES_BUFFER_LEN, 因为是3个通道, 所以采样3次就行了, 或者你喜欢浪费时间, 采样3的倍数也可以,如果不是3的倍数, 就会出现数据错位.

注册的回调时saadc_callback
这里使用的是非阻塞模式, 因为毕竟有蓝牙, 你阻塞好像不是那么回事.


// SAADC事件回调函数,只有一个缓存填满后才会进入事件回调函数
static void saadc_callback(nrfx_saadc_evt_t const *p_event) {
    float val; // 保存SAADC采样数据计算的实际电压值

    if (p_event->type == NRFX_SAADC_EVT_DONE) {
        ret_code_t err_code;

        // 设置好缓存,为下一次采样准备
        err_code = nrfx_saadc_buffer_convert(p_event->data.done.p_buffer, ADC_SAMPLES_BUFFER_LEN);
        APP_ERROR_CHECK(err_code);

        int i;
        // 串口输出ADC采样值。
        // NRF_LOG_INFO("ADC event number: %d \n", (int) m_adc_evt_counter);

        for (i = 0; i < ADC_SAMPLES_BUFFER_LEN; i++) {
            // 如果直接输出采样结果,使用这个代码
            int16_t adc_result = p_event->data.done.p_buffer[i];
            // NRF_LOG_INFO("Sample value: %d \n", adc_result);

            // 电压值 = 采样值 * 3.6 /2^10
            // val = p_event->data.done.p_buffer[i] * 3.6 / 1024;
            // NRF_LOG_INFO("Voltage = %.3fV\n", val);
        }

        uint8_t batVolPercentage = get_battery_percentage(p_event->data.done.p_buffer[0]);
        NRF_LOG_INFO("batVolPercentage:%d \n", batVolPercentage);

        dis_battery_level_update_handle(batVolPercentage);
        // 事件次数加1
        m_adc_evt_counter++;
    }
}

回调中, 先转换, 然后就可以打印每个数据的内容, 查看adc的采样值. 并根据业务需要, 比如把adc值转成mv为单位的电压值, 然后做char值修改等等.

static uint8_t get_battery_percentage(nrf_saadc_value_t adc_result) {
    uint16_t batt_lvl_in_milli_volts;
    batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS;
    NRF_LOG_INFO("battery = %d mv \n\r", batt_lvl_in_milli_volts);
    return bat_mini_volt_to_percentage(batt_lvl_in_milli_volts);
}

这里是adc转mv, 下面是我老板写的, mv转百分数.

// 针对4.2伏特锂电池的点亮百分比算法.
uint8_t bat_mini_volt_to_percentage(uint16_t mvolts) {
    uint8_t battery_level;

    if (mvolts >= 4200) {
        battery_level = 100;
    } else if (mvolts > 3720) {
        battery_level = 100 - (4200 - mvolts) / 6;
    } else if (mvolts > 3200) {
        battery_level = 20 - (3720 - mvolts) / 26;
    } else {
        battery_level = 0;
    }

    return battery_level;
}

原谅有这么多魔术数字, 你自己写的时候可不能这样哦…

你可能感兴趣的:(笔记,c语言)