MS51FB9AE – Giao tiếp DS1307

DS1307 là IC thời gian thực.
Giao tiếp bằng giao thức I2C.
Datasheet:
https://drive.google.com/open?id=1h7i61dd4pGvi3LDGA5gkrrooLoorBCVe
Địa chỉ khi đọc dữ liệu là 0xD1
Địa chỉ khi ghi dữ liệu là 0xD0.
IC có các thanh ghi thời gian từ địa chỉ 0x00 đến 0x06.
Thanh ghi cấu hình ở địa chỉ 0x07.
56 byte RAM từ địa chỉ 0x08 đến 0x3F. Các byte này có thể được dùng để lưu trữ dữ liệu khi sử dụng với vi điều khiển mà không cần gắn thêm EEPROM bên ngoài.

Code ví dụ sử dụng I2C của MS51FB9AE để giao tiếp với DS1307:

file ds1307.h

/* ds1307.h */

#ifndef DS1307_H_
#define DS1307_H_

#include <MS51.h>
#ifdef __C51__
#include "myIntType.h"
#else
#include <stdint.h>
#endif

void DS1307_Init(void);
uint8_t DS1307_Write(uint8_t Address, uint8_t *pData, uint8_t length);
uint8_t DS1307_Read(uint8_t Address, uint8_t *pData, uint8_t length);
uint8_t DS1307_CheckAddress(void);

#endif

File ds1307.c

/* ds1307.c */

#include "ds1307.h"

#define DS1307_ADDRESS_W 0xD0
#define DS1307_ADDRESS_R 0xD1

static uint8_t send_stop(void);

void DS1307_Init(void)
{
	I2CLK = 39;
	/* P1.3 */
	/* Quasi */
	P1M1 &= ~(1 << 3);
	P1M2 &= ~(1 << 3);
	/* P1.4 */
	/* Quasi */
	P1M1 &= ~(1 << 4);
	P1M2 &= ~(1 << 4);
	
	P13=1;
	P14=1;
	
	I2CEN=1;
}

uint8_t DS1307_Write(uint8_t Address, uint8_t *pData, uint8_t length)
{
	uint8_t i;
	uint16_t t;
	uint8_t u8TimeOut;
	
	if (I2STAT != 0xF8) {
		return 0;
	}
	
	/* start */
	STO = 0;
	STA = 1;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* start error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x08) {
		/* start error */
		send_stop();
		return 0;
	}
	
	/* send DS1307 address */
	STA = 0;
	STO = 0;
	I2DAT = DS1307_ADDRESS_W;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x18) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	/* send address */
	STA = 0;
	STO = 0;
	I2DAT = Address;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x28) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	/* send data */
	for (i = 0; i < length; ++i) {
		I2DAT = pData[i];
		SI = 0;
		t = 1;
		u8TimeOut = 0;
		while (1) {
			if (SI) {
				break;
			}
			if (!t) {
				u8TimeOut = 1;
				break;
			}
			++t;
		}
		if (u8TimeOut) {
			/* send data error */
			send_stop();
			return 0;
		}
		if (I2STAT != 0x28) {
			/* send data error */
			send_stop();
			return 0;
		}
	}
	
	/* stop */
	return send_stop();
}

uint8_t DS1307_Read(uint8_t Address, uint8_t *pData, uint8_t length)
{
	uint8_t i;
	uint16_t t;
	uint8_t u8TimeOut;
	
	if (I2STAT != 0xF8) {
		return 0;
	}
	
	/* start */
	STO = 0;
	STA = 1;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* start error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x08) {
		/* start error */
		send_stop();
		return 0;
	}
	
	/* send DS1307 address */
	STA = 0;
	STO = 0;
	I2DAT = DS1307_ADDRESS_W;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x18) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	/* send address */
	STA = 0;
	STO = 0;
	I2DAT = Address;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x28) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	/* start */
	STO = 0;
	STA = 1;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* start error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x10) {
		/* start error */
		send_stop();
		return 0;
	}
	
	/* send DS1307 address */
	STA = 0;
	STO = 0;
	I2DAT = DS1307_ADDRESS_R;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x40) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	/* get data */
	for (i = 0; i < length - 1; ++i) {
		AA = 1;
		SI = 0;
		t = 1;
		u8TimeOut = 0;
		while (1) {
			if (SI) {
				break;
			}
			if (!t) {
				u8TimeOut = 1;
				break;
			}
			++t;
		}
		if (u8TimeOut) {
			/* send data error */
			send_stop();
			return 0;
		}
		if (I2STAT != 0x50) {
			/* send data error */
			send_stop();
			return 0;
		}
		pData[i] = I2DAT;
	}
	
	/* last byte */
	AA = 0;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	if (u8TimeOut) {
		/* send data error */
		send_stop();
		return 0;
	}
	if (I2STAT != 0x58) {
		/* send data error */
		send_stop();
		return 0;
	}
	pData[i] = I2DAT;
	/* stop */
	return send_stop();
}

uint8_t DS1307_CheckAddress(void)
{
	uint16_t t;
	uint8_t u8TimeOut;
	
	if (I2STAT != 0xF8) {
		return 0;
	}
	
	/* start */
	STO = 0;
	STA = 1;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* start error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x08) {
		/* start error */
		send_stop();
		return 0;
	}
	
	/* send address */
	STA = 0;
	STO = 0;
	I2DAT = DS1307_ADDRESS_R;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	
	if (u8TimeOut) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	if (I2STAT != 0x40) {
		/* send address error */
		send_stop();
		return 0;
	}
	
	/* last byte */
	AA = 0;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (SI) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	if (u8TimeOut) {
		/* send data error */
		send_stop();
		return 0;
	}
	if (I2STAT != 0x58) {
		/* send data error */
		send_stop();
		return 0;
	}
	t = I2DAT;
	/* stop */
	return send_stop();
}

uint8_t send_stop(void)
{
	uint16_t t;
	uint8_t u8TimeOut;
	
	STA = 0;
	STO = 1;
	SI = 0;
	t = 1;
	u8TimeOut = 0;
	while (1) {
		if (I2STAT == 0xF8) {
			break;
		}
		if (!t) {
			u8TimeOut = 1;
			break;
		}
		++t;
	}
	return (!u8TimeOut);
}

file main.c

/* main.c */
#include "ms51.h"
#include "ds1307.h"
#include "delay.h"

uint8_t u8Buff[7];
uint8_t u8Last;

void main(void)
{
	P1M1 &= ~(1 << 5);
    P1M2 |= (1 << 5);
	P15 = 0;
	
	/* init */
	DS1307_Init();
	Delay_Init();
	
	/* check address */
	if (!DS1307_CheckAddress()) {
		while (1) {
			P15 = 1;
			Delay_Ms(50);
			P15 = 0;
			Delay_Ms(50);
		}
	}
	
	DS1307_Read(0x00, u8Buff, 1);
	u8Last = u8Buff[0];
	
	if (u8Buff[0] & 0x80) {
		u8Buff[0] = 0x00;
		u8Last = 0x00;
		DS1307_Write(0x00, u8Buff, 1);
	}
	
	while (1) {
		DS1307_Read(0x00, u8Buff, 1);
		if (u8Last != u8Buff[0]) {
			u8Last = u8Buff[0];
			P15 ^= 1;
		}
		Delay_Ms(100);
	}
}

Chương trình sẽ kiểm tra xem có tìm thấy ds1307 trên bus hay không.
Nếu tìm thấy thì sẽ đọc byte đầu tiên là byte chứa giây của ds1307 xem bit CH có giá trị bao nhiêu. Nếu bit này có giá trị 1 thì IC sẽ không hoạt động và cần ghi giá trị 0 vào bit này để IC chạy.
Trong vòng lặp while (1) chương trình sẽ đọc thanh ghi giây, mỗi khi có sự thay đổi giá trị của thanh ghi giây nghĩa là thời gian tăng lên 1 giây thì sẽ thay đổi trạng thái led trên KIT VĐK 1.0. Vì vậy sẽ thấy led trên KIT thay đổi trạng thái sau mỗi 1 giây:

Kết quả đo bằng logic analyzer

Project đính kèm:
https://drive.google.com/open?id=1MPLaWkX5BTOfBsNp7CU3QuXgX97V0hjO