📄 time_8515.c
字号:
//******************************************************************************
// *
// FileName : 实验板time_1302.c ICCAVR V6.31A编译 *
// Function : 实时时钟DS1302的读写操作应用 *
// Date : 2007-01-16 *
// Version : 1.0 *
// *
// Author : 开关电源 hongtusy@163.com *
// Company : 电子信息技术咨询网 http://www.itsn.cn *
// *
//***************************描述与记事*****************************************
//实验板的AVR程序,实时时钟DS1302应用,将实时时间通过串口打印到PC机上,并通过1602LCD
//显示出来。只要不在主电源掉电下拆除电池,LCD将可以一直显示当前的实时时间。
//接线定义:串口PD0(SW6-7)-RXD PD1(SW6-8)-TXD ,SW3-8为系统复位端。
// SW5-1=PA3时钟CLK,SW5-2=PA4数据DAT,SW5-3=PA5复位RET。
//PC(SW1-1~8)为LCD数据端,PD4(SW2-1),5(SW2-2),6(SW2-3) 为RS,R/W,EA脚 SW2-5为背光开关。
//记事:本程序旨在对1302驱动的理解与演示,程序适合初学者使用.
// 打开串口调试器(可能不能显示汉字)或windows自带的超级终端,调整波特率为9600bps,
// 即可用PC观察到当前的时间和日期。
//本例子使用片外8MHz晶体(注意熔丝位的设置)。
//秒寄存器的最高位在开机时默认是1,代表时钟振荡器停止,必须将其改为0后方可启动时钟。
//本实验是为演示实验板上的第二块主芯片ATmega8515而特意安排的。由于8515和主芯片8535的管脚
//安排完全兼容,所以平拨开关位置和实验6的实时时钟是一样的。
//ATmega8515是我们实验板上安排的第二块主芯片,其性能和8535类似,详见数据手册。
//******************************************************************************
#include <iom8515v.h> //头文件,ATmega8515单片机的寄存器定义
#include <macros.h> //包含有SEI()、CLI()、NOP()、WDR()、等宏定义.
typedef unsigned char uchar; //数据类型说明
typedef unsigned int uint;
uchar buf_time[]=" Day:2007-01-16 Time: 00:00:00 "; //LCD显示用的数组
uchar buf_read[8]; //从DS1302读出的时间数据,数据格式为:秒 分 时 日 月 星期 年 写保护字节
uchar buf_write[8]={0x01,0x20,0x01,0x16,0x01,0x02,0x07,0x00}; //往DS1302写入的时间数据
// 数据格式为:01秒 20分 01时 16日 01月 02星期 07年 00写保护字节
/************************************************
函 数 名: DelaymS()
功 能: 毫秒级延时函数
输入参数: 延迟时间/系统晶体
输出参数: 做相应的延迟处理
描 述: /
***********************************************/
void DelaymS (uint i) //延时函数,参数i为延时时间
{
uint j,k; //双重延时
for (j=0;j<i;j++)
{
for (k=0;k<=500;k++);
}
}
/********************************************************
子程序名: write_data()
功 能: 写入一字节LCD数据
输入参数: /
输出参数: /
描 述: /
********************************************************/
void write_data(uchar h)
{
PORTC = h; //先将数据送出
PORTD |= (1<<PD4); //RS=1,数据
PORTD &= ~(1<<PD5); //R/W=0,写
PORTD &= ~(1<<PD6); //EN=0 ,使能,产生一个下降沿。
DelaymS (1);
PORTD |= (1<<PD6); //EN=1 ,除能
}
/********************************************************
子程序名: write_code()
功 能: 写入一字节LCD指令/地址
输入参数: /
输出参数: /
描 述: /
********************************************************/
void write_code(uchar h)
{
PORTC = h; //先将地址送出
PORTD &= ~(1<<PD4); //RS=0,命令或数据
PORTD &= ~(1<<PD5); //R/W=0,写
PORTD &= ~(1<<PD6); //EN=0 ,使能,产生一个下降沿。
DelaymS (1);
PORTD |= (1<<PD6); //EN=1 ,除能
}
/********************************************************
子程序名: init_lcd()
功 能: 初始化LCD
输入参数: /
输出参数: /
描 述: /
********************************************************/
void init_lcd(void)
{
write_code(0x01); //清除屏幕
write_code(0x38); //功能设定,8位数据口/2行/5*7的点阵
write_code(0b00001111); //显示幕ON,光标ON,闪烁ON
write_code(0x06); //模式,加1,显示幕ON。
write_code(0b00000011); //光标回到原点
}
/********************************************************
子程序名: display_lcd()
功 能: 刷新显示一屏数据,独立的LCD显示程序,用户将显存内容更新后,只要调用此程序即可更新显示。
输入参数: /
输出参数: /
描 述: 在写一个字符前,先设定显示的位置地址,然后再写数据。系统可以自动地址加一。
********************************************************/
void display_lcd(uchar *p)
{
uchar i;
write_code(0x80); //第一行起始地址,0b10000000B=0x80.
for(i=0;i<16;i++)
{
write_data(p[i]);
}
write_code(0xc0); //第二行起始地址,0b11000000B=0xc0.
for(i=16;i<32;i++)
{
write_data(p[i]);
}
}
/************************************************
函 数 名: InputByte()
功 能: 串行写入1字节的数据函数
输入参数: /
输出参数: /
描 述: PA4为数据端,PA3为时钟端,bit0在先,时钟上升沿写入。
***********************************************/
void InputByte (uchar CD)
{
uchar i;
for(i=0;i<8;i++)
{
if((CD & (1<<i))==0)
PORTA &= ~(1<<PA4); //数据端输出0
else
PORTA |= (1<<PA4); //否则输出1
PORTA |= (1<<PA3); //时钟置高,产生上升沿。
PORTA &= ~(1<<PA3); //时钟置低
}
}
/************************************************
函 数 名: OutputByte
功 能: 从DS1302串行读出1字节的数据函数
输入参数: /
输出参数: /
描 述: PA4为数据端,PA3为时钟端,bit0在先,时钟下降沿读出。
***********************************************/
uchar OutputByte (void)
{
uchar i,mid=0;
for(i=0;i<8;i++)
{
if((PINA & 0x10)==0) //操作的是PA4
{
mid &= ~(1<<i); //读取0
}
else
{
mid |= (1<<i); //读取1
}
PORTA |= (1<<PA3); //时钟置高
PORTA &= ~(1<<PA3); //时钟置低,产生下降沿
}
return (mid);
}
/************************************************
函 数 名: write_DS1302
功 能: 给DS1302写入上电数据,置需要设定的时钟值
输入参数: /
输出参数: /
描 述: 单字节和多字节操作模式都用了。
数据格式为:秒 分 时 日 月 星期 年 写保护字节
***********************************************/
void write_DS1302 (void)
{
uchar i;
DDRA |= (1<<DDA5)|(1<<DDA4)|(1<<DDA3); //复位,数据和时钟脚都为输出
PORTA &= ~(1<<PA5); //RST=0
PORTA &= ~(1<<PA3); //CLK=0
PORTA |= (1<<PA5); //RST=1
NOP();
InputByte(0x8e); //写保护命令字节的地址
InputByte(0x00); //解除写保护命令
PORTA &= ~(1<<PA5); //RST=0
PORTA &= ~(1<<PA3); //CLK=0
PORTA |= (1<<PA5); //RST=1
NOP();
InputByte(0b10010000); //涓流充电寄存器的地址
InputByte(0b10101010); //设置涓流充电
PORTA &= ~(1<<PA5); //RST=0
PORTA &= ~(1<<PA3); //CLK=0
PORTA |= (1<<PA5); //RST=1
NOP();
InputByte(0xbe); //多字节写操作命令
for (i=0;i<8;i++)
{
InputByte(buf_write[i]);
}
PORTA &= ~(1<<PA5); //RST=0
}
/************************************************
函 数 名: read_DS1302
功 能: 读取DS1302的所有时间数据
输入参数: /
输出参数: /
描 述: 使用多字节方式。
数据格式为:秒 分 时 日 月 星期 年
***********************************************/
void read_DS1302 (void)
{
uchar i;
DDRA |= (1<<DDA5)|(1<<DDA3); //复位和时钟脚都为输出
PORTA &= ~(1<<PA5); //RST=0
PORTA &= ~(1<<PA3); //CLK=0
PORTA |= (1<<PA5); //RST=1
DDRA |= (1<<DDA4); //数据脚为输出
NOP();
InputByte(0xbf); //多字节读命令
DDRA &= ~(1<<DDA4); //数据脚改为输入
NOP();
for (i=0;i<8;i++)
{
buf_read[i]=OutputByte();
}
PORTA &= ~(1<<PA5); //RST=0
}
/********************************************************
子程序名: write_pc232()
功 能: 串口发送一个字节
输入参数: /
输出参数: /
描 述: 把数据发送出去先发送再检测,发完后,才离开
********************************************************/
void write_pc232(uchar i)
{
while(!(UCSRA&(1<<UDRE))); //1字节发送完毕?
UDR = i; //发送一个字符数据
DelaymS (10);
}
/************************************************
函 数 名: mcu_Init()
功 能: 单片机初始化函数
输入参数: /
输出参数: /
描 述: 相关口方向的设置等
***********************************************/
void mcu_Init(void)
{
DDRC = 0xff; //PC口为推挽1输出,段码
DDRD = 0xff; //PD口为推挽1输出,位码,PD7为485DE脚。
DDRA = 0xff; //PA口接DS1302
}
/********************************************************
子程序名: usart_Init()
功 能: 串口初始化
输入参数: /
输出参数: /
描 述: /
********************************************************/
void usart_Init (void)
{
UBRRL=51; //波特率寄存器,UART:9600bps,8.000MHz
UCSRB = (1<<RXEN)|(1<<TXEN); //UART控制寄存器,RXD&TXD使能
}
/************************************************
函 数 名: spk()
功 能: 蜂鸣器鸣叫一声函数
输入参数:
输出参数:
描 述: /
***********************************************/
void spk (uchar i)
{
DDRA |= (1<<2); //DDRA2为输出。
PORTA &= ~(1<<PA2); //蜂鸣器响
DelaymS (i); //延迟
PORTA |= (1<<PA2); //蜂鸣器关闭
}
/********************************************************
子程序名: data_conversion()
输入参数: 数据转换程序
输出参数: /
描 述: /1302读出的数据是BCD码形式,必须进行数制转换。
数据格式: 秒 分 时 日 月 星期 年 写保护字节
显示格式: 秒秒 分分 时时 日日 月月 年年 辅助
********************************************************/
void data_conversion (void)
{
buf_time[29] = (buf_read[0] & 0x0f) + '0'; //秒的低位
buf_time[28] = (buf_read[0] >> 4 ) + '0'; //秒的高位
buf_time[26] = (buf_read[1] & 0x0f) + '0'; //分的低位
buf_time[25] = (buf_read[1] >> 4 ) + '0'; //分的高位
buf_time[23] = (buf_read[2] & 0x0f) + '0'; //时的低位
buf_time[22] = (buf_read[2] >> 4 ) + '0'; //时的高位
buf_time[14] = (buf_read[3] & 0x0f) + '0'; //日的低位
buf_time[13] = (buf_read[3] >> 4 ) + '0'; //日的高位
buf_time[11] = (buf_read[4] & 0x0f) + '0'; //月的高位
buf_time[10] = (buf_read[4] >> 4 ) + '0'; //月的高位
buf_time[8] = (buf_read[6] & 0x0f) + '0'; //年的高位
buf_time[7] = (buf_read[6] >> 4 ) + '0'; //年的高位
}
/********************************************************
子程序名: out_data_pc232()
功 能: 串口发送时间数据到PC,
输入参数: /
输出参数: /
描 述: 包括"当前的温度是:xxx.xx摄氏度",此程序借助LCD的显示缓冲区
********************************************************/
void out_data_pc232(void)
{
uchar i;
uchar time1[16]=" 今天的日期是:";
uchar time2[16]=" 当前的时间是:";
for(i=0;i<16;i++) //向串口发送数据
{
write_pc232(time1[i]);
}
write_pc232('2'); //年
write_pc232('0');
write_pc232(buf_time[7]);
write_pc232(buf_time[8]);
write_pc232('-');
write_pc232(buf_time[10]); //月
write_pc232(buf_time[11]);
write_pc232('-');
write_pc232(buf_time[13]); //日
write_pc232(buf_time[14]);
for(i=0;i<16;i++) //向串口发送数据
{
write_pc232(time2[i]);
}
write_pc232(buf_time[22]); //时
write_pc232(buf_time[23]);
write_pc232(':');
write_pc232(buf_time[25]); //分
write_pc232(buf_time[26]);
write_pc232(':');
write_pc232(buf_time[28]); //秒
write_pc232(buf_time[29]);
write_pc232('\n');
write_pc232('\r'); //显示回车换行
}
//*****************主程序**********************************
void main (void)
{
uchar data_old;
uchar buf_logo[]=" welcome! www.itsn.cn! ";
mcu_Init(); //单片机初始化
usart_Init(); //串口初始化
init_lcd(); //lcd初始化
write_pc232('o'); //测试串口
write_pc232('k'); //测试串口
write_pc232('\n');
write_pc232('\r'); //显示回车换行
display_lcd(buf_logo); //显示LOGO
spk (1000); //上电蜂鸣器长响
DelaymS(2000); //长延迟
display_lcd(buf_time); //开始工作,LCD刷新显示一屏
spk (100); //开始工作,蜂鸣器短响
//---------此段测试1302是否已经写过内容了,若写过就不再重新写。
read_DS1302(); //读时间
if(buf_read[0] & 0x80)
{
write_DS1302(); //写入需要的初始时间值,
}
//------------------
DelaymS(1); //延迟
read_DS1302(); //读时间
data_old = buf_read[0]; //提取旧时钟的秒数值
while(1) //无限循环执行,此程序保证了一秒钟更新一次串口数据,更新一次LCD显示。
{
DelaymS(10); //延迟
read_DS1302(); //读时间
if (data_old == buf_read[0])
{
DelaymS(10); //延迟
}
else
{
data_conversion(); //将读出的数据分开,分别装入显存
display_lcd(buf_time); //刷新显示一屏
out_data_pc232(); //串口将时间数据送PC
data_old = buf_read[0]; //更新时钟的秒数值
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -