前言
因华大单片机没有单独VBAT管脚,无法使用,如果用单片机自带的RTC模块,系统断电后时间无法准确,需要重新设置,影响用户体验,说以系统加入单独的RTC芯片.
RTC时钟电路
单片机管脚定义
RTC芯片为 [BL(上海贝岭) 的 BM8563ESA 实时时钟RTC
BCD码 百度百科解释
BCD码(Binary-Coded Decimal?),用4位二进制数来表示1位十进制数中的0~9这10个数码,是一种二进制的数字编码形式,用二进制编码的十进制代码。BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行。
我的简单解释: 比如说02H地址寄存器中的数据表示秒 Bit7 是无效的 ,Bit0–Bit 6为有效的 . 0x00 至 0x59 ,0x00表示0秒 0x59是16进制数据,但是他表示59秒.程序中需要转换.
BM8563ESA驱动程序编写
BM8563ESA 是I2C驱动,标准的I2C驱动可以使用
#include "drvs.h"
#define RTC_SCL_COM PortB,Pin05
#define RTC_SDA_COM PortB,Pin04
#define RTC_SDA_IN() RTC_SET_SDA_IN()
#define RTC_SDA_OUT() RTC_SET_SDA_OUT()
#define RTC_IIC_SCL(v) v == Disable ? PORT_ResetBits(RTC_SCL_COM): PORT_SetBits(RTC_SCL_COM)
#define RTC_IIC_SDA(v) v == Disable ? PORT_ResetBits(RTC_SDA_COM): PORT_SetBits(RTC_SDA_COM)
#define RTC_READ_SDA PORT_GetBit(RTC_SDA_COM)
#define RTC_EE_DEV_ADDR 0xA2
static u8 ack = 0;
void bsp_DelayUS(int us)
{
uint16_t i;
for (i = 0; i < 30*us; i++);
}
void RTC_bsp_InitI2C(void)
{
PORT_DebugPortSetting(TRST,Disable);
PORT_DebugPortSetting(TDO_SWO,Disable);
stc_port_init_t stcPortInit;
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enPinOType = Pin_OType_Od;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
PORT_Init(RTC_SCL_COM, &stcPortInit);
PORT_Init(RTC_SDA_COM, &stcPortInit);
}
void RTC_SET_SDA_IN(void)
{
stc_port_init_t stcPortInit;
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_In;
stcPortInit.enExInt = Enable;
stcPortInit.enPullUp = Enable;
PORT_Init(RTC_SDA_COM, &stcPortInit);
}
void RTC_SET_SDA_OUT(void)
{
stc_port_init_t stcPortInit;
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enPinOType = Pin_OType_Od;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
PORT_Init(RTC_SDA_COM, &stcPortInit);
}
void RTC_IIC_Start(void)
{
RTC_SDA_OUT();
RTC_IIC_SDA(Enable);
RTC_IIC_SCL(Enable);
bsp_DelayUS(4);
RTC_IIC_SDA(Disable);
bsp_DelayUS(4);
RTC_IIC_SCL(Disable);
}
void RTC_IIC_Stop(void)
{
RTC_SDA_OUT();
RTC_IIC_SCL(Disable);
RTC_IIC_SDA(Disable);
bsp_DelayUS(4);
RTC_IIC_SCL(Enable);
bsp_DelayUS(4);
RTC_IIC_SDA(Enable);
bsp_DelayUS(4);
}
u8 RTC_IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
RTC_SDA_IN();
RTC_IIC_SDA(Enable);
bsp_DelayUS(1);
RTC_IIC_SCL(Enable);
bsp_DelayUS(1);
while(RTC_READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
RTC_IIC_Stop();
return 1;
}
}
RTC_IIC_SCL(Disable);
return 0;
}
void RTC_RTC_IIC_Ack(void)
{
RTC_IIC_SCL(Disable);
RTC_SDA_OUT();
RTC_IIC_SDA(Disable);
bsp_DelayUS(2);
RTC_IIC_SCL(Enable);
bsp_DelayUS(2);
RTC_IIC_SCL(Disable);
}
void RTC_IIC_NAck(void)
{
RTC_IIC_SCL(Disable);
RTC_SDA_OUT();
RTC_IIC_SDA(Enable);
bsp_DelayUS(2);
RTC_IIC_SCL(Enable);
bsp_DelayUS(2);
RTC_IIC_SCL(Disable);
}
void RTC_IIC_Send_Byte(u8 txd)
{
u8 t;
RTC_SDA_OUT();
RTC_IIC_SCL(Disable);;
for(t=0;t<8;t++)
{
if(txd & 0x80)
{
RTC_IIC_SDA(Enable);
}
else
{
RTC_IIC_SDA(Disable);
}
bsp_DelayUS(2);
RTC_IIC_SCL(Enable);
bsp_DelayUS(2);
RTC_IIC_SCL(Disable);
if(t == 7 )
{
RTC_IIC_SDA(Enable);
}
txd <<= 1;
bsp_DelayUS(2);
}
RTC_IIC_SDA(Enable);
RTC_IIC_SCL(Enable);
if(RTC_READ_SDA==1)
{
ack =0;
}
else
{
ack =1;
}
RTC_IIC_SCL(Disable);
}
u8 RTC_IIC_Read_Byte(void)
{
unsigned char i,receive=0;
RTC_SDA_IN();
for(i=0;i<8;i++ )
{
RTC_IIC_SCL(Disable);
bsp_DelayUS(2);
RTC_IIC_SCL(Enable);
receive<<=1;
if(RTC_READ_SDA)receive++;
bsp_DelayUS(1);
RTC_IIC_SCL(Disable);
}
return receive;
}
BM8563ESA 驱动部分
u8 GetBM8563(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
RTC_IIC_Start();
RTC_IIC_Send_Byte(sla);
if(ack==0)return(0);
RTC_IIC_Send_Byte(suba);
if(ack==0)return(0);
RTC_IIC_Start();
RTC_IIC_Send_Byte(sla+1);
if(ack==0)return(0);
for(i=0;i<no-1;i++)
{
*s = RTC_IIC_Read_Byte();
RTC_RTC_IIC_Ack();
s++;
}
*s = RTC_IIC_Read_Byte();
RTC_RTC_IIC_Ack();
RTC_IIC_Stop();
return 1;
}
u8 SetBM8563(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
RTC_IIC_Start();
RTC_IIC_Send_Byte(sla);
if(ack==0)return(0);
RTC_IIC_Send_Byte(suba);
if(ack==0)return(0);
for(i =0;i<no;i++)
{
RTC_IIC_Send_Byte(*s);
if(ack==0)return(0);
s++;
}
RTC_IIC_Stop();
return 1;
}
BM8563ESA 可用数据提取部分
因为我系统中至需要 年月日 时分秒
位操作宏的定义以及转换函数
#define GET_BIT(value,bit) ((value)&(1<<(bit)))
#define CPL_BIT(value,bit) ((value)^=(1<<(bit)))
#define SET0_BIT(value,bit) ((value)&=~(1<<(bit)))
#define SET1_BIT(value,bit) ((value)|= (1<<(bit)))
uchar SET_DATA(uchar value,unsigned int bitl,unsigned int bith,uchar data)
{
uchar v = value;
if(bitl<=bith)
{
unsigned int bcount = bith-bitl+1;
unsigned int cbit=0;
unsigned int cdata=0;
for(unsigned int i=0;i<bcount;i++)
{
cdata |=(1<<i);
cbit |=(1<<(bitl+i));
}
v &=~(cbit);
v |=((data&cdata)<<bitl);
}
return v;
}
int BCD2INT(uchar data)
{
int h = (data >> 4) & 0x0F;
int l = data & 0x0F;
int s = h*10 +l;
return s;
}
uchar INT2BCD(int data)
{
int h = data / 10;
int l = data % 10;
int s = h<<4 | l;
return s;
}
u8 Rtc_data[6];
int bm8533_timeFlag =0;
void R_bm8533_TimeData(void)
{
static uchar trdata[7];
if(GetBM8563(RTC_EE_DEV_ADDR,0x02,trdata,0x07))
{
Rtc_data[5] = BCD2INT(SET_DATA(trdata[0],7,7,0));
Rtc_data[4] = BCD2INT(SET_DATA(trdata[1],7,7,0));
Rtc_data[3] = BCD2INT(SET_DATA(trdata[2],6,7,0));
Rtc_data[2] = BCD2INT(SET_DATA(trdata[3],6,7,0));
Rtc_data[1] = BCD2INT(SET_DATA(trdata[5],5,7,0));
Rtc_data[0] = BCD2INT(trdata[6]);
bm8533_timeFlag =1;
}
}
int bm8533_r(int fd,void *buf,int len)
{
if(bm8533_timeFlag==1)
{
bm8533_timeFlag = 0;
char * data =(char *)buf;
memcpy(data,Rtc_data,sizeof(Rtc_data));
return sizeof(Rtc_data);
}
return -1;
}
uchar cs_wrdata[9];
int bm8533_w(int fd,void *buf,int len)
{
int * data =(int *)buf;
for(int i =0;i<len;i++)
{
cs_wrdata[i] = INT2BCD(data[i]);
}
SetBM8563(RTC_EE_DEV_ADDR,0x00,cs_wrdata,len);
return len;
}
void RTC_Init_IIC(void)
{
RTC_bsp_InitI2C();
rxm_reg_r(DEV_RTC,&bm8533_r);
rxm_reg_w(DEV_RTC,&bm8533_w);
rxm_addtim(500,&R_bm8533_TimeData);
}
DRV_INIT(RTC_Init_IIC);
int getWeekdayByYearday(int iY, int iM, int iD)
{
int iWeekDay = -1;
if (1 == iM || 2 == iM)
{
iM += 12;
iY--;
}
iWeekDay = (iD + 1 + 2 * iM + 3 * (iM + 1) / 5 + iY + iY / 4 - iY / 100 + iY / 400) % 7;
return iWeekDay;
}
int WRtcData[9]={0,0,0,13,10,8,2,2,22};
void UI_OK_btn_key(int key)
{
WRtcData[8] = rxw_GetEditValue(ctl_year_val);
WRtcData[7] = rxw_GetEditValue(ctl_month_val);
WRtcData[5] = rxw_GetEditValue(ctl_day_val);
WRtcData[4] = rxw_GetEditValue(ctl_hour_val);
WRtcData[3] = rxw_GetEditValue(ctl_minute_val);
WRtcData[2] = rxw_GetEditValue(ctl_second_val);
WRtcData[6] = getWeekdayByYearday(WRtcData[8],WRtcData[7],WRtcData[5]);
rxm_w(DEV_RTC,WRtcData,9);
}
总结:
驱动层负责数据的转换和时间读写,UI层负载显示需要的时间和设置时间,不需要计算.
|