因为业务需要, 需要在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;
}
原谅有这么多魔术数字, 你自己写的时候可不能这样哦…