前言

因华大单片机没有单独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"
//时钟芯片
//  RTC_SCL PB05
//  RTC_SDA PB04#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()//IO操作函数
#define RTC_IIC_SCL(v)      v == Disable ? PORT_ResetBits(RTC_SCL_COM): PORT_SetBits(RTC_SCL_COM) //SCL
#define RTC_IIC_SDA(v)      v == Disable ? PORT_ResetBits(RTC_SDA_COM): PORT_SetBits(RTC_SDA_COM) //SDA
#define RTC_READ_SDA        PORT_GetBit(RTC_SDA_COM)  //输入SDA #define RTC_EE_DEV_ADDR       0xA2        //设备static u8 ack = 0;//硬件延时
void bsp_DelayUS(int us)
{uint16_t i;/* CPU主频168MHz时,在内部Flash运行, MDK工程不优化。用台式示波器观测波形。循环次数为5时,SCL频率 = 1.78MHz (读耗时: 92ms, 读写正常,但是用示波器探头碰上就读写失败。时序接近临界)循环次数为10时,SCL频率 = 1.1MHz (读耗时: 138ms, 读速度: 118724B/s)循环次数为30时,SCL频率 = 440KHz, SCL高电平时间1.0us,SCL低电平时间1.2us上拉电阻选择2.2K欧时,SCL上升沿时间约0.5us,如果选4.7K欧,则上升沿约1us实际应用选择400KHz左右的速率即可*/for (i = 0; i < 30*us; i++);
}
/*************************************************************************
*   函 数 名: bsp_InitI2C
*   功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现
*   形    参:  无
*   返 回 值: 无
**************************************************************************/
void RTC_bsp_InitI2C(void)
{PORT_DebugPortSetting(TRST,Disable); //关闭JTDI 调试管脚PORT_DebugPortSetting(TDO_SWO,Disable); //关闭NJTRST调试管脚stc_port_init_t stcPortInit; MEM_ZERO_STRUCT(stcPortInit); stcPortInit.enPinMode = Pin_Mode_Out;  //输出模式stcPortInit.enPinOType = Pin_OType_Od;   //漏极开路stcPortInit.enExInt =  Disable;          //外部智力支持DisablestcPortInit.enPullUp = Disable;         //内部上拉电阻关闭/* BL10 Port/Pin 初始化 */PORT_Init(RTC_SCL_COM, &stcPortInit);//    SCLPORT_Init(RTC_SDA_COM, &stcPortInit);//  SDA
}void RTC_SET_SDA_IN(void)
{//  PORT_DebugPortSetting(TDO_SWO,Disable); //关闭NJTRST调试管脚stc_port_init_t stcPortInit;  /*配置结构初始化*/MEM_ZERO_STRUCT(stcPortInit);//设置销模式stcPortInit.enPinMode = Pin_Mode_In;//输入模式  stcPortInit.enExInt =  Enable;//Enable//DisablestcPortInit.enPullUp = Enable;//enPinDrv //内部上拉电阻使能PORT_Init(RTC_SDA_COM, &stcPortInit);// SDA
}void RTC_SET_SDA_OUT(void)
{//  PORT_DebugPortSetting(TDO_SWO,Disable); //关闭NJTRST调试管脚stc_port_init_t stcPortInit;  /*配置结构初始化*/MEM_ZERO_STRUCT(stcPortInit);//设置销模式stcPortInit.enPinMode = Pin_Mode_Out;//输入模式  stcPortInit.enPinOType = Pin_OType_Od;    //漏极开路stcPortInit.enExInt =  Disable;//Enable//DisablestcPortInit.enPullUp = Disable;//enPinDrv //内部上拉电阻使能PORT_Init(RTC_SDA_COM, &stcPortInit);// SDA
}//I2C驱动部分
//产生IIC起始信号
void RTC_IIC_Start(void)
{RTC_SDA_OUT();     //sda线输出RTC_IIC_SDA(Enable);RTC_IIC_SCL(Enable);bsp_DelayUS(4);RTC_IIC_SDA(Disable);bsp_DelayUS(4);RTC_IIC_SCL(Disable);
}
//产生IIC停止信号
void RTC_IIC_Stop(void)
{RTC_SDA_OUT();//sda线输出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);
}//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 RTC_IIC_Wait_Ack(void)
{u8 ucErrTime=0;RTC_SDA_IN();      //SDA设置为输入  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);//时钟输出0        return 0;
} //产生ACK应答
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);
}//不产生ACK应答
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);
}//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
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);   //对TEA5767这三个延时都是必须的RTC_IIC_SCL(Enable);bsp_DelayUS(2); RTC_IIC_SCL(Disable);if(t == 7 ){RTC_IIC_SDA(Enable);}txd <<= 1; /* 左移一个bit */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);
}//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 RTC_IIC_Read_Byte(void)
{unsigned char i,receive=0;RTC_SDA_IN();//SDA设置为输入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);}                   // if (!ack)
//          IIC_NAck();//发送nACK
//  else
//          IIC_Ack(); //发送ACK   return receive;
}

BM8563ESA 驱动部分

/********************************************************************
函 数 名: GetBM8563(void)
功 能:从 BM8563 的内部寄存器(时间、状态、报警等寄存器)读取数据
说 明:该程序函数用来读取 BM8563 的内部寄存器,譬如时间,报警,状态等寄存器采用页写的方式,设置数据的个数为 no,no 参数设置为 1 就是单字节方式
调 用:Start_I2C(),SendByte(),RcvByte(),Ack_I2C(),Stop_I2C()
入口参数:sla(BM8563 从地址), suba(BM8563 内部寄存器地址) *s(设置读取数据存储的指针), no(传输数据的个数)
返 回 值:有,返回布尔量(bit)用来鉴定传输成功否
***********************************************************************/
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;
}
/********************************************************************
函 数 名:SetBM8563(void)
功 能:设置 BM8563 的内部寄存器(时间,报警等寄存器)
说 明:该程序函数用来设置 BM8563 的内部寄存器,譬如时间,报警,状态等寄存器采用页写的方式,设置数据的个数为 no,no 参数设置为 1 就是单字节方式
调 用:Start_I2C(),SendByte(),Stop_I2C()
入口参数:sla(BM8563 从地址), suba(BM8563 内部寄存器地址) *s(设置初始化数据的指针), no(传输数据的个数)
返 回 值:有,返回布尔量(bit)用来鉴定传输成功否
***********************************************************************/
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))) //把某个位置0
#define SET1_BIT(value,bit) ((value)|= (1<<(bit))) //把某个位置1
//设置数据的某些位的值/*
value 需要设置的数据的指针
bitl 需要设置的位的低位
bith 需要设置的位的高位
data 需要设置的数据
*/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;
}
//把BCD码转成int型
int BCD2INT(uchar data)
{int h = (data >> 4) & 0x0F;int l = data  & 0x0F;int s = h*10 +l;return s;
}//把int型转换成BCD码
uchar INT2BCD(int data)
{int h = data / 10;int l = data % 10;int s = h<<4 | l;return s;
}u8 Rtc_data[6];//最终时间数据 //0 年,月,日,时,分,秒
int bm8533_timeFlag =0;
//每500MS获取一次时间
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));//秒 //把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; //接收转换完成}
}//RTC读时间驱动
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;
}//设置时间我们是一次性从00H寄存器到08H寄存器一共9个数据
uchar cs_wrdata[9];
//RTC写时间驱动
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]);//把int行年月日时分秒转换成BCD码,写入到RTC兴平}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); //装载函数并使用UI层调用///计算星期
//iY:年 iM:月 iD:日 返回当前月份
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);//设置时间 //把WRtcData 数据写入驱动层
}

总结:

驱动层负责数据的转换和时间读写,UI层负载显示需要的时间和设置时间,不需要计算.

华大单片机 HC32F460 驱动BM8563ESA RTC芯片相关推荐

  1. 华大单片机 HC32F460 驱动74HC595D

    在我刚学单片机时总是感觉很难理解,今天分析下74HC595串口转并口 IO扩展芯片,一般我们在IO口不够用的情况下才能祭出此神器. 那么我们如何驱动此神器呢? "念咒:天灵灵地灵灵,Q1开& ...

  2. 手把手教程1: 华大单片机HC32F460如何新建工程(ddl库版本)

    华大单片机HC32F460如何新建工程(ddl库版本) 目录 华大单片机HC32F460如何新建工程(ddl库版本) 准备工作 正式工作 开发板请点击:  https://item.taobao.co ...

  3. 华大单片机HC32F460 系列MCU

    1 摘要 本篇应用笔记主要介绍如何使用华大单片机 HC32F460 系列MCU的 DMA 模块传输数据. 2 DMA 简介 什么是 DMA? DMA(直接内存访问控制器)功能块可以不通过 CPU 高速 ...

  4. 华大单片机 HC32F460 串口调试

    华大单片机 HC32F460 串口调试 吐槽下,华大官方例程写到太复杂了,不熟练的一时摸不上手. #include "drvs.h" /********************** ...

  5. 国产(华大)单片机 hc32f460入门

    最近闹芯片慌,黄牛各种炒作,芯片价格居高不下,暂时选择国产方案替代. 本次选用了华大 m4内核方案, hc32f460芯片,型号很多,64pin的 keta(该版本实际有货),100脚的petb(实际 ...

  6. 华大单片机 HC32F460 调试管脚 SWCLK SWDIO PA15 PB3 PB4引脚复用问题

    耶稣说:施比受更为有福 直接上图 第一次LCD显示屏没有用PA15 ,改版把它放到PA15上,发现显示屏不显示了.管脚初始化以后变成高组态模式了. 程序 void LCD_GPIO_Init(void ...

  7. 【正点原子MP157连载】第四十三章 外置RTC芯片PCF8563实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  8. 段码液晶屏点亮思路--以华大单片机为例

    目录 前言 一.什么是段码液晶? 二.段码点亮基本原理 1.液晶发光的基本原理 2.LCD控制器简介 三.华大单片机LCD驱动简介 1.段码液晶seg-com表 2.LCD原理图 3.LCD输出配置寄 ...

  9. 华大HC32L130/HC32L136驱动RTC时钟芯片BL5372

    先放一张BL5372使用文档里的原理图 这里与RTC模块通信用的是模拟IIC 由手册知道IIC写地址为0x64 读为0x65 以下部分代码 为模拟IIC的一些函数 与设置/调取时间的一些函数 #inc ...

最新文章

  1. 使用Mootools动态添加Css样式表代码,兼容各浏览器
  2. python pdf处理 图片_在Python中从PDF提取图像而无需重新采样?
  3. kthread_work和kthread_worker机制
  4. 64位以内Rabin-Miller 强伪素数测试和Pollard rho 因数分解解析
  5. 网站搭建从零开始(七) WordPress站点的完善
  6. oracle分区表带入SQL语句,Oracle 分区表常用SQL语句 (转载)
  7. SAP License:SAP系统上线后的预收款处理
  8. Go语言练习:网络编程实例——简易图片上传网站
  9. 懂,你的App生,不懂,死!
  10. html页面自动跳转
  11. 每日英语:Targeting Grandpa: China’s Seniors Hunger for Ads
  12. .bat批处理命令常用操作
  13. EPICS记录参考2--EPICS过程数据库概念
  14. 余光中《写给未来的你》
  15. 这几个 GitHub 项目真带劲
  16. python参考手册 豆瓣_Python自定义豆瓣电影种类,排行,点评的爬取与存储(进阶上)...
  17. 【金猿信创展】恒生电子——全栈式信创解决方案,助力金融信创行稳致远
  18. 2019最新奶茶隐藏点单攻略!据说只有单身狗才会觉得好喝的餐单?
  19. SSM毕设项目 - 基于SSM的企业公寓宿舍后勤管理系统(含源码+论文)
  20. 2014年国际注册信息系统审计师CISA考试相关信息

热门文章

  1. 计算机网络实验(思科)
  2. AVPlayer 多媒体播放器
  3. 苹果电脑专业录音软件 电脑如何在线录音
  4. javascript工具类函数
  5. “大玩家”登场,暴风TV的AI版图再下一城
  6. 2023的展望:不积跬步,无以至千里;不积小流,无以成江海
  7. 【教程】如何在服务器上部署豆瓣小组抢沙发聊天机器人
  8. TIFF图像文件详解
  9. 2014年6月份第1周51Aspx源码发布详情
  10. MySql :分表、分库、分片和分区