嵌入式Linux开发14——ADC实验

程序编写

  ADC大家非常熟悉了,具体内容不再赘述,接下来只讨论和I.MX6ULL板子相关的ADC内容。首先要初始化ADC1_CH1相关的寄存器CFG寄存器、GC寄存器,初始化的过程中需要对初始化结果进行校准,我们单独编写一个校准函数,即需要关注GS寄存器的CALF位和HS寄存器的COCO0位,最后就是读取ADC寄存器R的值得到结果。

ADC.h

#include "imx6ul.h"

int adc1ch1_init(void);
status_t adc1_autocalibration(void);
uint32_t getadc_value(void);
unsigned short getadc_average(unsigned char times);
unsigned short getadc_volt(void);

ADC.c

#include "bsp_adc.h"
#include "bsp_delay.h"
#include "stdio.h"

/*
 * @description	: 初始化ADC1_CH1,使用GPIO1_IO01这个引脚。
 * @param		: 无
 * @return 		: 0 成功,其他值 错误代码
 */
int adc1ch1_init(void)
{
    int ret = 0;

    /* 1、初始化ADC1 CH1 */
    /* CFG寄存器
     * bit16        0       关闭复写功能
     * bit15:14     00      硬件平均设置为默认值,00的时候4次平均,
     *                      但是得ADC_GC寄存器的AVGE位置1来使能硬件平均
     * bit13        0       软件触发
     * bit12:1      00      参考电压为VREFH/VREFL,也就是3.3V/0V
     * bit10        0       正常转换速度
     * bit9:8       00      采样时间2/12,ADLSMP=0(短采样)的时候为2个周期
     *                      ADLSMP=1(长采样)的时候为12个周期
     * bit7         0       非低功耗模式
     * bit6:5       00      ADC时钟源1分频 
     * bit4         0       短采样
     * bit3:2       10      12位ADC
     * bit1:0       11      ADC时钟源选择ADACK   
     */
    ADC1->CFG = 0;
    ADC1->CFG |= (2 << 2) | (3 << 0);

    /* GC寄存器
     * bit7     0       先关闭校准功能,后面会校准
     * bit6     0       关闭持续转换
     * bit5     0       关闭硬件平均功能
     * bit4     0       关闭比较功能
     * bit3     0       关闭比较的Greater Than功能
     * bit2     0       关闭比较的Range功能
     * bit1     0       关闭DMA
     * bit0     1       使能ADACK
     */
    ADC1->GC = 0;
    ADC1->GC |= 1 << 0;

    /* 2、校准ADC */
    if(adc1_autocalibration() != kStatus_Success)
        ret = -1;

    return ret;
}

/*
 * @description	: 初始化ADC1校准
 * @param		: 无
 * @return 		: kStatus_Success 成功,kStatus_Fail 失败
 */
status_t adc1_autocalibration(void)
{
    status_t ret  = kStatus_Success;

    ADC1->GS |= (1 << 2);   /* 清除CALF位,写1清零 */
    ADC1->GC |= (1 << 7);   /* 使能校准功能 */

    /* 校准完成之前GC寄存器的CAL位会一直为1,直到校准完成此位自动清零 */
    while((ADC1->GC & (1 << 7)) != 0) { 
        /* 如果GS寄存器的CALF位为1的话表示校准失败 */
        if((ADC1->GS & (1 << 2)) != 0) {
            ret = kStatus_Fail;
            break;
        }
    }

    /* 校准成功以后HS寄存器的COCO0位会置1 */
    if((ADC1->HS  & (1 << 0)) == 0) 
        ret = kStatus_Fail;

    /* 如果GS寄存器的CALF位为1的话表示校准失败 */
        if((ADC1->GS & (1 << 2)) != 0) 
        ret = kStatus_Fail;

    return ret;
}

/*
 * @description	: 获取ADC原始值
 * @param		: 无
 * @return 		: 获取到的ADC原始值
 */
unsigned int getadc_value(void)
{

    /* 配置ADC通道1 */
    ADC1->HC[0] = 0;            /* 关闭转换结束中断    */
    ADC1->HC[0] |= (1 << 0);     /* 通道1            */

    while((ADC1->HS & (1 << 0)) == 0);  /* 等待转换完成 */

    return ADC1->R[0];    /* 返回ADC值 */
}

/*
 * @description	        : 获取ADC平均值
 * @param		times   : 获取次数
 * @return 		        : times次转换结果平均值
 */
unsigned short getadc_average(unsigned char times)
{
	unsigned int temp_val = 0;
	unsigned char t;
	for(t = 0; t < times; t++){
		temp_val += getadc_value();
		delayms(5);
	}
	return temp_val / times;
} 

/*
 * @description : 获取ADC对应的电压值
 * @param	    : 无
 * @return 	    : 获取到的电压值,单位为mV
 */
unsigned short getadc_volt(void)
{
    unsigned int adcvalue=0;
    unsigned int ret = 0;
    adcvalue = getadc_average(5);
    ret = (float)adcvalue * (3300.0f / 4096.0f);    	/* 获取计算后的带小数的实际电压值 */
    return  ret;
}


main.c

#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "bsp_lcd.h"
#include "bsp_lcdapi.h"
#include "bsp_rtc.h"
#include "bsp_backlight.h"
#include "bsp_adc.h"
#include "stdio.h"

/*
 * @description	: 使能I.MX6U的硬件NEON和FPU
 * @param 		: 无
 * @return 		: 无
 */
 void imx6ul_hardfpu_enable(void)
{
	uint32_t cpacr;
	uint32_t fpexc;

	/* 使能NEON和FPU */
	cpacr = __get_CPACR();
	cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk))
		   |  (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos);
	__set_CPACR(cpacr);
	fpexc = __get_FPEXC();
	fpexc |= 0x40000000UL;	
	__set_FPEXC(fpexc);
}

volatile 


/*
 * @description	: main函数
 * @param 		: 无
 * @return 		: 无
 */
int main(void)
{
	unsigned char i = 0;
	unsigned int adcvalue;
	unsigned char state = OFF;
	signed int integ; 	/* 整数部分 */
	signed int fract;	/* 小数部分 */
	
	imx6ul_hardfpu_enable();	/* 使能I.MX6U的硬件浮点 			*/
	int_init(); 				/* 初始化中断(一定要最先调用!) */
	imx6u_clkinit();			/* 初始化系统时钟 					*/
	delay_init();				/* 初始化延时 					*/
	clk_enable();				/* 使能所有的时钟 					*/
	led_init();					/* 初始化led 					*/
	beep_init();				/* 初始化beep	 				*/
	uart_init();				/* 初始化串口,波特率115200 */
	lcd_init();					/* 初始化LCD 					*/
	adc1ch1_init();				/* ADC1_CH1			 		*/ 

	tftlcd_dev.forecolor = LCD_RED;
	lcd_show_string(50, 10, 400, 24, 24, (char*)"ADC TEST");  
	lcd_show_string(50, 40, 200, 16, 16, (char*)"CSDN jiajia 2020");  
	lcd_show_string(50, 60, 200, 16, 16, (char*)"2021/8/3");   
	lcd_show_string(50, 90, 400, 16, 16, (char*)"ADC Ori Value:0000");  
	lcd_show_string(50, 110, 400, 16, 16,(char*)"ADC Val Value:0.00 V");  
	tftlcd_dev.forecolor = LCD_BLUE;
	
	while(1)					
	{
		adcvalue = getadc_average(5);
		lcd_showxnum(162, 90, adcvalue, 4, 16, 0);	/* ADC原始数据值 */
		printf("ADC orig value = %d\r\n", adcvalue);

		adcvalue = getadc_volt();
		integ = adcvalue / 1000;
		fract = adcvalue % 1000;
		lcd_showxnum(162, 110, integ, 1, 16, 0);	/* 显示电压值的整数部分,3.1111的话,这里就是显示3 */
		lcd_showxnum(178, 110, fract, 3, 16, 0X80);	/* 显示电压值小数部分(前面转换为了整形显示),这里显示的就是111. */
		printf("ADC vola = %d.%dV\r\n", integ, fract);

		delayms(50);
		i++;
		if(i == 10)
		{	
			i = 0;
			state = !state;
			led_switch(LED0,state);	
		}
	}
	return 0;
}

结果验证

在这里插入图片描述  编译下载后,程序正常运行,LCD显示的Ori Value为从ADC寄存器读取的值,Val Value为经过运算后得到的实际采集电压值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾贾乾杯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值