#include <iom128v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int
#define lcde_1 PORTA|=(1<<1)
#define lcde_0 PORTA&=~(1<<1)
#define lcddi_1 PORTA|=(1<<0)
#define lcddi_0 PORTA&=~(1<<0)
#define runled_1 PORTA|=(1<<7)
#define runled_0 PORTA&=~(1<<7)
#define ds1302clk_1 PORTB|=(1<<7)
#define ds1302clk_0 PORTB&=~(1<<7)
#define ds1302dat_1 PORTB|=(1<<5)
#define ds1302dat_0 PORTB&=~(1<<5)
#define ds1302rst_1 PORTB|=(1<<6)
#define ds1302rst_0 PORTB&=~(1<<6)
#define ds18b20_1 PORTG|=(1<<4)
#define ds18b20_0 PORTG&=~(1<<4)
unsigned char AC_TABLE[]={
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, //第一行汉字位置
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97, //第二行汉字位置
0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, //第三行汉字位置
0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, //第四行汉字位置
};
unsigned char str1[]="黄河远上白云间,一片孤城万仞山。羌笛何须怨杨柳,春风不度玉门关。";
uchar str2[]=" 09年 3月13日 21:22:22 温度: 21度 ";
uchar miao,fen,shi,re,yu,zhou,nian,temp,num,num1,num2;
void Delayms(unsigned int MS)
{
unsigned int i,j;
for(i=0;i<MS;i++)
for(j=0;j<1541;j++); //1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
}
void Delayus(unsigned int US)
{
unsigned int i;
US=US*3; //5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
for( i=0;i<US;i++);
}
/*******************************************
函数名称: lcd_write
功 能: 向LCD写入一个字节数据(没有RST操作)
参 数: dat--要写入的数据,di=1时写命令、di=0时写数据
返回值 : 无
/********************************************/
void lcd_write(uchar di,uchar dat)
{
if(di==1)
lcddi_0;
else
lcddi_1;
Delayus(10);
lcde_1;
Delayus(10);
PORTC=dat;
Delayus(10);
lcde_0;
}
void lcdinit()
{
lcd_write(1,0x30); //8BitMCU,基本指令集合
lcd_write(1,0x01); ///*清屏,地址指针指向00H*/
Delayms(100);
lcd_write(1,0x06); //*光标的移动方向*/
lcd_write(1,0x0c); //*开显示,关游标*/
}
//文本区清RAM函数
void LcmClearTXT( void )
{
unsigned char i;
lcd_write(1,0x30); //8BitMCU,基本指令集合
lcd_write(1,0x01); //AC归起始位
Delayms(300);
}
void PutStr(unsigned char row,unsigned char col,unsigned char *puts)
{
lcd_write(1,0x30); //8BitMCU,基本指令集合
lcd_write(1,AC_TABLE[8*row+col]); //起始位置
while(*puts != '\0') //判断字符串是否显示完毕
{
if(col==8) //判断换行
{ //若不判断,则自动从第一行到第三行
col=0;
row++;
}
if(row==4) row=0; //一屏显示完,回到屏左上角
lcd_write(1,AC_TABLE[8*row+col]);
lcd_write(0,*puts); //一个汉字要写两次
puts++;
lcd_write(0,*puts);
puts++;
col++;
}
}
/*******************************************
函数名称: DS1302_writeB
功 能: 向DS1302写入一个字节数据(没有RST操作)
参 数: byte--要写入的数据
返回值 : 无
/********************************************/
void DS1302_writeB(uchar byte)
{
uchar i;
DDRB|=(1<<5); //将数据端口设置为输出
for(i=0;i<8;i++) //8位数据计数
{
ds1302clk_0; //拉低时钟端
if(byte&0x01) //当前位是否是1
{
ds1302dat_1; //当前位是1,拉高数据端
}
else
{
ds1302dat_0; //当前位是0,拉低数据端
}
Delayus(10); //调整时钟和脉冲宽度
ds1302clk_1; //时钟上升沿(DS1302采样数据)
byte>>=1; //数据右移1位,为送出新数据位做准备
}
}
/*******************************************
函数名称: DS1302_readB
功 能: 从DS1302读出一个字节数据(没有RST操作)
参 数: 无
返回值 : byte--读出的数据
/********************************************/
uchar DS1302_readB(void)
{
uchar i,byte=0;
DDRB&=~(1<<5); //将数据端口设置为输入
PORTB&=~(1<<5); //无上拉电阻
for(i=0;i<8;i++) //8位数据计数
{
byte>>=1; //保存读入的数据位
ds1302clk_1; //时钟上升沿
Delayus(10); //延时,调整时钟脉冲宽度
ds1302clk_0; //时钟下降沿,DS1302输出数据位
Delayus(10); //等待数据变化(MEGA16太快,必须等待DS1302的数据位输出,否则不能正确读出)
if(PINB&(1<<5)) //当前位是否是高电平
{
byte|=(1<<7); //是高电平就将返回数据的当前位置1
}
else
{
byte&=~(1<<7); //是低电平就将返回数据的当前位置0
}
}
DDRB|=(1<<5); //最后将数据端口设置为输出
return byte; //返回读出的数据
}
/*******************************************
函数名称: DS1302_writeD
功 能: 向DS1302的某个地址写入一个字节数据
参 数: addr--地址值(寄存器或RAM)
data--要写入的地址
返回值 : 无
/********************************************/
void DS1302_writeD(uchar addr,uchar data)
{
ds1302rst_0; //拉低RST
ds1302clk_0; //拉低CLK
Delayus(10);
ds1302rst_1; //拉高RST
Delayus(10); //调整片选脉冲
DS1302_writeB(addr); //写入操作命令(地址)
Delayus(10);
ds1302clk_0; //拉低时钟端
Delayus(10);
DS1302_writeB(data); //写入数据
ds1302clk_0; //拉低时钟端
Delayus(10); //调整片选脉冲
ds1302rst_0; //拉低RST
}
/*******************************************
函数名称: DS1302_readD
功 能: 从DS1302的某个地址读出一个字节数据
参 数: addr--地址值(寄存器或RAM)
返回值 : data--读出的数据
/********************************************/
uchar DS1302_readD(uchar addr)
{
uchar data;
ds1302rst_0; //拉低RST
ds1302clk_0; //拉低时钟端
Delayus(10);
ds1302rst_1; //拉高RST
Delayus(10); //调整片选脉冲
DS1302_writeB(addr); //写入操作命令(地址)
Delayus(10);
data=DS1302_readB(); //读出数据
Delayus(10);
ds1302clk_0; //拉低时钟端
ds1302rst_0; //拉低RST
return data; //返回读出的数据
}
/********************************************
函数名称: uchar ds18b20rst()
功 能: 复位DS18B20,成功则返回0
参 数:
返回值 :
/********************************************/
uchar ds18b20rst()
{
uchar rstda;
ds18b20_0; //18B20置0
Delayus(600); //廷时600US
ds18b20_1; //18B20置1
Delayus(80); //廷时80US
DDRG&=~(1<<4); //将数据端口设置为输入
PORTG&=~(1<<4); //无上拉电阻
rstda=PING&0x10; //判断18B20口是否置1
if(rstda!=0) //是就返回1(不成功)
rstda=1;
while(!(PING&0x10)); //等待18B20口置0(成功)
DDRG|=(1<<4); //最后将数据端口设置为输出
return(rstda); //输出0
}
/********************************************
函数名称: ds18b20writ(uchar i)
功 能: 向18B20写一字节数据
参 数:
返回值 :
/********************************************/
void ds18b20writ(uchar i)
{
uchar aa;
for(aa=0;aa<8;aa++)
{
ds18b20_0; //18B20置0
Delayus(2); //廷时2US
if(i&1) //如果I的低位是1
ds18b20_1; //18B20置1
Delayus(70); //廷时70US,等待18B20读取数据
ds18b20_1; //18B20置1
i>>=1; //I左移一位
}
}
/********************************************
函数名称: uchar ds18b20read()
功 能: 读18B20一字节数据
参 数:
返回值 :
/********************************************/
uchar ds18b20read()
{
uchar aa,bb,rstda;
for(aa=0;aa<8;aa++)
{
ds18b20_0; //18B20置0
Delayus(2); //廷时2US
ds18b20_1; //18B20置1
DDRG&=~(1<<4); //将数据端口设置为输入
PORTG&=~(1<<4); //无上拉电阻
bb=PING&0x10; //看18B20是否输出是1
if(bb!=0) //如果是1,让RSTDA高位为1
rstda|=0x80;
DDRG|=(1<<4); //最后将数据端口设置为输出
ds18b20_1; //18B20置1
if(aa<7) //限制 RSTDA左移共7次
rstda>>=1; //RSTDA左移一位
Delayus(70); //廷时70US,等待下一次读取数据
}
return(rstda);
}
/********************************************
函数名称: init18b20()
功 能: 初始化DS18B20
参 数:
返回值 :
/********************************************/
void init18b20()
{
if(ds18b20rst()==0)
{
ds18b20writ(0xcc);
ds18b20writ(0x4e);
ds18b20writ(0x64);
ds18b20writ(0x8a);
ds18b20writ(0x7f);
}
}
void main()
{
uchar t1,t2;
DDRB=0xff;
DDRC=0xff;
DDRD=0xff;
DDRA=0xff;
DDRG=0xff;
Delayms(300);
lcdinit();
LcmClearTXT();
PutStr(0,0,str1);
runled_1;
init18b20(); //18B20初始化
Delayms(10000);
//DS1302_writeD(0x8e,0x00);//写保护开
//DS1302_writeD(0x80,0x30);//设置秒
//DS1302_writeD(0x82,0x00);//设置分
//DS1302_writeD(0x84,0x18);//设置时
//DS1302_writeD(0x86,0x28);//设置日期
//DS1302_writeD(0x88,0x02);//设置月份
//DS1302_writeD(0x8a,0x06);//设置星期
//DS1302_writeD(0x8c,0x09);//设置年份
//DS1302_writeD(0x8e,0x80);//写保护关
lcdinit();
LcmClearTXT();
PutStr(0,0,str2);
while(1)
{
ds18b20rst();
ds18b20writ(0xcc);
ds18b20writ(0x44);//转换命令
miao=DS1302_readD(0x81); //读秒
fen=DS1302_readD(0x83); //读分钟
shi=DS1302_readD(0x85); //读小时
re=DS1302_readD(0x87); //读日期
yu=DS1302_readD(0x89); //读月份
zhou=DS1302_readD(0x8b); //读星期
nian=DS1302_readD(0x8d); //读年份
if(miao&0x01)
runled_1;
else
runled_0;
ds18b20rst();
ds18b20writ(0xcc);
ds18b20writ(0xbe);//读取命令
t1=ds18b20read(); //低位温度
t2=ds18b20read(); //高位温度
temp=t2*16+t1*0.0625;
lcd_write(1,0x83);
lcd_write(0,(0x30+yu/16));
lcd_write(0,(0x30+(yu&0x0f)));
lcd_write(1,0x85);
lcd_write(0,(0x30+re/16));
lcd_write(0,(0x30+(re&0x0f)));
lcd_write(1,0x92);
lcd_write(0,(0x30+shi/16));
lcd_write(0,(0x30+(shi&0x0f)));
lcd_write(0,0x3a);
lcd_write(0,(0x30+fen/16));
lcd_write(0,(0x30+(fen&0x0f)));
lcd_write(0,0x3a);
lcd_write(0,(0x30+miao/16));
lcd_write(0,(0x30+(miao&0x0f)));
lcd_write(1,0x9d);
lcd_write(0,(0x30+temp/10));
lcd_write(0,(0x30+temp%10));
}
} |