原创 【ATMEGA16L】实验三十:ADC实验(纠错版)

2009-8-14 09:13 3457 8 8 分类: MCU/ 嵌入式

》》点此进入      http://bbs.armavr.com/   ARM-AVR嵌入式开发论坛


        ARM-AVR嵌入式开发论坛,专为AVR单片机初学者而建,以资源共享、经验交流为主旨,以共同进步和提高为目标。期待志同道合的朋友加入!


【相关实验】


【ATMEGA16L】实验一:流水灯实验(八种LED点亮模式)


【ATMEGA16L】实验二:有源蜂鸣器驱动实验


【ATMEGA16L】实验三:按键扫描(用KEY选择对应LED点亮)


【ATMEGA16L】实验四:键盘扫描+8种LED亮灭模式控制


【ATMEGA16L】实验二四:四线制LCD1602B驱动实验        


【ATMEGA16L】实验二五:八线制LCD1602B驱动实验


【ATMEGA16L】实验二八:USART综合实验


【ATMEGA16L】实验二九:模拟比较器实验


【ATMEGA16L】实验三十:ADC实验


*********************************************************************


        09年3月25日发表的日志:【ATMEGA16L】实验三十:ADC实验 “对ATMEGA16L的2.56V片内基准电压源存在疑问:为什么实际测得值是2.633V,误差似乎太大了,并且以此做为基准时,ADC转换结果不稳定,有较大波动。”


的表述是不正确的,今天发现程序有问题:function.c中void UartRecvData(void)中断函数对ADC通道进行重复配置,以致于main.c中void AdcInit(void)对ADC通道的配置失效。改正后验证通过,证明了2.56V片内基准电压源可以作为ADC的基准来使用。误导了大家,请见谅!


修改后的完整程序如下:


**********************************************************************


一、硬件电路:


a93f73bf-cb2a-48a4-be32-55998f47ec16.jpg


二、程序结构:


0ee61338-b592-4de0-bdeb-de219fd5b1c5.jpg


三、程序源代码


1、main.c


/*******************************************************************************
Platform: AVR mega16学习板(www.iccavr.com
Project : 实验三十:ADC实验
Clock F : 3.6864MHz
Software: ICCAVR7.14C
Author  : 林夕依然
Version : 09.03.24
Updata  : 09.04.01  确认2.56V片内基准可用
comments:
1、串口发送命令开启一次ADC,并将结果通过串口发送到PC,任意字符开始;
2、USART使用中断方式接收数据,当接收到数据后,开启一次ADC转换;
3、当ADC转换完成后产生中断,并置一个自定义的标志;
4、对ADC转换完成后的中断标志进行检测,为1时则将ADC转换数据发送给PC;
5、采用单通道AVCC外部参考源和2.56V 的片内基准电压源两种方式;
6、不用去管ADC转换结果的进制,这是由编译器完成的。转换得到的结果也不用管,是由单
   片自己完成的。
7、参考:D:\mcu\ICCAVR学习板\旧版例程\7-ADC
problem :
1、2.56V 的片内基准电压源实测值为2.634V,误差0.07V.
*******************************************************************************/
#include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint  unsigned int


uchar AdcData;                       //ADC转换的结果
uchar AdcConCom = 0;     //ADC转换完成标志
/*-----------------------------------------------------------------
函数名称: void AdcInit(void)
函数功能: ADC初始化
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void AdcInit(void)
{
 ADCSR = 0x00;  //ADC关闭
 //ADMUX = 0x67;  //外部参考源AVCC,左对齐,选择ADC7通道
 //ADMUX = 0xE7;  //2.56V 的片内基准电压源,左对齐,选择ADC7通道
 ADMUX = 0xE1;  //2.56V 的片内基准电压源,左对齐,选择ADC1通道
 ACSR =  0x80;  //模拟比较器控制和状态寄存器ACSR的ACD置1,使模拟比较器禁用
 ADCSR = 0x8B;  //开启ADC,8分频,ADC中断使能
}
/*-----------------------ADC转换中断程序--------------------------------------*/
#pragma interrupt_handler adc_isr:15
void adc_isr(void)
{
 AdcData= ADCH; //读ADC转换结果,只读高8位,即8位精度,此种情况Vin=(AVCC/256)*ADC
 AdcConCom = 1; //置ADC转换完成标志
}
/*-----------------------------------------------------------------
函数名称: void InitDevices(void)
函数功能: 初始化各种信息
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void InitDevices(void)
{
  CLI();           //关全部中断
  Usart_init03();                     //中断方式初始化
 AdcInit();


  MCUCR = 0x00;
  SEI();              //开全中断
}


void main(void)
{
 InitDevices();
  while(1)
 {
   if(AdcConCom)
  {
    AdcConCom = 0;    //清ADC转换完成标志
   USART_Transmit(AdcData); //向PC发送转换结果
  }
 }
}


/************************模拟比较器控制和状态寄存器ACSR************************
ACD    模拟比较起禁用
ACBG   模拟比较器的能隙基准源
ACO    模拟比较起输出
ACI    模拟比较器中断标志
ACIE   模拟比较器中断使能
ACIC   模拟比较器输入捕捉使能
ACIS1  模拟比较器中断模式选择
ACIS0
*******************************************************************************/


/*************************ADC控制和状态寄存器A-ADCSRA**************************
             ADEN   ADSC  ADATE   ADIF   ADIE  ADPS2  ADPS1  ADPS0
 ADEN      ADC使能模数转换
 ADSC      ADC开始转换
 ADATE     ADC自动触发使能
 ADIF      ADC 中断标志
 ADIE      ADC中断使能
 ADPS2     ADC 预分频器选择位
 ADPS1
 ADPS0
 *****************************************************************************/
/***********************************测试*************************************
1、ADMUX = 0x67;  //外部参考源AVCC,左对齐,选择ADC7通道
   AdcData= ADCH; //读ADC转换结果,只读高8位,即8位精度,此种情况Vin=(AVCC/256)*AdcData
   1)将RW2分得电压为3.92V接在ADC7上,用万用表测得AVCC=5.02V
      用串口助手接收AdcData的值为C7,即十进制199,经计算:Vin=5.02/256*199=3.902265625V
      据此可验证串口助手接收到的数据是准确的。
   2)将RW2分得电压为4.71V接在ADC7上,用万用表测得AVCC=5.02V
      用串口助手接收AdcData的值为F0,即十进制240,经计算:Vin=5.02/256*240=4.70625V
      据此可验证串口助手接收到的数据是准确的。
  
2、ADMUX = 0xE7;  //2.56V 的片内基准电压源,左对齐,选择ADC7通道
   AdcData= ADCH; //读ADC转换结果,只读高8位,即8位精度,此种情况Vin=(AREF/256)*AdcData
   1)将RW2分得电压为1.018V接在ADC1上,用万用表测得AREF=2.634V,并非手册上的2.56V,有0.07V偏差
      用串口助手接收AdcData的值为62,即十进制98,经计算:Vin=2.634/256*98=1.008V
   据此可验证串口助手接收到数据是准确的。
   2)将通道换为ADC0,结果同上。
*****************************************************************************/


2、function.c


#include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint  unsigned int
#define F_CPU 3686400


/*-----------------------------------------------------------------
函数名称: void Usart_init01(void)
函数功能: 串口初始化方式01(波特率设置用查表)
    波特率 9600 0.2% ,8bit,异步,倍速,无奇偶校验,1个停止位
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void Usart_init01(void)       //初始化串口方式1
{
  UCSRA="0X02";                 //倍速选择
  UCSRB=(1<<RXEN)|(1<<TXEN);  //使能接收,发送
  UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8bit,异步,无奇偶校验,1个停止位
  UBRR="47"; //9600波特率,见M16_cn中文P155:Table68-72通用振荡器频率下设置 UBRR                    
}
/*-----------------------------------------------------------------
函数名称: void Usart_init02(void)
函数功能: 串口初始化方式02(波特率设置用公式)
    波特率 9600 0.2% 8bit,异步,常速,无奇偶校验,2个停止位
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void Usart_init02( unsigned int baud )//初始化串口方式2,并设置波特率
{
unsigned int tmp;
tmp= F_CPU/baud/16-1;        //设置波特率,见M16_cn中文P135:Table60波特率计算公式
UBRRH = (unsigned char)(tmp>>8);
UBRRL = (unsigned char)tmp;
UCSRB = (1<<RXEN)|(1<<TXEN); //接收器与发送器使能
UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ0)|(1<<UCSZ1);//异步,8bit,2停止位,无奇偶校验
}
/*-----------------------------------------------------------------
函数名称: void Usart_init03(void)
函数功能: 串口初始化方式03(中断方式接收)
    波特率 9600 0.2%,8bit,异步,倍速,无奇偶校验,1个停止位
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void Usart_init03(void)
{
  UCSRB = 0x00;             //关串口
  UCSRA = 0x02;            //倍速模式   M16中文P151
  UCSRC = BIT(URSEL) | 0x06;         //写UCSRC寄存器,设定8个bit,1停止位,异步
  UBRR  = 47;                      //设定串口波特率为9600
  UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);//使能接收结束中断,使能收发
}


#pragma interrupt_handler UartRecvData:12
void UartRecvData(void)
{
  uchar temp;
 temp = UDR;
 ADCSRA|= (1<<ADSC);              //开启一次ADC转换
}


/*-----------------------------------------------------------------
函数名称: void USART_Transmit( unsigned char data )
函数功能: 数据发送【发送5 到8 位数据位的帧】
参    数:
返 回 值: 无
说    明:直接从数据手册上拷贝过来的
-----------------------------------------------------------------*/
void USART_Transmit( unsigned char data )
{
while ( !( UCSRA & (1<<UDRE)) ) ;  //等待发送缓冲器为空
UDR = data;                        // 将数据放入缓冲器,发送数据
}
/*-----------------------------------------------------------------
函数名称: unsigned char USART_Receive( void )
函数功能: 数据接收【以5 到8 个数据位的方式接收数 据帧】
参    数:
返 回 值: UDR
说    明:直接从数据手册上拷贝过来的
-----------------------------------------------------------------*/
unsigned char USART_Receive( void )
{
while ( !(UCSRA & (1<<RXC)) );  // 等待接收数据
return UDR;                     // 从缓冲器中获取并返回数据
}
/*-----------------------------------------------------------------
函数名称: void USART_Transmits01( void )
函数功能: 连续发送字符"Hello"
参    数:
返 回 值:
-----------------------------------------------------------------*/
void USART_Transmits01( void )
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'H';
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'e';
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'l';
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'l';
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'o';
}


/*-----------------------------------------------------------------
函数名称: void USART_Transmits02(unsigned char *str)
函数功能: 发送字符串(方法一)
参    数: str  发送字符串的首地址
返 回 值:
说    明:已通过验证,str必须定义为指针,调用时只需指针名即可
例    如:定义指针    uchar *buffer0="2009年03月26日23:40";
          调用函数    USART_Transmits02(buffer0);  即可
-----------------------------------------------------------------*/
void USART_Transmits02(unsigned char *ptr)//字符串
{
   while (*ptr)
   {
       USART_Transmit(*ptr);
       *ptr++;
   }
   newline();
}


/*-----------------------------------------------------------------
函数名称: void USART_Transmits03(uchar *str, uint len)
函数功能: 发送字符串(方法二)
参    数: str   发送字符串的首地址
      len   发送字符串的长度
返 回 值:
说    明:已通过验证,str必须定义为指针,调用时只需指针名即可
例    如:定义指针    uchar *buffer0="2009年03月26日23:40";
          调用函数    USART_Transmits03(buffer0,19);  即可
-----------------------------------------------------------------*/
void USART_Transmits03(uchar *str,uint len)
{
  uint i;
 for( i = 0; i < len; i++)
 {
    while ( !( UCSRA & (1<<UDRE)) );  //等待发送缓冲器为空   
  UDR = str;
 }
}


void newline()   //换行
{
   USART_Transmit(0x0d);  //发送一个回车
   USART_Transmit(0x0a);  //发送一个换行
}


void blank()    //空格
{
   USART_Transmit(0x20); 
}



/************************************************
  UMSEL  模式选择
    0    异步操作
    1    同步操作


  USBS 停止位位数
    0     1
    1     2


  UCSZ2 UCSZ1 UCSZ0 字符长度
    0     0     0     5 位
    0     0     1     6 位
    0     1     0     7 位
    0     1     1     8 位
    1     0     0     保留
    1     0     1     保留
    1     1     0     保留
    1     1     1     9 位
*************************************************/

文章评论0条评论)

登录后参与讨论
我要评论
0
8
关闭 站长推荐上一条 /2 下一条