📄 i2cint.c
字号:
/****************************************************************************
* 文件名:I2CINT.C
* 功能:硬件I2C软件包,利用中断方式操作。
* 说明:主程序要配置好I2C总线接口(I2C引脚功能和I2C中断,并已使能I2C主模式)
****************************************************************************/
#include "config.h"
/* 以下为I2C操作时所需要的变量 */
volatile uint8 I2C_sla; // 从机地址(即器件地址)
volatile uint8 I2C_suba; // 子地址
volatile uint8 *I2C_buf; // 数据缓冲区指针 (读操作时会被更改)
volatile uint8 I2C_num; // 操作数据个数 (会被更改)
volatile uint8 I2C_end; // 操作结束标志,为1时表示操作结束,为0xFF时表示操作失败 (会被设置)
volatile uint8 I2C_suba_en; // 子地址使能控制,读操作时请设置为1,写操作时请设置为2 (会被更改)
uint8 eeprom[256]; /* 定义EEPROM存储单元,256字节 */
uint8 adrpoint; /* 定义EEPROM读写操作指针 */
uint8 slarv; /* 定义子地址接收标志,为1时表示己接收从机地址 */
/*****************************************************************************/
void I2C_Init(uint32 fi2c)
{ if(fi2c>400000) fi2c = 400000;
PINSEL0 = (PINSEL0&0xFFFFFF0F) | 0x50; // 设置I2C控制口有效
I2SCLH = (Fpclk/fi2c + 1) / 2; // 设置I2C时钟为fi2c
I2SCLL = (Fpclk/fi2c) / 2;
I2CONCLR = 0x2C;
I2CONSET = 0x40; // 使能主I2C
/* 设置I2C中断允许 */
VICIntSelect = 0x00000000; // 设置所有通道为IRQ中断
VICVectCntl8 = 0x29; // I2C通道分配到IRQ slot 2,即优先级2
VICVectAddr8 = (uint32)IRQ_I2C; // 设置I2C中断向量地址
VICIntEnable = VICIntEnable|0x0200; // 使能I2C中断
}
/*********************************************************************************************************
** 函数名称:I2C_SlaveInit()
** 函数功能:从模式I2C初始化,包括初始化其中断为向量IRQ中断。
** 入口参数:adr 本从机地址
** 出口参数:无
********************************************************************************************************/
void I2C_SlavInit(uint8 adr)
{
PINSEL0 = (PINSEL0&0xFFFFFF0F) | 0x50; // 设置I2C控制口有效
I2ADR = adr&0xFE; // 设置从机地址
I2CONCLR = 0x28;
I2CONSET = 0x44; // I2C配置为从机模式
// 设置I2C中断允许
VICIntSelect = 0x00000000; // 设置所有通道为IRQ中断
VICVectCntl8 = 0x29; // I2C通道分配到IRQ slot 0,即优先级最高
VICVectAddr8 = (int)IRQ_I2C; // 设置I2C中断向量地址
VICIntEnable = 0x0200; // 使能I2C中断
}
//------------------------------------------------------------------------//
/*void __irq IRQ_I2C(void)
{ uint8 sta;
sta = I2STAT; // 取得I2C状态字
sta &= 0xF8;
switch(sta)
{ case 0x60: // 接收到自身SLA+W
case 0x68:
slarv = 0;
I2CONSET = 0x04;
break;
case 0xA8: // 接收到SLA+R,或已发送数据并接收到ACK位。
case 0xB0:
case 0xB8:
I2DAT = eeprom[adrpoint];
adrpoint++;
I2CONSET = 0x04;
break;
case 0x80: // 接收到数据
if(0==slarv)
{ adrpoint = I2DAT;
slarv = 1;
}
else
{ eeprom[adrpoint] = I2DAT;
adrpoint++;
}
I2CONSET = 0x04;
break;
case 0xA0: // 已发送数据,并接收到非ACK
case 0xC0: // 总线结束,或总线重新启动
default: // 其它状态
I2CONSET = 0x04;
break;
}
I2CONCLR = 0x38; // 清除标I2C标志位,STA、STO、SI
VICVectAddr = 0x00;
}
*/
void __irq IRQ_I2C(void)
{ uint8 sta;
sta = I2STAT; // 读出I2C状态字
switch(sta)
{ case 0x08: // 己发送起始条件
if(1==I2C_suba_en) I2DAT = I2C_sla&0xFE; // 指定子地址读时,先写入地址
else I2DAT = I2C_sla; // 否则直接发送从机地址
I2CONCLR = 0x28; // SI=0
break;
case 0x10:
I2DAT = I2C_sla; // 重启动总线后,发送从地址
I2CONCLR = 0x28; // SI=0
break;
case 0x18: // 已发送SLA+W,并已接收应答
if(0==I2C_suba_en) // 无子地址,则直接发送数据
{ if(I2C_num>0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28;
I2C_num--;
}
else
{ I2CONSET = 0x10; // 无数据发送,结束总线
I2CONCLR = 0x28;
I2C_end = 1; // 设置总线操作结束标志
}
break;
}
if(1==I2C_suba_en) // 发送子地址
{ I2DAT = I2C_suba;
I2CONCLR = 0x28;
}
if(2==I2C_suba_en)
{ I2DAT = I2C_suba;
I2CONCLR = 0x28;
I2C_suba_en = 0; // 子地址己处理
}
break;
case 0x28: // 已发送I2C数据,并接收到应答
if(0==I2C_suba_en) // 无子地址,则直接发送数据
{ if(I2C_num>0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28;
I2C_num--;
}
else
{ I2CONSET = 0x10; // 无数据发送,结束总线
I2CONCLR = 0x28;
I2C_end = 1;
}
break;
}
if(1==I2C_suba_en) // 若是指定地址读,则重新启动总线
{ I2CONSET = 0x20;
I2CONCLR = 0x08;
I2C_suba_en = 0; // 子地址己处理
}
break;
case 0x20:
case 0x30:
case 0x38:
I2CONCLR = 0x28; // 总线进入不可寻址从模式
I2C_end = 0xFF; // 总线出错,设置标志
break;
case 0x40: // 己发送SLA+R,并已接收到应答
if(1==I2C_num) // 最后一字节,接收数据后发送非应答信号
{ I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答
}
else // 接收数据并发送应答信号
{ I2CONSET = 0x04; // AA=1,接收到数据后产生应答
I2CONCLR = 0x28;
}
break;
case 0x50:
*I2C_buf++ = I2DAT; // 读取数据
I2C_num--;
if(1==I2C_num)
{ I2CONCLR = 0x2C; // AA=0,接收到数据后产生非应答
}
else
{ I2CONSET = 0x04; // AA=1,接收到数据后产生应答
I2CONCLR = 0x28;
}
break;
case 0x58:
*I2C_buf++ = I2DAT; // 读取最后一字节数据
I2CONSET = 0x10; // 结束总线
I2CONCLR = 0x28;
I2C_end = 1;
break;
case 0x48:
I2CONCLR = 0x28; // 总线进入不可寻址从模式
I2C_end = 0xFF;
break;
default:
break;
}
VICVectAddr = 0x00; // 中断处理结束
}
/****************************************************************************
* 名称:ISendByte()
* 功能:向无子地址器件发送一字节数据。
* 入口参数:sla 器件地址
* dat 要发送的数据
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 ISendByte(uint8 sla, uint8 dat)
{ /* 参数设置 */
I2C_sla = sla; // 写操作的器件地址
I2C_buf = &dat; // 待发送的数据
I2C_num = 1; // 发送1字节数据
I2C_suba_en = 0; // 无子地址
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:ISendStr()
* 功能:向有子地址器件发送多字节数据。
* 入口参数:sla 器件从机地址
* suba 器件子地址
* s 数据发送缓冲区指针
* no 发送数据个数
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
{ /* 参数设置 */
I2C_sla = sla; // 写操作的器件地址
I2C_suba = suba; // 子地址
I2C_buf = s;
I2C_num = no;
I2C_suba_en = 2; // 有子地址写
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:IRcvByte()
* 功能:向无子地址器件读取一字节数据。
* 入口参数:sla 器件地址
* dat 接收数据的变量指针
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 IRcvByte(uint8 sla, uint8 *dat)
{ /* 参数设置 */
I2C_sla = sla+1; // 读操作的器件地址
I2C_buf = dat;
I2C_num = 1;
I2C_suba_en = 0; // 无子地址
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
/****************************************************************************
* 名称:IRcvStr()
* 功能:向有子地址器件读取多字节数据。
* 入口参数:sla 器件地址
* suba 器件子地址
* s 数据接收缓冲区指针
* no 读取数据个数
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8 IRcvStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
{ if(0==no) return(0);
/* 参数设置 */
I2C_sla = sla+1; // 读操作的器件地址
I2C_suba = suba;
I2C_buf = s;
I2C_num = no;
I2C_suba_en = 1; // 有子地址读
I2C_end = 0;
I2CONCLR = 0x2C;
I2CONSET = 0x60; // 设置为主机,并启动总线
while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}
void DelayNS(uint32 timer)
{ uint32 i;
for(i=0;i<timer;i++)
{
i=i;i=i;i=i;i=i;i=i;
i=i;i=i;i=i;i=i;i=i;
i=i;i=i;i=i;i=i;i=i;
}
}
void GetTime(uint8 *Time)
{
// uint8 *time;
IRcvStr(PCF8563,0x02,&Time[0],1);
IRcvStr(PCF8563,0x03,&Time[1],1);
IRcvStr(PCF8563,0x04,&Time[2],1);
IRcvStr(PCF8563,0x05,&Time[3],1);
IRcvStr(PCF8563,0x06,&Time[4],1);
IRcvStr(PCF8563,0x07,&Time[5],1);
IRcvStr(PCF8563,0x08,&Time[6],1);
Time[0] = Time[0]&0x7f;Time[1] = Time[1]&0x7f;Time[2] = Time[2]&0x3f;
Time[3] = Time[3]&0x3f;Time[5] = Time[5]&0x1f;
}
void SetTime(uint8 *Time)
{
Time[0] = Time[0]&0x7f;Time[1] = Time[1]&0x7f;Time[2] = Time[2]&0x3f;
Time[3] = Time[3]&0x3f;Time[5] = Time[5]&0x1f;
ISendStr(PCF8563,0x02,&Time[0],1);
ISendStr(PCF8563,0x03,&Time[1],1);
ISendStr(PCF8563,0x04,&Time[2],1);
ISendStr(PCF8563,0x05,&Time[3],1);
ISendStr(PCF8563,0x06,&Time[4],1);
ISendStr(PCF8563,0x07,&Time[5],1);
ISendStr(PCF8563,0x08,&Time[6],1);
}
uint8 IIC_UART_Init(uint8 port)//9600
{
uint8 temp_mr;
//------------------uart复位-----------------------//
IO0CLR = RST_UART;
DelayNS(10000);
IO0SET = RST_UART;
//-------------------------------------------------//
port = port<<1;
temp_mr = 0x83;
ISendStr(IIC_UART2,0x18|port,&temp_mr,1);
DelayNS(3000);
temp_mr = 12;
ISendStr(IIC_UART2,0x00|port,&temp_mr,1);
DelayNS(3000);
temp_mr = 0x00;
ISendStr(IIC_UART2,0x08|port,&temp_mr,1);
DelayNS(3000);
temp_mr = 0x03;
ISendStr(IIC_UART2,0x18|port,&temp_mr,1);
DelayNS(3000);
temp_mr = 0x01;//0x01 //fcr
ISendStr(IIC_UART2,0x10|port,&temp_mr,1);
DelayNS(3000);
temp_mr = 0x01;
ISendStr(IIC_UART2,0x08|port,&temp_mr,1);
DelayNS(3000);
return 1;
}
uint8 IIC_UART_SenData(uint8 port,uint8 dat)//1200
{
uint8 temp_mr;
port = port<<1;
ISendStr(IIC_UART2,0x00|port,&dat,1);
while((temp_mr&0x40)==0)
{
IRcvStr(IIC_UART2,0x28|port,&temp_mr,1);
//DelayNS(500);
};
return 1;
}
uint8 IIC_Sendstr(uint8 port,uint8 *str,uint8 len)
{
uint8 temp_lenth;
for(temp_lenth=0;temp_lenth<len;temp_lenth++)
{
IIC_UART_SenData(port,str[temp_lenth]);
//DelayNS(1000);
}
return 1;
}
#define PCA9554_A 0x40
#define PCA9554_B 0x4E
uint16 Get_key(void)
{
uint8 temp_key,temp_key1;
uint16 temp_key2;
IRcvStr(PCA9554_A,0x00,&temp_key,1);
IRcvStr(PCA9554_B,0x00,&temp_key1,1);
temp_key2 = temp_key;
temp_key2 = ((temp_key2<<8)|temp_key1);
return temp_key2;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -