安信可小安派【Analog to digital】 ADC 基于AI-M6x
今天来分享一下我的ADC学习心得,首先说明当前的教程适用于所有的搭载AI-m61或者m62芯片的小安派。
重要的方法如下:
/**
* @brief 初始化GPIO端口作为analog
*
* @param [in] dev device handle
* @param [in] pin gpio pin, use @ref GPIO_PIN
* @param [in] cfgset gpio config mask
*/
void bflb_gpio_init(struct bflb_device_s *dev, uint8_t pin, uint32_t cfgset);
/**
* @brief 初始化ADC功能
*
* @param [in] ADC外设
* @param [in] ADC 配置结构体
*/
void bflb_adc_init(struct bflb_device_s *dev, const struct bflb_adc_config_s *config);
/**
* @brief ADC配置结构体
*
* @param clk_div adc时钟频率是否分频,频率越高精度越差,相反精度越高
* @param scan_conv_mode ADC scan mode enable, ADC扫描模式,我不清楚干什么用的
* @param continuous_conv_mode ADC continuous conversion enable ,Adc持续转换,不清楚干嘛额
* @param differential_mode ADC differential mode enable , adc 差异区分模式, 不清楚干嘛的
* @param resolution ADC resolution, use @ref ADC_RESOLUTION adc转换精度
* @param vref ADC reference select, use @ref ADC_VREF adc参考电压
*/
struct bflb_adc_config_s {
uint8_t clk_div;
uint8_t scan_conv_mode;
uint8_t continuous_conv_mode;
uint8_t differential_mode;
uint8_t resolution;
uint8_t vref;
};
/**
* @brief 绑定ADC和对用的通道
*
* @param [in] dev device handle
* @param [in] 所有的通道
* @param [in] 你所要使用的通道
* @return Zero on success; a negated errno value on failure
*/
int bflb_adc_channel_config(struct bflb_device_s *dev, struct bflb_adc_channel_s *chan, uint8_t channels);
这里定义的是所有的ADC通道,我这里只定义了 0 通道,就是gpio20
struct bflb_adc_channel_s chan[] = {
#if TEST_ADC_CHANNEL_0
{.pos_chan = ADC_CHANNEL_0,
.neg_chan = ADC_CHANNEL_GND},
#endif
};
/**
* @brief 开始转换ADC
*
* @param [in] dev device handle
*/
void bflb_adc_start_conversion(struct bflb_device_s *dev);
/**
* @brief 获取ADC转换结果
*
* @param [in] dev device handle
* @return conversion value
*/
uint32_t bflb_adc_read_raw(struct bflb_device_s *dev);
/**
* @brief 结束转换ADC
*
* @param [in] dev device handle
*/
void bflb_adc_stop_conversion(struct bflb_device_s *dev);
/**
* @brief 解析raw adc转换结果到毫伏, 以数字形式展示
*
* @param [in] dev device handle
* @param [in] bflb_adc_read_raw 方法转换的结果
* @param [out] result pointer to save parse result, 转换后保存的结果,需要自己定义
* @param [in] count count to parse。 不清楚干什么用的 传递0 即可
*/
void bflb_adc_parse_result(struct bflb_device_s *dev, uint32_t *buffer, struct bflb_adc_result_s *result, uint16_t count);
需要的库文件如
库文件 | 说明 |
bflb_adc.h | ADC功能 |
log.h | 用来打印日志 |
bflb_gpio.h | 初始化GPIO |
bflb_mtimer.h | 延时 |
board.h | 初始化系统 |
重要的方法如下:
/**
* @brief 初始化GPIO端口作为analog
*
* @param [in] dev device handle
* @param [in] pin gpio pin, use @ref GPIO_PIN
* @param [in] cfgset gpio config mask
*/
void bflb_gpio_init(struct bflb_device_s *dev, uint8_t pin, uint32_t cfgset);
/**
* @brief 初始化ADC功能
*
* @param [in] ADC外设
* @param [in] ADC 配置结构体
*/
void bflb_adc_init(struct bflb_device_s *dev, const struct bflb_adc_config_s *config);
/**
* @brief ADC配置结构体
*
* @param clk_div adc时钟频率是否分频,频率越高精度越差,相反精度越高
* @param scan_conv_mode ADC scan mode enable, ADC扫描模式,我不清楚干什么用的
* @param continuous_conv_mode ADC continuous conversion enable ,Adc持续转换,不清楚干嘛额
* @param differential_mode ADC differential mode enable , adc 差异区分模式, 不清楚干嘛的
* @param resolution ADC resolution, use @ref ADC_RESOLUTION adc转换精度
* @param vref ADC reference select, use @ref ADC_VREF adc参考电压
*/
struct bflb_adc_config_s {
uint8_t clk_div;
uint8_t scan_conv_mode;
uint8_t continuous_conv_mode;
uint8_t differential_mode;
uint8_t resolution;
uint8_t vref;
};
/**
* @brief 绑定ADC和对用的通道
*
* @param [in] dev device handle
* @param [in] 所有的通道
* @param [in] 你所要使用的通道
* @return Zero on success; a negated errno value on failure
*/
int bflb_adc_channel_config(struct bflb_device_s *dev, struct bflb_adc_channel_s *chan, uint8_t channels);
这里定义的是所有的ADC通道,我这里只定义了 0 通道,就是gpio20
struct bflb_adc_channel_s chan[] = {
#if TEST_ADC_CHANNEL_0
{.pos_chan = ADC_CHANNEL_0,
.neg_chan = ADC_CHANNEL_GND},
#endif
};
/**
* @brief 开始转换ADC
*
* @param [in] dev device handle
*/
void bflb_adc_start_conversion(struct bflb_device_s *dev);
/**
* @brief 获取ADC转换结果
*
* @param [in] dev device handle
* @return conversion value
*/
uint32_t bflb_adc_read_raw(struct bflb_device_s *dev);
/**
* @brief 结束转换ADC
*
* @param [in] dev device handle
*/
void bflb_adc_stop_conversion(struct bflb_device_s *dev);
/**
* @brief 解析raw adc转换结果到毫伏, 以数字形式展示
*
* @param [in] dev device handle
* @param [in] bflb_adc_read_raw 方法转换的结果
* @param [out] result pointer to save parse result, 转换后保存的结果,需要自己定义
* @param [in] count count to parse。 不清楚干什么用的 传递0 即可
*/
void bflb_adc_parse_result(struct bflb_device_s *dev, uint32_t *buffer, struct bflb_adc_result_s *result, uint16_t count);
#include "bflb_mtimer.h" #include "board.h" #include "bflb_adc.h" #define DBG_TAG "MAIN" #include "log.h" #include "bflb_gpio.h" struct bflb_device_s *adc; struct bflb_device_s *gpio; #define TEST_ADC_CHANNEL_0 0 // 定义所有的adc通道 struct bflb_adc_channel_s chan[] = { #if TEST_ADC_CHANNEL_0 {.pos_chan = ADC_CHANNEL_0, .neg_chan = ADC_CHANNEL_GND}, #endif }; int main(void) { board_init(); gpio = bflb_device_get_by_name("gpio"); // 初始化IO 20 作为 analog bflb_gpio_init(gpio, GPIO_PIN_20, GPIO_ANALOG | GPIO_SMT_EN | GPIO_DRV_0); adc = bflb_device_get_by_name("adc"); // 原始转换数据 volatile uint32_t raw_data; // adc 配置 struct bflb_adc_config_s cfg; // 始终分频, 分频约低速度越快,精度越低。 当前为最高分频,速度最快精度最低 cfg.clk_div = ADC_CLK_DIV_32; // 剩下这三个参数没有搞明白实际作用 cfg.scan_conv_mode = true; cfg.continuous_conv_mode = false; cfg.differential_mode = false; // 设置adc精度 cfg.resolution = ADC_RESOLUTION_16B; // adc参考电压 cfg.vref = ADC_VREF_3P2V; // 初始化ADC bflb_adc_init(adc, &cfg); // 绑定ADC通道 bflb_adc_channel_config(adc, chan, TEST_ADC_CHANNEL_0); while (1) { // 转换 bflb_adc_start_conversion(adc); // 结束转换 bflb_adc_stop_conversion(adc); //获取原生转换结果 raw_data = bflb_adc_read_raw(adc); struct bflb_adc_result_s result; printf("raw data:%08x\r\n", raw_data); //解析raw 转换结果 bflb_adc_parse_result(adc, (uint32_t *)&raw_data, &result, 1); printf("postive values is %d, negative is : %d mv is %d \r\n", result.pos_chan, result.neg_chan, result.millivolt); //适当的延时 bflb_mtimer_delay_ms(20); } }
转换结果如下: