原创 【ATMEGA16L】实验三三:ADC&LCD1602&DS1302&USART综合实验

2009-8-14 09:10 3147 9 11 分类: 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实验


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


经过两天的突击,终于搞定了实验三三,现贴出与大家共享。


一、硬件电路


a0f8750e-9191-427d-b14b-5e825a1a2914.jpg


二、程序结构


951a9a3f-2932-4323-a033-a475115a1e75.jpg


三、程序代码


1、main.c


/*******************************************************************************
Platform: AVR mega16学习板(www.iccavr.com
Project : 实验三三:ADC&LCD1602&DS1302&USART综合实验
Clock F : 3.6864MHz
Software: ICCAVR7.14C
Author  : 林夕依然
Version : 09.04.03-09.04.04
Updata  :
comments:
1、串口发送命令'1'开启一次ADC,并将结果通过串口发送到PC,同时在LCD1602上显示;
2、PC和LCD1602也同时显示每次更新ADC转换结果的时间;
3、USART使用中断方式接收数据,当接收到指定数据后,开启一次ADC转换;
4、当ADC转换完成后产生中断,并置位一个自定义的标志;
5、检测ADC转换完成后的中断标志,为1时则将ADC转换数据发送给PC,同时在LCD1602显示;
6、4种不同的配置方式;
7、参考:实验25,实验26,实验28,实验30
problem :
1、存放ADC转换结果的AdcData要定义为uint,当定义为uchar时,PC和LCD1602接收均错误
   04-03晚出现了此问题,04-04才找到问题的原因。
*******************************************************************************/
#include <iom16v.h>
#include <macros.h>
#include "ds1302.h"
#include "LCD1602.h"


#define uchar unsigned char
#define uint  unsigned int
#define ulong unsigned long


uint AdcData;                        //存放ADC转换的结果
uchar AdcConCom = 0;     //ADC转换完成标志
/*-----------------------------------------------------------------
函数名称: void AdcInit(void)
函数功能: ADC初始化
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void AdcInit(void)
{
 ADCSR = 0x00;    //ADC关闭
 ADMUX = 0x67;  //1:外部参考源AVCC,左对齐,选择ADC7通道
 //ADMUX = 0x46;  //2:外部参考源AVCC,右对齐,选择ADC7通道
 //ADMUX = 0xE0;    //3:2.56V 的片内基准电压源,左对齐,选择ADC0通道
 //ADMUX = 0xC1;  //4:2.56V 的片内基准电压源,右对齐,选择ADC0通道
 ACSR =  0x80;  //模拟比较器控制和状态寄存器ACSR的ACD置1,使模拟比较器禁用
 ADCSR = 0x8B;  //开启ADC,8分频,ADC中断使能
}
/*-----------------------ADC转换中断程序--------------------------------------*/
#pragma interrupt_handler adc_isr:15
void adc_isr(void)
{
 AdcData=(uint)((ulong)ADCH * 4930 / 256);  //1:将AD值转换为电压值(只读高8位)
 //AdcData=(uint)((ulong)ADC * 4930 / 1024);  //2:将AD值转换为电压值(读所有位)
 //AdcData=(uint)((ulong)ADCH * 2635 / 256);    //3:将AD值转换为电压值(只读高8位)
 //AdcData=(uint)((ulong)ADC * 2635 / 1024);  //4:将AD值转换为电压值(读所有位)
 AdcConCom = 1; //置ADC转换完成标志
}
/*-----------------------------------------------------------------
函数名称: void InitDevices(void)
函数功能: 初始化各种信息
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void InitDevices(void)
{
  CLI();           //关全部中断
  Usart_init03();                     //中断方式初始化
 Port_init();
 AdcInit();
 
 ds1302_init(); //DS1302初始化
 delay_ms(10);
 ds1302_write_time(); //写入初始值
    LCD_init(); //LCD初始化
 LCD_clear();//清屏
 LCD_write_str(0,0,"09-04-05 ACDtest");
 LCD_write_str(0,1,"ADC is so easy!");
 //delay_ms(2000);
 
  MCUCR = 0x00;
  SEI();              //开全中断
}


void main(void)
{
    unsigned char temp;
 InitDevices();
  while(1)
 {
      if(AdcConCom)
      {
        AdcConCom = 0;                      //清ADC转换完成标志
  
  //将电压值发送给PC
        USART_Transmit(AdcData/1000 + 0x30);        //得到电压值的千位并发送
        USART_Transmit('.');                          //发送小数点
        USART_Transmit(AdcData%1000/100 + 0x30);  //得到电压值的百位并发送
        USART_Transmit(AdcData%100/10 + 0x30);    //得到电压值的十位并发送
        USART_Transmit(AdcData%10 + 0x30);          //得到电压值的个位并发送
        USART_Transmit('V');                          //发送电压符号"V"
        newline();  //换行
  
  //读取时间并将其显示在LCD1602上
  ds1302_read_time();  //读取时间
  LCD_clear();         //清屏 
  temp = (time_buf[0] >> 4) + '0';
  LCD_write_char(0, 1, temp);/*年*/
  USART_Transmit(temp);
  
  temp = (time_buf[0] & 0x0F) + '0';
  LCD_write_char(1, 1, temp);
  USART_Transmit(temp);
  
  temp = (time_buf[1] >> 4) + '0';
  LCD_write_char(2, 1, temp);
  USART_Transmit(temp);
  
  temp = (time_buf[1] & 0x0F) + '0';
  LCD_write_char(3, 1, temp);
  USART_Transmit(temp);
  LCD_write_char(4, 1, '-');
  USART_Transmit('-');
  
  temp = (time_buf[2] >> 4) + '0';
  LCD_write_char(5, 1, temp);/*月*/
  USART_Transmit(temp);
  
  temp = (time_buf[2] & 0x0F) + '0';
  LCD_write_char(6, 1, temp);
  USART_Transmit(temp);
  
  LCD_write_char(7, 1, '-');
  USART_Transmit('-');
  
  temp = (time_buf[3] >> 4) + '0';
  LCD_write_char(8, 1, temp);/*日*/
  USART_Transmit(temp);
  
  temp = (time_buf[3] & 0x0F) + '0';
  LCD_write_char(9, 1, temp);
  USART_Transmit(temp);
  blank();
  
  //temp = (time_buf[7]) + '0';
  //LCD_write_char(1, 1, temp);  //不显示周
  
  temp = (time_buf[4] >> 4) + '0';
  LCD_write_char(11, 1, temp);  //时
  USART_Transmit(temp);
  
  temp = (time_buf[4] & 0x0F) + '0';
  LCD_write_char(12, 1, temp);
  USART_Transmit(temp);
  
  LCD_write_char(13, 1, ':');
  USART_Transmit(':');
  
  temp = (time_buf[5] >> 4) + '0';
  LCD_write_char(14, 1, temp);/*分*/
  USART_Transmit(temp);
  
  temp = (time_buf[5] & 0x0F) + '0';
  LCD_write_char(15, 1, temp);
  USART_Transmit(temp);
  newline();  //换行
  
  //LCD_write_char(13, 1, ':');
  
  //temp = (time_buf[6] >> 4) + '0';
  //LCD_write_char(14, 1, temp);        //秒不显示
  //temp = (time_buf[6] & 0x0F) + '0';
  //LCD_write_char(15, 1, temp);
  
  //将电压值显示在LCD1602上
  LCD_write_char(0, 0, 'A');
  LCD_write_char(1, 0, 'D');
  LCD_write_char(2, 0, 'C');
  LCD_write_char(3, 0, '=');
  LCD_write_char(4, 0, AdcData/1000 + 0x30);
     LCD_write_char(5, 0, '.');
  LCD_write_char(6, 0, AdcData%1000/100 + 0x30);
  LCD_write_char(7, 0, AdcData%100/10 + 0x30);
  LCD_write_char(8, 0, AdcData%10 + 0x30);
  LCD_write_char(9, 0, 'V');
      }
 }
}


/******************************4种不同配置测试*********************************
1、ADMUX = 0x67;  //1:外部参考源AVCC,左对齐,选择ADC7通道
   实测为1.824V,PC接收为1.810V,误差不足0.05V
2、ADMUX = 0x46;  //2:外部参考源AVCC,右对齐,选择ADC7通道
   实测为1.824V,PC接收为1.810V-1.829V,误差不足0.05V
3、ADMUX = 0xE0;  //3:2.56V 的片内基准电压源,左对齐,选择ADC0通道
   实测为1.824V,PC接收为1.811V-1.824V,误差不足0.05V
4、ADMUX = 0xC1;  //4:2.56V 的片内基准电压源,右对齐,选择ADC0通道
   实测为1.823V,PC接收为1.819V-1.827V,误差不足0.05V


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


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;
 if(temp=='1')     //如果接到到1,则开启一次ADC转换
 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 位
*************************************************/


3、LCD1602.c


/*******************************
Platform : AVR mega16学习板(www.iccavr.com
function :LCD1602八线制功能函数集
Clock F  : 3.6864M
Software : ICCAVR7.14C
Author   : 林夕依然
Version  : 09.04.03
comments :
1、两种方式实现延时
********************************/
#include <iom16v.h>
#include <macros.h>
#include "LCD1602.h"


//us延时函数
void delay_us(uint n)   //4*0.27=1.08us
{
    int i,j;
 for(j=0;j<4;j++)
 {
   for (i=0;i<n;i++)
   NOP();
 } 
}


//ms延时函数
void delay_ms(uint i)
{
    while(i--)
    {                         
     uint j;               
        for(j=1;j<=613;j++)  
      ;              
    }
}


//端口初始化
void Port_init()
{
  //PORTA=0XFF;   //不对ADC通道进行设置
  //DDRA =0X00;
  PORTB="0XFF";
  DDRB =0X00;
  PORTC="0X7F";
  DDRC =0X80;
  PORTD="0XFF";
  DDRD =0X00;
}


//显示屏初始化函数
void LCD_init(void)
{
 DDRB = 0xFF;          //I/O口方向设置
 DDRD|=(1<<PD3)|(1<<PD4)|(1<<PD6);
 delay_ms(15);                           //上电延时一段时间,使供电稳定
 Write_Instruction(0x38);    //8bit interface,2line,5*7dots
 delay_ms(5);
 Write_Instruction(0x38); 
 delay_ms(5);
 Write_Instruction(0x38); 


 Write_Instruction(0x08); //关显示,不显光标,光标不闪烁
 Write_Instruction(0x01); //清屏
 delay_ms(5);
 
 Write_Instruction(0x04); //写一字符,整屏显示不移动
 //Write_Instruction(0x05); //写一字符,整屏右移
 //Write_Instruction(0x06); //写一字符,整屏显示不移动
 //Write_Instruction(0x07); //写一字符,整屏左移
 delay_ms(5);
 
 //Write_Instruction(0x0B); //关闭显示(不显示字符,只有背光亮)
 Write_Instruction(0x0C); //开显示,光标、闪烁都关闭
 //Write_Instruction(0x0D); //开显示,不显示光标,但光标闪烁
 //Write_Instruction(0x0E); //开显示,显示光标,但光标不闪烁
 //Write_Instruction(0x0F); //开显示,光标、闪烁均显示
}


//控制LCD写时序
void LCD_en_write(void)        //EN端产生一个高电平脉冲,控制LCD写时序
  {
    EN_SET;
    delay_us(3);
    EN_CLR;
 delay_us(3);
  }
 
//清屏函数
void LCD_clear()
{
  Write_Instruction(0x01);
  delay_ms(5);
}
 
//写指令函数
void Write_Instruction(uchar command)
{
  RS_CLR;
  RW_CLR;
  EN_SET;
  PORTB="command";
  LCD_en_write();//写入指令数据
}


//写数据函数
void Write_Data(uchar Wdata)
{
  RS_SET;
  RW_CLR;
  EN_SET;
  PORTB="Wdata";
  LCD_en_write();//写入数据
}


//字符显示初始地址设置
void LCD_SET_XY(uchar X,uchar Y)
{
  uchar address;
  if(Y==0)
    address="0x80"+X;//Y=0,表示在第一行显示,地址基数为0x80
  else
    address="0xc0"+X;//Y非0时,表时在第二行显示,地址基数为0XC0
  Write_Instruction(address);//写指令,设置显示初始地址
}


//在第X行Y列开始显示,指针*S所指向的字符串
void LCD_write_str(uchar X,uchar Y,uchar *s)
{
  LCD_SET_XY(X,Y);//设置初始字符显示地址
  while(*s)//逐次写入显示字符,直到最后一个字符"/0"
  {
    Write_Data(*s);//写入当前字符并显示
 s++;//地址指针加1,指向下一个待写字符
  }
}


//在第X行Y列开始显示Wdata所对应的单个字符
void LCD_write_char(uchar X,uchar Y,uchar Wdata)
{
  LCD_SET_XY(X,Y);//写地址
  Write_Data(Wdata);//写入当前字符并显示
}


4、DS1302.C


#include <iom16v.h>


/******************复位脚*********************/
#define RST_CLR PORTC &= ~(1 << PC4)   /*电平置低*/
#define RST_SET PORTC |= (1 << PC4)    /*电平置高*/
#define RST_IN DDRC &= ~(1 << PC4)    /*方向输入*/
#define RST_OUT DDRC |= (1 << PC4)     /*方向输出*/


/*****************双向数据********************/
#define IO_CLR PORTC &= ~(1 << PC3)  /*电平置低*/
#define IO_SET PORTC |= (1 << PC3)   /*电平置高*/
#define IO_R PINC & (1 << PC3)     /*电平读取*/
#define IO_IN DDRC &= ~(1 << PC3)   /*方向输入*/
#define IO_OUT DDRC |= (1 << PC3)    /*方向输出*/


/*****************时钟信号*******************/
#define SCK_CLR PORTC &= ~(1 << PC2)  /*时钟信号*/
#define SCK_SET PORTC |= (1 << PC2)   /*电平置高*/
#define SCK_IN DDRC &= ~(1 << PC2)   /*方向输入*/
#define SCK_OUT DDRC |= (1 << PC2)    /*方向输出*/


#define ds1302_sec_add   0x80  //秒数据地址
#define ds1302_min_add   0x82  //分数据地址
#define ds1302_hr_add   0x84  //时数据地址
#define ds1302_date_add   0x86  //日数据地址
#define ds1302_month_add  0x88  //月数据地址
#define ds1302_day_add   0x8a  //星期数据地址
#define ds1302_year_add   0x8c  //年数据地址
#define ds1302_control_add  0x8e  //控制数据地址
#define ds1302_charger_add  0x90      
#define ds1302_clkburst_add  0xbe


unsigned char time_buf[8] = {0x20,0x09,0x04,0x05,0x01,0x21,0x00,0x03};


//DS1302初始化函数
void ds1302_init(void)
{
 RST_CLR;   /*RST脚置低*/
 SCK_CLR;   /*SCK脚置低*/
 RST_OUT;   /*RST脚设置为输出*/
 SCK_OUT;   /*SCK脚设置为输出*/
}


//向DS1302写入一字节数据
void ds1302_write_byte(unsigned char addr, unsigned char d) {


 unsigned char i;
 RST_SET;     /*启动DS1302总线*/
 
 /*写入目标地址:addr*/
 IO_OUT;
 addr = addr & 0xFE;   //最低位置零,寄存器0位为0时写,为1时读
 for (i = 0; i < 8; i ++) {
  if (addr & 0x01) {
   IO_SET;
   }
  else {
   IO_CLR;
   }
  SCK_SET;      //产生时钟
  SCK_CLR;
  addr = addr >> 1;
  }
 
 /*写入数据:d*/
 IO_OUT;
 for (i = 0; i < 8; i ++) {
  if (d & 0x01) {
   IO_SET;
   }
  else {
   IO_CLR;
   }
  SCK_SET;    //产生时钟
  SCK_CLR;
  d = d >> 1;
  }
 RST_CLR;  //停止DS1302总线
}


//从DS1302读出一字节数据
unsigned char ds1302_read_byte(unsigned char addr) {


 unsigned char i;
 unsigned char temp;
 RST_SET;     /*启动DS1302总线*/


 /*写入目标地址:addr*/
 IO_OUT;
 addr = addr | 0x01;    //最低位置高,寄存器0位为0时写,为1时读
 for (i = 0; i < 8; i ++) {
  if (addr & 0x01) {
   IO_SET;
   }
  else {
   IO_CLR;
   }
  SCK_SET;
  SCK_CLR;
  addr = addr >> 1;
  }
 
 /*输出数据:temp*/
 IO_IN;
 for (i = 0; i < 8; i ++) {
  temp = temp >> 1;
  if (IO_R) {
   temp |= 0x80;
   }
  else {
   temp &= 0x7F;
   }
  SCK_SET;
  SCK_CLR;
  }
 
 RST_CLR;     /*停止DS1302总线*/
 return temp;
}


//向DS302写入时钟数据
void ds1302_write_time(void) {


 ds1302_write_byte(ds1302_control_add,0x00);   //关闭写保护
 ds1302_write_byte(ds1302_sec_add,0x80);    //暂停时钟
 //ds1302_write_byte(ds1302_charger_add,0xa9);     //涓流充电
 ds1302_write_byte(ds1302_year_add,time_buf[1]);  //年
 ds1302_write_byte(ds1302_month_add,time_buf[2]); //月
 ds1302_write_byte(ds1302_date_add,time_buf[3]);  //日
 ds1302_write_byte(ds1302_hr_add,time_buf[4]);  //时
 ds1302_write_byte(ds1302_min_add,time_buf[5]);  //分
 ds1302_write_byte(ds1302_sec_add,time_buf[6]);  //秒
 ds1302_write_byte(ds1302_day_add,time_buf[7]);  //周
 ds1302_write_byte(ds1302_control_add,0x80);   //打开写保护
}


//从DS302读出时钟数据
void ds1302_read_time(void)  {


 time_buf[1]=ds1302_read_byte(ds1302_year_add);  //年
 time_buf[2]=ds1302_read_byte(ds1302_month_add);  //月
 time_buf[3]=ds1302_read_byte(ds1302_date_add);  //日
 time_buf[4]=ds1302_read_byte(ds1302_hr_add);  //时
 time_buf[5]=ds1302_read_byte(ds1302_min_add);  //分
 time_buf[6]=(ds1302_read_byte(ds1302_sec_add))&0x7F;//秒,屏蔽秒的第7位,避免超出59
 time_buf[7]=ds1302_read_byte(ds1302_day_add);  //周
}


5、LCD1602.h


#define uchar unsigned char
#define uint unsigned int
#define RS_CLR PORTD &= ~(1 << PD3)
#define RS_SET PORTD |= (1 << PD3)


#define RW_CLR PORTD &= ~(1 << PD4)
#define RW_SET PORTD |= (1 << PD4)


#define EN_CLR PORTD &= ~(1 << PD6)
#define EN_SET PORTD |= (1 << PD6)


6、ds1302.h


extern unsigned char time_buf[8];


void ds1302_read_time(void);
void ds1302_write_time(void);
void ds1302_init(void);



四、测试附图


1、ADMUX = 0x67;  //1:外部参考源AVCC,左对齐,选择ADC7通道
   实测为1.824V,PC接收为1.810V,误差不足0.05V


5336cd2d-3953-4ced-938a-34a1743aab52.jpg


2、ADMUX = 0x46;  //2:外部参考源AVCC,右对齐,选择ADC7通道
   实测为1.824V,PC接收为1.810V-1.829V,误差不足0.05V


26965442-73d0-4b54-a785-162fcb83ad43.jpg


3、ADMUX = 0xE0;  //3:2.56V 的片内基准电压源,左对齐,选择ADC0通道
   实测为1.824V,PC接收为1.811V-1.824V,误差不足0.05V


1cbda533-d3bc-4298-a6ba-3b2888952a88.jpg


4、ADMUX = 0xC1;  //4:2.56V 的片内基准电压源,右对齐,选择ADC0通道
   实测为1.823V,PC接收为1.819V-1.827V,误差不足0.05V


b6471e01-18a2-47e3-9d67-b4f5117bcae5.jpg

文章评论2条评论)

登录后参与讨论

用户1326417 2009-4-15 11:47

顶!!

tengjingshu_112148725 2009-4-10 21:50

程序写得很规范地说
相关推荐阅读
用户1400544 2012-09-24 08:55
【分享】ATmega16学习笔记PDF完整版下载(WinAVR)
  笔记均为原创,欢迎转载,转载请注明出处!   笔记1:8种LED点亮模式_GCC.pdf 笔记2:有源蜂鸣器驱动实验_GCC.pdf 笔记3:按键扫描(用KEY选择对应LED...
用户1400544 2011-01-19 23:26
博主邀请您:加入千脑,拥有“我的在线电脑”
点击加入千脑,拥有“我的在线电脑”在线电脑随时随地可用,安全可靠您可能遇到以下情况: 用户场景一:        我是一个集团公司的企业白领,经常负责写些策划书,制作各类表格等,有时候上班时间做不完就...
用户1400544 2010-04-07 00:43
ATmega16_Basic_V1.1范例2:8种LED点亮模式(ICC)
一、程序结构二、程序源码1、main.c /******************************************************************************...
用户1400544 2010-04-07 00:22
ATmega16_Basic_V1.1范例1:LED流水灯(ICC)
一、程序结构二、程序源码1、main.c /******************************************************************************...
用户1400544 2010-03-30 14:39
Altium Designer 6原理图元件库大全(7个种类)
》》点此进入      http://bbs.armavr.com/   ARM-AVR嵌入式开发论坛       ARM-AVR嵌入式开发论坛推出【Altium Designer 6 原理图元件库大...
用户1400544 2010-03-30 14:39
protel99原理图元件库大全(8个种类)
》》点此进入      http://bbs.armavr.com/   ARM-AVR嵌入式开发论坛       ARM-AVR嵌入式开发论坛推出【protel99原理图元件库大全(8个种类)】,共...
我要评论
2
9
关闭 站长推荐上一条 /2 下一条