專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

簡易12684液晶和Atmega32的電子萬年歷

作者:未知   來源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2014年04月01日   【字體:

//端口配置是這樣的:液晶的DB0-DB7數(shù)據(jù)口連接在單片機(jī)的PA口。

//液晶直接定義成并口方式,所以也就的PSB直接接高電平,低電平是串行方式。

//頭文件包含
#include <avr/io.h>        //io端口寄存器配置文件,必須包含
#include <util/delay.h>       //GCC中的延時(shí)函數(shù)頭文件
#include <string.h>
//端口位定義
#define RS PC2          //數(shù)據(jù)/命令控制端 0命令,1數(shù)據(jù)
#define RW PC1           //讀/寫選擇控制端 0寫,1讀
#define E PC0            //使能端          下降沿讀,高電平寫
//#define PSB PC7          //數(shù)據(jù)傳輸方式選擇端,H,8位或4位并口方式;L,串口方式

//常量聲明
#define BAUD 115200
#define TURE 1
#define FALSE 0
//時(shí)鐘/日歷寄存器
#define RD    0x01         //讀
#define WR    0x00         //寫
#define SECOND  0x80 //秒
#define MINUTE  0x82 //分
#define HOUR  0x84 //時(shí)
#define DAY   0x86 //日
#define MONTH  0x88 //月
#define WEEK  0x8A //星期 DATE
#define YEAR  0x8C //年
#define WR_PROTECT 0x8E //控制(寫保護(hù))
#define CHARGE     0x90 //涓流充電
#define BURST  0xBE //時(shí)鐘多字節(jié)
//配置位
#define CLK_HALT  0x80 //停止時(shí)鐘控制位    SECOND bit7
#define CLK_START  0x00 //啟動(dòng)時(shí)鐘
#define M12_24   0x80 //12/24小時(shí)值選擇位 HOUR  bit7
#define PROTECT   0x80 //寫保護(hù)控制位      CONTROL bit7
#define UPROTECT  0x00 //寫保護(hù)控制位      CONTROL bit7
//涓流充電控制常量
#define TC_D1R2   0xA5 //充電時(shí)選擇一個(gè)二極管和2K電阻
#define TC_D2R8   0xAB //充電時(shí)選擇二個(gè)二極管和8K電阻 
#define TC_DISABLED  0x00 //禁止充電功能
//RAM 命令
#define RAMBASE  0xC0 //RAM起始位為0XCO,RAM范圍0-31

//全局變量聲明
unsigned char Get_Time[7] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00};

//全局變量聲明
unsigned char logo[]="==小電子萬年歷==";

//函數(shù)聲明
void Delayus(unsigned int lus);         //us延時(shí)函數(shù)
void Delayms(unsigned int lms);        //ms延時(shí)函數(shù)
unsigned char DS1302_ReadByte(void);         //從DS1302讀一個(gè)字節(jié)數(shù)據(jù)
void DS1302_WriteByte(unsigned char dat);    //向DS1302寫一個(gè)字節(jié)數(shù)據(jù)
unsigned char DS1302_ReadData(unsigned addr); //從DS1302的指定地址讀一個(gè)字節(jié)數(shù)據(jù)
void DS1302_WriteData(unsigned char addr,unsigned data);
                                                 //向DS1302的指定地址寫一個(gè)字節(jié)數(shù)據(jù)
void DS1302_SetTime(unsigned char *time);  //對(duì)DS1302設(shè)置時(shí)間
void DS1302_GetTime(void);   //從DS1302讀取時(shí)間
unsigned char DS1302_Check(void);           //DS1302是否工作檢測
void DS1302_Init(void);                      //DS1302初始化
void DS1302_DisCharge(void); //關(guān)閉涓流充電
unsigned char DS1302_Alarm(unsigned char hour,unsigned char min); //鬧鈴
void System_Beep(void);

void Port_Init(void);   //端口初始化
void LCD_Init(void);    //LCD初始化
void Write_Com(unsigned char LCD_Com);   //LCD寫指令
void Write_Data(unsigned char LCD_Data);  //LCD寫數(shù)據(jù)
void Check_Busy(void);   //讀寫檢測函數(shù),每次對(duì)液晶操作前都要進(jìn)行讀寫檢測
void Put_CHS_String(unsigned char x,unsigned char y,char *STR);

int main(void)          
{
 unsigned char Disp_Number;
 char str_time[64];
 unsigned char Set_Time[7] = {0x30,0x57,0x20,0x12,0x04,0x01,0x10};
                               //設(shè)置秒,分,時(shí),日,月,星期,年
 char chs_week[7][6]={"星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
 _delay_ms(200);

 Port_Init();   //端口初始化
 LCD_Init();    //LCD初始化

 DS1302_DisCharge();
 DS1302_GetTime();
 if(Get_Time[2] == 0x00)
  DS1302_SetTime(Set_Time);

 Put_CHS_String(0,0,logo);
 DS1302_GetTime();
 
 Put_CHS_String(0,1,"現(xiàn)在時(shí)間:");
 while(1)
 {
  sprintf(str_time,"20%01x%01x年%01x%01x月%01x%01x日",Get_Time[6] / 16,Get_Time[6] % 16
                     ,Get_Time[4] / 16,Get_Time[4] % 16
                     ,Get_Time[3] / 16,Get_Time[3] % 16 );
  Put_CHS_String(0,2,str_time);
 
  sprintf(str_time,"星期%01x %01x%01x:%01x%01x:%01x%01x",Get_Time[5] % 16       
                  ,Get_Time[2] / 16,Get_Time[2] % 16
                     ,Get_Time[1] / 16,Get_Time[1] % 16
                     ,Get_Time[0] / 16,Get_Time[0] % 16 );
  Put_CHS_String(0,3,str_time);
 
  DS1302_GetTime();
  _delay_ms(500);
 
 }

}

void Port_Init()
{    
 //LCD數(shù)據(jù)端口設(shè)置
 PORTA = 0X00;         //
 DDRA = 0XFF;           //配置端口PA全部為輸出口,LCD數(shù)據(jù)端口
 
 PORTD = 0X00;
 DDRD |= 1<<PD6;
 PORTD |= 1<<PD6;
 
 //LCD控制端口設(shè)置
 PORTC = 0X00;         //
 DDRC |= (1 << RS) | (1 << RW) | (1 << E);

 PORTB = 0XFF;
 DDRB |= (1 << PB1) | (1 << PB0); //DS1302的IO和SCLK引腳設(shè)為輸出
 DDRB |= (1 << PB2);                //DS1302的RST引腳設(shè)為輸出

}

void LCD_Init()
{
 Write_Com(0X01);  //清屏
 _delay_us(5);
 Write_Com(0X38);  //顯示模式設(shè)置 16x2顯示,5x7點(diǎn)陣,8位數(shù)據(jù)接口
 _delay_us(5);
 //Write_Com(0X0f);  //顯示開關(guān)控制,開顯示,光標(biāo)顯示,光標(biāo)閃爍
 Write_Com(0X0c);  //顯示開關(guān)控制,開顯示,光標(biāo)不顯示,光標(biāo)不閃爍
 _delay_us(5);
 Write_Com(0X06);  //光標(biāo)設(shè)置,讀或?qū)懸粋(gè)字符后,地址指針加一,光標(biāo)加一,整屏不移動(dòng)
 _delay_us(5);
}

void Write_Com(unsigned char LCD_Com)
{
 Check_Busy();
 
 PORTC &= ~(1 << RS);     //RS=0,寫命令
 PORTC &= ~(1 << RW);     //RW=0,寫指令
 PORTC |= (1 << E);       //E=1,寫操作
 _delay_us(5);
 PORTA = LCD_Com;         //指令送數(shù)據(jù)端口
 PORTC &= ~(1 << E);     //E=0,停止寫操作
 _delay_us(5);
 
}

void Write_Data(unsigned char LCD_Data)
{
 Check_Busy();

 PORTC |= (1 << RS);      //RS=1,寫數(shù)據(jù)
 PORTC &= ~(1 << RW);    //RW=0,寫指令
 PORTC |= (1 << E);      //E=1,寫操作
 _delay_us(5);
 PORTA = LCD_Data;        // 數(shù)據(jù)送數(shù)據(jù)端口 
 PORTC &= ~(1 << E);    //E=0,停止寫操作
 _delay_us(5);
 
}

void Check_Busy()
{
   
 DDRA = 0X00;             //PA口置為輸入口,準(zhǔn)備讀取數(shù)據(jù)
 PORTC &= ~(1 << RS);      //RS=0,讀命令
 PORTC |= (1 << RW);    //RW=1,讀指令
 PORTC |= (1 << E);      //E=1,使能
 
 while(0X80 & PINA);   //監(jiān)測忙信號(hào),直到忙信號(hào)為0,才能進(jìn)行讀寫操作
 PORTC &= ~(1 << E);   //E=0
 DDRA = 0XFF;          //PA口置為輸出口,準(zhǔn)備向端口發(fā)送數(shù)據(jù)
}

void Put_CHS_String(unsigned char x,unsigned char y,char *STR)
{
 unsigned char Disp_Number;
 switch(y)
 {
  case 0:
   Write_Com(0X80+x);
   break;
  case 1:
   Write_Com(0X90+x);
   break;
  case 2:
   Write_Com(0X88+x);
   break;
  case 3:
   Write_Com(0X98+x);
   break;
  default:
   break;
 }
 for(Disp_Number = 0;Disp_Number < strlen(STR);Disp_Number++)
 {
  Write_Data(STR[Disp_Number]);
  _delay_us(5);
 }
}

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

//從DS1302讀一個(gè)字節(jié)數(shù)據(jù)
unsigned char DS1302_ReadByte(void)       
{
 unsigned char i,dat = 0;  //dat存放讀出的數(shù)據(jù),初始化為0
 PORTB &= ~(1 << PB1);     //DS1302的I/O口上拉不使能,
 DDRB &= ~(1 << PB1);      //DS1302的I/O口設(shè)置為輸入口,準(zhǔn)備讀數(shù)據(jù)
 
 for(i = 0;i < 8;i++)     //讀8位,低位在前,右移
 {
  dat >>= 1;           //讀出的數(shù)據(jù)右移一位
  PORTB |= (1 << PB0);  //DS1302的SCLK端口拉高
  Delayus(10);          //
  PORTB &= ~(1 << PB0);  //DS1302的SCLK端口拉低,產(chǎn)生下降沿,
  Delayus(10);
  if(PINB & (1 << PB1))     //讀數(shù)據(jù)端口狀態(tài)
  {
   dat |= 0x80;          //如果數(shù)據(jù)端口位高,相應(yīng)數(shù)據(jù)位置1
  }
 }
 DDRB |= (1 << PB1);   //最后將數(shù)據(jù)端口設(shè)置為輸出
    return dat;     //返回讀出的數(shù)據(jù)
}

//向DS1302寫一個(gè)字節(jié)數(shù)據(jù)
void DS1302_WriteByte(unsigned char dat)  
{
 unsigned char i;
 
 for(i = 0;i < 8;i++)      //寫8位,低位在前
 {
  PORTB &= ~(1 << PB0);  //DS1302的SCLK置低
  if(dat & 0x01)        //寫數(shù)據(jù)位
  {
   PORTB |= (1 << PB1);   //如果該位為1,則I/O口置高
  }
  else
  {
   PORTB &= ~(1 << PB1);   //如果該位為0,則I/O口置低
  }
  Delayus(10);          //
  PORTB |= (1 << PB0);   //DS1302的SCLK置高,產(chǎn)生上升沿
  dat >>= 1;               //數(shù)據(jù)右移1位
 }
}

//從DS1302的指定地址讀一個(gè)字節(jié)數(shù)據(jù)
unsigned char DS1302_ReadData(unsigned addr)
{
 unsigned char data;
 
 PORTB &= ~(1 << PB2); //拉低片選端
 PORTB &= ~(1 << PB0);//拉低時(shí)鐘端
 Delayus(10);
 PORTB |= (1 << PB2);//拉高片選端
 Delayus(10);
 DS1302_WriteByte(addr);//寫入操作命令(地址)
 Delayus(10);
 data = DS1302_ReadByte();//讀出數(shù)據(jù)
 Delayus(10);
 PORTB &= ~(1 << PB0);  //拉低時(shí)鐘端
 PORTB &= ~(1 << PB2); //拉低片選端
 
 return data;
}

//向DS1302的指定地址寫一個(gè)字節(jié)數(shù)據(jù)
void DS1302_WriteData(unsigned char addr,unsigned data)
{
 PORTB &= ~(1 << PB2); //拉低片選端
 PORTB &= ~(1 << PB0);//拉低時(shí)鐘端
 Delayus(10);
 PORTB |= (1 << PB2);//拉高片選端
 Delayus(10);
 DS1302_WriteByte(addr);//寫入操作命令(地址)
 Delayus(10);
 PORTB &= ~(1 << PB0);//拉低時(shí)鐘端
 Delayus(10);
 DS1302_WriteByte(data);//寫入數(shù)據(jù)
 PORTB &= ~(1 << PB0);  //拉低時(shí)鐘端

 Delayus(10);
 PORTB &= ~(1 << PB2); //拉低片選端
}

//對(duì)DS1302設(shè)置時(shí)間          
void DS1302_SetTime(unsigned char *time)
{
 unsigned char i;
 unsigned char addr = 0x80;//寫入地址從秒寄存器開始
 
 DS1302_WriteData(WR_PROTECT | WR,UPROTECT);//控制命令,WP位為0,允許寫操作
 Delayms(5);
 for(i = 0;i < 7;i++)
 {
  DS1302_WriteData(addr | WR,time[i]);// 秒 分 時(shí) 日 月 星期年 
  addr += 2;
  Delayms(1);
 }
 DS1302_WriteData(WR_PROTECT | WR,PROTECT);//控制命令,WP位為1,不允許寫操作  
}

//從DS1302讀取時(shí)間
void DS1302_GetTime(void) 
{
 unsigned char i;
 PORTB &= ~(1 << PB2);
 Delayus(10);
 PORTB |= (1 << PB2);
 Delayus(10);
 DS1302_WriteByte(0xbf);
 for(i = 0;i < 8;i++)
 {
  Get_Time[i] = DS1302_ReadByte();
 }
 PORTB &= ~(1 << PB2);
 PORTB &= ~(1 << PB0);
}

//DS1302是否工作檢測
unsigned char DS1302_Check(void)         
{
 DS1302_WriteData(WR_PROTECT | WR,UPROTECT);
 DS1302_WriteData(RAMBASE | WR,0x31);
 
 if(DS1302_ReadData(RAMBASE | WR) == 0x31)
 {
  return TURE;
 }
 else
 {
  return FALSE;
 }
}

void DS1302_DisCharge(void)
{
 DS1302_WriteData(CHARGE|WR,TC_DISABLED);
 Delayus(10);
}

unsigned char DS1302_Alarm(unsigned char hour,unsigned char min)
{

}

void System_Beep(void)
{

}

//DS1302初始化
void DS1302_Init(void)
{
 DS1302_WriteData(WR_PROTECT | WR,UPROTECT);   //寫入寫允許命令
 DS1302_WriteData(SECOND | WR,CLK_START);      //啟動(dòng)振蕩器,DS1302開始工作
 DS1302_WriteData( WR_PROTECT | WR,PROTECT);     //控制命令,WP位為1,不允許寫操作  
}


//us級(jí)別的延時(shí)函數(shù)
void Delayus(unsigned int lus)
{
 while(lus--)
 {
  _delay_loop_2(3);      //_delay_loop_2(1)是延時(shí)4個(gè)時(shí)鐘周期,參數(shù)為3則延時(shí)12
             //個(gè)時(shí)鐘周期,本實(shí)驗(yàn)用12M晶體,則12個(gè)時(shí)鐘周期為12/12=1us
    }
}

//ms級(jí)別的延時(shí)函數(shù)
void Delayms(unsigned int lms)
{
 while(lms--)
 {
  Delayus(800);        //延時(shí)1ms
    }
}

關(guān)閉窗口

相關(guān)文章