RA8900CE计时芯片介绍及开发方案

计时芯片

就是一个需要连接32.768k晶振的RTC芯片

规格书阅读

首先我们先读懂这个芯片是怎么用的。

引脚表

封装是这样的,一共10个引脚。

基本上一看这个引脚表就知道大概。

T1和T2是工厂测试的,不用管。

SCL和SDA是IIC通讯用的。

FOUT和FOE就是链接晶振的。

INT是中断输出,闹钟、唤醒啥的都靠它。

其他的都是电源和地了。

模块框图

这个也简单,就是个S-35390A的简化版,有需要的朋友可以看我另一篇文章。S-35390A计时芯片介绍及开发方案_s35390-CSDN博客

软件设计

寄存器定义

里面有好几组寄存器,可以按照命令来读取。

基础信息寄存器

// RX-8900 Basic Time and Calendar Register definitions
#define RA8900_BTC_SEC					0x00
#define RA8900_BTC_MIN					0x01
#define RA8900_BTC_HOUR					0x02
#define RA8900_BTC_WEEK					0x03
#define RA8900_BTC_DAY					0x04
#define RA8900_BTC_MONTH				0x05
#define RA8900_BTC_YEAR					0x06
#define RA8900_BTC_RAM					0x07
#define RA8900_BTC_ALARM_MIN			0x08
#define RA8900_BTC_ALARM_HOUR			0x09
#define RA8900_BTC_ALARM_WEEK_OR_DAY	0x0A
#define RA8900_BTC_TIMER_CNT_0			0x0B
#define RA8900_BTC_TIMER_CNT_1			0x0C
#define RA8900_BTC_EXT					0x0D
#define RA8900_BTC_FLAG					0x0E
#define RA8900_BTC_CTRL					0x0F

扩展寄存器1

// RX-8900 Extension Register 1 definitions
#define RA8900_EXT_SEC					0x10
#define RA8900_EXT_MIN					0x11
#define RA8900_EXT_HOUR					0x12
#define RA8900_EXT_WEEK					0x13
#define RA8900_EXT_DAY					0x14
#define RA8900_EXT_MONTH				0x15
#define RA8900_EXT_YEAR					0x16
#define RA8900_EXT_TEMP					0x17
#define RA8900_EXT_BACKUP				0x18

#define RA8900_EXT_TIMER_CNT_0			0x1B
#define RA8900_EXT_TIMER_CNT_1			0x1C
#define RA8900_EXT_EXT					0x1D
#define RA8900_EXT_FLAG					0x1E
#define RA8900_EXT_CTRL					0x1F

#define RA8900_EXT_0X30   			    0x30
#define RA8900_EXT_0X32   			    0x32
#define RA8900_EXT_0X40   			    0x40
#define RA8900_EXT_0X5A					0x5a
#define RA8900_EXT_0X5C					0x5c

扩展寄存器

// Flag RA8900_BTC_EXT Register bit positions
#define RA8900_BTC_EXT_TSEL0		(1 << 0)
#define RA8900_BTC_EXT_TSEL1		(1 << 1)
#define RA8900_BTC_EXT_FSEL0		(1 << 2)
#define RA8900_BTC_EXT_FSEL1		(1 << 3)
#define RA8900_BTC_EXT_TE 			(1 << 4)
#define RA8900_BTC_EXT_USEL			(1 << 5)
#define RA8900_BTC_EXT_WADA			(1 << 6)
#define RA8900_BTC_EXT_TEST			(1 << 7)

标志位寄存器

#define RA8900_BTC_FLAG_VDET 		(1 << 0)
#define RA8900_BTC_FLAG_VLF 		(1 << 1)
#define RA8900_BTC_FLAG_AF 			(1 << 3)
#define RA8900_BTC_FLAG_TF 			(1 << 4)
#define RA8900_BTC_FLAG_UF 			(1 << 5)

控制寄存器

#define RA8900_BTC_CTRL_RESET 		(1 << 0)
#define RA8900_BTC_CTRL_AIE 		(1 << 3)
#define RA8900_BTC_CTRL_TIE 		(1 << 4)
#define RA8900_BTC_CTRL_UIE 		(1 << 5)
#define RA8900_BTC_CTRL_CSEL0 		(1 << 6)
#define RA8900_BTC_CTRL_CSEL1		(1 << 7)

初始化

就是调用两个接口,用配置结构体初始化,接个状态回来。由于我这里用的是软件IIC,用到硬件IIC的朋友请自行初始化,调用下LPI2C_DRV_MasterInit函数。

RA8900_Init(&rtc_Config,&g_RA8900State);

结构体长这样,按照内容配置就行,不会的可以照抄。

rtc_user_config rtc_Config=
{
    ONCE_PER_SECONDS,//按照秒或者分钟计时
    FREQ_32dot768KHZ,//晶振选择
    CLOCK_EVERY_SECOND,//时钟频率
    EXECUTE_PER_2_SEC,//时钟补偿
    false,//是否使能修正周期
    false,//是否使能时钟更新
    false,//是否使能闹钟
    WEEK_ALARM,//闹钟按照天还是周
    /*year,month,day,hour,min,second,week*///默认时钟
	{ 18, 1,  1  ,0  , 0,  0,  1 },
	/*min ,hour ,week, day ,AF ,enabled,wada,pending*///默认闹钟
	{ 0,  0,   1    ,1   ,0,   0,       0,   0  }
};

代码如下

rtc_state g_RA8900State;
rtc_state *g_RA8900StatePtr=&g_RA8900State;
void RA8900_Init(rtc_user_config *userConfigPtr, rtc_state *rtc)
{
	uint8_t ctrl[3]={0x02,0x00,0x61};/*the default data*/
	g_RA8900StatePtr = rtc;

    ctrl[0]=(userConfigPtr->WADA<<6)|(ctrl[0]&(~RA8900_BTC_EXT_WADA));
	ctrl[0]=(userConfigPtr->updateTime <<5)|(ctrl[0]&(~RA8900_BTC_EXT_USEL));
	ctrl[0]=(userConfigPtr->outputFreq<<2)|(ctrl[0]&(~(RA8900_BTC_EXT_FSEL0|RA8900_BTC_EXT_FSEL1)));
	ctrl[0]=(userConfigPtr->timerClock)|(ctrl[0]&(~(RA8900_BTC_EXT_TSEL0|RA8900_BTC_EXT_TSEL1)));
    /*config the ext reg must set TE \TEST to 1,RESET to 1 (when set clock need to stop clock) */
	/*set TE \TEST to 1,RESET to 1,anothers are the config */
    RA8900_WriteRegs(RA8900_BTC_EXT,3,ctrl);
    RA8900_ReadRegs(RA8900_BTC_EXT,3,ctrl);
	RA8900_SetTime(&(userConfigPtr->defaulRtcTime));

	/*check the time fixedCycle function*/
	if(userConfigPtr->isFixedCycleEnable)
	{
        /*if enable ,set the TE bit in EXT Reg*/
		ctrl[0]=(userConfigPtr->isFixedCycleEnable<<4)|(ctrl[0]&(~RA8900_BTC_EXT_TE));
	}/*if not enable,dont't need to change, it is 0 alreadly*/

	/*set the function interrupt*/
	ctrl[2]=(userConfigPtr->isAlarmEnable<<3)|(ctrl[2]&(~RA8900_BTC_CTRL_AIE));
	ctrl[2]=(userConfigPtr->isFixedCycleEnable<<4)|(ctrl[2]&(~RA8900_BTC_CTRL_TIE));
	ctrl[2]=(1<<5)|(ctrl[2]&(~RA8900_BTC_CTRL_UIE));
	/*set the Temperature compensation */
	ctrl[2]=(userConfigPtr->temperCompensation<<6)|(ctrl[2]&(~(RA8900_BTC_CTRL_CSEL0|RA8900_BTC_CTRL_CSEL1)));
   /*reset the device*/
	ctrl[2]=0;
	RA8900_WriteRegs(RA8900_BTC_EXT,3,ctrl);

	g_RA8900StatePtr->extReg=ctrl[0];
	g_RA8900StatePtr->ctrlreg=ctrl[2];
	g_RA8900StatePtr->flagReg=ctrl[1];
}

读取接口

互斥锁的作用就是防止同时读和写。

static bool RA8900_ReadRegs(uint8_t regIdx, uint8_t length,uint8_t *values)
{
	bool ret = false;
    uint8_t Try = 3;

    if( xSemaphore_i2c != NULL )//互斥锁
    {
        if( xSemaphoreTake( xSemaphore_i2c, ( TickType_t ) 50 ) == pdTRUE )
        {
            while((Try--)&&(ret != true))  // allow setting 3 times
			{
              ret=I2C_read_bytes(RA8900_ADDRESS,regIdx,RTC_ADDR_BYTES,length,values);
			}
            xSemaphoreGive( xSemaphore_i2c);
        }
    }
	return	ret;
}

写入接口

因为要把命令先写进去,所以这里开了个buffer把命令和数据拼起来再发出去。地址默认为0x32

bool RA8900_WriteRegs(uint8_t regIdx,uint8_t length, uint8_t *values)
{
	bool ret = false;
	uint8_t Try = 3;

	uint8_t masterbuffer[32]={0};
	masterbuffer[0]=regIdx;
	memcpy(&masterbuffer[1],values,length);

    if( xSemaphore_i2c != NULL )
    {
        if( xSemaphoreTake( xSemaphore_i2c, ( TickType_t ) 50 ) == pdTRUE )
        {
			while((Try--)&&(ret != true))// allow setting 3 times
			{
				ret = I2C_write_bytes(RA8900_ADDRESS,length+ 1,masterbuffer);
			}
			xSemaphoreGive( xSemaphore_i2c);
        }
    }
	return	ret;
}

获取时间

time就是个结构体,里面有的东西下面都能看到了。将时间信息获取到regdate里面之后按照字节来转换BCD码。

uint8_t RA8900_GetTime(rtc_time *time)
{
	uint8_t regdate[16]={0,0,0,0,0,0,0};
	uint8_t err = 0;

	err = RA8900_ReadRegs(RA8900_BTC_SEC,7,regdate);
	time->second  = RA8900_Bcd2Dec(regdate[0] & 0x7f);
	time->minute  = RA8900_Bcd2Dec(regdate[1] & 0x7f);
	time->hour = RA8900_Bcd2Dec(regdate[2] & 0x3f);
	time->week = RA8900_GetWeekDay(regdate[3] & 0x7f);
	time->day = RA8900_Bcd2Dec(regdate[4] & 0x3f);
	time->month  = RA8900_Bcd2Dec(regdate[5] & 0x1f)-1;
	time->year = RA8900_Bcd2Dec(regdate[6])+2000;

	if (err==false)
	{
		return 0;
	}
    return 1;
}

设置当前时间

按照位置去写入就行。

uint8_t  RA8900_SetTime(rtc_time *time)
{
	uint8_t date[7];
	int ret = 0;

	date[0]   = RA8900_Dec2Bcd(time->second);
	date[1]   = RA8900_Dec2Bcd(time->minute);
	date[2]  = RA8900_Dec2Bcd(time->hour);
	date[3]  = 1 << (time->week);
	date[4]   = RA8900_Dec2Bcd(time->day);
	date[5] = RA8900_Dec2Bcd(time->month+1);
	date[6]  = RA8900_Dec2Bcd(time->year % 100);
	ret =  RA8900_WriteRegs(RA8900_BTC_SEC, 7, date);
	return ret;
}

十进制转换BCD码

这种基本都是标准的

uint8_t RA8900_Dec2Bcd(uint8_t binData)
{
    uint8_t ret;
    ret = binData/10;//十位
    binData %= 10; //个位
    ret <<= 4; 
    ret += binData;
    return ret;
}

BCD码转换为十进制

uint8_t RA8900_Bcd2Dec(uint8_t bcdData)
{
  uint8_t ret;
  ret = bcdData&0x0f;//个位。
  bcdData >>= 4;
  bcdData &= 0x0f;
  bcdData *= 10;//十位
  ret += bcdData;//相加
  return ret;
}

获取闹钟时间

uint8_t RA8900_GetAlarm(rtc_alarm *alarmTime)
{
	uint8_t alarmvals[3];//分,时,天
	uint8_t ctrl[3];//标志位
	int err;

	//获取闹钟时间,分
	err = RA8900_ReadRegs(RA8900_BTC_ALARM_MIN, 3, alarmvals);
    if (!err){return err;}

	//获取标志位:extension, flag, control values
	err = RA8900_ReadRegs(RA8900_BTC_EXT, 3, ctrl);
    if (!err){return err;}

	//将获取到的闹钟信息转换为十进制
	alarmTime->minute = RA8900_Bcd2Dec(alarmvals[0] & 0x7f);
	alarmTime->hour = RA8900_Bcd2Dec(alarmvals[1] & 0x3f);

	if (ctrl[0] & RA8900_BTC_EXT_WADA )//闹钟为每天
	{
		alarmTime->week = 0xff;
		alarmTime->day = RA8900_Bcd2Dec(alarmvals[2] & 0x3f);
	}
	else//闹钟为每周
	{ 
		alarmTime->week = RA8900_GetWeekDay( alarmvals[2] & 0x7f );
		alarmTime->day = 0xff;
		alarmTime->WADA=0;
	}

	//检查闹钟中断是否使能
	alarmTime->enabled = !!(ctrl[2] & RA8900_BTC_CTRL_AIE);
	//检查闹钟是否已经触发,就是是否响了
	alarmTime->pending = (ctrl[1] & RA8900_BTC_FLAG_AF) && alarmTime->enabled;

	return err;
}

设置闹钟时间

可以是日闹钟,可以是周闹钟。

int RA8900_SetAlarmClock(rtc_alarm *alarmClockTime)
{
    uint8_t alarmvals[3];//分, 时, 天
	uint8_t ctrl[3];//控制信息
	int err;

	alarmvals[0] = RA8900_Dec2Bcd(alarmClockTime->minute);
	alarmvals[1] = RA8900_Dec2Bcd(alarmClockTime->hour);
    
    //获取控制信息
	RA8900_ReadRegs(RA8900_BTC_EXT, 3, ctrl);
	if(alarmClockTime->WADA)
	{
		alarmvals[2] = RA8900_Dec2Bcd(alarmClockTime->day);
		ctrl[0] |= RA8900_BTC_EXT_WADA;
	}
	else
	{
		/*  bit:  7   6    5    4     3    2     1    0    */
		/* week:  0   Sat  Fri  Thur  Wed  Tue   Mon  Sun  */
		alarmvals[2] = alarmClockTime->week;
		ctrl[0] &= ~(RA8900_BTC_EXT_WADA);
	}
	RA8900_WriteRegs( RA8900_BTC_EXT, 1, &ctrl[0]);
	
	ctrl[2]= RA8900_BTC_CTRL_AIE|ctrl[2];
	ctrl[2] &= ~(RA8900_BTC_CTRL_UIE | RA8900_BTC_CTRL_TIE);
	RA8900_WriteRegs(RA8900_BTC_CTRL, 1, &ctrl[2]);
	RA8900_WriteRegs(RA8900_BTC_ALARM_MIN, 3, alarmvals);

	ctrl[1] &= ~RA8900_BTC_FLAG_AF;
	err = RA8900_WriteRegs(RA8900_BTC_FLAG, 1 ,&ctrl[1]);
    return err;
}

停止闹钟

int RA8900_StopAlarm(void)
{
	uint8_t ctrl[1];//控制位 ext, flag registers
	int err;
	
	RA8900_ReadRegs(RA8900_BTC_CTRL, 1, ctrl);
	ctrl[0] &= ~RA8900_BTC_CTRL_AIE;
	err = RA8900_WriteRegs(RA8900_BTC_CTRL, 1, ctrl);
	return err;
}

清除所有标志位

void  RA8900_ClearFlag(uint8_t flag)
{
	uint8_t currentFlag;

	RA8900_ReadRegs(RA8900_BTC_FLAG,1,&currentFlag);
	currentFlag=currentFlag & (~flag);
	RA8900_WriteRegs(RA8900_BTC_FLAG,1,&currentFlag);
}

转换为周几

长度7位,从低到高哪位为1就是周几。

static uint_8 RA8900_GetWeekDay(uint8_t regWeekDay )
{
	uint_8 index, timeWeekDay;

	for ( index=0; index < 7; index++ )
	{
		if ( regWeekDay & 1 )
		{
			timeWeekDay = index;
			break;
		}
		regWeekDay >>= 1;
	}
	return 	timeWeekDay;
}

获取温度

只是个功能,没啥用,将获取到的数值按公式算就行。

#define RA8900_EXT_TEMP					0x17

uint8_t RA8900_GetTemp(void)
{
	uint8_t tempvalue = 0;
	float   RtcTemp = 0.0;

	RA8900_ReadRegs(RA8900_EXT_TEMP,1,&tempvalue);
	RtcTemp = (tempvalue*2 - 187.19)/3.218;

	tempvalue = (uint8_t)RtcTemp;
	return tempvalue;
}

保持增强功能

他有个增强功能,要在初始化的时候做这几件事,50ms为周期调用下面这个初始化接口。其实就是写入几个命令。

#define RA8900_EXT_0X30   			    0x30
#define RA8900_EXT_0X32   			    0x32
#define RA8900_EXT_0X40   			    0x40
#define RA8900_EXT_0X5A					0x5a
#define RA8900_EXT_0X5C					0x5c

uint8_t RA8900CE_Inhance(void)
{
    bool err = false;
    uint8_t ctrl = 0;
    static uint8_t s_Step = FSM_STEP_01;//默认为第一步

    switch(s_Step)
    {
       case FSM_STEP_01://第一步
       {
        	ctrl = 0xd1;
            err = RA8900_WriteRegs(RA8900_EXT_0X30,1,&ctrl);
            if (!err){return err;}

            ctrl = 0x00;
            err = RA8900_WriteRegs(RA8900_EXT_0X40,1,&ctrl);
            if (!err){return err;}

            ctrl = 0x81;
            err = RA8900_WriteRegs(RA8900_EXT_0X32,1,&ctrl);
            if (!err){return err;}

            s_Step = FSM_STEP_02;//跳到第二步 
        }break;

       case FSM_STEP_02://第二步
       {
           ctrl = 0x80;
           err = RA8900_WriteRegs(RA8900_EXT_0X32,1,&ctrl);
           if (!err){return err;}

           s_Step = FSM_STEP_03;//跳到第三步 
           break;
        }

        case FSM_STEP_03://第三步
        {
            ctrl = 0x04;
            err = RA8900_WriteRegs( RA8900_EXT_0X32, 1, &ctrl);
            if (!err){return err;}

            s_Step = FSM_STEP_04;//跳到第四步 
            break;
        }

        case FSM_STEP_04://第四步
        {
            ctrl = 0x00;
            err = RA8900_ReadRegs(RA8900_EXT_0X5C,1,&ctrl);
            if (!err){return err;}

            ctrl &= ~0x0f;
            ctrl |= 0x0c;
            err = RA8900_WriteRegs(RA8900_EXT_0X5C,1,&ctrl);
            if (!err){return err;}

            err = RA8900_ReadRegs(RA8900_EXT_0X5A,1,&ctrl);
            if (!err){return err;}

            ctrl &= ~0xe0;
            ctrl |= 0xe0;
            err = RA8900_WriteRegs( RA8900_EXT_0X5A, 1, &ctrl);
            if (!err){return err;}

            ctrl = 0x00;
            err = RA8900_WriteRegs(RA8900_EXT_0X30,1, &ctrl);
            if (!err){return err;}

             s_Step = FSM_STEP_END;//结束
             break;
         }

        default:
            s_Step = FSM_STEP_END;
            break;
    }
    return err;
}
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃鱼的羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值