http://hi.baidu.com/mpc2010/blog/item/bbfd3423e7d738278644f916.html
tinyArm调试————PCF8563
2011-02-23 20:52
对于tinyARm介绍及我们的工程详见前面的日志(浅谈TinyARm调试——MOdbus协议栈调试经验)。现在我来总结这段时间我所做的工作,在调试好的485通讯基础上调试实时时钟PCF8563.
一、简介PCF8563
PCF8563 是低功耗的 CMOS 实时时钟/日历芯片,它提供一个可编程时钟输出,一个中断输出和掉电检测器,所有的地址和数据通过 I2C 总线接口串行传递。最大总线速度为400Kbits/s,每次读写数据后,内嵌的字地址寄存器会自动产生增量。具体说明可详见此芯片的datasheet。
值得注意的是内存地址02H~08H 用于时钟计数器(秒~年计数器)编码格式为 BCD,所以我们如果想要显示时间格式必须要进行BCD_TO_HEC的转换。
二、硬件连接图
通用的硬件连接图如下所示。 在我们的硬件中pcf8563的SCL与SDA脚分别于TinyArm的P0.19与P0.20脚相连。所以在软件中引脚设置也要将LPC2300PinCfg.h中的两个引脚的功能选择为I2c1.即
#define P0_19_FNUC P0_19_SDA1
#define P0_20_FNUC P0_20_SCL1
具体引脚的设置根据自己的设计可以采用I2c0或I2c1。
三、调试程序(主要工作)
由于这是一款时钟芯片,初始化当前时间之后,芯片会自动跟踪当地实际时间。我们调试的目的是对芯片进行初始化,然后把时间读出来,再发送到上位机通过串口调试助手判断结果。
首先,我们可以明确的知道,这2个功能分别是通过I2c的读写来实现。于是我们通过I2c的读写功能写了2个函数分别用于设置和读取PCF内部寄存器。具体程序段如下:
#define PCF8563 0xA2 /*I2C 总线从地址:读,0A3H;写,0A2H*/
#define BCD_to_HEC(b) ((INT8U)(((b>>4)*10)+(b&0x0fu)))
#define HEC_to_BCD(h) ((INT8U)(((h/10)<<4)|(h%10)))
#define I2C_INTERFACE 1 /* 0: PCF8563接在I2C0上 */
/* 1: PCF8563接在I2C1上 */
extern int32 I2CWrite(uint8 , uint8* ,uint16 ,uint8 *,uint32 ,void (*)(INT8U));
extern int32 I2CRead(uint8, uint8* , uint16 ,uint8 *,uint32 ,void(*)(INT8U));
extern int32 I2CGetFlag(void);
/*********************************************************************************************************
** Function name: pcf8563SetTime
** Descriptions: 设置PCF8563的时间
** input parameters: pTime -日期时间
************************************************************************/
INT32S pcf8563SetTime (PCF8563_Time *pTime)
{
INT8U ucTimeBuff[10];
if (pTime == NULL) {
return -1;
}
ucTimeBuff[0] = 0x00; /*从机子地址设置*/
ucTimeBuff[1] = 0x00; /*控制/状态寄存器1设置*/
ucTimeBuff[2] = 0x12; /*控制/状态寄存器2设置*/
ucTimeBuff[3] = HEC_to_BCD(pTime->Second);
ucTimeBuff[4] = HEC_to_BCD(pTime->Minute);
ucTimeBuff[5] = HEC_to_BCD(pTime->Hour);
ucTimeBuff[6] = HEC_to_BCD(pTime->Day);
ucTimeBuff[7] = HEC_to_BCD(pTime->Week);
ucTimeBuff[8] = HEC_to_BCD(pTime->Month);
if (pTime->Year >= 2000){
ucTimeBuff[8] |= 0x80;
ucTimeBuff[9] = HEC_to_BCD((INT8U)(pTime->Year - 2000));
}else{
ucTimeBuff[9] = HEC_to_BCD((INT8U)(pTime->Year - 1900));
}
/*
* 通过I2C写PCF8563
*/
#if I2C_INTERFACE == 0
I2CWrite(I2C0,PCF8563, ucTimeBuff, ONE_BYTE_SADDR, (ucTimeBuff+1), 9,NULL);
while(1) {
if(I2CGetFlag()==I2C_WRITE_END) {
break;
}
OSTimeDly(1);
}
#endif
#if I2C_INTERFACE == 1
I2cWrite(I2C1, PCF8563, ucTimeBuff, ONE_BYTE_SADDR, ucTimeBuff+1, 9,NULL);
while(1) {
if(I2cGetFlag(I2C1) == I2C_WRITE_END) {
break;
}
OSTimeDly(1);
}
#endif
return 0;
}
*********************************************************************************************************
** Function name: pcf8563GetTime
** Descriptions: 设置PCF8563的时间
** input parameters: pTime -日期时间
************************************************************************/
INT32S pcf8563GetTime (PCF8563_Time *pTime)
{
INT8U ucTimeBuff[10];
if (pTime == NULL) {
return -1;
}
/*
* 通过I2C读PCF8563
*/
#if I2C_INTERFACE == 0
memset(ucTimeBuff, 0, 10);
ucTimeBuff[0]=0x02;
I2CRead(PCF8563+1, ucTimeBuff, 1, ucTimeBuff, 7,NULL); */ /* 读取外部PCF8563时钟 */
while(1) {
if(I2CGetFlag() == I2C_READ_END) {
break;
}
OSTimeDly(1);
}
#endif
#if I2C_INTERFACE == 1
memset(ucTimeBuff, 0, 10);
ucTimeBuff[0]=0x02;
I2cRead(I2C1, PCF8563 + 1, ucTimeBuff, ONE_BYTE_SADDR, ucTimeBuff, 7,NULL);
while(1) {
if(I2cGetFlag(I2C1) ==I2C_READ_END) {
break;
}
OSTimeDly(1);
}
#endif
pTime->Second = BCD_to_HEC((ucTimeBuff[0] &0x7f)); /* 秒 */
pTime->Minute = BCD_to_HEC((ucTimeBuff[1] & 0x7f)); /*分 */
pTime->Hour = BCD_to_HEC((ucTimeBuff[2] & 0x3f)); /* 小时 */
pTime->Day = BCD_to_HEC((ucTimeBuff[3] & 0x3f)); /* 日 */
pTime->Week = BCD_to_HEC((ucTimeBuff[4] & 0x07)); /* 星期 */
if (ucTimeBuff[5]&0x80){
pTime->Month = BCD_to_HEC((ucTimeBuff[5] & 0x1f)); /* 月 */
pTime->Year = (INT16U)(BCD_to_HEC(ucTimeBuff[6]) + 2000); /* 年为20XX */
}else{
pTime->Month = BCD_to_HEC((ucTimeBuff[5]&0x1f));
pTime->Year = (INT16U)(BCD_to_HEC(ucTimeBuff[6]) + 1900); /* 年为19XX */
}
return 0;
}
这2个函数写好之后后面就可以进行我们的任务调度了,该任务会将读出的实时时钟以固定日期的格式通过RS485通讯到上位机显示出来。任务程序如下:
void TASK0 (void *pdata)
{
#define I2C_INTERFACE 1
PCF8563_Time time;
char cStrTmp[32];
char uartInitArg[] = "RxBufSize=8 TxBufSize=64 BaudRate=9600";
char rs485Arg[32]; /* RS-485参数缓存 */
/*
* 初始化UART0
*/
UartInit(UART0, uartInitArg, NULL); /* 初始化UART0 */
sprintf(rs485Arg, "RS485Dir=%u", P0_04); /* 获取RS-485方向控制引脚 */
/* P0.4的编号值 */
UartSetMode(UART0, SET_RS485, rs485Arg); /* 使能RS-485设置其方向控制引脚 */
SetVICIRQ(UART0_IRQ_CHN, 8, (uint32)UART0_ISR); /* 设置UART0中断 */
/*
* 初始化I2C
*/
while(I2cInit(I2C1, "Speed=400000", NULL) == OPERATE_FAIL) {
OSTimeDly(1);
}
SetVICIRQ(I2C1_IRQ_CHN, 2, (uint32)I2C1_ISR); /* 设置I2C中断 */
/*
* 通过I2C写PCF8563 设置PCF8563的时间
*/
time.Year = 2011;
time.Month = 2;
time.Day = 16;
time.Week = 3;
time.Hour = 10;
time.Minute = 10;
time.Second = 10;
pcf8563SetTime (&time);
while (1) {
/*
* 读PCF8563的时间,并通过串口发送
*/
if(pcf8563GetTime(&time)==0)
{
/*
* 格式化要显示的字符串
*/
sprintf(cStrTmp, "%04d-%02d-%02d %01d %02d:%02d:%02d",
time.Year, time.Month, time.Day, time.Week,
time.Hour, time.Minute, time.Second);
cStrTmp[21] = '\r';
cStrTmp[22] = '\n';
UartWrite(UART0, (uint8 *)cStrTmp, 23, NULL); /* 通过UART0发送日期时间 */
OSTimeDly(OS_TICKS_PER_SEC);
}
}
}
如果硬件连接么有问题的话,到此就OK了。
四、调试结果
如图所示:
工程完整文件我会传到csdn上,以后有需要的同学可以去下载~~~