Tiếp theo là về module I2C, một chuẩn giao tiếp quan trọng khi giao tiếp với ngoại vi như EEPROM, RTS(DS1307),...
Do đó, mình xin cung cấp cho các bạn các hàm và thực thi của các hàm này trên HTPIC. Mình có tham khảo cả ở bọn htsoft nhưng nó viết sai một số hàm không chạy được, mình đã viết lại toàn bộ.
Đầu tiên là hàm I2C.h:
Code:
//I2C.h
//Declare some functions
void I2C_Init(void); // khởi tạo I2C ở chế độ Master, Baud = 100 Khz
void I2C_waitForIdle(void); // Chờ khi nào đường bus ở chế độ Idle (rảnh rỗi)
void I2C_Start(void); // Khởi động I2C - Master chiếm đường bus
void I2C_repStart(void); // Chế độ Restart
void I2C_stop(void); // Stop I2C - Master nhường đường bus cho thiết bị khác
unsigned char I2C_write( unsigned char I2CWriteData ); // ghi một byte lên đường SDA
unsigned char I2C_read( unsigned char ack ); // Đọc một byte với mã ACK (ACK = 0 nếu ack = 1, và ACK = 1 nếu ack = 0) -> dùng xác nhận từ master đối với slave.
void I2C_NACK(void); // tạo bít Not Ack
Và sau đây là thực thi của các hàm này:
Code:
// I2C.c
# include "pic.h"
# include "I2C.h"
//======================================================================================================
void I2C_Init(void){
/* // Configure for Master Mode
SSPM3 = 1;
SSPM2 = 0;
SSPM1 = 0;
SSPM0 = 0; ss // I2C Master Mode, clock = Fosc/(4*(SSPADD + 1));
WCOL = 0; //No conllision
SSPEN = 1; // Enables the serial port and
*/
SSPCON = 0b00101000; // set IIC port to Master mode with BRG
SSPSTAT = 0b00000000; // Standard speed mode - 100Hz
SSPCON2 = 0;
//TRIS_SCL = 0;
//TRIS_SDA = 0; // configure SDA and SCL as Output
SSPADD = 9; // BAUD = 100KHz
SSPIF = 0; // clear SSPIF interrupt flag
BCLIF = 0; // clear bus collision flag
STAT_CKE = 0; // use I2C levels worked also with '0'
STAT_SMP = 1; // disable slew rate control worked also with '0'
}
//=============================================================================
void I2C_waitForIdle(void)
{
while (( SSPCON2 & 0x1F ) | STAT_RW) ; //CLRWDT(); // wait for idle and not writing
}
//=============================================================================
void I2C_Start(void){
//SSPIF = 0;
SEN = 1;
//while(!SSPIF);
while(SEN);
}
//==============================================================================
void I2C_repStart(void)
{
I2C_waitForIdle();
RSEN = 1;
}
//=============================================================================
void I2C_stop(void)
{
I2C_waitForIdle();
PEN = 1;
}
//==============================================================================
unsigned char I2C_write( unsigned char I2CWriteData ){
I2C_waitForIdle();
SSPBUF = I2CWriteData;
I2C_waitForIdle();
return (!ACKSTAT); // function returns '1' if transmission is acknowledged
// 1: Success
// 0: Fail to send
}
//============================================================================
unsigned char I2C_read( unsigned char ack ){
unsigned char I2C_ReadData;
I2C_waitForIdle();
RCEN = 1;
I2C_waitForIdle();
I2C_ReadData = SSPBUF;
I2C_waitForIdle();
if ( ack ) ACKDT=0;
else ACKDT = 1;
ACKEN = 1; // send acknowledge sequence
I2C_waitForIdle();
return( I2C_ReadData );
}
/******************************************************************************************/
void I2C_NACK(void)
{
I2C_waitForIdle();
if (ACKSTAT){
PEN=1; //Stop
I2C_waitForIdle(); //Wait until action is finished
while(PEN);
};
}
Còn việc dùng nó quá đơn giản, ví dụ với Ds1307 thì đầu tiên bạn phải:
- Khởi tạo I2C bằng
I2C_Start();
- Start bằng
I2C_Start();
- Chọn slave giao tiếp bằng cách ghi địa chỉ và bit RW tương ứng với chế độ đọc hay ghi.
- Ghi dữ liệu lựa chọn byte nào cần ghi hay cần đọc trong bảng RAM của DS1307.
- Ghi dữ liệu hay là đọc dữ liệu.
Chú ý: khi ghi xong, muốn đọc thì phải làm lại tức là phải restart nhé.
Chúc các bạn thành công.