ADC(Analog-to-Digital Converter) 指模数转换器。将模拟电压信号转换成数字信号,通常ADC接口会连接一些传感器,如:温度传感器;陀螺仪加速度计;电位器等等。
开发前准备
- 硬件平台:nxp rt10xx单片机
- IDE: Keil
1.Kconfig 修改和menuconfig配置
在Env环境menuconfig中 RT-Thread Components->Device Drivers 设备驱动默认为n,所以需要开启。
先在Kconfig中添加如下语句,然后在Env环境menuconfig中 Hardware Drivers Config->On-Chip Peripheral Drivers 使能ADC
2.工程添加ADC驱动框架和BSP驱动接口
设备驱动框架:adc.c BSP接口:drv_adc.c fsl_adc.c fsl_adc_etc.c(imxrt 特有功能,本章用不到)
3.添加或修改drv_adc.c
笔者查阅了文件,发现 drv_adc.c 这个文件,只写了很初级的adc查询的方法,这种方式简单,适用于比较单一的adc项目。实际在应用中我们通常会采用中断方式,或者adc dma这样会让整个系统更加灵活,系统也不会等待adc状态消耗cpu资源。补充一下:imxrt系列 的adc,可使用adc etc结合外设pit 和 xbara触发转换,本章不会添加这些,后期有时间,再去完善drv_adc.c 和 adc.c文件,暂时使用现成已经写好的框架文件。
struct rt_adc_ops
{
rt_err_t (*enabled)(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled);
rt_err_t (*convert)(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value);
};
struct rt_adc_device
{
struct rt_device parent;
const struct rt_adc_ops *ops;
};
static struct rt_adc_ops imxrt_adc_ops =
{
.enabled = imxrt_hp_adc_enabled,
.convert = imxrt_hp_adc_convert,
};
这里笔者只简单修改了一点,采样精度改成10bit,降低一些功耗吧,具体看项目来,另外新增硬件平均
int rt_hw_adc_init(void)
{
int result = RT_EOK;
#if defined(BSP_USING_ADC1)
ADC_GetDefaultConfig(&ADC1_config_value);
ADC1_config_value.resolution = kADC_Resolution10Bit;
ADC_Init(ADC1, &ADC1_config_value);
#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
ADC_EnableHardwareTrigger(ADC1, false);
#endif
ADC_SetHardwareAverageConfig(ADC1, kADC_HardwareAverageCount16);
ADC_DoAutoCalibration(ADC1);
result = rt_hw_adc_register(&adc1_device, "adc1", &imxrt_adc_ops, ADC1);
if (result != RT_EOK)
{
LOG_E("register adc1 device failed error code = %d\n", result);
}
#endif /* BSP_USING_ADC1 */
#if defined(BSP_USING_ADC2)
ADC_GetDefaultConfig(&ADC2_config_value);
ADC_Init(ADC2, &ADC2_config_value);
#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
ADC_EnableHardwareTrigger(ADC2, false);
#endif
ADC_DoAutoCalibration(ADC2);
result = rt_hw_adc_register(&adc2_device, "adc2", &imxrt_adc_ops, ADC2);
if (result != RT_EOK)
{
LOG_E("register adc2 device failed error code = %d\n", result);
}
#endif /* BSP_USING_ADC2 */
return result;
}
INIT_DEVICE_EXPORT(rt_hw_adc_init);
内容很简单直接贴代码
static rt_err_t imxrt_hp_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
{
return RT_EOK;
}
static rt_err_t imxrt_hp_adc_convert(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
{
adc_channel_config_t adc_channel;
ADC_Type *base;
base = (ADC_Type *)(device->parent.user_data);
adc_channel.channelNumber = channel;
adc_channel.enableInterruptOnConversionCompleted = false;
ADC_SetChannelConfig(base, 0, &adc_channel);
while (0U == ADC_GetChannelStatusFlags(base, 0))
{
continue;
}
*value = ADC_GetChannelConversionValue(base, 0);
return RT_EOK;
}
4.搭建应用层demo
底层IO初始化
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_14_GPIO1_IO14, 0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_14_GPIO1_IO14, 0xB0U);
应用读取adc1 通道3数据
/**************************************************START OF FILE*****************************************************/
/*------------------------------------------------------------------------------------------------------------------
Includes
*/
#include <rtthread.h>
#include <rtdevice.h>
/*------------------------------------------------------------------------------------------------------------------
Macros
*/
#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
#define ADC_DEV_CHANNEL 3 /* ADC 通道 */
/*------------------------------------------------------------------------------------------------------------------
Variables
*/
static rt_adc_device_t adc_dev;
/*------------------------------------------------------------------------------------------------------------------
Functions
*/
static int adcSample(int argc, char *argv[])
{
rt_uint32_t value;
rt_err_t ret = RT_EOK;
/* 查找设备 */
adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
if (adc_dev == RT_NULL)
{
rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
return RT_ERROR;
}
rt_kprintf("adc start", value);
return ret;
}
static void adcRead(void)
{
rt_uint32_t value;
rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
rt_kprintf("the value is :%d \n", value);
rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(adcSample, adc voltage convert sample);
MSH_CMD_EXPORT(adcRead, adc read);
/****************************************************END OF FILE*****************************************************/
输入命令adcSample运行应用,输入adcRead打印当前adc值,笔者就仅仅将adc引脚触碰GND和3.3V测试