计时芯片
就是一个需要连接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 valueserr = 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 registersint 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,¤tFlag);currentFlag=currentFlag & (~flag);RA8900_WriteRegs(RA8900_BTC_FLAG,1,¤tFlag);
}
转换为周几
长度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 0x17uint8_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 0x5cuint8_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;
}