IIC總線特點(diǎn):
1. 二線傳輸;
2. 無中心主機(jī);
3. 軟件尋址;
4. 應(yīng)答式數(shù)據(jù)傳輸過程;
5. 節(jié)點(diǎn)可帶點(diǎn)接入或撤出;
6. IIC的SCL和SDA都需要接上拉電阻,保證空閑狀態(tài)的穩(wěn)定性;
數(shù)據(jù)傳輸過程:
由主機(jī)發(fā)出起始信號(hào)和停止信號(hào)。
起始信號(hào):當(dāng)SCL保持為高電平時(shí),SDA產(chǎn)生一個(gè)下降沿,則代表起始信號(hào);
停止信號(hào):當(dāng)SCL保持為高電平時(shí),SDA產(chǎn)生一個(gè)上升沿,則代表停止信號(hào);
數(shù)據(jù)傳輸:
??? ??? ??? ?SCL的下降沿后 ----> 發(fā)送方發(fā)送數(shù)據(jù)位;
??? ??? ??? ?SCL的上升沿后SDA總線數(shù)據(jù)穩(wěn)定 ----> 接收方接收數(shù)據(jù)位(因?yàn)樯仙睾?,SCL為高電平,SDA不能有任何電平跳變,只能接收數(shù)據(jù));
應(yīng)答信號(hào):發(fā)送方釋放SDA總線。若SDA保持低電平,代表接收方發(fā)送了一個(gè)應(yīng)答位并拉低了SDA總線;因?yàn)槟J(rèn)情況下,SDA為高電平。否則,代表接收方未應(yīng)答。
????????
?
注:IIC信號(hào)在數(shù)據(jù)傳送的過程中,當(dāng)SCL=1時(shí),數(shù)據(jù)線SDA必須保持穩(wěn)定狀態(tài),不允許有電平跳變,否則都會(huì)被為是總線的起始信號(hào)或者停止信號(hào)。只有在時(shí)鐘線上的信號(hào)為低電平期間,數(shù)據(jù)線上的電平狀態(tài)才允許變化,所以在代碼中會(huì)經(jīng)??吹?strong>對(duì)SCL引腳置0的操作。
代碼實(shí)現(xiàn)(通用):
- 主機(jī)發(fā)送數(shù)據(jù)
//主機(jī)向從機(jī)寫數(shù)據(jù)(一個(gè)字節(jié))
void IIC_Write_One_Byte(I2C_n i2cn,uint8_t daddr,uint8_t addr,uint8_t data)
{
IIC_Start(i2cn); //1.主機(jī)產(chǎn)生一個(gè)開始條件
IIC_Send_Byte(i2cn,daddr<<1); //2.主機(jī)發(fā)送從機(jī)地址和方向。前7位為從機(jī)地址,第8位表示方向:0表示知己發(fā)送數(shù)據(jù),1表示主機(jī)接收數(shù)據(jù)
IIC_Wait_Ack(i2cn);//等待接收方應(yīng)答
IIC_Send_Byte(i2cn,addr); //3.發(fā)送從機(jī)內(nèi)部寄存器地址
IIC_Wait_Ack(i2cn);
IIC_Send_Byte(i2cn,data); //4.發(fā)送數(shù)據(jù)字節(jié)
IIC_Wait_Ack(i2cn);
IIC_Stop(i2cn);//5.主機(jī)產(chǎn)生一個(gè)停止條件
DELAY_US(100);
}
- 主機(jī)接收數(shù)據(jù)
//主機(jī)從從機(jī)讀數(shù)據(jù)(一個(gè)字節(jié))
uint8_t IIC_Read_One_Byte(I2C_n i2cn,uint8_t daddr,uint8_t addr)
{
uint8_t temp=0;
IIC_Start(i2cn); //1.主機(jī)產(chǎn)生一個(gè)開始條件
IIC_Send_Byte(i2cn,daddr<<1);//2.主機(jī)發(fā)送從機(jī)地址和方向,暫時(shí)主機(jī)需要向從機(jī)發(fā)送從機(jī)內(nèi)部寄存器地址,所以最后一位任然是0
IIC_Wait_Ack(i2cn);
IIC_Send_Byte(i2cn,addr); //3.發(fā)送從機(jī)內(nèi)部寄存器地址
IIC_Wait_Ack(i2cn);
IIC_Start(i2cn);
IIC_Send_Byte(i2cn,(daddr<<1)|0x01); //4.前面主機(jī)需要發(fā)送的數(shù)據(jù)已經(jīng)發(fā)送完了,之后進(jìn)入接收模式,所以最后一位發(fā)送1
IIC_Wait_Ack(i2cn);
temp=IIC_Read_Byte(i2cn,0);
IIC_Stop(i2cn);//5.產(chǎn)生一個(gè)停止條件
return temp;
}
MSP430F5529的IIC配置:
- 基本過程
(官方文檔的Users Guide)
The recommended USCI initialization/reconfiguration process is:
-
Set UCSWRST (BIS.B #UCSWRST,&UCxCTL1). 設(shè)置UCSWRST位
-
Initialize all USCI registers with UCSWRST = 1. 在UCSWRST位為1的條件下,初始化其他寄存器
-
Configure ports. 配置引腳
-
Clear UCSWRST through software (BIC.B #UCSWRST,&UCxCTL1). 清除UCSWRST位
-
Enable interrupts (optional).使能中斷(可選)
- 代碼實(shí)現(xiàn)
void I2C_MasterInit(I2Cn i2cn,uint16_t SlaveID,uint32_t BaudRate)
{
WordType BR;
BR.Word=g_sClock.SMCLK.nHZ/BaudRate; //求取波特率所需的分頻系數(shù)
GPIO_Init(I2C_PIN[i2cn-I2C0].SCL.Port,I2C_PIN[i2cn-I2C0].SCL.Pin,GPO);
//輸出9個(gè)時(shí)鐘以恢復(fù)I2Cn總線狀態(tài)
for(uint8_t i=0;i<9;i++)
{
GPIO_WriteBit (I2C_PIN[i2cn-I2C0].SCL.Port,I2C_PIN[i2cn-I2C0].SCL.Pin, BIT_SET);
DELAY_US(5);
GPIO_WriteBit (I2C_PIN[i2cn-I2C0].SCL.Port,I2C_PIN[i2cn-I2C0].SCL.Pin,RESET);
DELAY_US(5);
}
//初始化引腳
//3. Configure ports.
GPIO_Init(I2C_PIN[i2cn-I2C0].SCL.Port,I2C_PIN[i2cn-I2C0].SCL.Pin,SEL);
GPIO_Init(I2C_PIN[i2cn-I2C0].SDA.Port,I2C_PIN[i2cn-I2C0].SDA.Pin,SEL);
//初始化寄存器
//1. Set UCSWRST (BIS.B #UCSWRST,&UCxCTL1).
USCIX[i2cn]->CTL1 = UCSWRST; // 軟件復(fù)位使能,保持復(fù)位狀態(tài)
//2. Initialize all USCI registers with UCSWRST = 1.
USCIX[i2cn]->CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C主機(jī),同步模式
if(SlaveID > 0x7F)
{
USCIX[i2cn]->SLA10 = BIT_SET; //10-bit address
}
else
{
USCIX[i2cn]->SLA10 = RESET; //7-bit address
}
USCIX[i2cn]->I2CSA = SlaveID; //從機(jī)地址寄存器 賦值
USCIX[i2cn]->CTL1 |= UCSSEL__SMCLK; //使用SMCLK作為時(shí)鐘源
USCIX[i2cn]->BR0 = BR.Byte[0];
USCIX[i2cn]->BR1 = BR.Byte[1];
//4. Clear UCSWRST through software (BIC.B #UCSWRST,&UCxCTL1).
USCIX[i2cn]->CTL1 &=~ UCSWRST; //清除軟件復(fù)位,正常操作
//5. Enable or disable interrupts (optional)
USCIX[i2cn]->IE = 0u; //關(guān)閉所有中斷
USCIX[i2cn]->RXIFG = RESET; //清除接收數(shù)據(jù)標(biāo)志
USCIX[i2cn]->TXIFG = BIT_SET; //置位發(fā)送緩沖區(qū)為空標(biāo)志
}
- 代碼解析
1、MSP430的I2C有一個(gè)BUSY位:
The bus busy bit, UCBBUSY, is set after a START and cleared after a STOP
BUSY位為1或者UCTCSTP位為1時(shí),代表I2C總線忙。
?
//代碼實(shí)現(xiàn)如下:
while((USCIX[i2cn]->UC_BUSY==BIT_SET) || (USCIX[i2cn]->TXSTP==BIT_SET));//確保總線空閑
//起始位發(fā)送:
inline void I2C_Start(I2Cn i2cn)
{
while((USCIX[i2cn]->UC_BUSY==BIT_SET) || (USCIX[i2cn]->TXSTP==BIT_SET));//確??偩€空閑
USCIX[i2cn]->TXSTT = BIT_SET;
}
//停止位發(fā)送:
inline void I2C_Stop(I2Cn i2cn)
{
while(USCIX[i2cn]->UC_BUSY == BIT_SET); //等待空閑
/*
TXSTP位是一個(gè)條件位,該條件在NACK之前:
當(dāng)該位為1時(shí),代表需要產(chǎn)生一個(gè)STOP位,在STOP產(chǎn)生后,會(huì)自動(dòng)清除該位。
于是就有了下面兩行代碼。
*/
USCIX[i2cn]->TXSTP =BIT_SET; //發(fā)送停止位
while(USCIX[i2cn]->TXSTP == BIT_SET); //等待停止位發(fā)送完成
}
/*******************************************************************************
* 函數(shù)名稱:I2C_WaitBusy(I2Cn i2cn)
* 功能說明:I2C等待空閑
* 參數(shù)說明:I2Cn i2cn :模塊號(hào)
* 函數(shù)返回:無
* 使用示例:I2C_WaitBusy(I2C1); //等待I2C1模塊不忙
********************************************************************************/
inline void I2C_WaitBusy(I2Cn i2cn)
{
while(USCIX[i2cn]->UC_BUSY == BIT_SET); //等待發(fā)送或接收完成
}
2、模式切換
inline void I2C_EnterSend (I2Cn i2cn)
{
USCIX[i2cn]->TR = BIT_SET; //進(jìn)入發(fā)送模式
}
inline void I2C_EnterRead (I2Cn i2cn)
{
USCIX[i2cn]->TR = RESET; //進(jìn)入接收模式
}
3、開發(fā)板內(nèi)部操作,并未涉及到主從之間的信息傳遞:發(fā)送/接收一字節(jié)
/*******************************************************************************
* 函數(shù)名稱:I2C_SendByte (I2Cn i2cn,uint8_t data)
* 功能說明:I2C發(fā)送一字節(jié)數(shù)據(jù)
* 參數(shù)說明:I2Cn i2cn :模塊號(hào)
uint8_t data :要發(fā)送的數(shù)據(jù)
* 函數(shù)返回:無
* 使用示例:I2C_SendByte (I2C1,0x01); //I2C1模塊發(fā)送一字節(jié)數(shù)據(jù)0x01
********************************************************************************/
inline void I2C_SendByte (I2Cn i2cn,uint8_t data)
{
/*
當(dāng)UCBxTXBUF寄存器為空時(shí),TXIFG位被置為1
*/
while(USCIX[i2cn]->TXIFG == RESET); //等待TXBUF為空
USCIX[i2cn]->TXBUF = data; //發(fā)送要寫入的數(shù)據(jù)
}
/*******************************************************************************
* 函數(shù)名稱:I2C_ReadByte (I2Cn i2cn)
* 功能說明:IIC讀取一個(gè)字節(jié)數(shù)據(jù)
* 參數(shù)說明:I2Cn i2cn :模塊號(hào)
* 函數(shù)返回:讀取到的數(shù)據(jù)
* 使用示例:uint8 data = I2C_ReadByte (I2C1); //讀取數(shù)據(jù)
********************************************************************************/
inline uint8_t I2C_ReadByte (I2Cn i2cn)
{
/*
當(dāng)UCBxRXBUF寄存器接收到一個(gè)完整的字節(jié)時(shí),RXIFG位被置為1
*/
while(USCIX[i2cn]->RXIFG == RESET); //等待接收到數(shù)據(jù)
return USCIX[i2cn]->RXBUF;
}
4、Data on SDA must be stable during the high period of SCL (see Figure 38-4). The high and low state of SDA can only change when SCL is low, otherwise START or STOP conditions are generated.
下面這種時(shí)序?qū)τ跀?shù)據(jù)傳輸過程才是安全的,即在SCL為高電平時(shí),SDA總線的電平不發(fā)生改變;數(shù)據(jù)的接收和發(fā)送(SDA的邊沿處)總是發(fā)生在SCL為低電平時(shí)。
?5、主從機(jī)之間通信
/*******************************************************************************
* 函數(shù)名稱: I2C_WriteReg(I2Cn i2cn, uint8_t address, char data)
* 功能說明: 往某一個(gè)地址寫入一字節(jié)數(shù)據(jù)
* 參數(shù)說明: I2Cn i2cn :模塊號(hào)
uint8_t address :寄存器地址
uint8_t data :對(duì)該地址要寫入的數(shù)據(jù)內(nèi)容
* 函數(shù)返回:無
* 使用示例:I2C_WriteReg(I2C1, 0x20, 0x12); //對(duì)地址為0x20處寫入內(nèi)容0x12
********************************************************************************/
void I2C_WriteReg(I2Cn i2cn, uint8_t address, uint8_t data)
{
I2C_EnterSend(i2cn);
I2C_Start (i2cn); //發(fā)送一個(gè)起始信號(hào)
I2C_SendByte (i2cn,address); //發(fā)送要寫入的地址
I2C_SendByte (i2cn,data); //發(fā)送要寫入的數(shù)據(jù)
I2C_Stop (i2cn); //發(fā)送停止位
I2C_WaitBusy (i2cn);
}
/*******************************************************************************
* 函數(shù)名稱: I2C_ReadReg(I2Cn i2cn, uint8_t address)
* 功能說明: 對(duì)外部芯片讀取某一地址的內(nèi)容
* 參數(shù)說明: I2Cn i2cn :模塊號(hào)
uint8_t address :寄存器地址
* 函數(shù)返回: 讀取到的內(nèi)容
* 使用示例: uint8_t data = I2C_ReadReg(I2C1, 0x20); //讀取寄存器地址為0x20處的內(nèi)容
********************************************************************************/
uint8_t I2C_ReadReg(I2Cn i2cn, uint8_t address)
{
I2C_EnterSend (i2cn); //進(jìn)入發(fā)送模式
I2C_Start (i2cn); //發(fā)送一個(gè)起始信號(hào)
I2C_SendByte (i2cn,address); //發(fā)送一字節(jié)數(shù)據(jù)
I2C_WaitBusy (i2cn); //等待傳輸完畢
I2C_EnterRead (i2cn); //進(jìn)入接收模式
I2C_Start (i2cn); //發(fā)送一個(gè)起始信號(hào)
I2C_WaitBusy (i2cn); //等待空閑
I2C_Stop (i2cn); //發(fā)送一個(gè)停止信號(hào),讀的話要先發(fā)送停止位
return I2C_ReadByte(i2cn); //讀取數(shù)據(jù)
}
/*
注:
1、對(duì)比這里的代碼和上面的通用代碼,就會(huì)發(fā)現(xiàn)這里少了發(fā)送從機(jī)地址的步驟,我沒有找到具體的描述文字,猜測(cè)應(yīng)該是將從機(jī)地址存入對(duì)應(yīng)的寄存器且指定模式(發(fā)送或接收模式)后,MSP430內(nèi)部有自動(dòng)找到正確從機(jī)的機(jī)制。
2、跟通用代碼還有個(gè)不一樣的點(diǎn),就是MSP430的I2C數(shù)據(jù)接收是在發(fā)送STOP位之后。官方文檔中有這么一句:If UCBxRXBUF is not read, the master holds the bus during reception of the last data bit and until the UCBxRXBUF is read. 猜測(cè)大概意思是,RXBUF中的數(shù)據(jù)如果沒有被讀出去的話,主機(jī)應(yīng)該會(huì)保持SCL總線的電平,直到數(shù)據(jù)被讀取。
*/
?6、連續(xù)寫/讀文章來源:http://www.zghlxwxcb.cn/news/detail-648491.html
//IIC主機(jī)連續(xù)寫
//i2cn:IIC模塊號(hào)
//reg:寄存器地址
//len:寫入長度
//buf:數(shù)據(jù)區(qū)
//返回值:0,正常
// 其他,錯(cuò)誤代碼
char I2C_Write_Len(I2Cn i2cn,uint8_t reg,uint8_t len,uint8_t *buf)
{
uint8_t i;
I2C_EnterSend (i2cn);
I2C_Start(i2cn);
I2C_SendByte(i2cn,reg); //寫寄存器地址
I2C_WaitBusy(i2cn); //等待應(yīng)答
for(i=0;i<len;i++)
{
I2C_SendByte(i2cn,buf[i]); //發(fā)送數(shù)據(jù)
I2C_WaitBusy(i2cn);
}
I2C_Stop(i2cn);
return 0;
}
//IIC主機(jī)連續(xù)讀
//i2cn:IIC模塊號(hào)
//reg:要讀取的寄存器地址
//len:要讀取的長度
//buf:讀取到的數(shù)據(jù)存儲(chǔ)區(qū)
//返回值:0,正常
// 其他,錯(cuò)誤代碼
uint8_t I2C_Read_Len(I2Cn i2cn,uint8_t reg,uint8_t len,uint8_t *buf)
{
I2C_EnterSend (i2cn);
I2C_Start(i2cn);
I2C_SendByte(i2cn,reg); //寫寄存器地址
I2C_WaitBusy(i2cn); //等待應(yīng)答
I2C_EnterRead (i2cn);
I2C_Start(i2cn);
while(len)
{
if(len==1)*buf=I2C_ReadByte(i2cn);//讀數(shù)據(jù),發(fā)送nACK
else *buf=I2C_ReadByte(i2cn); //讀數(shù)據(jù),發(fā)送ACK
len--;
buf++;
}
I2C_Stop(i2cn); //產(chǎn)生一個(gè)停止條件
return 0;
}
7、其他文章來源地址http://www.zghlxwxcb.cn/news/detail-648491.html
/*******************************************************************************
* 函數(shù)名稱: I2C_ITConfig (I2Cn i2cn,I2C_IRQn irqn,STATUS ITState)
* 功能說明: 設(shè)置使能或禁止I2Cn的某一個(gè)中斷
* 參數(shù)說明: I2Cn i2cn :模塊號(hào)
I2C_IRQn irqn :中斷類型
* 函數(shù)返回:無
* 使用示例:I2C_ITConfig (I2C1,I2C_RX_IRQn,ENABLE); //使能I2C1的接收中斷
********************************************************************************/
void I2C_ITConfig (I2Cn i2cn,I2C_IRQn irqn,STATUS ITState)
{
if(ITState != DISABLE)
{
USCIX[i2cn]->IE |= irqn;
}
else
{
USCIX[i2cn]->IE &=~irqn;
}
}
/*******************************************************************************
* 函數(shù)名稱: I2C_GetITStatus(I2Cn i2cn,I2C_IRQn irqn)
* 功能說明: 獲取I2C的某一個(gè)中斷標(biāo)志
* 參數(shù)說明: I2Cn i2cn :模塊號(hào)
I2C_IRQn irqn :中斷類型
* 函數(shù)返回: STATUS : TRUE 中斷事件發(fā)生,F(xiàn)ALSE 中斷事件未發(fā)生
* 使用示例: if(TRUE == I2C_GetITStatus(I2C0,I2C_RX_IRQn)){...} //判斷I2C0模塊是否接收完成事件中斷發(fā)生
********************************************************************************/
STATUS I2C_GetITStatus(I2Cn i2cn,I2C_IRQn irqn)
{
return ((USCIX[i2cn]->IFG & irqn) ? TRUE :FALSE);
}
/*******************************************************************************
* 函數(shù)名稱: I2C_ClearITPendingBit(I2Cn i2cn,I2C_IRQn irqn)
* 功能說明: 清除I2Cn的某一個(gè)中斷標(biāo)志
* 參數(shù)說明: I2Cn i2cn :模塊號(hào)
I2C_IRQn irqn :中斷類型
* 函數(shù)返回: 無
* 使用示例: I2C_ClearITPendingBit(I2C0,I2C_RX_IRQn); //清除I2C1模塊接收中斷標(biāo)志位
********************************************************************************/
void I2C_ClearITPendingBit(I2Cn i2cn,I2C_IRQn irqn)
{
USCIX[i2cn]->IFG &=~ irqn;
}
到了這里,關(guān)于I2C用法和MSP430F5299上的I2C的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!