姚磊基于AVR的atmega128单片机读取DS1307数据在LCD12864上显示程序.docx
《姚磊基于AVR的atmega128单片机读取DS1307数据在LCD12864上显示程序.docx》由会员分享,可在线阅读,更多相关《姚磊基于AVR的atmega128单片机读取DS1307数据在LCD12864上显示程序.docx(20页珍藏版)》请在冰豆网上搜索。
姚磊基于AVR的atmega128单片机读取DS1307数据在LCD12864上显示程序
//////////以下是DS1307头文件/////////////////////////////
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#defineIIC_PORTPORTF//定义是使用PROTF口,定义scl连接的是PF1,定义sda连接的是PF0
#defineIIC_DDRDDRF//IIC_DDR&=SSDA;-设置SDA为输入口//IIC_DDR|=SDA;-设置SDA为输出口
#defineSCL0X02//IIC_PORT|=SCL;-scl置1
#defineSDA0X01//IIC_PORT|=SDA;-sda置1
#defineSSCL0XFD//IIC_PORT&=SSCL;-scl置0
#defineSSDA0XFE//IIC_PORT&=SSDA;-sda置0
uintaa[7];//定义一个数组以便接受数据
voiddelay(unsignedintus)
{while(us--);}
voidStart_I2C(void)
{
IIC_PORT|=SDA;//sda
IIC_PORT|=SCL;//scl
asm("nop");
IIC_PORT&=~SDA;
asm("nop");
IIC_PORT&=~SCL;
}
/********************************************
内部函数,I2C结束
********************************************/
voidStop_I2C(void)
{
IIC_PORT&=~SDA;
IIC_PORT&=~SCL;
asm("nop");
IIC_PORT|=SCL;
asm("nop");
IIC_PORT|=SDA;
asm("nop");
}
/********************************************
内部函数,等待ACK
********************************************/
voidAck_I2C(void)
{
unsignedcharerrtime=20;
IIC_PORT|=SDA;//上拉
IIC_DDR&=~SDA;//设置为输入口
IIC_PORT|=SCL;
asm("nop");
while(PIND&SDA)
{
errtime--;
if(!
errtime)
{
Stop_I2C();
IIC_PORT&=~SDA;//超时,给他个离开的理由
}
}
IIC_PORT&=~SCL;
asm("nop");
IIC_DDR|=SDA;//设置为输出口
}
/********************************************
内部函数,I2C发送ACK
********************************************/
voidSendAck_I2C()
{
IIC_PORT&=~SDA;//数据线保持拉低,时钟线发生一次从高低的跳变发送一个应答信号
asm("nop");
IIC_PORT|=SCL;
asm("nop");
IIC_PORT&=~SCL;
}
/********************************************
内部函数,向总线传送非响应
********************************************/
voidSendNotAck_I2C()
{
IIC_PORT|=SDA;//数据线保持高,时钟线发生一次从高低的跳变没有应答
asm("nop");
IIC_PORT|=SCL;
asm("nop");
IIC_PORT&=~SCL;
}
/********************************************
内部函数,向总线传送字节
@ch数据
********************************************/
voidSend_I2C(intch)
{
inti,a;
for(i=1;i<=8;i++)//发送八位
{
IIC_PORT&=~SCL;//总线放空
delay
(1);
a=(ch&0x80);//根据给定数据,又高位到低位逐步提出字节位,发送到总线上
if(a)
{IIC_PORT|=SDA;}
else
{IIC_PORT&=~SDA;}
ch<<=1;//左循环以便输出下一位
delay
(1);
IIC_PORT|=SCL;//总线使能,发送总线数据
delay
(1);
}
IIC_PORT&=~SCL;//总线8位传送完成,总线放空
}
/********************************************
内部函数,向总线传送字
********************************************/
unsignedintReceive_I2C()
{
unsignedchari,a;
IIC_DDR&=~SDA;//设置为输入口
IIC_PORT|=SDA;//不知道为啥,1的时候读入正确0的时候读入全部为0;
for(i=1;i<=8;i++)//读入八个位
{
a<<=1;//读入数据左循环
IIC_PORT&=~SCL;//总线放空
delay
(1);
IIC_PORT|=SCL;//时钟做一次从低到高的跳变可以接收一位数据
delay
(1);
if(PINF&SDA)////////////////////////此处特别注意,变更SDA引脚时这个一定要跟着变
{a|=1;}
else
{a|=0;}//将数据编入变量a
}
IIC_PORT&=~SCL;//总线放空
IIC_DDR|=SDA;//io变成输出
returna;//反馈接收到的信息
}
/********************************************
外部函数
向芯片D1307之中地址为address的寄存器写入数据date仅为八位字节
@addtess要写数据的地址
@date要写的数据
********************************************/
voidwrite_time(intaddress,intdate)
{
Start_I2C();//启动总线
Send_I2C(0xD0);//呼叫芯片D1307,并定义为写动作
Ack_I2C();//等待响应信号
Send_I2C(address);//发送地址
Ack_I2C();//等待响应信号
Send_I2C(date);//发送数据
Ack_I2C();//等待响应信号
Stop_I2C();//停止总线
}
/********************************************
外部函数
从芯片D1307读出10为字节地址1:
秒2:
分3:
时4:
星期5:
号6:
月7:
年8控制字
@addtess要读数据的地址
********************************************/
intread_time()
{
inti=0;
Start_I2C();//启动传送
Send_I2C(0xD0);//呼叫芯片D1307,并定义为写动作
Ack_I2C();//等待响应信号
Send_I2C(0x00);//发送起始地址
Ack_I2C();//等待响应信号
Stop_I2C();//关闭总线
Start_I2C();//启动总线
Send_I2C(0xD1);//呼叫芯片D1307,并定义为读动作
Ack_I2C();
for(i=0;i<7;i++)
{aa[i]=Receive_I2C();//接受自初始地址开始的10个字节地址1:
秒2:
分3:
时4:
星期5:
号6:
月7:
年8控制字
if(i<6)SendAck_I2C();//每成功接受一位发送一个响应信号以便接受下一位
if(i==6)SendNotAck_I2C();
}
Stop_I2C();//接受完成停止
}
voidds1307init()
{
write_time(0x00,0x40);
write_time(0x01,0x32);
write_time(0x02,0x10);
write_time(0x03,0x01);
write_time(0x04,0x30);
write_time(0x05,0x10);
write_time(0x06,0x17);
}
//////////以下是LCD12864头文件/////////////////////////////
/*
*========================================================================================================
*
*File:
ws_lcd_st7920.h
*HardwareEnvironment:
*BuildEnvironment:
AVRStudio4.16+Winavr20090313
*Version:
V1.0
*By:
WuZe
*
*(c)Copyright2005-2009,WaveShare
*http:
//www.waveS
*AllRightsReserved
*
*========================================================================================================
*/
#include
#include
#include
#include
#defineLCD_DELAY()_delay_us(75)
unsignedintlcd_buffer[64];
/*
*-------------------------------------------------------------------------------------------------------
*
*从SPI接口发送1byte的数据
*
*-------------------------------------------------------------------------------------------------------
*/
voidspiSendChar(uint8_tsend_char)
{
SPDR=send_char;
while(!
(SPSR&(1<}
/*
*-------------------------------------------------------------------------------------------------------
*
*给LCD控制芯片ST7920发送指令的函数
*
*-------------------------------------------------------------------------------------------------------
*/
voidsendCodeST7920(uint8_tcode)
{
spiSendChar(0xF8);
spiSendChar(code&0xF0);
spiSendChar((code<<4));
LCD_DELAY();
}
/*
*-------------------------------------------------------------------------------------------------------
*
*给LCD控制芯片ST7920发送数据的函数
*
*-------------------------------------------------------------------------------------------------------
*/
voidsendDataST7920(uint8_tdata)
{
spiSendChar(0xFA);
spiSendChar(data&0xF0);
spiSendChar((data<<4));
LCD_DELAY();
}
/*
*-------------------------------------------------------------------------------------------------------
*
*读取数据栈内容刷新LCD函数
**lcd_stack指向用于刷新LCD的数据栈,需64byte容量
*
*-------------------------------------------------------------------------------------------------------
*/
voidrefreshLCD(constuint8_t*lcd_stack)
{
uint8_taddr;
sendCodeST7920(0x02);/*地址归位*/
for(addr=0;addr<16;addr++)
{
sendDataST7920(*(lcd_stack+addr));
}
for(addr=32;addr<48;addr++)
{
sendDataST7920(*(lcd_stack+addr));
}
for(addr=16;addr<32;addr++)
{
sendDataST7920(*(lcd_stack+addr));
}
for(addr=48;addr<64;addr++)
{
sendDataST7920(*(lcd_stack+addr));
}
}
/*
*-------------------------------------------------------------------------------------------------------
*
*将十进制数据转换成ASCII字符的函数
**str是转换ASCII后存放用的栈
*dec是需要转换的十进制数据
*width是转换成ASCII后的宽度(高位填充'0')
*
*-------------------------------------------------------------------------------------------------------
*/
voiddecToAscii(uint8_t*str,uint16_tdec,uint8_twidth)
{
while(width)
{
switch(width)
{
case5:
{
*str=(dec/10000+'0');
dec%=10000;
break;
}
case4:
{
*str=(dec/1000+'0');
dec%=1000;
break;
}
case3:
{
*str=(dec/100+'0');
dec%=100;
break;
}
case2:
{
*str=(dec/10+'0');
dec%=10;
break;
}
case1:
{
*str=(dec+'0');
break;
}
default:
*str='0';
}
width--;
str++;
}
}
/*
*-------------------------------------------------------------------------------------------------------
*
*将十六进制数据转换成ASCII字符的函数
**str是转换ASCII后存放用的栈
*hex是需要转换的十六进制数据
*width是转换成ASCII后的宽度(高位填充'0')
*
*-------------------------------------------------------------------------------------------------------
*/
voidhexToAscii(uint8_t*str,uint16_thex,uint8_twidth)
{
uint16_ttmp;
while(width)
{
switch(width)
{
case4:
{
tmp=(hex>>12);
if(tmp>9)*str=tmp+('A'-10);
else*str=tmp+'0';
break;
}
case3:
{
tmp=(hex>>8)&0x000F;
if(tmp>9)*str=tmp+('A'-10);
else*str=tmp+'0';
break;
}
case2:
{
tmp=(hex>>4)&0x000F;
if(tmp>9)*str=tmp+('A'-10);
else*str=tmp+'0';
break;
}
case1:
{
tmp=hex&0x000F;
if(tmp>9)*str=tmp+('A'-10);
else*str=tmp+'0';
break;
}
default:
*str='0';
}
width--;
str++;
}
}
/*
*-------------------------------------------------------------------------------------------------------
*
*showLine是用于编辑LCD数据栈的函数
*showLine的使用方法与功能类似于ANSIC的printf函数
*例子:
showLine(0,0,lcd_buffer,"Mynameis%c%c.%d3...",'W','s',12);
*上面的例子通过refreshLCD函数刷新后,在带有ST7920控制芯片的LCD上显示的效果为"MynameisWs.012..."
*x对应LCD的横坐标
*y对应LCD的纵坐标
**lcd_stack指向用于刷新LCD的数据栈
**str指向用于将要显示的内容
*
*-------------------------------------------------------------------------------------------------------
*/
voidshowLine(constuint8_tx,constuint8_ty,uint8_t*lcd_stack,char*str,...)
{
uint8_tcoordinate=16*y+x;
va_listmarker;
va_start(marker,str);/*Initializevariablearguments.*/
while(*str!
='\0')
{
if(coordinate>64)break;/*防止堆栈溢出*/
if(*str=='\\')
{
str++;
lcd_stack[coordinate]=*str;
}
elseif(*str=='%')
{
str++;
if(*str=='d'||*str=='D')
{
str++;
decToAscii(&lcd_stack[coordinate],va_arg(marker,uint16_t),(*str-'0'));
coordinate+=(*str-'0'-1);
}
elseif(*str=='c'||*str=='C')
{
lcd_stack[coordinate]=va_arg(marker,uint16_t);
}
elseif(*str=='x'||*str=='X')
{
str++;
hexToAscii(&lcd_stack[coordinate],va_arg(marker,uint16_t),(*str-'0'));
coordinate+=(*str-'0'-1);
}
}
/*如有新的转义符指令请添加在这里*/
else
{
lcd_stack[coordinate]=*str;
}
str++;
coordinate++;
}
va_end(marker);/*Resetvariablearguments.*