// Made by DAEWOO RYU
// NEW TECHNOLOGY COMPANY(N.T.C)
// Email : davdiryu@newtc.co.kr
// http://www.NTC.co.kr
// You can use this source code freely, but we don't support for upgrading or
// we do have no responsiblilty for using this source code for commercial purpose.
// When you spread this source code out, then please leave my name and company name.
// ****************************** //
// *** I2C Hardware Interface *** //
// ****************************** //
#define F_CPU (16000000L)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
#include <compat/twi.h>
#define MAX_TRIES 50
#define DS1307_ID 0xD0 // I2C DS1307 Device Identifier
#define DS1307_ADDR 0x00 // I2C DS1307 Device Address
#define I2C_START 0
#define I2C_DATA 1
#define I2C_DATA_ACK 2
#define I2C_STOP 3
#define ACK 1
#define NACK 0
// DS1307 Register Address
// Second: ds1307_addr[0]
// Minute: ds1307_addr[1]
// Hour : ds1307_addr[2]
// Day : ds1307_addr[3]
// Date : ds1307_addr[4]
// Month : ds1307_addr[5]
// Year : ds1307_addr[6]
#define HOUR_24 0
#define HOUR_12 1
char ds1307_addr[7];
char sdigit[3]={'0','0','\0'};
char *weekday[]={"Null","Sun","Mon","Tue","Wed","Thr","Fri","Sat"};
char *month[]={"Null","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
char hour_mode, ampm_mode;
/* START I2C Routine */
unsigned char i2c_transmit(unsigned char type)
{
switch(type) {
case I2C_START: // Send Start Condition
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
break;
case I2C_DATA: // Send Data with No-Acknowledge
TWCR = (1 << TWINT) | (1 << TWEN);
break;
case I2C_DATA_ACK: // Send Data with Acknowledge
TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
break;
case I2C_STOP: // Send Stop Condition
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
return 0;
}
// Wait for TWINT flag set on Register TWCR
while (!(TWCR & (1 << TWINT)));
// Return TWI Status Register, mask the prescaller bits (TWPS1,TWPS0)
return (TWSR & 0xF8);
}
char i2c_start(unsigned int dev_id, unsigned int dev_addr, unsigned char rw_type)
{
unsigned char n = 0;
unsigned char twi_status;
char r_val = -1;
i2c_retry:
if (n++ >= MAX_TRIES) return r_val;
// Transmit Start Condition
twi_status=i2c_transmit(I2C_START);
// Check the TWI Status
if (twi_status == TW_MT_ARB_LOST) goto i2c_retry;
if ((twi_status != TW_START) && (twi_status != TW_REP_START)) goto i2c_quit;
// Send slave address (SLA_W)
TWDR = (dev_id & 0xF0) | (dev_addr & 0x07) | rw_type;
// Transmit I2C Data
twi_status=i2c_transmit(I2C_DATA);
// Check the TWSR status
if ((twi_status == TW_MT_SLA_NACK) || (twi_status == TW_MT_ARB_LOST)) goto i2c_retry;
if (twi_status != TW_MT_SLA_ACK) goto i2c_quit;
r_val=0;
i2c_quit:
return r_val;
}
void i2c_stop(void)
{
unsigned char twi_status;
// Transmit I2C Data
twi_status=i2c_transmit(I2C_STOP);
}
char i2c_write(char data)
{
unsigned char twi_status;
char r_val = -1;
// Send the Data to I2C Bus
TWDR = data;
// Transmit I2C Data
twi_status=i2c_transmit(I2C_DATA);
// Check the TWSR status
if (twi_status != TW_MT_DATA_ACK) goto i2c_quit;
r_val=0;
i2c_quit:
return r_val;
}
char i2c_read(char *data,char ack_type)
{
unsigned char twi_status;
char r_val = -1;
if (ack_type) {
// Read I2C Data and Send Acknowledge
twi_status=i2c_transmit(I2C_DATA_ACK);
if (twi_status != TW_MR_DATA_ACK) goto i2c_quit;
} else {
// Read I2C Data and Send No Acknowledge
twi_status=i2c_transmit(I2C_DATA);
if (twi_status != TW_MR_DATA_NACK) goto i2c_quit;
}
// Get the Data
*data=TWDR;
r_val=0;
i2c_quit:
return r_val;
}
// Convert Decimal to Binary Coded Decimal (BCD)
char dec2bcd(char num)
{
return ((num/10 * 16) + (num % 10));
}
// Convert Binary Coded Decimal (BCD) to Decimal
char bcd2dec(char num)
{
return ((num/16 * 10) + (num % 16));
}
void Read_DS1307(void)
{
char data;
// First we initial the pointer register to address 0x00
// Start the I2C Write Transmission
i2c_start(DS1307_ID,DS1307_ADDR,TW_WRITE);
// Start from Address 0x00
i2c_write(0x00);
// Stop I2C Transmission
i2c_stop();
// Start the I2C Read Transmission
i2c_start(DS1307_ID,DS1307_ADDR,TW_READ);
// Read the Second Register, Send Master Acknowledge
i2c_read(&data,ACK);
ds1307_addr[0]=bcd2dec(data & 0x7F);
// Read the Minute Register, Send Master Acknowledge
i2c_read(&data,ACK);
ds1307_addr[1]=bcd2dec(data);
// Read the Hour Register, Send Master Acknowledge
i2c_read(&data,ACK);
if ((data & 0x40) == 0x40) {
hour_mode = HOUR_12;
ampm_mode=(data & 0x20) >> 5; // ampm_mode: 0-AM, 1-PM
ds1307_addr[2]=bcd2dec(data & 0x1F);
} else {
hour_mode = HOUR_24;
ampm_mode=0;
ds1307_addr[2]=bcd2dec(data & 0x3F);
}
// Read the Day of Week Register, Send Master Acknowledge
i2c_read(&data,ACK);
ds1307_addr[3]=bcd2dec(data);
// Read the Day of Month Register, Send Master Acknowledge
i2c_read(&data,ACK);
ds1307_addr[4]=bcd2dec(data);
// Read the Month Register, Send Master Acknowledge
i2c_read(&data,ACK);
ds1307_addr[5]=bcd2dec(data);
// Read the Year Register, Send Master No Acknowledge
i2c_read(&data,NACK);
ds1307_addr[6]=bcd2dec(data);
// Stop I2C Transmission
i2c_stop();
}
void Write_DS1307(void)
{
unsigned char i, hour_format;
// Make sure we enable the Oscillator control bit CH=0 on Register 0x00
ds1307_addr[0]=ds1307_addr[0] & 0x7F;
// Start the I2C Write Transmission
i2c_start(DS1307_ID,DS1307_ADDR,TW_WRITE);
// Start from Address 0x00
i2c_write(0x00);
// Write the data to the DS1307 address start at 0x00
// DS1307 automatically will increase the Address.
for (i=0; i<7; i++) {
if (i == 2) {
hour_format=dec2bcd(ds1307_addr[i]);
if (hour_mode) {
hour_format |= (1 << 6);
if (ampm_mode)
hour_format |= (1 << 5);
else
hour_format &= ~(1 << 5);
} else {
hour_format &= ~(1 << 6);
}
i2c_write(hour_format);
} else {
i2c_write(dec2bcd(ds1307_addr[i]));
}
}
// Stop I2C Transmission
i2c_stop();
}
void port_init(void)
{
PORTB = 0x00;
DDRB = 0x00;
PORTC = 0x00; //m103 output only
DDRC = 0x0f;
PORTD = 0x00;
DDRD = 0x00;
}
unsigned char digit_num=0;
const char segment_data[10] = {63, 6,91,79,102,109,125,39,127,103};
unsigned char display_num[4]={0,0,0,0}; // Seven segment 4자리 숫자 출력 버퍼
unsigned int FourDigit=1234;
volatile int display_now = 0;
void Display(void){
display_num[0] = (FourDigit%10000)/1000;
display_num[1] = (FourDigit%1000)/100;
display_num[2] = (FourDigit%100)/10;
display_num[3] = (FourDigit%10);
}
typedef unsigned char BYTE;
volatile BYTE RS_Char=0x00;
int SendByte(BYTE data)
{
// while (!((UCSRA) & (1<<UDRE)));
loop_until_bit_is_set(UCSRA,UDRE);
UDR = data;
return 0;
}
SIGNAL(SIG_UART_RECV) // UART0 수신 인터럽트
{
RS_Char = UDR;
SendByte(RS_Char);
}
SIGNAL(SIG_OVERFLOW0)
{
static unsigned char count = 0;
TCNT0= 0xFF - 157; // overflow at 10 mSec
if(count > 10) { // every 100ms
display_now = 1;
count = 0;
return;
}
count++;
}
void UART_Init(unsigned long BaudRate)
{
// Not Double mode, Not multi_communication
UCSRA = 0X00;
// 0b 1001 1000 RXCIE,TXCIE,UDRIE,RxEN,TxEN,xxx
UCSRB = 0X98;
UCSRC = 0X06;
// Setting BaudRate
UBRRH = 0X00;
UBRRL = (F_CPU/BaudRate/16 - 1);
}
int main()
{
asm volatile ("cli"); //disable all interrupts
port_init();
TCCR0=(1<<CS02)|(1<<CS00); // Use maximum prescaller: Clk/1024
// 64us per 1 clk
TCNT0= 0xFF - 157; // overflow at 10 mSec
TIMSK=(1<<TOIE0); // Enable Counter Overflow Interrupt
UART_Init(9600);
// Initial ATMega168 TWI/I2C Peripheral
TWSR = 0x00; // Select Prescaler of 1
// SCL frequency = 11059200 / (16 + 2 * 48 * 1) = 98.743 khz
TWBR = 0x30; // 48 Decimal
asm volatile ("sei"); //re-enable interrupts
fdevopen(SendByte, 0);
while(1) {
// Read DS1307
if(display_now) {
display_now = 0;
Read_DS1307();
printf("%s,%s(%d:%d:%d)\r\n",weekday[ds1307_addr[3]],month[ds1307_addr[5]],ds1307_addr[2],ds1307_addr[1],ds1307_addr[0]);
}
}
return 1;
}