RTC (DS1307) powered by ATmega128

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi everyone,

 

I have recently been tinkering with a piece of code from Bruce E. Hall which enables the use of the DS1307 with the HD44780 LCD. (A very well documented issue, I'm aware) However, I have an issue that I was hoping someone could help me solve after spending a lot of time searching the forums.

 

The issue:

When programming the code into my ATmega128, the LCD fire up as it should. It gives the fixed address of the DS1307 and then goes to the time and date.

The time and date is displayed in the attachment 'LCD' or like below.

 

00:00:80

01/01/00

 

It does not update every 1 second as anticipated, it just remains "frozen".

 

My Mega128 is running at 16Mhz from an external clock.

A capture of the fuses is also in the attachment 'Fuses'.

 

So the LCD is wired correctly, hence the fact that its displaying info and I assume the DS1307 is also wired correctly as it is displaying its address and time and date settings (SDA and SCL are wired to PD0/PD1.

I don't own any testing equipment so I cant use a scope or anything like that unfortunately.

I thought it may have had something to do with the clock settings as i removed this line of code because it was being redefined in the make file.

 

#define F_CPU 16000000L // CPU clock speed 16 MHz

Here is the Source code and Make file in question:

 

Any guidance is always appreciated cool

 

//-----------------------------------------------------------------------------
// i2c01: Experiments with interfacing ATmega328 to an DS1307 RTC
//
// Author : Bruce E. Hall <bhall66@gmail.com>
// Website : w8bh.net
// Version : 1.1
// Date : 7 Sep 2013
// Target : ATTmega328P microcontroller
// Language : C, using AVR studio 6
// Size : 1386 bytes, using -O1 optimization
//
// Fuse settings: 8 MHz osc with 65 ms Delay, SPI enable; *NO* clock/8
// ---------------------------------------------------------------------------
// GLOBAL DEFINES

#define LED 5 // Boarduino LED on PB5
#define ClearBit(x,y) x &= ~_BV(y) // equivalent to cbi(x,y)
#define SetBit(x,y) x |= _BV(y) // equivalent to sbi(x,y)
// ---------------------------------------------------------------------------
// INCLUDES
#include <avr/io.h> // deal with port registers
#include <util/delay.h> // used for _delay_ms function
#include <string.h> // string manipulation routines
#include <stdlib.h>
// ---------------------------------------------------------------------------
// TYPEDEFS
typedef uint8_t byte; // I just like byte & sbyte better
typedef int8_t sbyte;
// ---------------------------------------------------------------------------
// MISC ROUTINES
void InitAVR(void)
{
DDRB = 0x3F; // 0011.1111; set B0-B5 as outputs
DDRC = 0x00; // 0000.0000; set PORTC as inputs
}
void msDelay(int delay) // put into a routine
{ // to remove code inlining
for (int i=0;i<delay;i++) // at cost of timing accuracy
_delay_ms(1);
}
void FlashLED(void)
{
SetBit(PORTB,LED);
msDelay(250);
ClearBit(PORTB,LED);
msDelay(250);
}
// ---------------------------------------------------------------------------
// HD44780-LCD DRIVER ROUTINES
//
// Routines:
// LCD_Init initializes the LCD controller
// LCD_Cmd sends LCD controller command
// LCD_Char sends single ascii character to display
// LCD_Clear clears the LCD display & homes cursor
// LCD_Home homes the LCD cursor
// LCD_Goto puts cursor at position (x,y)
// LCD_Line puts cursor at start of line (x)
// LCD_Hex displays a hexadecimal value
// LCD_Integer displays an integer value
// LCD_String displays a string
//
// The LCD module requires 6 I/O pins: 2 control lines & 4 data lines.
// PortB is used for data communications with the HD44780-controlled LCD.
// The following defines specify which port pins connect to the controller:
#define LCD_RS 0 // pin for LCD R/S (eg PB0)
#define LCD_E 1 // pin for LCD enable
#define DAT4 2 // pin for d4
#define DAT5 3 // pin for d5
#define DAT6 4 // pin for d6
#define DAT7 5 // pin for d7
// The following defines are HD44780 controller commands
#define CLEARDISPLAY 0x01
#define SETCURSOR 0x80
void PulseEnableLine (void)
{
SetBit(PORTB,LCD_E); // take LCD enable line high
_delay_us(40); // wait 40 microseconds
ClearBit(PORTB,LCD_E); // take LCD enable line low
}
void SendNibble(byte data)
{
PORTB &= 0xC3; // 1100.0011 = clear 4 data lines
if (data & _BV(4)) SetBit(PORTB,DAT4);
if (data & _BV(5)) SetBit(PORTB,DAT5);
if (data & _BV(6)) SetBit(PORTB,DAT6);
if (data & _BV(7)) SetBit(PORTB,DAT7);
PulseEnableLine(); // clock 4 bits into controller
}
void SendByte (byte data)
{
SendNibble(data); // send upper 4 bits
SendNibble(data<<4); // send lower 4 bits
ClearBit(PORTB,5); // turn off boarduino LED
}
void LCD_Cmd (byte cmd)
{
ClearBit(PORTB,LCD_RS); // R/S line 0 = command data
SendByte(cmd); // send it
}
void LCD_Char (byte ch)
{
SetBit(PORTB,LCD_RS); // R/S line 1 = character data
SendByte(ch); // send it
}
void LCD_Init(void)
{
LCD_Cmd(0x33); // initialize controller
LCD_Cmd(0x32); // set to 4-bit input mode
LCD_Cmd(0x28); // 2 line, 5x7 matrix
LCD_Cmd(0x0C); // turn cursor off (0x0E to enable)
LCD_Cmd(0x06); // cursor direction = right
LCD_Cmd(0x01); // start with clear display
msDelay(3); // wait for LCD to initialize
}
void LCD_Clear(void) // clear the LCD display
{
LCD_Cmd(CLEARDISPLAY);
msDelay(3); // wait for LCD to process command
}
void LCD_Home(void) // home LCD cursor (without clearing)
{
LCD_Cmd(SETCURSOR);
}
void LCD_Goto(byte x, byte y) // put LCD cursor on specified line
{
byte addr = 0; // line 0 begins at addr 0x00
switch (y)
{
case 1: addr = 0x40; break; // line 1 begins at addr 0x40
case 2: addr = 0x14; break;
case 3: addr = 0x54; break;
}
LCD_Cmd(SETCURSOR+addr+x); // update cursor with x,y position
}
void LCD_Line(byte row) // put cursor on specified line
{
LCD_Goto(0,row);
}
void LCD_String(const char *text) // display string on LCD
{
while (*text) // do until /0 character
LCD_Char(*text++); // send char & update char pointer
}
void LCD_Hex(int data)
// displays the hex value of DATA at current LCD cursor position
{
char st[8] = ""; // save enough space for result
itoa(data,st,16); // convert to ascii hex
//LCD_Message("0x"); // add prefix "0x" if desired
LCD_String(st); // display it on LCD
}
void LCD_Integer(int data)
// displays the integer value of DATA at current LCD cursor position
{
char st[8] = ""; // save enough space for result
itoa(data,st,10); // convert to ascii
LCD_String(st); // display in on LCD
}
// ---------------------------------------------------------------------------
// I2C (TWI) ROUTINES
//
// On the AVRmega series, PA4 is the data line (SDA) and PA5 is the clock (SCL
// The standard clock rate is 100 KHz, and set by I2C_Init. It depends on the AVR osc. freq.
#define F_SCL 100000L // I2C clock speed 100 KHz
#define READ 1
#define TW_START 0xA4 // send start condition (TWINT,TWSTA,TWEN)
#define TW_STOP 0x94 // send stop condition (TWINT,TWSTO,TWEN)
#define TW_ACK 0xC4 // return ACK to slave
#define TW_NACK 0x84 // don't return ACK to slave
#define TW_SEND 0x84 // send data (TWINT,TWEN)
#define TW_READY (TWCR & 0x80) // ready when TWINT returns to logic 1.
#define TW_STATUS (TWSR & 0xF8) // returns value of status register
#define I2C_Stop() TWCR = TW_STOP // inline macro for stop condition
void I2C_Init(void)
// at 16 MHz, the SCL frequency will be 16/(16+2(TWBR)), assuming prescalar of 0.
// so for 100KHz SCL, TWBR = ((F_CPU/F_SCL)-16)/2 = ((16/0.1)-16)/2 = 144/2 = 72.
{
TWSR = 0; // set prescalar to zero
TWBR = ((F_CPU/F_SCL)-16)/2; // set SCL frequency in TWI bit register
}
byte I2C_Detect(byte addr)
// look for device at specified address; return 1=found, 0=not found
{
TWCR = TW_START; // send start condition
while (!TW_READY); // wait
TWDR = addr; // load device's bus address
TWCR = TW_SEND; // and send it
while (!TW_READY); // wait
return (TW_STATUS==0x18); // return 1 if found; 0 otherwise
}
byte I2C_FindDevice(byte start)
// returns with address of first device found; 0=not found
{
for (byte addr=start;addr<0xFF;addr++) // search all 256 addresses
{
if (I2C_Detect(addr)) // I2C detected?
return addr; // leave as soon as one is found
}
return 0; // none detected, so return 0.
}
void I2C_Start (byte slaveAddr)
{
I2C_Detect(slaveAddr);
}
byte I2C_Write (byte data) // sends a data byte to slave
{
TWDR = data; // load data to be sent
TWCR = TW_SEND; // and send it
while (!TW_READY); // wait
return (TW_STATUS!=0x28);
}
byte I2C_ReadACK (void) // reads a data byte from slave
{
TWCR = TW_ACK; // ack = will read more data
while (!TW_READY); // wait
return TWDR;
//return (TW_STATUS!=0x28);
}
byte I2C_ReadNACK (void) // reads a data byte from slave
{
TWCR = TW_NACK; // nack = not reading more data
while (!TW_READY); // wait
return TWDR;
//return (TW_STATUS!=0x28);
}
void I2C_WriteByte(byte busAddr, byte data)
{
I2C_Start(busAddr); // send bus address
I2C_Write(data); // then send the data byte
I2C_Stop();
}
void I2C_WriteRegister(byte busAddr, byte deviceRegister, byte data)
{
I2C_Start(busAddr); // send bus address
I2C_Write(deviceRegister); // first byte = device register address
I2C_Write(data); // second byte = data for device register
I2C_Stop();
}
byte I2C_ReadRegister(byte busAddr, byte deviceRegister)
{
byte data = 0;
I2C_Start(busAddr); // send device address
I2C_Write(deviceRegister); // set register pointer
I2C_Start(busAddr+READ); // restart as a read operation
data = I2C_ReadNACK(); // read the register data
I2C_Stop(); // stop
return data;
}
// ---------------------------------------------------------------------------
// DS1307 RTC ROUTINES
#define DS1307 0xD0 // I2C bus address of DS1307 RTC
#define SECONDS_REGISTER 0x00
#define MINUTES_REGISTER 0x01
#define HOURS_REGISTER 0x02
#define DAYOFWK_REGISTER 0x03
#define DAYS_REGISTER 0x04
#define MONTHS_REGISTER 0x05
#define YEARS_REGISTER 0x06
#define CONTROL_REGISTER 0x07
#define RAM_BEGIN 0x08
#define RAM_END 0x3F
void DS1307_GetTime(byte *hours, byte *minutes, byte *seconds)
// returns hours, minutes, and seconds in BCD format
{
*hours = I2C_ReadRegister(DS1307,HOURS_REGISTER);
*minutes = I2C_ReadRegister(DS1307,MINUTES_REGISTER);
*seconds = I2C_ReadRegister(DS1307,SECONDS_REGISTER);
if (*hours & 0x40) // 12hr mode:
*hours &= 0x1F; // use bottom 5 bits (pm bit = temp & 0x20)
else *hours &= 0x3F; // 24hr mode: use bottom 6 bits
}
void DS1307_GetDate(byte *months, byte *days, byte *years)
// returns months, days, and years in BCD format
{
*months = I2C_ReadRegister(DS1307,MONTHS_REGISTER);
*days = I2C_ReadRegister(DS1307,DAYS_REGISTER);
*years = I2C_ReadRegister(DS1307,YEARS_REGISTER);
}
void SetTimeDate(void)
// simple, hard-coded way to set the date.
{
I2C_WriteRegister(DS1307,MONTHS_REGISTER, 0x08);
I2C_WriteRegister(DS1307,DAYS_REGISTER, 0x31);
I2C_WriteRegister(DS1307,YEARS_REGISTER, 0x13);
I2C_WriteRegister(DS1307,HOURS_REGISTER, 0x08+0x40); // add 0x40 for PM
I2C_WriteRegister(DS1307,MINUTES_REGISTER, 0x51);
I2C_WriteRegister(DS1307,SECONDS_REGISTER, 0x00);
}
// ---------------------------------------------------------------------------
// APPLICATION ROUTINES
void ShowDevices(void)
// Scan I2C addresses and display addresses of all devices found
{
LCD_Line(1); LCD_String("Found:");
byte addr = 1;
while (addr>0)
{
LCD_Char(' ');
addr = I2C_FindDevice(addr);
if (addr>0) LCD_Hex(addr++);
}
}
void LCD_TwoDigits(byte data)
// helper function for WriteDate()
// input is two digits in BCD format
// output is to LCD display at current cursor position
{
byte temp = data>>4;
LCD_Char(temp+'0');
data &= 0x0F;
LCD_Char(data+'0');
}
void WriteDate(void)
{
byte months, days, years;
DS1307_GetDate(&months,&days,&years);
LCD_TwoDigits(months);
LCD_Char('/');
LCD_TwoDigits(days);
LCD_Char('/');
LCD_TwoDigits(years);
}
void WriteTime(void)
{
byte hours, minutes, seconds;
DS1307_GetTime(&hours,&minutes,&seconds);
LCD_TwoDigits(hours);
LCD_Char(':');
LCD_TwoDigits(minutes);
LCD_Char(':');
LCD_TwoDigits(seconds);
}
void LCD_TimeDate(void)
{
LCD_Line(0); WriteTime();
LCD_Line(1); WriteDate();
}
// ---------------------------------------------------------------------------
// PROGRAM LOOP
void MainLoop(void)
{
while(1)
{
LCD_TimeDate(); // put time & date on LCD
msDelay(1000); // one second between updates
}
}
// ---------------------------------------------------------------------------
// MAIN PROGRAM
int main(void)
{
InitAVR(); // set port direction
LCD_Init(); // initialize HD44780 LCD controller
I2C_Init(); // set I2C clock frequency
LCD_String("Ready.");
ShowDevices(); // show that I2C is working OK
msDelay(4000);
LCD_Clear();
MainLoop(); // display time
}

 

 

*Make file*

 

 

 

# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
#                Please customize the avrdude settings below first!
#
# make debug = Start either simulavr or avarice as specified for debugging, 
#              with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
#                   bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------


# MCU name
MCU = atmega128


# Processor frequency.
#     This will define a symbol, F_CPU, in all source code files equal to the 
#     processor frequency. You can then use this symbol in your source code to 
#     calculate timings. Do NOT tack on a 'UL' at the end, this will be done
#     automatically to create a 32-bit value in your source code.
#     Typical values are:
#         F_CPU =  1000000
#         F_CPU =  1843200
#         F_CPU =  2000000
#         F_CPU =  3686400
#         F_CPU =  4000000
#         F_CPU =  7372800
#         F_CPU =  8000000
#         F_CPU = 11059200
#         F_CPU = 14745600
#         F_CPU = 16000000
#         F_CPU = 18432000
#         F_CPU = 20000000
F_CPU = 16000000


# Output format. (can be srec, ihex, binary)
FORMAT = ihex


# Target file name (without extension).
TARGET = RTC


# Object files directory
#     To put object files in current directory, use a dot (.), do NOT make
#     this an empty or blank macro!
OBJDIR = .


# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c


# List C++ source files here. (C dependencies are automatically generated.)
CPPSRC = 


# List Assembler source files here.
#     Make them always end in a capital .S.  Files ending in a lowercase .s
#     will not be considered source files but generated files (assembler
#     output from the compiler), and will be deleted upon "make clean"!
#     Even though the DOS/Win* filesystem matches both .s and .S the same,
#     it will preserve the spelling of the filenames, and gcc itself does
#     care about how the name is spelled on its command-line.
ASRC =


# Optimization level, can be [0, 1, 2, 3, s]. 
#     0 = turn off optimization. s = optimize for size.
#     (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s


# Debugging format.
#     Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
#     AVR Studio 4.10 requires dwarf-2.
#     AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2


# List any extra directories to look for include files here.
#     Each directory must be seperated by a space.
#     Use forward slashes for directory separators.
#     For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS = 


# Compiler flag to set the C Standard level.
#     c89   = "ANSI" C
#     gnu89 = c89 plus GCC extensions
#     c99   = ISO C99 standard (not yet fully implemented)
#     gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99


# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL


# Place -D or -U options here for ASM sources
ADEFS = -DF_CPU=$(F_CPU)


# Place -D or -U options here for C++ sources
CPPDEFS = -DF_CPU=$(F_CPU)UL
#CPPDEFS += -D__STDC_LIMIT_MACROS
#CPPDEFS += -D__STDC_CONSTANT_MACROS



#---------------- Compiler Options C ----------------
#  -g*:          generate debugging information
#  -O*:          optimization level
#  -f...:        tuning, see GCC manual and avr-libc documentation
#  -Wall...:     warning level
#  -Wa,...:      tell GCC to pass this to the assembler.
#    -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
#CFLAGS += -mshort-calls
#CFLAGS += -fno-unit-at-a-time
#CFLAGS += -Wundef
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)


#---------------- Compiler Options C++ ----------------
#  -g*:          generate debugging information
#  -O*:          optimization level
#  -f...:        tuning, see GCC manual and avr-libc documentation
#  -Wall...:     warning level
#  -Wa,...:      tell GCC to pass this to the assembler.
#    -adhlns...: create assembler listing
CPPFLAGS = -g$(DEBUG)
CPPFLAGS += $(CPPDEFS)
CPPFLAGS += -O$(OPT)
CPPFLAGS += -funsigned-char
CPPFLAGS += -funsigned-bitfields
CPPFLAGS += -fpack-struct
CPPFLAGS += -fshort-enums
CPPFLAGS += -fno-exceptions
CPPFLAGS += -Wall
CPPFLAGS += -Wundef
#CPPFLAGS += -mshort-calls
#CPPFLAGS += -fno-unit-at-a-time
#CPPFLAGS += -Wstrict-prototypes
#CPPFLAGS += -Wunreachable-code
#CPPFLAGS += -Wsign-compare
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
#CPPFLAGS += $(CSTANDARD)


#---------------- Assembler Options ----------------
#  -Wa,...:   tell GCC to pass this to the assembler.
#  -adhlns:   create listing
#  -gstabs:   have the assembler create line number information; note that
#             for use in COFF files, additional information about filenames
#             and function names needs to be present in the assembler source
#             files -- see avr-libc docs [FIXME: not yet described there]
#  -listing-cont-lines: Sets the maximum number of continuation lines of hex 
#       dump that will be displayed for a given single line of source input.
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100


#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min

# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt

# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB = 
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)


# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min

# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt

# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB = 
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)


MATH_LIB = -lm


# List any extra directories to look for libraries here.
#     Each directory must be seperated by a space.
#     Use forward slashes for directory separators.
#     For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS = 



#---------------- External Memory Options ----------------

# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff

# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff

EXTMEMOPTS = 



#---------------- Linker Options ----------------
#  -Wl,...:     tell GCC to pass this to linker.
#    -Map:      create map file
#    --cref:    add cross reference to  map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
#LDFLAGS += -T linker_script.x



#---------------- Programming Options (avrdude) ----------------

# Programming hardware
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = avrisp2

# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = com1    # programmer connected to serial device

AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep


# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y

# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V

# Increase verbosity level.  Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> 
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v

AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)



#---------------- Debugging Options ----------------

# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)

# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight

# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr

# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit

# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1

# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242

# Debugging host used to communicate between GDB / avarice / simulavr, normally
#     just set to localhost unless doing some sort of crazy debugging when 
#     avarice is running on a different computer.
DEBUG_HOST = localhost



#============================================================================


# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
REMOVEDIR = rm -rf
COPY = cp
WINSHELL = cmd


# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = --------  end  --------
MSG_SIZE_BEFORE = Size before: 
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_COMPILING_CPP = Compiling C++:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
MSG_CREATING_LIBRARY = Creating library:




# Define all object files.
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) 

# Define all listing files.
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) 


# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d


# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)





# Default target.
all: begin gccversion sizebefore build sizeafter end

# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib


elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)



# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
	@echo
	@echo $(MSG_BEGIN)

end:
	@echo $(MSG_END)
	@echo


# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf

sizebefore:
	@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
	2>/dev/null; echo; fi

sizeafter:
	@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
	2>/dev/null; echo; fi



# Display compiler version information.
gccversion : 
	@$(CC) --version



# Program the device.  
program: $(TARGET).hex $(TARGET).eep
	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)


# Generate avr-gdb config/init file which does the following:
#     define the reset signal, load the target file, connect to target, and set 
#     a breakpoint at main().
gdb-config: 
	@$(REMOVE) $(GDBINIT_FILE)
	@echo define reset >> $(GDBINIT_FILE)
	@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
	@echo end >> $(GDBINIT_FILE)
	@echo file $(TARGET).elf >> $(GDBINIT_FILE)
	@echo target remote $(DEBUG_HOST):$(DEBUG_PORT)  >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
	@echo load  >> $(GDBINIT_FILE)
endif
	@echo break main >> $(GDBINIT_FILE)

debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
	@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
	@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
	$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
	@$(WINSHELL) /c pause

else
	@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
	$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
	@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)




# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000



coff: $(TARGET).elf
	@echo
	@echo $(MSG_COFF) $(TARGET).cof
	$(COFFCONVERT) -O coff-avr $< $(TARGET).cof


extcoff: $(TARGET).elf
	@echo
	@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
	$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof



# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
	@echo
	@echo $(MSG_FLASH) $@
	$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $< $@

%.eep: %.elf
	@echo
	@echo $(MSG_EEPROM) $@
	-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
	--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0

# Create extended listing file from ELF output file.
%.lss: %.elf
	@echo
	@echo $(MSG_EXTENDED_LISTING) $@
	$(OBJDUMP) -h -S -z $< > $@

# Create a symbol table from ELF output file.
%.sym: %.elf
	@echo
	@echo $(MSG_SYMBOL_TABLE) $@
	$(NM) -n $< > $@



# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
	@echo
	@echo $(MSG_CREATING_LIBRARY) $@
	$(AR) $@ $(OBJ)


# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
	@echo
	@echo $(MSG_LINKING) $@
	$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)


# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
	@echo
	@echo $(MSG_COMPILING) $<
	$(CC) -c $(ALL_CFLAGS) $< -o $@ 


# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
	@echo
	@echo $(MSG_COMPILING_CPP) $<
	$(CC) -c $(ALL_CPPFLAGS) $< -o $@ 


# Compile: create assembler files from C source files.
%.s : %.c
	$(CC) -S $(ALL_CFLAGS) $< -o $@


# Compile: create assembler files from C++ source files.
%.s : %.cpp
	$(CC) -S $(ALL_CPPFLAGS) $< -o $@


# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
	@echo
	@echo $(MSG_ASSEMBLING) $<
	$(CC) -c $(ALL_ASFLAGS) $< -o $@


# Create preprocessed source for use in sending a bug report.
%.i : %.c
	$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ 


# Target: clean project.
clean: begin clean_list end

clean_list :
	@echo
	@echo $(MSG_CLEANING)
	$(REMOVE) $(TARGET).hex
	$(REMOVE) $(TARGET).eep
	$(REMOVE) $(TARGET).cof
	$(REMOVE) $(TARGET).elf
	$(REMOVE) $(TARGET).map
	$(REMOVE) $(TARGET).sym
	$(REMOVE) $(TARGET).lss
	$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
	$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
	$(REMOVE) $(SRC:.c=.s)
	$(REMOVE) $(SRC:.c=.d)
	$(REMOVE) $(SRC:.c=.i)
	$(REMOVEDIR) .dep


# Create object files directory
$(shell mkdir $(OBJDIR) 2>/dev/null)


# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)


# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion \
build elf hex eep lss sym coff extcoff \
clean clean_list program debug gdb-config


 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hello.
Excuse me but i don't see refreshing timestamp in the main loop. I mean, do you get updated time from ds1307 in every loop? Because i don't see it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was under the impression that the code in the main loop below was updating every second??

 

// PROGRAM LOOP
void MainLoop(void)
{
while(1)
{
LCD_TimeDate(); // put time & date on LCD
msDelay(1000); // one second between updates
}
}

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you >>really<< write all your C code flush-left?

 

As the previous comment indicates, it is hard for us to grasp/decipher.

 

What does ShowDevices report?

 

Do you always get the "null" time and date, even after a reset?  Have you told the DS1307 to start?

 

Tell your wiring to the DS1307, in particular pullups.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No I don't write code like that, it was a quick copy and paste job to get it working.

Are u referring to device information from studio 7?

And apologies for the lack of understanding as this is a pretty new topic for me. This is why I'm trying to get assistance

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ShowDevices reports d0, which is the fixed address of the DS1307

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

there's a function setDateTime() that needs to be called to set a valid date/time. You also need to specifically start the ds1307 - there doesn't seem to be any code for that. The ds1307 datasheet explains what needs to be done

Last Edited: Thu. Dec 3, 2015 - 07:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well thus far, I haven't made any changes to address this as i was not aware it would be different. (first time using I2C) and probably in a little over my head.

 

After reading your comment, I went through the data sheet and was looking at two wire interface section.

 

I looked at these two lines of code:

#define TW_START 0xA4 // send start condition (TWINT,TWSTA,TWEN)
#define TW_STOP 0x94 // send stop condition (TWINT,TWSTO,TWEN)

and the hex appears to be correct in selecting whats needed.

So I'm not really sure where to go from here to address the issue.

 

Thanks for your help so far.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The problem is not with i2c. I suggested the datasheet for the ds1307 chip.
http://datasheets.maximintegrated.com/en/ds/DS1307.pdf

Seems the function SetTimeDate() does what is required. Call that function and that will set the time and start the clock.

Last Edited: Thu. Dec 3, 2015 - 12:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well that you're correct, that function definitely set the time. now to add push button inputs and work out a way to set the time other than with the code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

danrulz01 wrote:

... work out a way to set the time other than with the code.

 

Huh? Setting the time must be via code.

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I meant other than hard coding the time and date.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK.. the last I did this, my customer's requirements differed a "little" probably from yours so this might not be exactly what you are looking for.

 

 

Ignoring the "Reset" button because it is not associated with the time setting features, I had a single menu button that would cycle through year, month, day, hour, minutes and seconds and finally save. The Plus and Minus should be self evident. As the buttons were used the display would provide realtime update of the current values.

 

So I think you need a minimum of 3 buttons... and the code to go with them. Sorry I cannot share the code as it is proprietary.

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Valusoft, I figured i would make a menu system using a switch statement. i've done this before in another project. once i have given it a crack, i will post back what i come up with :)

Last Edited: Fri. Dec 4, 2015 - 01:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have started attempting to write this switch statement... now i haven't written C for a long time so please grit your teeth and come along for the ride XD.

 

Is my understanding correct here. I believe my switch statement is not being reached due to the while(1) loop in Mainloop();? is that correct?

// ---------------------------------------------------------------------------
// PROGRAM LOOP
void MainLoop(void)
	{
		while(1)
	{
			LCD_TimeDate(); // put time & date on LCD
			msDelay(1000); // one second between updates
		}
	}
// ---------------------------------------------------------------------------
// Switch Statement
#define MASK 		0b01111111
#define SWITCH_0 	0b01111110
//#define SWITCH_1 	0b01111101
//#define SWITCH_2 	0b01111011
//#define SWITCH_3 	0b01110111
//----------------------------------------------------------------------------

// MAIN PROGRAM
int main(void)
	{
		DDRA = 0x00;
		PORTA = MASK;
		
		InitAVR(); // set port direction
		LCD_Init(); // initialize HD44780 LCD controller
		I2C_Init(); // set I2C clock frequency
		LCD_String("Real Time Clock");
		ShowDevices(); // show that I2C is working OK
		msDelay(1000);
		LCD_Clear();
		SetTimeDate();
		MainLoop(); // display time
		
		for(;;){
			if((PINA & MASK) != MASK){
			switch (PINA & MASK){
				case SWITCH_0:
					LCD_Clear();
					LCD_String("Do something!!");
					msDelay(1000);
					break;
					}}}
			
	}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The entire for(;;) loop is unreachable.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

how does one make it reachable, or is my whole approach wrong?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
The entire for(;;) loop is unreachable.

danrulz01 wrote:
how does one make it reachable

Think about what prevents it from being reached.

 

Fix that ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As far as I know, the 1307 is normally configured to put out a 1Hz (50% duty cycle) square wave.  Then this signal [SQW] is fed to one of the AVR's External Interrupts.  The interrupt sets a boolean flag to the main code indicating that it is time to refresh the real-time-display screen.  The screen gets updated, the flag is cleared, and the program goes on to do other things until a second has passed and the interrupt gets triggered again.

 

I don't see if you are using the 1307's 1Hz signal.  It is activated by the control register 0x07.  The data sheet says that the 1307 clock registers get updated on the rising edge, so I assume that

this signal needs to be turned on for the clock to update its time display.

 

I've never seen anyone look through all the I2C addresses for a device.  People just assume that if they put a device on the I2C, then it will be there: working and documented.
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

danrulz01 wrote:
how does one make it reachable, or is my whole approach wrong?
Will MainLoop() ever return?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know what i want it to do, but i don't know how to write the code. I want it to be able to run other processes and still update the screen each second after being interrupted or something frown

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You really don't need the interrupt from the RTC. Reading the RTC should take a few hundred microseconds, so you can do plenty of other things and read the RTC at a regular rate. I wrote a tutorial called multi - tasking part1 in the tutorial section. This might give you some ideas on how to structure your code to do other things apart from reading the time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

that sounds like exactly what i need! I'll give it a read now, thanks