📄 i2c.c
字号:
#define IN_I2C
#include "config.h"
#define I2C_WRITE_END 1
#define I2C_READ_END 2
#define I2C_NOT_GET_BUS 4
#define I2C_ACK_ERR 8
static OS_EVENT *I2cSem;
static OS_EVENT *I2cMbox;
/* 定义用于和I2C中断传递信息的全局变量 */
static uint8 *I2C_buf;
static uint8 I2C_sla; /* I2C器件从地址 */
static uint16 I2C_suba; /* I2C器件内部子地址 */
static uint8 I2C_suba_num; /* I2C子地址字节数 */
static uint16 I2C_num; /* 要读取/写入的数据个数 */
static uint8 I2C_suba_en; /* 子地址控制。
0--子地址已经处理或者不需要子地址
1--读取操作
2--写操作
*/
uint8 I2cInit(uint32 FI2c)
{
VICIntEnClr = 1<<9;
if( FI2c > 400000)
{
FI2c = 400000;
}
PINSEL0 = (PINSEL0 & 0XFFFFFF0F) | 0X50;
I2C0CONCLR = 0X6C;
I2C0SCLH = (Fpclk / FI2c + 1 ) / 2;
I2C0SCLL = (Fpclk / FI2c ) / 2;
I2cSem = OSSemCreate(1);
I2cMbox = OSMboxCreate(NULL);
if( I2cMbox == NULL )
{
return FALSE;
}
if(I2cSem != NULL)
{
return TRUE;
}
return FALSE;
}
/*
*********************************************************************************************************
** 函数名称 :I2C_ReadNByte()
** 函数功能 :从有子地址器件任意地址开始读取N字节数据
** 入口参数 : sla 器件从地址
** suba_type 子地址结构 1-单字节地址 3-8+X结构 2-双字节地址
** suba 器件子地址
** s 数据接收缓冲区指针
** num 读取的个数
** 出口参数 : TRUE 操作成功
** FALSE 操作失败
*********************************************************************************************************
*/
void I2C_ReadNByte (uint8 sla, uint16 suba_type, uint16 suba, uint8 *s, uint16 num)
{
uint8 err;
OSSemPend(I2cSem,0,&err); //无限等待ISR程序释放I2C总线
if (num > 0) /* 判断num个数的合法性 */
{ /* 参数设置 */
if (suba_type == 1)
{ /* 子地址为单字节 */
I2C_sla = sla + 1; /* 读器件的从地址,R=1 */
I2C_suba = suba; /* 器件子地址 */
I2C_suba_num = 1; /* 器件子地址为1字节 */
}
if (suba_type == 2)
{ /* 子地址为2字节 */
I2C_sla = sla + 1; /* 读器件的从地址,R=1 */
I2C_suba = suba; /* 器件子地址 */
I2C_suba_num = 2; /* 器件子地址为2字节 */
}
if (suba_type == 3)
{ /* 子地址结构为8+X*/
I2C_sla = sla + ((suba >> 7 )& 0x0e) + 1; /* 读器件的从地址,R=1 */
I2C_suba = suba & 0x0ff; /* 器件子地址 */
I2C_suba_num = 1; /* 器件子地址为8+x */
}
I2C_buf = s; /* 数据接收缓冲区指针 */
I2C_num = num; /* 要读取的个数 */
I2C_suba_en = 1; /* 有子地址读 */
VICIntEnable = 1<<9;
/* 清除STA,SI,AA标志位 */
I2CONCLR = (1 << 2)| /* AA */
(1 << 3)| /* SI */
(1 << 5); /* STA */
/* 置位STA,启动I2C总线 */
I2CONSET = (1 << 5)| /* STA */
(1 << 6); /* I2CEN */
OSMboxPend(I2cMbox,0,&err); //无限等待ISR程序释放I2C总线
VICIntEnClr = 1<<9;
OSSemPost(I2cSem);
}
}
/*
*********************************************************************************************************
** 函数名称 :I2C_WriteNByte()
** 函数功能 :向有子地址器件写入N字节数据
** 入口参数 : sla 器件从地址
** suba_type 子地址结构 1-单字节地址 3-8+X结构 2-双字节地址
** suba 器件内部物理地址
** *s 将要写入的数据的指针
** num 将要写入的数据的个数
** 出口参数 : TRUE 操作成功
** FALSE 操作失败
*********************************************************************************************************
*/
void I2C_WriteNByte(uint8 sla,uint8 suba_type, uint16 suba, uint8 *s, uint16 num)
{
uint8 err;
OSSemPend(I2cSem,0,&err); //无限等待ISR程序释放I2C总线
if (num > 0)/* 如果读取的个数为0,则返回错误 */
{ /* 设置参数 */
if (suba_type == 1)
{ /* 子地址为单字节 */
I2C_sla = sla; /* 读器件的从地址 */
I2C_suba = suba; /* 器件子地址 */
I2C_suba_num = 1; /* 器件子地址为1字节 */
}
if (suba_type == 2)
{ /* 子地址为2字节 */
I2C_sla = sla; /* 读器件的从地址 */
I2C_suba = suba; /* 器件子地址 */
I2C_suba_num = 2; /* 器件子地址为2字节 */
}
if (suba_type == 3)
{ /* 子地址结构为8+X */
I2C_sla = sla + ((suba >> 7 )& 0x0e); /* 读器件的从地址 */
I2C_suba = suba & 0x0ff; /* 器件子地址 */
I2C_suba_num = 1; /* 器件子地址为8+X */
}
I2C_buf = s; /* 数据 */
I2C_num = num; /* 数据个数 */
I2C_suba_en = 2; /* 有子地址,写操作 */
VICIntEnable = 1<<9;
/* 清除STA,SI,AA标志位 */
I2CONCLR = (1 << 2)| /* AA */
(1 << 3)| /* SI */
(1 << 5); /* STA */
/* 置位STA,启动I2C总线 */
I2CONSET = (1 << 5)| /* STA */
(1 << 6); /* I2CEN*/
//
OSMboxPend(I2cMbox,0,&err); //无限等待ISR程序释放I2C总线
VICIntEnClr = 1<<9;
OSSemPost(I2cSem);
}
}
/*
*********************************************************************************************************
** 函数名称 :__irq IRQ_I2C()
** 函数名次 :硬件I2C中断服务程序。
** 入口参数 :无
** 出口参数 :无
** 说明 :注意处理子地址为2字节的情况。
*********************************************************************************************************
*/
void I2c_Exception(void)
{ /* 读取I2C状态寄存器I2DAT */
/* 按照全局变量的设置进行操作及设置软件标志 */
/* 清除中断逻辑,中断返回 */
OS_ENTER_CRITICAL();
switch (I2STAT & 0xF8)
{ /* 根据状态码进行相应的处理 */
case 0x08: /* 已发送起始条件 */ /* 主发送和主接收都有 */
/* 装入SLA+W或者SLA+R */
if(I2C_suba_en == 1)/* SLA+R */ /* 指定子地址读 */
{ I2DAT = I2C_sla & 0xFE; /* 先写入地址 */
}
else /* SLA+W */
{ I2DAT = I2C_sla; /* 否则直接发送从机地址 */
}
/* 清零SI位 */
I2CONCLR = (1 << 3)| /* SI */
(1 << 5); /* STA */
break;
case 0x10: /*已发送重复起始条件 */ /* 主发送和主接收都有 */
/* 装入SLA+W或者SLA+R */
I2DAT = I2C_sla; /* 重起总线后,重发从地址 */
I2CONCLR = 0x28; /* 清零SI,STA */
break;
case 0x18:
case 0x28: /* 已发送I2DAT中的数据,已接收ACK */
if (I2C_suba_en == 0)
{
if (I2C_num > 0)
{ I2DAT = *I2C_buf++;
I2CONCLR = 0x28; /* 清零SI,STA */
I2C_num--;
}
else /* 没有数据发送了 */
{ /* 停止总线 */
I2CONSET = (1 << 4); /* STO */
I2CONCLR = 0x28; /* 清零SI,STA */
OSMboxPost(I2cMbox,(void *)I2C_WRITE_END); //写结束
VICIntEnClr = 1<<9;
}
}
if(I2C_suba_en == 1) /* 若是指定地址读,则重新启动总线 */
{
if (I2C_suba_num == 2)
{ I2DAT = ((I2C_suba >> 8) & 0xff);
I2CONCLR = 0x28; /* 清零SI,STA */
I2C_suba_num--;
break;
}
if(I2C_suba_num == 1)
{ I2DAT = (I2C_suba & 0xff);
I2CONCLR = 0x28; /* 清零SI,STA */
I2C_suba_num--;
break;
}
if (I2C_suba_num == 0)
{ I2CONSET = 0x20;
I2CONCLR = 0x08;
I2C_suba_en = 0; /* 子地址己处理 */
break;
}
}
if (I2C_suba_en == 2)/* 指定子地址写,子地址尚未指定,则发送子地址 */
{
if (I2C_suba_num > 0)
{ if (I2C_suba_num == 2)
{ I2DAT = ((I2C_suba >> 8) & 0xff);
I2CONCLR = 0x28;
I2C_suba_num--;
break;
}
if (I2C_suba_num == 1)
{ I2DAT = (I2C_suba & 0xff);
I2CONCLR = 0x28;
I2C_suba_num--;
I2C_suba_en = 0;
break;
}
}
}
break;
case 0x40: /* 已发送SLA+R,已接收ACK */
if (I2C_num <= 1) /* 如果是最后一个字节 */
{ I2CONCLR = 1 << 2; /* 下次发送非应答信号 */
}
else
{ I2CONSET = 1 << 2; /* 下次发送应答信号 */
}
I2CONCLR = 0x28; /* 清零SI,STA */
break;
case 0x20: /* 已发送SLA+W,已接收非应答 */
case 0x30: /* 已发送I2DAT中的数据,已接收非应答 */
case 0x48: /* 已发送SLA+R,已接收非应答 */
I2CONSET = 1<<4;
I2CONCLR = 0x28;
OSMboxPost(I2cMbox,(void *)I2C_ACK_ERR);
break;
case 0x38: /* 在SLA+R/W或数据字节中丢失仲裁 */
I2CONCLR = 0x28;
OSMboxPost(I2cMbox,(void *)I2C_NOT_GET_BUS);
break;
case 0x50: /* 已接收数据字节,已返回ACK */
*I2C_buf++ = I2DAT;
I2C_num--;
if (I2C_num == 1)/* 接收最后一个字节 */
{ I2CONCLR = 0x2C; /* STA,SI,AA = 0 */
}
else
{ I2CONSET = 0x04; /* AA=1 */
I2CONCLR = 0x28;
}
break;
case 0x58: /* 已接收数据字节,已返回非应答 */
*I2C_buf++ = I2DAT; /* 读取最后一字节数据 */
I2CONSET = 0x10; /* 结束总线 */
I2CONCLR = 0x28;
OSMboxPost(I2cMbox,(void *)I2C_READ_END);
break;
default:
I2CONCLR = 0x28;
break;
}
VICVectAddr = 0x00; /* 中断处理结束 */
OS_EXIT_CRITICAL();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -