发布网友 发布时间:2022-04-26 09:20
共1个回答
热心网友 时间:2023-10-09 05:08
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <avr/interrupt.h>//ISR(BADISR_vect){ //服务程序}
#include<1602_PADATA_PB13CON.h>//LCD1602驱动
//#include<ws_iic_port.h>//IIC的驱动
#include<ws_iic.h>
/////////////////////sssssssssssssssssssssssssssssssssssssss///////////////////////////////////////////////////////////////////////////
//若有 这样的错误 c:/avr/winavr/lib/gcc/../../avr/include/util/delay.h:85:3: warning: #warning "F_CPU not defined for <util/delay.h>"
//一定要定义:在PROJECT===》CONFIGURATION OPTIONS===>GENNRAL===》Frequency===》填写你晶体的频率,就这样,你的问题就可以解决掉了。
//#define _pcf8563_ 4
#define uchar unsigned char
#define uint unsigned int
uchar line1[11]={0,0,'-',0,0,'-',0,0,'w','0'};//显示年月日和星期;放一个空字符。可能是lcd写字符串函数存在问题
uchar line2[9]={0,0,'-',0,0,'-',0,0};//小时,分,秒
//PCF8563的时间存储为 秒-分-小时-日-星期-月/世纪-年; 7个字节
uchar set_time[7]={56,59,9,27,4,128+7,11};//这些是十进制,使用时要转为bcd码
uchar get_time[7];//读出为bcd码,使用时转为十进制
volatile uchar int_time;//设置报警中断的次数
//PCF 8563 iic总线,INTA低电平有效,32.768KHz 的振荡
//16 个寄存器设计成可寻址的8 位并行寄存器但不是所有位都有用前两个寄存器内存地址00H 01H 用于控制寄存器和状态寄存器内存地址02H 08H 用于时钟计数器秒~年计数器地址
//09H 0CH 用于报警寄存器定义报警条件地址0DH 控制CLKOUT 管脚的输出频率地址0EH 和0FH分别用于定时器控制寄存器和定时器寄存器秒分钟小时日月年分钟报警小时报警日报
//警寄存器编码格式为BCD 星期和星期报警寄存器不以BCD 格式编码
/*
400kHz I2C 总线(VDD=1.8 5.5V) 其从地址读0A3H;写0A2H
//地址 寄存器名称 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
00H 控制/状态寄存器1 TEST1 0 STOP 0 TESTC 0 0 0 .1)TEST1=0 普通模式;TEST1=1 EXT_CLK 测试模式;2)STOP=0 芯片时钟运行STOP=1 所有芯片分频器异步置逻辑
0 芯片时钟停止运行CLKOUT 在32.768kHz 时可用;3)TESTC=0 电源复位功能失效普通模式时置逻辑0
TESTC=1 电源复位功能有效;4)位6,4,2,1,0 缺省值置逻辑0
01H 控制/状态寄存器2 0 0 0 TI/TP AF TF AIE TIE
AF 和AIE 都有效时则INT 一直有效;
当报警发生时AF 被置逻辑1 在定时器倒计数结束时TF 被置逻辑1
AIE=0 报警中断无效AIE=1 报警中断有效
TIE=0 定时器中断无效TIE=1 定时器中断有效
0DH CLKOUT 输出寄存器 FE ·····FD1 FD0
0EH 定时器控制寄存器 TE ·····TD1 TD0
0FH 定时器倒计数数值寄存器 定时器倒计数数值(二进制)
02h 秒 VL 00 -59BCD 码格式数 VL=0 保证准确的时钟/日历数据;VL=1 不保证准确的时钟/日历数据
03h 分钟 00 -59BCD 码格式数
04h 小时 00 -59BCD 码格式数
05h 日 01- 31BCD 码格式数
06h 星期 0- 6
07h 月/世纪 C 01 -12 BCD 码格式数
08h 年 00- 99 BCD 码格式数
09h 分钟报警 AE 00 -59 BCD 码格式数
0Ah 小时报警 AE 00 -23 BCD 码格式数
0BH 日报警 AE 01- 31 BCD 码格式数
0CH 星期报警 AE 0- 6
*/
/*
atmega16中,IIC 的SCL, SDA端口可以设置上拉电阻,这样可节约外部上拉电阻。
SCL frequency= CPU Clock frequency/(16 + 2(TWBR) . 4^TWPS)
TWI 工作在主机模式时,TWBR 值应该不小于10。否则主机会在SDA 与 SCL 产生错误输出作为提示信号。问题出现于TWI 工作在主机模式下,向从机发送Start + SLA + R/W 的
时候( 不需要真的有从机与总线连接)。
*/
//器件地址:A0 A1 A2 = 0 0 0
#define WR_SLA8563_ADDR0xA2//write device-address
#define RD_SLA8563_ADDR0xA3//read device-address
//以下为控制器寄存器地址
//以下为二进制存储
#define CTRL_BUF10x00
#define CTRL_BUF20x01
//以下为BCD 存储
#define SECOND_DATA_BUF0x02
#define MINUTE_DATA_BUF0x03
#define HOUR_DATA_BUF0x04
#define DAY_DATA_BUF0x05
#define WEEK_DATA_BUF0x06
#define MONTH_DATA_BUF0x07
#define YEAR_DATA_BUF0x08
#define MINUTE_AE_BUF0x09
#define HOUR_AE_BUF0x0A
#define DAY_AE_BUF0x0B
#define WEEK_AE_BUF0x0C
//以下为二进制存储
#define CLK_FRQ_BUF0x0D //80-37.768kHz;81--1024Hz;82--32Hz;83--1Hz
#define TIMER_CTRL_BUF0x0E
#define COUNT_VAL_BUF0x0F
#define PCF8563_ERR0
#define PCF8563_CRR1
//十进制转BCD码,即高位取出来后左移4位,低位取出不变
//BCD码这种编码形式利用了四个位元来储存一个十进制的数码
#define Int_To_BCD(dec) (((dec/10)<<4)+dec%10)//PCF8563的时间以及报警设置都是BCDB码 32(DEC)-->32(BCD)
#define BCD_To_Int(bcd) ((bcd>>4)*10+(bcd&0x0f)) //高位乘10,低位不变
//写一个数据
uchar Write_Abyte(uchar Addr,uchar data)
{
//判断写地址是否成功,成功返回1,否者范围0
if ((I2C_Write(WR_SLA8563_ADDR,Addr,data))==PCF8563_ERR)
return PCF8563_ERR;
return PCF8563_CRR;
}
//设置小时,分,秒
void Set_time_HSS(uchar hour,uchar minute,uchar second)
{
hour=Int_To_BCD(hour);
minute=Int_To_BCD(minute);
second=Int_To_BCD(second);
Write_Abyte(HOUR_DATA_BUF,hour);
Write_Abyte(MINUTE_DATA_BUF,minute);
Write_Abyte(SECOND_DATA_BUF,second);
}
//设置年月日
void Set_time_YMD(uchar year,uchar month,uchar day)
{
year=Int_To_BCD(year);
month=Int_To_BCD(month);
day=Int_To_BCD(day);
Write_Abyte(YEAR_DATA_BUF,year);
Write_Abyte(MONTH_DATA_BUF,month);//包含世纪
Write_Abyte(DAY_DATA_BUF,day);
}
void Set_Time_Week(uchar week)
{
week=Int_To_BCD(week);
Write_Abyte(WEEK_DATA_BUF,week );
}
//一次将数组中时间写入芯片,n应<=7.
void Set_Time_All(uchar start_adr,uchar *ptdata,uchar n)
{
uchar i,temp;
for(i=0;i<n;i++)
{
temp=Int_To_BCD(ptdata[i]);//化为bcd码
Write_Abyte(start_adr+i,temp);
}
}
//读N个数据
uchar Read_Nbyte(uchar start_addr,uchar *pRdDat,uchar num)//使用 uint8_t I2C_Read_(uint16_t wrDAdr,uint8_t wordAdr,uint8_t rdDAdr,uint8_t *pRdDat,uint8_t num)
{
if( I2C_Read_(WR_SLA8563_ADDR,start_addr,RD_SLA8563_ADDR,pRdDat,num)==I2C_ERR )
return PCF8563_ERR;
return PCF8563_CRR;
}
//uchar get_time(uchar start_adr,uchar *ptdata,uchar n)
//{
//}
//初始化8563的工作方式
void PCF8563_Init(void)
{
//报警设置
//CTRL_BUF1=0x00 ;//TEST1 0 STOP 0 TESTC 0 0 0 普通模式都置0
//CTRL_BUF2= 0x00010010;//0 0 0 TI/TP AF TF AIE TIE 报警中断有效
//这里需要将控制字内容写入,需要调用IIC的写数据操作 uint8_t I2C_Write(uint16_t wrDAdr,uint8_t wordAdr,uint8_t dat) wrDAdr-->器件写地址
Write_Abyte(CTRL_BUF1,0x00);
Write_Abyte(HOUR_AE_BUF,Int_To_BCD(10) );
Write_Abyte(MINUTE_AE_BUF,Int_To_BCD(20) );
Write_Abyte(CTRL_BUF2,0x13);
}
void Disp_Time_In_LCD1602( )
{
uchar i ;
//第一行 年月日 周次;第二行 小时 分 秒
Read_Nbyte(SECOND_DATA_BUF, get_time,7);//一次获得所有数据
get_time[0]= get_time[0]&0x7f;//秒
get_time[1]= get_time[1]&0x7f;//分
get_time[2]= get_time[2]&0x3f;//小时
get_time[3]= get_time[3]&0x3f;//日
get_time[4]= get_time[4]&0x0f;//星期
get_time[5]= get_time[5]&0x1f;//月; 再下一个为年
for(i=0;i<7;i++)
{
get_time[i]=BCD_To_Int(get_time[i]);//将BCD转为十进制后处理
}
//uchar line1[11]={0,0,'-',0,0,'-',0,0,'w','0'};//显示年月日和星期
line1[0]=(get_time[6]/10)|0x30;//取十位数
line1[1]=(get_time[6]%10)|0x30;//取个位数,其它同
line1[3]=(get_time[5]/10)|0x30;//取十位数
line1[4]=(get_time[5]%10)|0x30;//取个位数,其它同
line1[6]=(get_time[3]/10)|0x30;//取十位数
line1[7]=(get_time[3]%10)|0x30;//取个位数,其它同
line1[9]=get_time[4]|0x30;//取个位数,其它同,week
//uchar line2[8]={0,0,'-',0,0,'-',0,0};//小时,分,秒
line2[0]=(get_time[2]/10)|0x30;//取十位数
line2[1]=(get_time[2]%10)|0x30;//取个位数,其它同
line2[3]=(get_time[1]/10)|0x30;//取十位数
line2[4]=(get_time[1]%10)|0x30;//取个位数,其它同
line2[6]=(get_time[0]/10)|0x30;//取十位数
line2[7]= get_time[0] |0x30 ;//取个位数,其它同
i=LCD_Show_Num_New(0,0,20);//在年份前加入20
LCD_Str_Write(i,0,line1);
LCD_Str_Write(0,1,line2);
}
//增加中断1来设置初始时间;低电平有效
ISR(INT1_vect)
{
Set_Time_All(SECOND_DATA_BUF,set_time,7);
//Write_Abyte(CTRL_BUF2,0x1f);
}
//增加中断0来记录报警次数;低电平有效
ISR(INT0_vect)
{
int_time++;
//Write_Abyte(CTRL_BUF2,0x0A);//清除中断
//Write_Abyte(HOUR_AE_BUF,Int_To_BCD(11));
}
void Interrupt_init()
{
DDRD&=~(_BV(PD2)|_BV(PD3));//2个中断口为输入口
GICR|=_BV(7)|_BV(6);//开启中断0,1
MCUCR|=_BV(3)|_BV(1) ;//INT1下降沿触发,INT0下降沿中断
GIFR|=_BV(7)|_BV(6);//清除中断标志
SREG|=_BV(7);//开启中断
}
int main(void)
{uchar i;
TWBR = 0X0F;//设置TWI波特率
TWSR &= 0XFC;//设置TWI预分频 为 1
LCD_Init();
PCF8563_Init();
_delay_ms(100);
///中断设置
Interrupt_init();
//Write_Abyte(CLK_FRQ_BUF,0x81);//1024Hz的频率发生
i=LCD_Str_Write(8,1,"times");
while(1)
{
_delay_ms(100);
Disp_Time_In_LCD1602();
LCD_Show_Num_New(13,1,int_time);//显示中断次数
}
}