?? i2c.c
字號:
/*********************************************************************************************************
**文件名稱:I2CINT.c
**功能說明:硬件I2C中斷方式軟件包。
**使用說明:軟件包采用中斷方式進行操作。
********************************************************************************************************/
#include "config1.h"
/*定義用于和I2C中斷傳送信息的全局變量*/
volatile uint8 slarv; //子地址接收標志,為1時表示已接收從機子地址
volatile uint32 adrpoint; //定義從機緩沖區讀寫操作指針
volatile uint8 I2C_n; //I2C器件順序號
volatile uint8 I2C_sla; //I2C器件從地址
volatile uint32 I2C_suba; //I2C器件的內部子地址
volatile uint8 I2C_suba_num; //I2C子地址字節數
volatile uint8 *I2C_buf; //I2C數據緩沖區指針,
//如果要將I2C接口設置為從機模式,
//那么,在調用軟件包前要設置I2C數據緩沖區指針 I2C_buf
volatile uint32 I2C_num; //要讀取/寫入的數據個數
volatile uint8 I2C_end; //I2C總線結束標志:結束總線時置1
volatile uint8 I2C_suba_en; /* 子地址控制
0-子地址已經處理或者不需要子地址
1-讀取操作
2-寫操作
*/
/*********************************************************************************************************
**函數名稱:IRQ_I2C()
**函數功能:硬件I2C服務程序
**入口參數:無
**出口參數:無
**說明:注意處理子地址為2字節的情況
********************************************************************************************************/
void IRQ_I2C(void)
{
/* 讀取I2C狀態寄存器I2STAT
按照全局變量的設置進行操作及設置軟件標志
清除中斷邏輯,中斷返回
*/
uint8 stat; //用來讀取I2C狀態寄存器I2STAT
stat = *((volatile uint32 *)(&I2C0STAT) + (I2C_n*0x10000)); //讀取I2STAT,I2STAT=0xE001C004
switch(stat & 0xF8)
{
/*根據狀態碼進行相應的處理*/
case 0x08: /*已發送起始條件*/ //主發送和主接收都有
/*裝入SLA+W或者SLA+R*/
if(I2C_suba_en == 1) /*SLA+R*/ //指定子地址讀
{
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = I2C_sla &0xfe; //先寫入地址
}
else /*SLA+W*/
{
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = I2C_sla &0xfe; //直接發送從機地址
}
/*清零SI位*/
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = (1<<3)| //SI
(1<<5); //STA
break;
case 0x10: /*已發送重復起始條件*/ //主發送和主接收都有
/*裝入SLA+W或者SLA+R*/
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = I2C_sla; //重起總線后,重發從地址
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000))= 0x28; //清零SI,STA
break;
case 0x18:
case 0x28: /*已發送I2DAT中的數據,已接收ACK*/
if(I2C_suba_en == 0)
{
if(I2C_num > 0) //如果還有數據需要讀取
{
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = *I2C_buf++; //讀取數據
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28; //清零SI,STA
I2C_num--; //字節數減1
}
else /*沒有數據發送了*/
{
/*停止總線*/
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = (1<<4); //STO
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28; //清零SI,STA
I2C_end = 1; //總線已經停止
}
}
if(I2C_suba_en == 1) /*若是指定地址讀,則重新啟動總線*/
{
if(I2C_suba_num == 2) //如果是雙字節子地址
{
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = ((I2C_suba>>8) & 0xff); //先發送地址字節
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28; //清零SI,STA
I2C_suba_num--; //子地址字節數減1
break;
}
if(I2C_suba_num == 1) //如果是雙字節子地址
{
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = (I2C_suba & 0xff); //發送子地址低字節或單字節子地址
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28; //清零SI,STA
I2C_suba_num--;
break;
}
if(I2C_suba_num == 0)
{
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x08; //清零SI
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x20; //置位STA
I2C_suba_en = 0; //子地址已經處理
break;
}
}
if(I2C_suba_en == 2) /*指定子地址寫,子地址尚未指定,則發送子地址*/
{
if(I2C_suba_num > 0)
{
if(I2C_suba_num == 2) //如果是雙字節子地址
{
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) =((I2C_suba>>8) & 0xff); //先發送子地址高字節
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) =0x28; //清零SI,STA
I2C_suba_num--; //子地址字節數減1
break;
}
if(I2C_suba_num == 1) //如果是雙字節子地址
{
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) =(I2C_suba & 0xff); //發送子地址低字節或單字節子地址
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) =0x28; //清零SI,STA
I2C_suba_num--;
I2C_suba_en = 0;
break;
}
}
}
break;
case 0x40: /*已發送SLA+R,已接收ACK*/
if(I2C_num <= 1) /*如果是最后一個字節*/
{
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) =1<<2; //下次發送非應答信號
}
else
{
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 1<<2; //下次發送應答信號
}
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28; //清零SI,SLA
break;
case 0x20: /*已發送SLA+W,已接收非應答*/
case 0x30: /*已發送I2DAT中的數據,已接收非應答*/
case 0x38: /*在SLA+R/W或數據字節中丟失仲裁*/
case 0x48: /*已發送SLA+R,已接收非應答*/
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;
I2C_end = 0xff; //總線出錯
break;
case 0x50: /*已接收數據字節,已返回ACK*/
*I2C_buf++ = *((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000));
I2C_num--;
if(I2C_num == 1) /*接收最后一個字節*/
{
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x2c; //STA,SI,AA=0
}
else
{
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04; //AA=1
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;
}
break;
case 0x58: /*已接收數據字節,已返回非應答*/
*I2C_buf++ = *((volatile uint32 *)(&I2DAT) + ((I2C_n*0x40000)/4)); //讀取最后一字節數據
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x10; //結束總線
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x28;
I2C_end = 1;
break;
/////////以下為從機模式所對應的狀態信息/////////
case 0x60: //接收到自身SLA+W
case 0x68:
slarv = 0;
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x38; //清除I2C標志位,STA、STO、SI
break;
case 0xa8: //接收到SLA+R,或已經發送數據并接收到ACK位
case 0xb0:
case 0xb8:
*((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000)) = *(I2C_buf+adrpoint); //將對應地址處的數據放入I2DAT中
adrpoint++;
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x38; //清除I2C標志位,STA、STO、SI
break;
case 0x80: //接收到數據
if(slarv==0)
{
adrpoint = *((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000));
slarv = 1;
}
else
{
*(I2C_buf+adrpoint) = *((volatile uint32 *)(&I2DAT) + (I2C_n*0x10000));
adrpoint++;
}
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x38; //清除I2C標志位,STA、STO、SI
break;
case 0xc0: //總線結束,或總線重新啟動
default: //其它狀態
*((volatile uint32 *)(&I2CONSET) + (I2C_n*0x10000)) = 0x04;
*((volatile uint32 *)(&I2CONCLR) + (I2C_n*0x10000)) = 0x38; //清除I2C標志位,STA、STO、SI
break;
}
VICVectAddr = 0x00; //中斷處理結束
}
/*********************************************************************************************************
**函數名稱:uint8 I2C_Init(uint8 n,uint8 MODE,uint32 Fi2c,uint8 Adr,uint8 slot)
**函數功能:初始化I2C接口
**入口參數:n :I2C接口號,0--I2C0,1--I2C1
** MODE :工作模式,0--從模式,1--主模式
** Fi2c :I2C通信速率,0~400K,如果超過400K,則會強制設置為400KHz,如果設置為從機,該參數無效
** Adr :當設置為從模式時,Adr表示從地址,在主模式下,該參數是無效的,可以任意設置
** slot :由于I2C采用IRQ中斷方式,所以需要指定對應的通道,0~15
**出口參數:1--接口初始化成功,0--接口初始化失敗
********************************************************************************************************/
uint8 I2C_Init(uint8 n,uint8 MODE,uint32 Fi2c,uint8 Adr,uint8 slot)
{
if(Fi2c > 400000)
{
Fi2c = 400000; //強制將通信速率限制在0~400KHz的范圍內
}
if((n!=0)&&(n!=1))
{
return(0); //n只能為0 1
}
if((MODE!=0)&&(MODE!=1))
{
return(0); //MODE只能為0 1
}
if(slot>15)
{
return(0); //IRQ中斷號0~15
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -