通过Atmel SAMG55上的i2c/TWI接口进行MCP79411 RTC连接
我做了一个基于ATSAMG55J19单片机的项目,用Atmel Studio和ASF 3编程 现在我尝试添加一个外部RTC时钟,因为内部SAMg55 RTC没有备用电池。 该模块将用于读取电源故障后的当前时间,然后我将使用内部RTC,所以我只需要基本的通信。无需在EEPROM中写入特定数据或设置报警 我有一个MCP79411,通过i2c连接,但是没有任何库适合使用ASF TWI库的MCU 有很多Arduino实现,但它们使用Wire.h库,我不能移植它 我尝试移植这个简单的“驱动程序”: 这里有一些代码通过Atmel SAMG55上的i2c/TWI接口进行MCP79411 RTC连接,i2c,cortex-m,microchip,atmelstudio,I2c,Cortex M,Microchip,Atmelstudio,我做了一个基于ATSAMG55J19单片机的项目,用Atmel Studio和ASF 3编程 现在我尝试添加一个外部RTC时钟,因为内部SAMg55 RTC没有备用电池。 该模块将用于读取电源故障后的当前时间,然后我将使用内部RTC,所以我只需要基本的通信。无需在EEPROM中写入特定数据或设置报警 我有一个MCP79411,通过i2c连接,但是没有任何库适合使用ASF TWI库的MCU 有很多Arduino实现,但它们使用Wire.h库,我不能移植它 我尝试移植这个简单的“驱动程序”: 这里有
static void i2c_start(void){
static twi_options_t ext3_twi_options;
flexcom_enable(FLEXCOM4);
flexcom_set_opmode(FLEXCOM4, FLEXCOM_TWI);
ext3_twi_options.master_clk = sysclk_get_cpu_hz();
ext3_twi_options.speed = 100000;
ext3_twi_options.smbus = 0;
twi_master_init(TWI4, &ext3_twi_options);
}
// Init Real Time Clock
void rtc_Init(void)
{
uint8_t seconds = 0;
i2c_start();
twi_write_byte(TWI4, ADDR_RTCC_WRITE); // WR to RTC
twi_write_byte(TWI4, ADDR_SEC); // REG 0
twi_write_byte(TWI4, ADDR_RTCC_READ); // RD from RTC
seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in rtc
//i2c_stop();
//seconds &= 0x7F;
seconds |= 0x80; //set to 1 bit 7 of seconds(ST) enabling oscillator
delay_us(3);
twi_write_byte(TWI4, ADDR_RTCC_WRITE); // WR to RTC
twi_write_byte(TWI4, ADDR_SEC); // REG 0
twi_write_byte(TWI4, bin2bcd(seconds) | 0x80); // Start oscillator with current "seconds value
twi_write_byte(TWI4, ADDR_RTCC_WRITE); // WR to RTC
twi_write_byte(TWI4, 0x07); // Control Register
twi_write_byte(TWI4, 0x80); // Disable squarewave output pin
//i2c_stop();
}
然后我尝试了rtc设置日期时间(uint8天、uint8月、uint8年、uint8道指、uint8小时、uint8分钟、uint8秒)
及
但我总是得到“0”字节
我无法理解打开通信和从i2c读取字节的正确方法
我找到的唯一参考资料是,但它似乎是一种非常不同的交流方式
通过i2c发送和接收字节的正确方式是什么?我设法获取和设置了数据。我张贴了一份图书馆的草稿:
#include "asf.h"
#include "conf_board_3in4out.h"
#include "external_rtc.h"
#include <time.h>
//#include <time_utils.h>
twi_packet_t packet_tx, packet_rx;
// helper functions to manipulate BCD and binary to integers
static int bcd2dec(char r_char)
{
MSN = (r_char & 0xF0)/16;
LSN = r_char & 0x0F;
return(10*MSN + LSN);
}
static char msn(char tim)
{
return (tim & 0xF0)/16;
}
static char lsn(char tim)
{
return (tim & 0x0F);
}
#define RTC_ADDR 0x6F // 7 bits
char config_t[10];
char config_2[8];
char tim_read[8];
#define ADDR_SEC 0x00 // address of SECONDS register
#define ADDR_MIN 0x01 // address of MINUTES register
#define ADDR_HOUR 0x02 // address of HOURS register
#define ADDR_DAY 0x03 // address of DAY OF WEEK register
#define ADDR_STAT 0x03 // address of STATUS register
#define ADDR_DATE 0x04 // address of DATE register
#define ADDR_MNTH 0x05 // address of MONTH register
#define ADDR_YEAR 0x06 // address of YEAR register
#define ADDR_CTRL 0x07 // address of CONTROL register
#define ADDR_CAL 0x08 // address of CALIB register
#define ADDR_ULID 0x09 // address of UNLOCK ID register
#define ADDR_SAVtoBAT_MIN 0x18 // address of T_SAVER MIN(VDD->BAT)
#define ADDR_SAVtoBAT_HR 0x19 // address of T_SAVER HR (VDD->BAT)
#define ADDR_SAVtoBAT_DAT 0x1a // address of T_SAVER DAT(VDD->BAT)
#define ADDR_SAVtoBAT_MTH 0x1b // address of T_SAVER MTH(VDD->BAT)
#define START_32KHZ 0x80 // start crystal: ST = b7 (ADDR_SEC)
#define OSCON 0x20 // state of the oscillator(running or not)
#define VBATEN 0x08 // enable battery for back-up
static uint8_t bin2bcd(uint8_t binary_value)
{
uint8_t temp;
uint8_t retval;
temp = binary_value;
retval = 0;
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else
{
retval += temp;
//break;
}
return(retval);
}
static uint8_t bcd2bin(uint8_t bcd_value)
{
uint8_t temp;
temp = bcd_value;
temp >>= 1;
temp &= 0x78;
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
static void setConfig(void){
config_2[0] = tim_read[0] | START_32KHZ; // bitwise OR sets Start osc bit = 1
config_2[1] = tim_read[1];
config_2[2] = tim_read[2];
//0x03h – Contains the BCD day. The range is 1-7.
//Bit 3 is the VBATEN bit. If this bit is set, the
//internal circuitry is connected to the VBAT pin
//when VCC fails. If this bit is ‘0’ then the VBAT pin is
//disconnected and the only current drain on the
//external battery is the VBAT pin leakage.
config_2[3] = tim_read[3] | VBATEN;
config_2[4] = tim_read[4];
config_2[5] = tim_read[5];
config_2[6] = tim_read[6];
config_2[7] = 0x00; // control b3 - extosc = 0
}
static void initialize(void){
uint8_t buf[7]; // Fill this with RTC clock data for all seven registers
// read stored time data
config_t[0] = 0x00; //reset pointer reg to '00'
// Set up config to read the time and set the control bits
//i2c.write(addr, config_t, 1); // write address 00
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_t;
packet_tx.length = 1;
twi_master_write(TWI4, &packet_tx);
delay_ms(250);
//
//i2c.read(addr, tim_read, 7); //read time ss mm hh from r1, r2, r3
packet_rx.chip = RTC_ADDR;
packet_rx.addr[0] = 0; // RTCSEC
packet_rx.addr_length = 1;
packet_rx.buffer = tim_read;
packet_rx.length = sizeof(tim_read);
twi_master_read(TWI4, &packet_rx);
delay_ms(250);
setConfig(); //puts RTCC data into config array from tim_read array
// write the config data
//i2c.write(addr, config_t, 9); // write the config data back to the RTCC module
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
}
static void write_time(void){
// re-calculate mins
mins = 8; //ORE 10:08
mins = mins%60;
ch_mins = 16*(mins/10) + mins%10;
MSN = msn(ch_mins);
LSN = lsn(ch_mins);
tim_read[1] = ch_mins;
inc_mins = 0;
//write the data back to RTCC
setConfig();
//i2c.write(addr, config_t, 9);
/* Configure the data packet to be transmitted */
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
//Display and set hours
//hrs = bcd2dec(tim_read[2]);
// re-calculate hrs
hrs = 10; //ORE 10:08
hrs = hrs%24;
ch_hrs = 16*(hrs/10) + hrs%10;
MSN = msn(ch_hrs);
LSN = lsn(ch_hrs);
tim_read[2] = ch_hrs;
inc_hr = 0;
//write the data back to RTCC
setConfig();
/* Configure the data packet to be transmitted */
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
}
static void read_time(void){
//config_t[0] = 0x00; //reset pointer reg to '00'
//// First Get the time
////i2c.write(addr, config_t, 1); // write address 00
//packet_tx.chip = RTC_ADDR;
//packet_tx.addr[0] = 0; // RTCSEC
//packet_tx.addr_length = 1;
//packet_tx.buffer = config_t;
//packet_tx.length = 1;
//
//twi_master_write(TWI4, &packet_tx);
delay_ms(250);
uint8_t buf[7]; // Fill this with RTC clock data for all seven registers
/* Configure the data packet to be received */
packet_rx.chip = RTC_ADDR;
packet_rx.addr[0] = 0; // RTCSEC
packet_rx.addr_length = 1;
packet_rx.buffer = buf;
packet_rx.length = sizeof(buf);
twi_master_read(TWI4, &packet_rx);
for(uint8_t i = 0; i < sizeof(buf); i++){
tim_read[i] = buf[i];
}
}
void example_print_time(void){
//initialize();
delay_ms(1000);
//write_time(); //commented to see if time is permanent
delay_ms(1000);
read_time();
while(1){
printf("Reading time\n");
printf("%d:%d:%d\n", bcd2dec(tim_read[2]), bcd2dec(tim_read[1]), bcd2dec(tim_read[0] ^ START_32KHZ));
delay_ms(1000);
read_time();
}
}
#包括“asf.h”
#包括“conf_board_3in4out.h”
#包括“外部_rtc.h”
#包括
//#包括
两个数据包发送,数据包接收;
//用于将BCD和二进制操作为整数的辅助函数
静态整数bcd2dec(字符r\u字符)
{
MSN=(r_char&0xF0)/16;
LSN=r_字符&0x0F;
返回(10*MSN+LSN);
}
静态字符msn(字符tim)
{
返回(tim&0xF0)/16;
}
静态字符lsn(字符tim)
{
返回(tim&0x0F);
}
#定义RTC_ADDR 0x6F//7位
字符配置[10];
字符配置_2[8];
char tim_read[8];
#定义ADDR_SEC 0x00//秒寄存器的地址
#定义ADDR_MIN 0x01//分钟寄存器的地址
#定义ADDR_HOUR 0x02//小时寄存器的地址
#定义地址0x03//星期几寄存器的地址
#定义ADDR_STAT 0x03//状态寄存器的地址
#定义地址日期0x04//日期寄存器的地址
#定义地址0x05//月份寄存器的地址
#定义地址年份0x06//年份寄存器地址
#定义ADDR\u CTRL 0x07//控制寄存器的地址
#定义地址CAL 0x08//CALIB寄存器的地址
#定义地址ULID 0x09//解锁ID寄存器的地址
#定义地址SAVtoBAT\u MIN 0x18//地址savt\u MIN(VDD->BAT)
#定义ADDR_SAVtoBAT_HR 0x19//T_SAVER HR的地址(VDD->BAT)
#定义ADDR_SAVtoBAT_DAT 0x1a//T_SAVtoBAT DAT的地址(VDD->BAT)
#定义ADDR_SAVtoBAT_MTH 0x1b//T_SAVER MTH的地址(VDD->BAT)
#定义起始频率32KHZ 0x80//起始晶体:ST=b7(地址秒)
#定义振荡器的OSCON 0x20//状态(运行或不运行)
#定义VBATEN 0x08//启用备用电池
静态uint8_t二进制值2BCD(uint8_t二进制值)
{
uint8温度;
uint8_t retval;
温度=二进制值;
retval=0;
如果(温度>=10)
{
温度-=10;
retval+=0x10;
}
其他的
{
retval+=温度;
//中断;
}
返回(retval);
}
静态uint8\u t bcd2bin(uint8\u t bcd\u值)
{
uint8温度;
温度=bcd_值;
温度>>=1;
温度&=0x78;
返回(temp+(temp>>2)+(bcd_值&0x0f));
}
静态void setConfig(void){
config_2[0]=tim_read[0]| START_32KHZ;//按位或设置START osc bit=1
config_2[1]=tim_read[1];
config_2[2]=tim_read[2];
//0x03h–包含BCD日。范围为1-7。
//位3是VBATEN位。如果设置了此位,则
//内部电路连接到VBAT引脚
//当VCC失败时。如果此位为“0”,则VBAT引脚为
//已断开,并且是上唯一的电流消耗
//外部电池是VBAT引脚泄漏。
config_2[3]=tim_read[3]| VBATEN;
config_2[4]=tim_read[4];
config_2[5]=tim_read[5];
config_2[6]=tim_read[6];
config_2[7]=0x00;//控件b3-extosc=0
}
静态void初始化(void){
uint8_t buf[7];//用这七个寄存器的RTC时钟数据填充
//读取存储的时间数据
config_t[0]=0x00;//将指针注册表重置为“00”
//设置配置以读取时间并设置控制位
//i2c.write(地址,配置,1);//写入地址00
packet_tx.chip=RTC_ADDR;
数据包_tx.addr[0]=0;//RTCSEC
数据包发送地址长度=1;
数据包\u tx.buffer=config\u t;
数据包发送长度=1;
twi\u主机写入(TWI4和数据包发送);
延迟时间(250);
//
//i2c.read(addr,tim_read,7);//从r1、r2、r3读取时间ss mm hh
packet_rx.chip=RTC_ADDR;
数据包_rx.addr[0]=0;//RTCSEC
数据包接收地址长度=1;
数据包接收缓冲区=tim读取;
数据包接收长度=sizeof(tim读取);
两次主控读取(两次4和数据包接收);
延迟时间(250);
setConfig();//将RTCC数据从tim_读取数组放入配置数组
//写入配置数据
//i2c.write(addr,config_t,9);//将配置数据写回RTCC模块
packet_tx.chip=RTC_ADDR;
数据包_tx.addr[0]=0;//RTCSEC
数据包发送地址长度=1;
数据包_tx.buffer=config_2;
数据包长度=sizeof(配置2);
twi\u主机写入(TWI4和数据包发送);
}
静态无效写入时间(无效){
//重新计算分钟
分钟=8;//或10:08
分钟=分钟%60;
Chu_mins=16*(分钟/10)+分钟%10;
MSN=MSN(每分钟);
LSN=LSN(每分钟);
tim_read[1]=Chu mins;
inc_mins=0;
//将数据写回RTCC
setConfig();
//i2c.write(地址,配置,9);
/*配置要传输的数据包*/
帕
#include "asf.h"
#include "conf_board_3in4out.h"
#include "external_rtc.h"
#include <time.h>
//#include <time_utils.h>
twi_packet_t packet_tx, packet_rx;
// helper functions to manipulate BCD and binary to integers
static int bcd2dec(char r_char)
{
MSN = (r_char & 0xF0)/16;
LSN = r_char & 0x0F;
return(10*MSN + LSN);
}
static char msn(char tim)
{
return (tim & 0xF0)/16;
}
static char lsn(char tim)
{
return (tim & 0x0F);
}
#define RTC_ADDR 0x6F // 7 bits
char config_t[10];
char config_2[8];
char tim_read[8];
#define ADDR_SEC 0x00 // address of SECONDS register
#define ADDR_MIN 0x01 // address of MINUTES register
#define ADDR_HOUR 0x02 // address of HOURS register
#define ADDR_DAY 0x03 // address of DAY OF WEEK register
#define ADDR_STAT 0x03 // address of STATUS register
#define ADDR_DATE 0x04 // address of DATE register
#define ADDR_MNTH 0x05 // address of MONTH register
#define ADDR_YEAR 0x06 // address of YEAR register
#define ADDR_CTRL 0x07 // address of CONTROL register
#define ADDR_CAL 0x08 // address of CALIB register
#define ADDR_ULID 0x09 // address of UNLOCK ID register
#define ADDR_SAVtoBAT_MIN 0x18 // address of T_SAVER MIN(VDD->BAT)
#define ADDR_SAVtoBAT_HR 0x19 // address of T_SAVER HR (VDD->BAT)
#define ADDR_SAVtoBAT_DAT 0x1a // address of T_SAVER DAT(VDD->BAT)
#define ADDR_SAVtoBAT_MTH 0x1b // address of T_SAVER MTH(VDD->BAT)
#define START_32KHZ 0x80 // start crystal: ST = b7 (ADDR_SEC)
#define OSCON 0x20 // state of the oscillator(running or not)
#define VBATEN 0x08 // enable battery for back-up
static uint8_t bin2bcd(uint8_t binary_value)
{
uint8_t temp;
uint8_t retval;
temp = binary_value;
retval = 0;
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else
{
retval += temp;
//break;
}
return(retval);
}
static uint8_t bcd2bin(uint8_t bcd_value)
{
uint8_t temp;
temp = bcd_value;
temp >>= 1;
temp &= 0x78;
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
static void setConfig(void){
config_2[0] = tim_read[0] | START_32KHZ; // bitwise OR sets Start osc bit = 1
config_2[1] = tim_read[1];
config_2[2] = tim_read[2];
//0x03h – Contains the BCD day. The range is 1-7.
//Bit 3 is the VBATEN bit. If this bit is set, the
//internal circuitry is connected to the VBAT pin
//when VCC fails. If this bit is ‘0’ then the VBAT pin is
//disconnected and the only current drain on the
//external battery is the VBAT pin leakage.
config_2[3] = tim_read[3] | VBATEN;
config_2[4] = tim_read[4];
config_2[5] = tim_read[5];
config_2[6] = tim_read[6];
config_2[7] = 0x00; // control b3 - extosc = 0
}
static void initialize(void){
uint8_t buf[7]; // Fill this with RTC clock data for all seven registers
// read stored time data
config_t[0] = 0x00; //reset pointer reg to '00'
// Set up config to read the time and set the control bits
//i2c.write(addr, config_t, 1); // write address 00
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_t;
packet_tx.length = 1;
twi_master_write(TWI4, &packet_tx);
delay_ms(250);
//
//i2c.read(addr, tim_read, 7); //read time ss mm hh from r1, r2, r3
packet_rx.chip = RTC_ADDR;
packet_rx.addr[0] = 0; // RTCSEC
packet_rx.addr_length = 1;
packet_rx.buffer = tim_read;
packet_rx.length = sizeof(tim_read);
twi_master_read(TWI4, &packet_rx);
delay_ms(250);
setConfig(); //puts RTCC data into config array from tim_read array
// write the config data
//i2c.write(addr, config_t, 9); // write the config data back to the RTCC module
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
}
static void write_time(void){
// re-calculate mins
mins = 8; //ORE 10:08
mins = mins%60;
ch_mins = 16*(mins/10) + mins%10;
MSN = msn(ch_mins);
LSN = lsn(ch_mins);
tim_read[1] = ch_mins;
inc_mins = 0;
//write the data back to RTCC
setConfig();
//i2c.write(addr, config_t, 9);
/* Configure the data packet to be transmitted */
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
//Display and set hours
//hrs = bcd2dec(tim_read[2]);
// re-calculate hrs
hrs = 10; //ORE 10:08
hrs = hrs%24;
ch_hrs = 16*(hrs/10) + hrs%10;
MSN = msn(ch_hrs);
LSN = lsn(ch_hrs);
tim_read[2] = ch_hrs;
inc_hr = 0;
//write the data back to RTCC
setConfig();
/* Configure the data packet to be transmitted */
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
}
static void read_time(void){
//config_t[0] = 0x00; //reset pointer reg to '00'
//// First Get the time
////i2c.write(addr, config_t, 1); // write address 00
//packet_tx.chip = RTC_ADDR;
//packet_tx.addr[0] = 0; // RTCSEC
//packet_tx.addr_length = 1;
//packet_tx.buffer = config_t;
//packet_tx.length = 1;
//
//twi_master_write(TWI4, &packet_tx);
delay_ms(250);
uint8_t buf[7]; // Fill this with RTC clock data for all seven registers
/* Configure the data packet to be received */
packet_rx.chip = RTC_ADDR;
packet_rx.addr[0] = 0; // RTCSEC
packet_rx.addr_length = 1;
packet_rx.buffer = buf;
packet_rx.length = sizeof(buf);
twi_master_read(TWI4, &packet_rx);
for(uint8_t i = 0; i < sizeof(buf); i++){
tim_read[i] = buf[i];
}
}
void example_print_time(void){
//initialize();
delay_ms(1000);
//write_time(); //commented to see if time is permanent
delay_ms(1000);
read_time();
while(1){
printf("Reading time\n");
printf("%d:%d:%d\n", bcd2dec(tim_read[2]), bcd2dec(tim_read[1]), bcd2dec(tim_read[0] ^ START_32KHZ));
delay_ms(1000);
read_time();
}
}