• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC + I2C + MicroC

Status
Not open for further replies.

Hesam Kamalan

New Member
hi,

unfortunately i can not understand MicroC I2C sample.

if it's possible, learn me how can i use defined function (Software I²C Library
or I²C Library) for PIC16F877A and DS1307, please.

i want one sample code for learning that functions.
 

arhi

Member
hi,

unfortunately i can not understand MicroC I2C sample.

if it's possible, learn me how can i use defined function (Software I²C Library
or I²C Library) for PIC16F877A and DS1307, please.

i want one sample code for learning that functions.
I'm not sure I understand the question. Do you want "sample code" that uses MikroC libraries for hardware and software I2C to talk with DS1307 ? or you want us to "explain" sample code you have ?
 

Hesam Kamalan

New Member
Thank you arhi,

yes i want "sample code" that uses MikroC libraries for hardware and software I2C to talk with DS1307.

i want that be simple to understand and learning.
 

arhi

Member
Thank you arhi,

yes i want "sample code" that uses MikroC libraries for hardware and software I2C to talk with DS1307.

i want that be simple to understand and learning.
I cannot make it simpler then this:
Code:
unsigned short hh;
unsigned short mm;
unsigned short ss;

void write_DS1307(unsigned short address, unsigned short data)
{
   unsigned short status;
   I2C_Start();
   I2C_Wr(0xd0);
   I2C_Wr(address);
   I2C_Wr(data);
   I2C_Stop();
}

unsigned short read_DS1307(unsigned short address)
{
   unsigned short data;
   I2C_Start();
   I2C_Wr(0xd0);
   I2C_Wr(address);
   I2C_Repeated_Start();
   I2C_Wr(0xd1);
   data=I2C_Rd(0);
   while (!I2C_Is_Idle()) asm nop;
   I2C_Stop();
   return(data);
}


void main(){
  PORTB = 0;
  TRISB = 0;

  PORTD = 0;
  TRISD = 0;

  hh = 0;
  mm = 0;
  ss = 0;
  
  Lcd_Init(&PORTD);
  Lcd_Out(1,1,"Init...");
  I2C_Init(100000); //DS1307 operates at 100Khz only

  ss=read_ds1307(0);
  write_ds1307(0, ss & 0x7F); // enable oscillator(bit 7 =0)

  ss=read_ds1307(2);
  write_ds1307(2, ss & 0b10111111); // set 24H mode
  


   while(1)
   {
     ss=read_ds1307(0);   // read second
     mm=read_ds1307(1);   // read minute
     hh=read_ds1307(2);  // read hour
     /*
     day=read_ds1307(3);   // read day
     date=read_ds1307(4);  // read date
     month=read_ds1307(5); // read month
     year=read_ds1307(6);  // read year
     */

     Lcd_Chr(1,1, 48+ ((hh & 0b00110000) >> 4));
     Lcd_Chr(1,2, 48+ (hh & 0b00001111) );

     Lcd_Chr(1,3, ':');

     Lcd_Chr(1,4, 48+ ((mm & 0b01110000) >> 4));
     Lcd_Chr(1,5, 48+ (mm & 0b00001111) );

     Lcd_Chr(1,6, ':');

     Lcd_Chr(1,7, 48+ ((ss & 0b01110000) >> 4));
     Lcd_Chr(1,8, 48+ (ss & 0b00001111) );

     delay_ms(1000);
  }
}
this is using HW i2c library ... tested (in ISIS) and working as expected ...
using the software library is exactly the same, only you have to use
Soft_I2C_Start(); Soft_I2C_Write(12); .. and similar functions from software library, just use them instead of these from the hw library and it will work (do not forget to first run Soft_I2C_Config() to configure software library for the pins you will use for SDA and SCL

you have here 2 simple functions defined
write_DS1307()
read_DS1307()

these two functions are basically "read/write single byte from I2C device" only the 0xD0 slave address of the DS1307 is hardcoded. if for example you use some other slave device, you can read write from any other I2C device (for e.g. 24cxxx i2c eeprom)

if you have any questions .. feel free to ask. If you have ISIS I can upload the design so you can play with it
 

Hesam Kamalan

New Member
Dear arhi,
thank you very much for your assistance.

it was very good to me. i have ISIS, please upload that files, if it's possible.

have a nice day
 

Hesam Kamalan

New Member
thank you dear arhi,
you solved my problem. my english is not well and i can not tell my intention to you.

so i can say thank you, only.
 

Hesam Kamalan

New Member
Dear Arhi,

i understood your code but i have a problem with this part of code:

Lcd_Chr(1,1, 48+ ((hh & 0b00110000) >> 4));
Lcd_Chr(1,2, 48+ (hh & 0b00001111) );

i can not understand this segment. please explain me why you
"and" hh and 0b00110000?
why you shift 4 times?
and why add those with 48?
 

Pommie

Well-Known Member
Most Helpful Member
The first line is printing the 10s of hours. I.E 21:45
So, hh & 0b00110000 will give either 0x00, 0x10 or 0x02. When shifted it becomes 0,1 or 2. The add 48 then converts it to "0", "1" or "2".
The second line prints the unit hours and so doesn't need the shift. I.E 21:45

This will only work if the DS1307 is in 24 hour mode.

Mike.
 

arhi

Member
@hesam,
You have to read the data sheet to be able to use any device .. same thing is with DS1307 ...

If you look at the datasheet, on the address 0x02 bit 6 set's the clock in 12/24 hour mode.
the line
Code:
  ss=read_ds1307(2);
  write_ds1307(2, ss & 0b10111111); // set 24H mode
set's the device to 24h mode. (first read the content of address 0x02 and then return it with 6th bit cleared). The other way you could do this is to read the bit, and then read the data accordingly (you interpret data from address 0x02 differently for 24h and 12h mode)

As Mike already explained, the anding and shifting is used to read data as per data sheet. If you look at the data sheet carefully, you will notice that for minutes and seconds the "first digit" or "tens of seconds/minutes" is written in bits 4,5,6, so I use and to mask those bits and then shift left 4 times to get the actual value. 48 is ASCII of '0' so adding digit value to 48 will result of ASCII value of that digit. the second digit (seconds/minutes) is just masked (no need to shift as it is already at right place)

If you want "value" of the minutes for example and not "ASCII DIGITS" then you would do something like:
Code:
minute =((mm & 0b01110000) >> 4)*10 + (mm & 0b00001111);
note also that you need to turn the internal oscillator ON (CH, 7th bit of address 0x00) .. the example code does it:
Code:
  ss=read_ds1307(0);
  write_ds1307(0, ss & 0x7F); // enable oscillator(bit 7 =0)
What you can try to do now is to upgrade this app to display also the DATE, and additionally, you can upgrade it to "SET NEW DATE" ... you have all the software components you need, you only need to add some button switches to ISIS model so you can test user input to be able to set new time/date.

note also that DS1307 have 56 bytes of RAM that you can use to store data from your program. That data will be present while batt is connected to the DS1307 so you can use it as a small i2c eeprom to store 56 bytes of data...

example how to read/write data :
Code:
//first parameter is address, you can use 0x08-0x3fH
//second parametar is the 8bit value you want to save
write_DS1307(0x08, 123); 

//first parameter is address, you can use 0x08-0x3fH
val = read_DS1307(0x08); //val now have value of 123 as that is what we stored in prev statement
all clear now? if not, first read the datasheet and if still not clear post a question
 

Hesam Kamalan

New Member
thank you very much dear arhi.
i am designing a watch with 12, 7-segments and some latchs and decoder and lm35, buzzer, led, . . .

when schematic is done, for understanding of my designing errors, i will send it to you.

thank you so much...
 

Hesam Kamalan

New Member
Hi,
i wrote this code with "Software I²C Library" functions. after rewriting Arhi code with "Software I²C Library" functions, i compiled it, but when i simulate it with ISIS, nothing appeared on LCD. i think that my program is not right. tell me where is my problem, please.

//--------------------------------------------------------------------------------------
unsigned short hh;
unsigned short mm;
unsigned short ss;
unsigned char x[17];

void write_DS1307(unsigned short address, unsigned short data)
{
unsigned short status;
Soft_I2C_Start();
Soft_I2C_Write(0xd0);
Soft_I2C_Write(address);
Soft_I2C_Write(data);
Soft_I2C_Stop();
}

unsigned short read_DS1307(unsigned short address)
{
unsigned short data;
Soft_I2C_Start();
Soft_I2C_Write(0xd0);
Soft_I2C_Write(address);
//Soft_I2C_Read();
Soft_I2C_Write(0xd1);
data=Soft_I2C_Read(0);
//while (!I2C_Is_Idle()) asm nop;
Soft_I2C_Stop();
return(data);
}


void main(){

PORTD = 0;
TRISD = 0;

hh = 0;
mm = 0;
ss = 0;

Lcd_Init(&PORTD);
Lcd_Out(1,1,"Init...");
//I2C_Init(100000); //DS1307 operates at 100Khz only

Soft_I2C_Config(&PORTC, 0, 1);

ss=read_ds1307(0);
write_ds1307(0, ss & 0x7F); // enable oscillator(bit 7 =0)

ss=read_ds1307(2);
write_ds1307(2, ss & 0b10111111); // set 24H mode



while(1)
{
ss=read_ds1307(0); // read second
mm=read_ds1307(1); // read minute
hh=read_ds1307(2); // read hour
/*
day=read_ds1307(3); // read day
date=read_ds1307(4); // read date
month=read_ds1307(5); // read month
year=read_ds1307(6); // read year
*/

Lcd_Chr(1,1, 48+ ((hh & 0b00110000) >> 4));
Lcd_Chr(1,2, 48+ (hh & 0b00001111) );

Lcd_Chr(1,3, ':');

Lcd_Chr(1,4, 48+ ((mm & 0b01110000) >> 4));
Lcd_Chr(1,5, 48+ (mm & 0b00001111) );

Lcd_Chr(1,6, ':');

Lcd_Chr(1,7, 48+ ((ss & 0b01110000) >> 4));
Lcd_Chr(1,8, 48+ (ss & 0b00001111) );


delay_ms(1000);
}
}
 

futz

Active Member
i wrote this code
Here's a nice tip. :) When you post code here, be sure to put it inside Code tags. Easiest way is to click the # in the menu just before pasting your code. Alternately, you can type in
Code:
 before your code and [/co[COLOR="Black"]de][/COLOR] after your code. This forces the web-site to keep your formatting so people can actually read your code. When you don't do this, it loses all indentation and turns into the unreadable lump in your original post.
 

arhi

Member
the code looks ok, but when using software i2c implementation you have to pay attention on few things:
- interrupts must be disabled as it is time critical operation
- you have to setup the correct frequency in mikroC project for it to be able to calculate delays properly. So if you are using 8MHz crystal with internal 4xpll then you have to enter 32MHz to the mikroC project etc..
- making software i2c work with internal oscillator never worked for me, maybe because the internal oscillator was not precise enough or because I miss configured something, but in any case, I never made it work with internal oscillator (that by any mens do not mean it cannot be done, just that *I* have not manage to do it)
- the frequency your project have set, your config is setup for and the one selected in ISIS for the uC must be the same. The ISIS by default set the "speed" to 1MHz AFAIK, and that will work for hw i2c but not for sw i2c implementation.

On top of all this, you also have I2C analyzer in ISIS so you can actually look at the I2C communication. Do not forget to put pull up resistors to I2C lines in ISIS because I2C will not work without pull up resistors.
 

arhi

Member
u r welcome, just check the frequencies and post back if everything works ok. I never personally used that software i2c lib as most of the uC's have hw i2c and as I use i2c a lot for communication between my devices (eprom, rtc, port extender, glcd...) I tend to use hw one.
 

zzssww8936

New Member
hi, bro, i am having a problem of displaying the time of the digital clock, i use the pic16f877a and ds1307, can u help me find the problems? i'm using mikroc pro for pic.

Code:
// LCD module connections-------------------------------------------------------------------------------------
sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;
// End LCD module connections---------------------------------------------------------------------------------

//------------------------------Declare Variables section--------------------------------------------------------
unsigned short read_ds1307(unsigned short address );
void write_ds1307(unsigned short address,unsigned short w_data);
unsigned short sec;
unsigned short minute;
unsigned short hour;
unsigned short day;
unsigned short date;
unsigned short month;
unsigned short year;
unsigned short dataa;
unsigned short a=0;
unsigned short b=0;
unsigned short yr=0;
unsigned short hour1;
char ddate[11];
char time[15];
char time1[15];
char ampm;
unsigned char dday;
unsigned char dhour;

unsigned char BCD2UpperCh(unsigned char bcd);
unsigned char BCD2LowerCh(unsigned char bcd);
//------------------------------End of Declare Variables section--------------------------------------------------------


void main(){
//------------------------------Start of Initialization Section-------------------------------------------------------------
I2C1_Init(100000); //DS1307 I2C is running at 100KHz
TRISB = 0x00; // Configure PORTB as output
TRISC = 0xFF;
TRISD = 0xFF;
PORTD=0x00;
Lcd_Init();
Lcd_Cmd(_Lcd_CLEAR); // Clear display
Lcd_Cmd(_Lcd_CURSOR_OFF); // Turn cursor off


//Set Time
write_ds1307(0,0x80); //Reset second to 0 sec. and stop Oscillator
write_ds1307(1,0x59); //write min 59
write_ds1307(2,0x11); //write hour 11 PM
write_ds1307(3,0x04); //write day
write_ds1307(4,0x15); // write date 15
write_ds1307(5,0x06); // write month June
write_ds1307(6,0x11); // write year 11 --> 2011
write_ds1307(7,0x10); //SQWE output at 1 Hz
write_ds1307(0,0x00); //Reset second to 0 sec. and start Oscillator
//------------------------------End of Initialization Section---------------------------------------------------------

while(1)
{
sec=read_ds1307(0); // read second
minute=read_ds1307(1); // read minute
hour=read_ds1307(2); // read hour
day=read_ds1307(3); // read day
date=read_ds1307(4); // read date
month=read_ds1307(5); // read month
year=read_ds1307(6); // read year

a=BCD2UpperCh(year);
b=BCD2LowerCh(year);
yr=a*10+b;
hour1 =hour;

//------------------------------Start of Setting Clock Time Section-------------------------------------------------------

if (PORTD.F0==1 && PORTD.F6==0)
{
   if (PORTD.F1==1){
   minute=minute+1;
   if (minute==0x0A||minute==0x1A||minute==0x2A||minute==0x3A||minute==0x4A){
   minute=minute+6;}
   else if (minute==0x5A){
   minute=0x00;} }

   else if (PORTD.F2==1)
   {
   hour=hour+1;
   if (hour==0x0A||hour==0x1A||hour==0x2A){
   hour=hour+6;}
   else if (hour==0x24){
   hour=0x00;} }

   else if (PORTD.F3==1) {
   date=date+1;
   day=day+1;
   if (month==0x01||month==0x03||month==0x05||month==0x07||month==0x08||month==0x10||month==0x12){
   if (date==0x0A||date==0x1A||date==0x2A){
   date=date+6;}
   else if (date==0x32){
   date=0x01;}

   if(day==8)
   day=1;}

   else if (month==0x04||month==0x06||month==0x09||month==0x11){
   if (date==0x0A||date==0x1A||date==0x2A){
   date=date+6;}
   else if (date==0x31){
   date=0x01;}

   if(day==8)
   day=1;}

   else if (month==0x02){
   if (yr%4==0){
   if (date==0x0A||date==0x1A){
   date=date+6;}
   else if (date==0x2A){
   date=0x01;}

   if(day==8)
   day=1;}

   else if (yr%4==3||yr%4==0||yr%4==1){
   if (date==0x0A||date==0x1A){
   date=date+6;}
   else if (date==0x29){
   date=0x01;}

   if(day==8)
   day=1;}
   }
   }

   else if (PORTD.F4==1) {
   month=month+1;
   if (month==0x0A||month==0x1A){
   month=month+6;}
   else if (month==0x13){
   month=0x01;}
   }



   else if (PORTD.F5==1) {
   year=year+1;
   if (year==0x0A||year==0x1A||year==0x2A||year==0x3A||year==0x4A||year==0x5A||year==0x6A||year==0x7A||year==0x8A){
   year=year+6;}
   else if (year==0x9A){
   year=0x11;}
   }

   else if (PORTD.F7 = 1){
   day = day + 1 ;
   if (day==0x8){
   year=0x01;}
   }

   Delay_ms(100);



write_ds1307(0,0x80);
write_ds1307(1, minute);
write_ds1307(2, hour);
write_ds1307(3, day);
write_ds1307(4, date);
write_ds1307(5, month);
write_ds1307(6, year);
write_ds1307(0,0x00);



dday = BCD2LowerCh(day);
if (dday == '1') {
Lcd_Out(1,1,"Sun");
}
else if (dday == '2') {
Lcd_Out(1,1,"Mon");
}
else if (dday == '3') {
Lcd_Out(1,1,"Tue");
}
else if (dday == '4') {
Lcd_Out(1,1,"Wed");
}
else if (dday == '5') {
Lcd_Out(1,1,"Thu");
}
else if (dday == '6') {
Lcd_Out(1,1,"Fri");
}
else if (dday == '7') {
Lcd_Out(1,1,"Sat");
}

ddate[0] = BCD2UpperCh(date);
ddate[1] = BCD2LowerCh(date);
ddate[2] = '/';
ddate[3] = BCD2UpperCh(month);
ddate[4] = BCD2LowerCh(month);
ddate[5] = '/';
ddate[6] = '2';
ddate[7] = '0';
ddate[8] = BCD2UpperCh(year);
ddate[9] = BCD2LowerCh(year);
ddate[10] = '\0';


time[0] = BCD2UpperCh(hour);
time[1] = BCD2LowerCh(hour);
time[2] = ':';
time[3] = BCD2UpperCh(minute);
time[4] = BCD2LowerCh(minute);
time[5] = ':';
time[6] = BCD2UpperCh(sec);
time[7] = BCD2LowerCh(sec);
time[8] = ' ';
time[9] = ' ';
time[10] = ' ';
time[11] = ' ';
time[12] = '\0';

Lcd_Out(1,5,ddate);
Lcd_Out(2,1,time);
Delay_ms(50);






   }
else if (PORTD.F0==0 && PORTD.F6==0)
{

dday = BCD2LowerCh(day);
if (dday == '1') {
Lcd_Out(1,1,"Sun");
}
else if (dday == '2') {
Lcd_Out(1,1,"Mon");
}
else if (dday == '3') {
Lcd_Out(1,1,"Tue");
}
else if (dday == '4') {
Lcd_Out(1,1,"Wed");
}
else if (dday == '5') {
Lcd_Out(1,1,"Thu");
}
else if (dday == '6') {
Lcd_Out(1,1,"Fri");
}
else if (dday == '7') {
Lcd_Out(1,1,"Sat");
}

ddate[0] = BCD2UpperCh(date);
ddate[1] = BCD2LowerCh(date);
ddate[2] = '/';
ddate[3] = BCD2UpperCh(month);
ddate[4] = BCD2LowerCh(month);
ddate[5] = '/';
ddate[6] = '2';
ddate[7] = '0';
ddate[8] = BCD2UpperCh(year);
ddate[9] = BCD2LowerCh(year);
ddate[10] = '\0';

time[0] = BCD2UpperCh(hour);
time[1] = BCD2LowerCh(hour);
time[2] = ':';
time[3] = BCD2UpperCh(minute);
time[4] = BCD2LowerCh(minute);
time[5] = ':';
time[6] = BCD2UpperCh(sec);
time[7] = BCD2LowerCh(sec);
time[8] = ' ';
time[9] = ' ';
time[10] = ' ';
time[11] = ' ';
time[12] = '\0';

Lcd_Out(1,5,ddate);
Lcd_Out(2,1,time);
Delay_ms(50);
}

//------------------------------End of Setting Clock Time Section-------------------------------------------------------
//------------------------------Start of Display Time in 12 hr system Section------------------------------------------
else if (PORTD.F0==0 && PORTD.F6==1)
{

dday = BCD2LowerCh(day);
if (dday == '1') {
Lcd_Out(1,1,"Sun");
}
else if (dday == '2') {
Lcd_Out(1,1,"Mon");
}
else if (dday == '3') {
Lcd_Out(1,1,"Tue");
}
else if (dday == '4') {
Lcd_Out(1,1,"Wed");
}
else if (dday == '5') {
Lcd_Out(1,1,"Thu");
}
else if (dday == '6') {
Lcd_Out(1,1,"Fri");
}
else if (dday == '7') {
Lcd_Out(1,1,"Sat");
}

ddate[0] = BCD2UpperCh(date);
ddate[1] = BCD2LowerCh(date);
ddate[2] = '/';
ddate[3] = BCD2UpperCh(month);
ddate[4] = BCD2LowerCh(month);
ddate[5] = '/';
ddate[6] = '2';
ddate[7] = '0';
ddate[8] = BCD2UpperCh(year);
ddate[9] = BCD2LowerCh(year);
ddate[10] = '\0';

if (hour1<0x12){
if (hour1==0){
hour1=0x12;
ampm= 'A';

}
else
ampm= 'A';
}

else if (hour1 == 0x12){
ampm= 'P';
}

else if (hour1>0x12 && hour1<0x20){
hour1=hour1-0x12;
ampm= 'P';
}

else if (hour1==0x20){
hour1=0x08;
ampm= 'P';
}

else if (hour1==0x21){
hour1=0x09;
ampm= 'P';
}

else if (hour1==0x22){
ampm= 'P';
hour1=0x10;
}

else if (hour1==0x23){
ampm= 'P';
hour1=0x11;
}

time1[0] = BCD2UpperCh(hour1);
time1[1] = BCD2LowerCh(hour1);
time1[2] = ':';
time1[3] = BCD2UpperCh(minute);
time1[4] = BCD2LowerCh(minute);
time1[5] = ':';
time1[6] = BCD2UpperCh(sec);
time1[7] = BCD2LowerCh(sec);
time1[8] = ' ';
time1[9] = ampm;
time1[10] = 'M';
time1[11] = '\0';

Lcd_Out(1,5,ddate);
Lcd_Out(2,1,time1);
Delay_ms(50);


hour1=hour;

}
}
//------------------------------Start of Display Time in 12 hr system Section------------------------------------------

}


unsigned short read_ds1307(unsigned short address)
{
I2C1_Start();
I2C1_Wr(0xd0); //address 0x68 followed by direction bit (0 for write, 1 for read) 0x68 followed by 0 --> 0xD0
I2C1_Wr(address);
I2C1_Repeated_Start();
I2C1_Wr(0xd1); //0x68 followed by 1 --> 0xD1
dataa=I2C1_Rd(0);
I2C1_Stop();
return(dataa);
}

unsigned char BCD2UpperCh(unsigned char bcd)
{
return ((bcd >> 4) + '0');
}

unsigned char BCD2LowerCh(unsigned char bcd)
{
return ((bcd & 0x0F) + '0');
}

void write_ds1307(unsigned short address,unsigned short w_data)
{
I2C1_Start(); // issue I2C start signal
//address 0x68 followed by direction bit (0 for write, 1 for read) 0x68 followed by 0 --> 0xD0
I2C1_Wr(0xD0); // send byte via I2C (device address + W)
I2C1_Wr(address); // send byte (address of DS1307 location)
I2C1_Wr(w_data); // send data (data to be written)
I2C1_Stop(); // issue I2C stop signal
}

[ATTACH=CONFIG]68366[/ATTACH][ATTACH=CONFIG]68366[/ATTACH]
 
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top