历史上的今天
返回首页

历史上的今天

今天是:2024年11月04日(星期一)

正在发生

2021年11月04日 | 一起学mini2440裸机开发(十三)--ADC原理与实验

2021-11-04 来源:eefocus

概述

S3C2440的CMOS模拟数字转换器ADC可以对8通道模拟输入信号进行循环检测,S3C2440的ADC和触摸屏公用一个ADC转换器,所以学习ADC也是学习触摸屏的基础。


    S3C2440ADC的主要特性如下:


    ●分辨率:10位


    ●最大转换速率:500KSPS


    ●微分线性度误差:±1.0 LSB


    ●积分线性度误差:±2.0 LSB


    ●供电电压:3.3V


    ●模拟输入电压范围:0~3.3V


ADC原理

ADC是一种将模拟信号转化为数字信号的方法,一般要经过采样、保持、量化、编码4个步骤。在实际电路中,有些过程是合并进行的,如采样和保持,量化和编码在转换过程中时同时实现的。由奈奎特采样定理可知,当采样频率大于模拟信号中最高频率的2倍时,采样值才能不失真地反映原来模拟信号。


主要技术指标如下:


●  分辨率


通常以输出二进制的位数表示分辨率的高低,一般位数越多,量化单位越小,对输入信号的分辨能力就越高。例如,输入模拟电压的变化范围为0±~3.3V、分辨率为12位时,可以分辨的最小模拟电压为3.3V/2^12≈0.8mV;而分辨率为10位时,可以分辨的最小模拟电压为3.3V/2^10≈3.2mV。


●  转换误差


它是指在零点和满度都校准以后,在整个转换范围内,分别测量各个数字量所对应的模拟输入电压实测范围与理论范围之间的偏差,取其中的最大偏差作为转换误差的指标。它通常以相对误差的形式出现,并以LSB为单位表示。


●  转换速度


完成一次模数转换所需要的时间称为转换时间。在大多数情况下,转换速度是转换时间的倒数。


ADC的转换速度主要取决于转换电路的类型,并联比较型ADC的转换速度最高,逐次逼近型ADC次之,双积分型ADC转换速度最低。


S3C2440处理器ADC功能图如图1所示,其中虚线框是与触摸屏有关的功能模块,可以暂不考虑,学完ADC基本实验后,再学触摸屏部分也可以。

从图1可以看出,ADC共有8路模拟输入,其中XP、XM、YP和YM是触摸屏使用的4路,剩下的4路模拟输入A[3:0]可以用于一般的ADC输入通道。


此外还需要注意ADC的输入时钟是如何产生的。对于S3C2440处理器,ADC输入时钟是由PCLK分频得到的,如图2所示

ADC相关寄存器


使用ADC只需要对相应的寄存器进行配置,然后启动ADC即可,启动ADC有两种方法:


         ①手动启动


         ②读取完上一次转换结果后自动启动下一次ADC转换


     得到ADC是否转换完成的信息有两种方法


         ①查询法:查询寄存器ADCCON的第15位(ADC转换结束标志位)


         ②中断法:转换完成后,产生ADC中断信号,如图1中的INT_ADC信号。


当不使用触摸屏时,与ADC相关的寄存器主要有寄存器ADCCON和寄存器ADCDAT0。寄存器ADCCON主要用于ADC的启动方式、设置ADC转换时钟以及ADC转换结束标志位等,如下图3。寄存器ADCDAT0中存放了ADC转换所得到的的数据,ADC转换结束后,可以通过读该寄存器的值来得到转换结果。

     

ADC初始化

对ADC初始化只需要做好以下两个方面的工作:


① 设置ADC输入时钟。


② 选择ADC输入通道。


可以使用如下代码初始化:


#define PRSC_EN   1 //允许预分频

#define PRSCVL   19 //预分频值

#define STDBM   0  //正常工作模式

#define READ_START  0  //读数时不进行A/D转换


void ADC_Init(unsigned char channel)    

{

    ADCCON&=(~((1<<14)|(0xff<<6)|(0x7<<3)|(1<<2)|(1<<1)|(1<<0)));

    ADCCON|=(PRSC_EN<<14)|(PRSCVL<<6)|(channel<<3)|(STDBM<<2)|(READ_START<<1);


}


此时,对PCLK进行50分频,则可以计算出ADC输入时钟=PCLK/50=1MHz。


ADC基础实验


在我的mini2440上有一个可调电位器,如下图所示。电位器的中间抽头部分接在ADC输入通道0上,当电位器滑动头位于最下端时,AIN0引脚电压为0V;当电位器滑动头位于最上端时,AIN0引脚电压为3.3V;当电位器上、下滑动时,AIN0引脚的电压值会在0~3.3V之间变换。因此,本实验使用ADC输入通道0对AIN0引脚电压进行A/D转换。

下图为我的ADC实验的文件布局:

下面贴出我的实验代码


main.c文件


/************************************************

* 调节mini2440上的可调电位器,然后使用ADC输入通道2对

* AIN2引脚电压尽心转换,将取得的数字量输出到串口

*************************************************/


#include"adc.h"

#include"uart.h"


int main()

{

    int value;

    Uart0_Init(115200);

    ADC_Init(0);


     value=ADC_Read();   //将A/D转换值发送到串口,这里我没有使用

     Uart0_Printf("%d",value/1000);      //while()循环是为了看清楚值

     Uart0_Printf("%d",value%1000/100);   //调节电位器后,可以重启

     Uart0_Printf("%d",value%100/10);    //开发板,看到串口输出值

     Uart0_Printf("%d",value%10);     //不一样了

  

}


uart.h文件


#ifndef __UART_H__

#define __UART_H__


/***********************************************

*函数名称:void Uart0_Init(unsigned int baudrate)

*参数说明:baudrate:波特率

*返 回 值:无

*全局变量: 无

*功    能:对UART0进行初始化                         

************************************************/

void Uart0_Init(unsigned int baudrate);


/***********************************************

*函数名称:void putc(unsigned char c)

*参数说明:c:通过串口接收到的字符,注意这里是8位数据

*返 回 值:无

*全局变量: 无

*功    能:将通过串口接收到的字符发送给PC机并显示在

*          串口调试工具。                

************************************************/

void putc(unsigned char c);


/***********************************************

*函数名称:unsigned char getc(void)

*参数说明:无

*返 回 值:c:通过串口接收到的字符,注意这里是8位数据

*全局变量: 无

*功    能:接收并保存通过串口输入的数据                         

************************************************/

unsigned char getc(void);


/***********************************************

*函数名称:void Uart0_Printf(const char *fmt,...)

*参数说明:可变参数

*返 回 值:无

*全局变量: 无

*功    能:将()的内容通过串口发送并在PC机显示                

************************************************/

void Uart0_Printf(const char *fmt,...);


#endif


uart.c文件


#include

#include

#include"uart.h"


#define PCLK   50000000

#define UART_BRD     (int)((PCLK/(baudrate*16))-1)


/***********************************************

*函数名称:void Uart0_Init(unsigned int baudrate)

*参数说明:baudrate:波特率

*返 回 值:无

*全局变量: 无

*功    能:对UART0进行初始化                         

************************************************/

void Uart0_Init(unsigned int baudrate)

{

 GPHCON&=~((3<<4)|(3<<6));  //GPH2--TXD0;GPH3--RXD0

 GPHCON|=((2<<4)|(2<<6));    //设置GPH2、GPH3为TXD0、RXD0功能

 GPHUP=0x00;                 //上拉电阻使能

 ULCON0|=0x03;              //设置数据发送格式:8个数据位,1个停止位,无校验位

 UCON0=0x05;                //发送模式和接收模式都使用查询模式

 UBRDIV0=UART_BRD;         //设置波特率,其中波特率作为一个参数传递到该初始化函数

 URXH0=0;          //将URXH0清零

}


/***********************************************

*函数名称:void putc(unsigned char c)

*参数说明:c:通过串口接收到的字符,注意这里是8位数据

*返 回 值:无

*全局变量: 无

*功    能:将通过串口接收到的字符发送给PC机并显示在

*          串口调试工具。                

************************************************/

void putc(unsigned char c)

{

 UTXH0=c;

 while(!(UTRSTAT0&(1<<2)));    //等待发送完成

}


/***********************************************

*函数名称:unsigned char getc(void)

*参数说明:无

*返 回 值:c:通过串口接收到的字符,注意这里是8位数据

*全局变量: 无

*功    能:接收并保存通过串口输入的数据                         

************************************************/

unsigned char getc(void)

{

 unsigned char c;

 while(!(UTRSTAT0&(1<<0)));     //查询是否接收到有效数据

 c=URXH0;

 return c;

}

/***********************************************

*函数名称:static void Uart0_SendByte(int data)

*参数说明:data:一个字节的数据

*返 回 值:无

*全局变量: 无

*功    能:向串口发送一个字节的数据。这个函数只在本

*          C文件内使用,不被其他文件所调用,故使用

*     static来修饰。                 

************************************************/


static void Uart0_SendByte(int data)

{

    if(data=='n')      //注意,在超级终端中使用的换行符是'r',因此当遇到'n'时

    {                      //需要将其转换为'r'

     while(!(UTRSTAT0&(1<<2)));    //等待发送完成

     UTXH0='r';  

    }

    while(!(UTRSTAT0&(1<<2)));    //等待发送完成完成后,将新发送

    UTXH0=data;                            //的数据写入发送寄存器

}

/***********************************************

*函数名称:static void Uart0_SendString(char *pt)

*参数说明:pt:指针,指向将要发送的数据所在数组的地址

*返 回 值:无

*全局变量: 无

*功    能:发送字符串                 

************************************************/

static void Uart0_SendString(char *pt)

{

  while(*pt)

  {

       Uart0_SendByte(*pt++); 

  }

}

/***********************************************

*函数名称:void Uart0_Printf(const char *fmt,...)

*参数说明:可变参数

*返 回 值:无

*全局变量: 无

*功    能:将()的内容通过串口发送并在PC机显示                

************************************************/

void Uart0_Printf(const char *fmt,...)

{

 va_list ap;      //定义了一个指向可变参数列表指针

 char string[50];  //存储要发送的内容


 va_start(ap,fmt);   //是参数列表指针ap指向函数参数列表中的第一个可变参数

 vsprintf(string,fmt,ap);

 va_end(ap);         //清空参数列表

 Uart0_SendString(string);   //将该缓冲区中的数据打印到串口中

}

//详细讲解请看博客:http://blog.csdn.net/mybelief321/article/details/8934635


adc.h文件


#ifndef __ADC_H__

#define __ADC_H__

/***********************************************

*函数名称:void ADC_Init(unsigned char channel)

*参数说明:channel:通道

*返 回 值:无

*全局变量: 无

*功    能:ADC初始化,手动启动ADC,ADC输入时钟为1MHz                       

************************************************/

void ADC_Init(unsigned char channel);


/***********************************************

*函数名称:void ADC_Init(unsigned char channel)

*参数说明:channel:通道

*返 回 值:无

*全局变量: 无

*功    能:ADC初始化,手动启动ADC,ADC输入时钟为1MHz                       

************************************************/

int ADC_Read(void);

#endif


adc.c文件


#include

#include"adc.h"


#define PRSC_EN   1 //允许预分频

#define PRSCVL   19 //预分频值

#define STDBM   0  //正常工作模式

#define READ_START  0  //读数时不进行A/D转换

#define Adc_Start()  {ADCCON|=1;}


/***********************************************

*函数名称:void ADC_Init(unsigned char channel)

*参数说明:channel:通道

*返 回 值:无

*全局变量: 无

*功    能:ADC初始化,手动启动ADC,ADC输入时钟为1MHz                       

************************************************/

void ADC_Init(unsigned char channel)    

{

   ADCCON&=(~((1<<14)|(0xff<<6)|(0x7<<3)|(1<<2)|(1<<1)|(1<<0)));

   ADCCON|=(PRSC_EN<<14)|(PRSCVL<<6)|(channel<<3)|(STDBM<<2)|(READ_START<<1);


}


/***********************************************

*函数名称:int ADC_Read(void)

推荐阅读

史海拾趣

Eutech公司的发展小趣事

在电源适配器和服务器电源市场,EUtech公司凭借技术创新迅速崛起。他们不断优化产品设计,提高产品性能,同时注重节能环保。随着下游AI行业的快速发展,公司及时抓住机遇,推出了一系列高性能、高可靠性的电源产品,赢得了市场的广泛认可。

ESS [ESS Technology,Inc]公司的发展小趣事

ESS的创始人陈兆良是一位具有远见卓识的领导者。他不仅带领公司成功转型,专注于个人电脑音频技术,还推动了公司向更广泛的半导体芯片领域发展。陈兆良凭借其在半导体语音芯片领域的深厚造诣,一度夺得了全球80%的市场份额,被誉为“数码音频和视频之父”。他的领导才能和对市场的敏锐洞察力为ESS的成功奠定了坚实基础。

福声科技(FUET)公司的发展小趣事

随着市场的不断变化和技术的飞速发展,福声科技深知技术创新的重要性。公司不断加大研发投入,组建了一支高素质的研发团队,专注于电磁式蜂鸣器、压电式蜂鸣器等新型产品的研发。通过持续的技术创新和产品升级,福声科技成功推出了一系列具有自主知识产权的电声元器件,不仅提升了产品的市场竞争力,还进一步拓宽了应用领域,如智能家居、安防系统等新兴市场。

HB公司的发展小趣事

背景:Fritz Hartmann Gerätebau KG成立于1961年,起初专注于电子元器件的研发与生产。随着技术的不断积累和市场的逐步拓展,公司业务逐渐壮大,并更名为Hartmann Codier GmbH。这一时期,公司凭借对开关技术的深刻理解,逐步在行业内建立了良好的声誉。

发展:在初创阶段,Hartmann Codier GmbH致力于提升产品质量和技术水平,通过不断的技术创新和产品优化,逐渐在旋转编码开关和微动开关领域占据了一席之地。同时,公司也积极拓展国内外市场,为后续的快速发展奠定了坚实的基础。

联智(Celfras)公司的发展小趣事

联智的半导体集成电路芯片研发及产业化项目是其发展历程中的又一重要里程碑。该项目总投资高达20亿元,分两期建设。一期项目将建设半导体集成电路模拟芯片封测生产线,预计年产量可达1.5亿颗。二期项目将研发更高功率有线无线融合一体化电源管理芯片和新一代A4WP远距离无线充电芯,同时布局物联网IoT芯片市场。这一项目的实施将进一步提升联智的技术实力和市场竞争力。

Feller US公司的发展小趣事

随着市场竞争的加剧和资金问题的持续困扰,菲斯克在某一时期不得不宣布停产六周。这一决定引发了外界的广泛关注和质疑。然而,菲斯克并没有因此放弃,而是利用这段时间进行了深入的内部反思和策略调整。通过优化生产流程、降低成本以及加强与其他汽车制造商的合作,公司逐渐走出了困境,重新焕发出新的生机。

问答坊 | AI 解惑

中国IC产业销售收入规模及增长趋势

中国IC产业销售收入规模及增长趋势 2006-7-11     2006年第一季度,我国集成电路产业全行业共实现销售收入总额214.88亿元,同比增长54.8%。 …

查看全部问答>

基于PXA255的ARM Linux操作系统移植

摘要: Linux在嵌入式领域中应用越来越广泛,已成为最有潜力的嵌入式操作系统。操作系统的移植是进行嵌入式应用开发的前提和基础。ARM Linux是一种针对ARM体系结构的Linux操作系统。本文以新一代高端嵌入式处理器PXA255为例,进行ARM Linux的移植, ...…

查看全部问答>

请教各位前辈!!!

我是一名在校大学生,想问一下,现在Multisim 8这个电路设计软件怎么样?在实际工作中运用的多不多?本人想好好学一学!是否有这个必要?也请各位推荐下好的教程!!!…

查看全部问答>

CPES-IBM未来通信电源功率架构

CPES-IBM未来通信电源功率架构…

查看全部问答>

小车控制算法研究 高手大牛 来说说思路

车图 跑道 现在  要控制车子速度 通过一个舵机控制车头转动方向 转动的方向由前面的红外传感器检测到跑道的识别码得到 但是检测的识别码只可能尽量的和实际吻合但仍会有几度的误差 有时甚至会更多 程序会不停的扫描道路得到识 ...…

查看全部问答>

下载wince5.0内核液晶不亮,但wince4.2正常

我用的是QQ2440板子,液晶屏是FriendlyARM 8.4\'\'LCD,我将光盘自带的wince4.2的nk.bin下载后,液晶屏正常显示,但是换成wince5.0的nk.bin液晶屏却是黑屏,刚开机时能隐约看到5.0的界面,但慢慢就变黑了,哪位知道原因。对液晶屏的供电是3.3V和5V ...…

查看全部问答>

嵌入式问题

题目如下: 设计一个针对某一具体应用的嵌入式系统 要求:1有完整的系统设计方案 2对系统方案有完整说明 3有相应的印制版图 4有完整的系统调试方案 5软件流程及其说明 急 麻烦高手指点迷津 谢谢…

查看全部问答>

双网卡热备份(双网卡冗余备份)如何设计与实现呢(2)?

你好?WIN2000下,以太网网络,双网卡热备份,也就是一个网卡坏了,另一个冗余网卡热切换,两个网卡同一个IP地址,实现方案是什么?使用哪些工具,技术?代码是什么?请问做双网卡热备份,是不是在ndis的例子PASSTHRU的代码基础上,修改即可?怎么修改?希望不 ...…

查看全部问答>

求助:USB HID设备无法访问题

我在做一块usb声卡,这是一个USB Composite Device,Firmware写完了,现在想做pc host的app,要对HID的endpoint4写数据,打开设备的时候能得到设备路径,但是无法读写,部分代码如下。     //Open the USB device     char c ...…

查看全部问答>

类CPdd16550中m_dwWaterMark是用来干什么的?

类CPdd16550中m_dwWaterMark是用来干什么的? 是波特率的mark呢还是安全相关的mark? 有劳各位!…

查看全部问答>