一、首先需要把BM8563设备挂起到I2C设备总线上
根据board.h中I2C的挂起方式将I2C挂起
打开宏定义,根据你实际的管脚,把对应的管脚写进去。。
新建.c和.h文件
drv_hw_rtc_.c文件内容:
#include "drv_hw_rtc.h"
#define RTC_IIC_NAME "i2c1"
#define RTC_IIC_WRITE_ADDR (0XA3)
#define RTC_IIC_READ_ADDR (0XA2)
#define RTC_IIC_ADDR (RTC_IIC_WRITE_ADDR>>1)
#define RTC_SECOND_REG_ADDR (0X02) //秒计数器地址
#define RTC_MINUTE_REG_ADDR (0X03)
#define RTC_HOUR_REG_ADDR (0X04)
#define RTC_DAY_REG_ADDR (0X05)
#define RTC_WEEK_REG_ADDR (0X06)
#define RTC_MONTH_REG_ADDR (0X07)
#define RTC_YEAR_REG_ADDR (0X08)
struct rt_i2c_bus_device* rtc_iic_handler;
/**
* 八位无符号数转为BCD码
* @param decimal
* @param bcd
*/
rt_uint8_t DecimaltoBCD(rt_uint8_t decimal)
{
return ((decimal / 10) << 4) | (decimal % 10);
}
rt_uint8_t BCDtoDecimal(rt_uint8_t BCD)
{
return ((BCD >> 4) * 10 + (BCD & 0x0f));
}
void hw_rtc_init(void)
{
rtc_iic_handler = (struct rt_i2c_bus_device*) rt_device_find(RTC_IIC_NAME);
if (rtc_iic_handler == RT_NULL)
{
rt_kprintf("I2C Bus Not Find\n");
}
}
rt_err_t hw_rtc_read(rt_uint8_t reg_addr, rt_uint8_t *recv_buff)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = RTC_IIC_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®_addr;
msgs[0].len = 1;
msgs[1].addr = RTC_IIC_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = recv_buff;
msgs[1].len = 1;
if (rt_i2c_transfer(rtc_iic_handler, msgs, 2) != 2)
{
return -RT_ERROR;
}
return RT_EOK;
}
/**
*
* @param year 年 0~99
* @param month 月
* @param day 日
* @return
*/
rt_err_t hw_rtc_set_date(rt_uint8_t year, rt_uint8_t month, rt_uint8_t day)
{
rt_uint8_t buf[5];
struct rt_i2c_msg msgs;
//将uint8_t转为BCD码
year = DecimaltoBCD(year);
month = DecimaltoBCD(month);
day = DecimaltoBCD(day);
//寄存器起始地址 BM8563 地址会自增
buf[0] = RTC_DAY_REG_ADDR;
buf[1] = day;
buf[2] = 0;
buf[3] = month;
buf[4] = year;
msgs.addr = RTC_IIC_ADDR;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = 5;
if (rt_i2c_transfer(rtc_iic_handler, &msgs, 1) == 1)
{
return RT_EOK;
}
else
{
rt_kprintf("set date for hw_rtc failed\n");
return -RT_ERROR;
}
}
/**
*
* @param hour 时
* @param minute 分
* @param second 秒
* @return
*/
rt_err_t hw_rtc_set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
{
rt_uint8_t buf[4];
struct rt_i2c_msg msgs;
//将uint8_t转为BCD码
second = DecimaltoBCD(second);
minute = DecimaltoBCD(minute);
hour = DecimaltoBCD(hour);
//寄存器起始地址 BM8563 地址会自增
buf[0] = RTC_SECOND_REG_ADDR;
buf[1] = second;
buf[2] = minute;
buf[3] = hour;
msgs.addr = RTC_IIC_ADDR;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = 4;
if (rt_i2c_transfer(rtc_iic_handler, &msgs, 1) == 1)
{
return RT_EOK;
}
else
{
rt_kprintf("set time for hw_rtc failed\n");
return -RT_ERROR;
}
}
rt_err_t hw_rtc_get_time(hw_time *tm)
{
rt_uint8_t reg_addr = RTC_SECOND_REG_ADDR;
rt_uint8_t recv_buffer[7] = { 0 };
rt_uint8_t i;
struct rt_i2c_msg msgs[2];
msgs[0].addr = RTC_IIC_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = ®_addr;
msgs[0].len = 1;
msgs[1].addr = RTC_IIC_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = recv_buffer;
msgs[1].len = 7;
if (rt_i2c_transfer(rtc_iic_handler, msgs, 2) != 2)
{
return -RT_ERROR;
}
//剔除一些不需要的位
recv_buffer[0] &= 0x7F;
recv_buffer[1] &= 0x7F;
recv_buffer[2] &= 0x3F;
recv_buffer[3] &= 0x3F;
//星期不需要
recv_buffer[4] &= 0x07;
//月
recv_buffer[5] &= 0x1F;
//由BCD码转为十进制
for (i = 0; i < 7; i++)
{
recv_buffer[i] = BCDtoDecimal(recv_buffer[i]);
}
tm->year = recv_buffer[6];
tm->month = recv_buffer[5];
tm->day = recv_buffer[3];
tm->hour = recv_buffer[2];
tm->min = recv_buffer[1];
tm->sec = recv_buffer[0];
return RT_EOK;
}
drv_hw_rtc.h内容:
typedef struct{
rt_uint8_t year;
rt_uint8_t month;
rt_uint8_t day;
rt_uint8_t hour;
rt_uint8_t min;
rt_uint8_t sec;
}hw_time;
void hw_rtc_init(void);
rt_err_t hw_rtc_set_date(rt_uint8_t year,rt_uint8_t month,rt_uint8_t day);
rt_err_t hw_rtc_set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second);
rt_err_t hw_rtc_get_time(hw_time *tm);
此程序封装了三个函数,写入年月日、写入时分秒、读取年月日时分秒的函数。
这个时候直接调用这个三个函数,写的时候需要将写入函数一起写入。
到关键了!!!!!!!!!!!!
如何使用ntp对时呢?其实rt_thread中有很成熟的软件包了!!!,只需要打开软件包就可以!
这个是rt_thread给的软件包!
这其中有三个服务器,如果你需要有特殊的接口就写特殊的,不是特殊的就默认就可以了。!!
然后就可以直接使用里面软件包封装的函数直接获取时间了!!
/*ntp对时,将时间同步到rtc bm8563中*/
void ntp_rtcget_time(void)
{
time_t cur_time;
cur_time = ntp_sync_to_rtc(NULL);
if (cur_time)
{
struct tm *local_time = localtime(&cur_time);
// 设置RTC时间
hw_rtc_set_time(local_time->tm_hour, local_time->tm_min, local_time->tm_sec);
hw_rtc_set_date(local_time->tm_year, local_time->tm_mon, local_time->tm_mday);
}
}
我是封装了一个函数,让程序运行起来先进行ntp对时,时间写入内部时钟里面,再从其他的地方获取时间!
struct tm *local_time 这个结构体是rt_thread中自带的结构体,直接可以用,不需要重新定义了。
这就可以通过ntp进行对时,再把时间写入到定时器BM8563中了。
读取时间的话,直接调用我写好的hw_rtc_get_time()就可以了。这个需要自己定义一个新得结构体,系统自带得结构体数据很多,可能存在问题,所以我巨自己定义了个结构体接收。
以上就是我关于ntp对时且把获取到的时间写入到BM8563中封装好的函数了。
如果有大佬看到小弟代码可以优化得地方,帮忙给弟弟提提把,弟弟目前还在学习阶段。感谢大佬!!!