1 |   //***************************************************************************** |
2 |   // |
3 |   //  File  Name    :  'i2c.c' |
4 |   //  Title                :  Itronove  hodiny  |
5 |   #define  __PIC18F8720A__ |
6 |   //  Author              :  http://www.prochazka.zde.cz  -&rsaquo   hacesoft  2017 |
7 |   //  Created            :  30-06-2017,  11:58 |
8 |   //  Revised            :  04-07-2017,  08:52 |
9 |   //  Version            :  1.3 |
10 |   //  Target  MCU   :  PIC  18F8720 |
11 |   // |
12 |   //  This  code  is  distributed  under  the  GNU  Public  License |
13 |   //  Vsechny  informace  jsou  zahrnuty  pod  GPL  licenci,  pokud  není  explicitne  uveden  jiný  typ  licence. |
14 |   //  Pouzivání  techto  stránek  ke  komercním  úcelum  lze  jen  se  souhlasem  autora. |
15 |   //  Vsechna  práva  vyhrazena  (c)  1997  -  2017  hacesoft. |
16 |   // |
17 |   //***************************************************************************** |
18 |   |
19 |   #include &lsaquo xc.h&rsaquo |
20 |   #include &lsaquo stdint.h&rsaquo   //uint8_t,  uint16_t,  uint32_t |
21 |   #include  "i2c.h" |
22 |   |
23 |   //***************************************************************************** |
24 |   void  I2C_Start(uint8_t  type){ |
25 |        if  (type  ==  _SW){I2C_StartMasterSW();} |
26 |        else  i2c_Start(); |
27 |   } |
28 |   //***************************************************************************** |
29 |   void  I2C_StartMasterSW(void){ |
30 |        i2c_WaitGeneral(); |
31 |           SDA_MasterSW  =  1;              //  Pull  SDA  High |
32 |        __delay_us(_wt_speed_i2c_Master); |
33 |        SCL_MasterSW  =  1;      //  Pull  SCL  High |
34 |           __delay_us(_wt_speed_i2c_Master); |
35 |           SDA_MasterSW  =  0;              //  Pull  SDA  Low |
36 |           __delay_us(_wt_speed_i2c_Master); |
37 |        SCL_MasterSW  =  0; |
38 |        i2c_WaitGeneral(); |
39 |   } |
40 |   //***************************************************************************** |
41 |   //  i2c_Start  -  Start  I2C  communication |
42 |   void  i2c_Start(void){ |
43 |        GIE  =  0;         //  Global  interrupt  stop |
44 |        i2c_WaitGeneral(); |
45 |        I2C_HW_Wait(); |
46 |        SEN=1; |
47 |        i2c_WaitGeneral(); |
48 |   } |
49 |   //***************************************************************************** |
50 |   //  i2c_Start  -  Start  I2C  communication |
51 |   void  I2C_Start_PCA955PW(void){ |
52 |        GIE  =  0;         //  Global  interrupt  stop |
53 |        i2c_WaitGeneral_PCA955PW(); |
54 |        I2C_HW_Wait_PCA955PW(); |
55 |        SEN=1; |
56 |        i2c_WaitGeneral_PCA955PW(); |
57 |   } |
58 |   //***************************************************************************** |
59 |   void  I2C_Stop(uint8_t  type){ |
60 |        if  (type  ==  _SW){I2C_StopMasterSW();} |
61 |        else  i2c_Stop(); |
62 |   } |
63 |   //***************************************************************************** |
64 |   void  I2C_StopMasterSW(void){ |
65 |        i2c_WaitGeneral(); |
66 |        SCL_MasterSW  =  1; |
67 |           __delay_us(_wt_speed_i2c_Master); |
68 |           SDA_MasterSW  =  1;          |
69 |           i2c_WaitGeneral(); |
70 |   } |
71 |   //***************************************************************************** |
72 |   //  i2c_Stop  -  Stop  I2C  communication |
73 |   void  i2c_Stop(void){ |
74 |        i2c_WaitGeneral(); |
75 |        I2C_HW_Wait(); |
76 |        PEN=1; |
77 |        i2c_WaitGeneral(); |
78 |        GIE  =  1;         //  Global  interrupt  enable |
79 |   } |
80 |   //***************************************************************************** |
81 |   //  i2c_Stop  -  Stop  I2C  communication |
82 |   void  I2C_Stop_PCA955PW(void){ |
83 |        i2c_WaitGeneral_PCA955PW(); |
84 |        I2C_HW_Wait_PCA955PW(); |
85 |        PEN=1; |
86 |        i2c_WaitGeneral_PCA955PW(); |
87 |        GIE  =  1;         //  Global  interrupt  enable |
88 |   } |
89 |   //***************************************************************************** |
90 |   void  I2C_Write(uint8_t  type,  unsigned  char  data){ |
91 |        if  (type  ==  _SW){I2C_WriteMasterSW(data);} |
92 |        else  i2c_Write(data); |
93 |   } |
94 |   //***************************************************************************** |
95 |   void  I2C_WriteMasterSW(unsigned  char  data){ |
96 |           uint8_t  i; |
97 |           uint8_t  SdaBuffer; |
98 |           |
99 |           for(i=0;i&lsaquo 8;i++){                                          //  loop  8  times  to  send  1-byte  of  data |
100 |            i2c_WaitGeneral(); |
101 |                   SdaBuffer  =  data  &  (unsigned)  0x80;                    //  Send  Bit  by  Bit  on  SDA  line |
102 |                if  (SdaBuffer  ==  0x80){SDA_MasterSW  =  1;} |
103 |                else  {SDA_MasterSW  =  0;}  |
104 |                   I2C_ClockMasterSW();                    //  Generate  Clock  at  SCL |
105 |                   data  =  (unsigned)  data &lsaquo &lsaquo   1; |
106 |           } |
107 |        i2c_WaitGeneral(); |
108 |        SDA_MasterSW  =  1;                          //  Set  SDA  at  last |
109 |        i2c_WaitGeneral(); |
110 |        I2C_AckNowLedgeMasterSW(); |
111 |   } |
112 |   //***************************************************************************** |
113 |   //  i2c_Write  -  Sends  one  byte  of  data |
114 |   void  i2c_Write(unsigned  char  data){ |
115 |        I2C_HW_Wait(); |
116 |        SSPBUF  =  data; |
117 |        i2c_WaitGeneral(); |
118 |   } |
119 |   //***************************************************************************** |
120 |   //  i2c_Write  -  Sends  one  byte  of  data |
121 |   void  I2C_Write_PCA955PW(unsigned  char  data){ |
122 |        I2C_HW_Wait_PCA955PW(); |
123 |        SSPBUF  =  data; |
124 |        i2c_WaitGeneral_PCA955PW(); |
125 |   } |
126 |   //***************************************************************************** |
127 |   //  i2c_Address  -  Sends  Slave  Address  and  Read/Write  mode |
128 |   //  mode  is  either  I2C_WRITE  or  I2C_READ |
129 |   void  i2c_Address(unsigned  char  address,  unsigned  char  mode){ |
130 |        unsigned  char  l_address; |
131 |   |
132 |        l_address  =  (unsigned)  address &lsaquo &lsaquo   1; |
133 |        l_address+=mode; |
134 |        I2C_HW_Wait(); |
135 |        SSPBUF  =  l_address; |
136 |        i2c_WaitGeneral(); |
137 |   } |
138 |   //***************************************************************************** |
139 |   unsigned  char  I2C_Read(uint8_t  type,  unsigned  char  ack){ |
140 |        unsigned  char  nBuffer; |
141 |        |
142 |        if  (type  ==  _SW){  nBuffer  =  I2C_ReadMasterSW();} |
143 |        else  nBuffer  =  i2c_Read(ack); |
144 |       return  nBuffer; |
145 |   } |
146 |   //***************************************************************************** |
147 |   //I2C_Read() |
148 |   //I/P  Arguments:  none |
149 |   //Return  value  :  Unsigned  char(received  byte) |
150 |   //Description  :This  fun  is  used  to  receive  a  byte  on  SDA  line  using  I2C  protocol. |
151 |   //8bit  data  is  received  bit-by-bit  each  clock  and  finally  packed  into  Byte. |
152 |   //MSB(bit)  is  received  first  and  LSB(bit)  is  received  at  last. |
153 |   //I2C  read.png |
154 |   unsigned  char  I2C_ReadMasterSW(void){ |
155 |           unsigned  char  i  =  0;  |
156 |        unsigned  char  nBuffer  =  0x00; |
157 |           |
158 |           SDA_MasterSW  =  1;                    //Make  SDA  as  I/P |
159 |           for(i=0;i&lsaquo 8;i++){                     //  loop  8times  to  read  1-byte  of  data |
160 |                   i2c_WaitGeneral(); |
161 |             SCL_MasterSW  =  1;                //Pull  SCL  High |
162 |            i2c_WaitGeneral(); |
163 |                   nBuffer  =  (unsigned)nBuffer &lsaquo &lsaquo   1;         //dat  is  Shifted  each  time  and |
164 |                   nBuffer  =  (unsigned)nBuffer  |  SDA_MasterSW;          //ORed  with  the  received  bit  to  pack  into  byte |
165 |                   //dat  =  dat  |  (PIND,  SDAbit);   //ORed  with  the  received  bit  to  pack  into  byte |
166 |                   SCL_MasterSW  =  0;                 //  Clear  SCL  to  complete  the  Clock |
167 |            i2c_WaitGeneral(); |
168 |           } |
169 |           return  (nBuffer);                          //  Finally  return  the  received  Byte* |
170 |   } |
171 |   //***************************************************************************** |
172 |   //  i2c_Read  -  Reads  a  byte  from  Slave  device |
173 |   unsigned  char  i2c_Read(unsigned  char  ack){ |
174 |        //  Read  data  from  slave |
175 |        //  ack  should  be  1  if  there  is  going  to  be  more  data  read |
176 |        //  ack  should  be  0  if  this  is  the  last  byte  of  data  read |
177 |        //  ack  nastavit  na  1  v  p?ípad?,  ?e  se  ma  cist  vice  dat  ... |
178 |        //  ack  nastavit  na  0,  pokud  se  jedna  o  posledni  bajt  ... |
179 |        unsigned  char  i2cReadData; |
180 |   |
181 |        I2C_HW_Wait(); |
182 |        RCEN=1; |
183 |        I2C_HW_Wait(); |
184 |        i2cReadData  =  SSPBUF; |
185 |        I2C_HW_Wait(); |
186 |        if  (  ack  )  ACKDT=0;          //  Ack |
187 |        else        ACKDT=1;          //  NAck |
188 |        ACKEN=1;                     //  send  acknowledge  sequence |
189 |        return(  i2cReadData  ); |
190 |   } |
191 |   //***************************************************************************** |
192 |   //  i2c_Read  -  Reads  a  byte  from  Slave  device |
193 |   unsigned  char  I2C_Read_PCA955PW(unsigned  char  ack){ |
194 |        //  Read  data  from  slave |
195 |        //  ack  should  be  1  if  there  is  going  to  be  more  data  read |
196 |        //  ack  should  be  0  if  this  is  the  last  byte  of  data  read |
197 |        //  ack  nastavit  na  1  v  p?ípad?,  ?e  se  ma  cist  vice  dat  ... |
198 |        //  ack  nastavit  na  0,  pokud  se  jedna  o  posledni  bajt  ... |
199 |        unsigned  char  i2cReadData; |
200 |   |
201 |        I2C_HW_Wait_PCA955PW(); |
202 |        RCEN=1; |
203 |        I2C_HW_Wait_PCA955PW(); |
204 |        i2cReadData  =  SSPBUF; |
205 |        I2C_HW_Wait_PCA955PW(); |
206 |        if  (  ack  )  ACKDT=0;          //  Ack |
207 |        else        ACKDT=1;          //  NAck |
208 |        ACKEN=1;                     //  send  acknowledge  sequence |
209 |        return(  i2cReadData  ); |
210 |   } |
211 |   //***************************************************************************** |
212 |   void  i2c_Ack_HW(unsigned  char  ack){ |
213 |        i2c_WaitGeneral(); |
214 |        if  (  ack  )  ACKDT=0;          //  Ack |
215 |        else        ACKDT=1;          //  NAck |
216 |        I2C_HW_Wait(); |
217 |        ACKEN=1;                     //  send  acknowledge  sequence |
218 |        i2c_WaitGeneral(); |
219 |   } |
220 |   //***************************************************************************** |
221 |   void  I2C_AckNowLedgeMasterSW(void){ |
222 |        //i2c_WaitGeneral(); |
223 |           ////__delay_us(_wt_speed_i2c_Master);      //  Wait  for  Some  time |
224 |           SCL_MasterSW  =  1;  |
225 |           __delay_us(_wt_speed_i2c_Master);              //  Wait  for  Some  time |
226 |           SCL_MasterSW  =  0; |
227 |        //i2c_WaitGeneral(); |
228 |        __delay_us(_wt_speed_i2c_Master); |
229 |   } |
230 |   //***************************************************************************** |
231 |   void  I2C_ReStart(uint8_t  type){ |
232 |        if  (type  ==  _SW){  I2C_ReStartMasterSW();} |
233 |        else  i2c_Restart();  |
234 |   } |
235 |   //***************************************************************************** |
236 |   void  I2C_ReStartMasterSW  (void){ |
237 |        //i2c_WaitGeneral(); |
238 |        __delay_us(_wt_speed_i2c_Master); |
239 |        SDA_MasterSW  =  1; |
240 |        SCL_MasterSW  =  0; |
241 |        __delay_us(_wt_speed_i2c_Master); |
242 |        SCL_MasterSW  =  1; |
243 |        __delay_us(_wt_speed_i2c_Master); |
244 |        SDA_MasterSW  =  0; |
245 |        __delay_us(_wt_speed_i2c_Master); |
246 |        SCL_MasterSW  =  0; |
247 |        __delay_us(_wt_speed_i2c_Master); |
248 |   } |
249 |   //***************************************************************************** |
250 |   //  i2c_Restart  -  Re-Start  I2C  communication |
251 |   void  i2c_Restart(void){ |
252 |        i2c_WaitGeneral(); |
253 |        I2C_HW_Wait(); |
254 |        RSEN=1; |
255 |        i2c_WaitGeneral(); |
256 |   } |
257 |   //***************************************************************************** |
258 |   //  i2c_Restart  -  Re-Start  I2C  communication |
259 |   void  I2C_ReStart_PCA955PW(void){ |
260 |        i2c_WaitGeneral_PCA955PW(); |
261 |        I2C_HW_Wait_PCA955PW(); |
262 |        RSEN=1; |
263 |        i2c_WaitGeneral_PCA955PW(); |
264 |   } |
265 |   //***************************************************************************** |
266 |   //  i2c_Wait  -  wait  for  I2C  transfer  to  finish |
267 |   void  I2C_HW_Wait_PCA955PW(void){ |
268 |        __delay_ms(2); |
269 |        while  ((SSPSTAT  &  0x04)  ||  (SSPCON2  &  0x1F));  //Transmit  is  in  progress |
270 |   } |
271 |   //***************************************************************************** |
272 |   void  i2c_WaitGeneral_PCA955PW(void){ |
273 |        __delay_us(_wt_speed_i2c_Master  *  2); |
274 |   } |
275 |   //***************************************************************************** |
276 |   //  i2c_Wait  -  wait  for  I2C  transfer  to  finish |
277 |   void  I2C_HW_Wait(void){ |
278 |        __delay_ms(2); |
279 |        while  ((SSPSTAT  &  0x04)  ||  (SSPCON2  &  0x1F));  //Transmit  is  in  progress |
280 |   |
281 |   } |
282 |   //***************************************************************************** |
283 |   void  i2c_WaitGeneral(void){ |
284 |        __delay_us(_wt_speed_i2c_Master  *  2); |
285 |   } |
286 |   //***************************************************************************** |
287 |   void  I2C_ClockMasterSW(void){ |
288 |        SCL_MasterSW  =  0;  |
289 |           __delay_us(_wt_speed_i2c_Master);              //  Wait  for  Some  time |
290 |           SCL_MasterSW  =  1;   |
291 |           __delay_us(_wt_speed_i2c_Master);              //  Wait  for  Some  time |
292 |           SCL_MasterSW  =  0;  |
293 |        __delay_us(_wt_speed_i2c_Master);      //  Wait  for  Some  time |
294 |   } |
295 |   //***************************************************************************** |
296 |   void  InitMasterPort(uint8_t  type){ |
297 |        if  (type  ==  _SW){  InitMasterSwPort();} |
298 |        else  InitMasterHwPort();  |
299 |   } |
300 |   //***************************************************************************** |
301 |   |
302 |   void  InitMasterSwPort(void){ |
303 |        BitClear  (PORTB,SCL_MasterSW_PIN); |
304 |        BitClear  (PORTB,SDA_MasterSW_PIN); |
305 |        BitClear  (LATB,SCL_MasterSW_PIN); |
306 |        BitClear  (LATB,SDA_MasterSW_PIN); |
307 |        SDAt_MasterSW  =  Output;                    //  SDA  Output                |
308 |        SCLt_MasterSW  =  Output;                    //  SCL  Output                |
309 |        SDA_MasterSW   =  1; |
310 |        SCL_MasterSW   =  1; |
311 |   } |
312 |   //***************************************************************************** |
313 |   void  InitMasterHwPort(void){ |
314 |       BitClear  (PORTC,SCL_MasterHW_PIN); |
315 |       BitClear  (PORTC,SDA_MasterHW_PIN); |
316 |       BitClear  (LATC,SCL_MasterHW_PIN); |
317 |       BitClear  (LATC,SDA_MasterHW_PIN); |
318 |       |
319 |       SCLt_MasterHW  =  Input;                            //  SCL  Input      |
320 |       SDAt_MasterHW  =  Input;                            //  SDA  Input      |
321 |   |
322 |       SSPCON1  =  0b00101000;         //  I2C  enabled,  Master  mode |
323 |       SSPCON2  =  0x00; |
324 |       SSPADD  =  254;            //  100kHz  bus  with  20Mhz  xtal |
325 |   |
326 |   } |