📄 i2cint.c
字号:
/****************************************************************************************************************
调用说明:
1. 此中函数规定在RTX中使用;
2. 参数设置除了按配置设置外,不同I2C控制器的引脚分配需另外设定;
3. 同一个I2C控制器函数只能在同一线程中使用,不同I2C控制器可以在不同线程中使用
*****************************************************************************************************************/
/*
// *** <<< Use Configuration Wizard in Context Menu >>> ***
*/
/*
// Peripheral clock, depends on VPBDIV
// <o> PCLK value <1-1000000000>
*/
#define PCLK 12000000
/*
// <e>Use I2C Controller0
*/
#define USE_I2C_CTRL0 1
/*
// </e>
*/
/*
// <e>Use I2C Controller1
*/
#define USE_I2C_CTRL1 0
/*
// </e>
*/
/*
// <e>Use I2C Controller2
*/
#define USE_I2C_CTRL2 1
/*
// </e>
*/
/*
// *** <<< End of Configuration section >>> ***
*/
#include <LPC23xx.H>
#include <RTL.h>
#include "I2CINT.H"
/* 定义用于和I2C中断传递信息的全局变量 */
#if USE_I2C_CTRL0 == 1
volatile U8 I2C0_sla; /* I2C器件从地址 */
volatile U32 I2C0_suba; /* I2C器件内部子地址 */
volatile U8 I2C0_suba_num; /* I2C子地址字节数 */
volatile U8 *I2C0_buf; /* 数据缓冲区指针 */
volatile U32 I2C0_num; /* 要读取/写入的数据个数 */
volatile U8 I2C0_suba_en; /* 子地址控制。
0--子地址已经处理或者不需要子地址
1--读取操作
2--写操作 */
OS_SEM wait_end0_sem; /* 等待I2C0总线结束信号量 */
#endif
#if USE_I2C_CTRL1 == 1
volatile U8 I2C1_sla; /* I2C器件从地址 */
volatile U32 I2C1_suba; /* I2C器件内部子地址 */
volatile U8 I2C1_suba_num; /* I2C子地址字节数 */
volatile U8 *I2C1_buf; /* 数据缓冲区指针 */
volatile U32 I2C1_num; /* 要读取/写入的数据个数 */
volatile U8 I2C1_suba_en; /* 子地址控制。
0--子地址已经处理或者不需要子地址
1--读取操作
2--写操作 */
OS_SEM wait_end1_sem; /* 等待I2C1总线结束信号量 */
#endif
#if USE_I2C_CTRL2 == 1
volatile U8 I2C2_sla; /* I2C器件从地址 */
volatile U32 I2C2_suba; /* I2C器件内部子地址 */
volatile U8 I2C2_suba_num; /* I2C子地址字节数 */
volatile U8 *I2C2_buf; /* 数据缓冲区指针 */
volatile U32 I2C2_num; /* 要读取/写入的数据个数 */
volatile U8 I2C2_suba_en; /* 子地址控制。
0--子地址已经处理或者不需要子地址
1--读取操作
2--写操作 */
OS_SEM wait_end2_sem; /* 等待I2C2总线结束信号量 */
#endif
/****************************************************************************************************************
* 函数名称:I2C_Init
* 函数功能:初始化I2C接口
* 入口参数:channel 通道 : 0--I2C0 1--I2C1 2--I2C2
mode 工作模式: 0--从模式 1--主模式
fi2c 通信速率 0~400000(如果高于400kHz ,强制设为400kHz,如果设置为从机,参数无效)
adr 从地址。(当在主模式下,该参数无效,可随意设置)
prio I2C中断优先级(0~15)
*
* 出口参数:1 操作成功
0 操作失败
*****************************************************************************************************************/
U8 I2C_Init(U8 channel,U8 mode,U32 fi2c,U8 adr,U8 prio)
{
BIT init_ok_flag = __FALSE;
if(mode != 0 && mode != 1)return __FALSE ;
if(fi2c > 400000) fi2c = 400000;
switch(channel)
{
case 0: // Enable clock for I2C0
#if USE_I2C_CTRL0 == 1
PCONP |= 1 << 7;
PINSEL1 &= 0XFC3FFFFF; //P0.27 P0.28
PINSEL1 |= 0X01400000;
VICIntSelect = ~(1 << 9); //IRQ中断
if(prio > 15)VICVectPriority9 = 15;
else VICVectPriority9 = prio;
VICVectAddr9 = (U32)IRQ_I2C; //设置中断服务地址
VICIntEnable = 1 << 9; //使能I2C0中断
if(mode == 1) //设置为主模式
{
I20SCLH = (PCLK / fi2c) / 2; //设置I2C时钟
I20SCLL = (PCLK / fi2c) / 2;
I20CONCLR = 0X2C;
I20CONSET = 0X40; //使能主I2C
}
else //设置为从模式
{
I20ADR = adr & 0XFE; //设置从机地址
I20CONSET = 0X44; //使能从I2C
I20CONCLR = 0X28;
}
os_sem_init (wait_end0_sem, 0); //初始化I2C0等待信号量
init_ok_flag = __TRUE;
#endif
break;
case 1:
#if USE_I2C_CTRL1 == 1
PCONP |= 1 << 19; // Enable clock for I2C1
PINSEL1 &= 0XFFFFFC3F; //P0.19 P0.20
PINSEL1 |= 0X000003C0;
VICIntSelect = ~(1 << 19); //IRQ中断
if(prio > 15)VICVectPriority19 = 15;
else VICVectPriority19 = prio;
VICVectAddr19 = (U32)IRQ_I2C; //设置中断服务地址
VICIntEnable = 1 << 19; //使能I2C1中断
if(mode == 1) //设置为主模式
{
I21SCLH = (PCLK / fi2c) / 2; //设置I2C时钟
I21SCLL = (PCLK / fi2c) / 2;
I21CONCLR = 0X2C;
I21CONSET = 0X40; //使能主I2C
}
else //设置为从模式
{
I21ADR = adr & 0XFE; //设置从机地址
I21CONSET = 0X44; //使能从I2C
I21CONCLR = 0X28;
}
os_sem_init (wait_end1_sem, 0); //初始化I2C1等待信号量
init_ok_flag = __TRUE;
#endif
break;
case 2:
#if USE_I2C_CTRL2 == 1
PCONP |= 1 << 26; // Enable clock for I2C2
PINSEL0 &= 0XFF0FFFFF; //P0.10 P0.11
PINSEL0 |= 0X00A00000;
VICIntSelect = ~(1 << 30); //IRQ中断
if(prio > 15)VICVectPriority30 = 15;
else VICVectPriority30 = prio;
VICVectAddr30 = (U32)IRQ_I2C; //设置中断服务地址中断
VICIntEnable = 1 << 30; //使能I2C2中断
if(mode == 1) //设置为主模式
{
I22SCLH = (PCLK / fi2c) / 2; //设置I2C时钟
I22SCLL = (PCLK / fi2c) / 2;
I22CONCLR = 0X2C;
I22CONSET = 0X40; //使能主I2C
}
else //设置为从模式
{
I22ADR = adr & 0XFE; //设置从机地址
I22CONSET = 0X44; //使能从I2C
I22CONCLR = 0X28;
}
os_sem_init (wait_end2_sem, 0); //初始化I2C2等待信号量
init_ok_flag = __TRUE;
#endif
break;
}
if(init_ok_flag == __TRUE)return __TRUE;
else return __FALSE ;
}
/*
**********************************************************************************************************
** 函数名称:ISendByte
** 函数功能:向无子地址器件发送1字节数据。
** 入口参数:channel 通道 : 0--I2C0 1--I2C1 2--I2C2
sla 器件地址
** dat 要发送的数据
** timeout 等待时间(以系统时间衡量)
** 出口参数:返回值为0时表示出错,为1时表示操作正确。
** 说明: 使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
*********************************************************************************************************
*/
U8 ISendByte(U8 channel, U8 sla, U8 dat, U16 timeout)
{
switch(channel)
{
case 0: //I2C0
#if USE_I2C_CTRL0 == 1
I2C0_sla = sla; // 写操作的器件地址
I2C0_buf = &dat; // 待发送的数据
I2C0_num = 1; // 发送1字节数据
I2C0_suba_en = 0; // 无子地址
while(os_sem_wait (wait_end0_sem, 0) == OS_R_OK); //清令牌数
I20CONCLR = 0x2C;
I20CONSET = 0x60; // 设置为主机,并启动总线
if(os_sem_wait (wait_end0_sem, timeout) != OS_R_TMO)return __TRUE;
#endif
break;
case 1: //I2C1
#if USE_I2C_CTRL1 == 1
I2C1_sla = sla; // 写操作的器件地址
I2C1_buf = &dat; // 待发送的数据
I2C1_num = 1; // 发送1字节数据
I2C1_suba_en = 0; // 无子地址
while(os_sem_wait (wait_end1_sem, 0) == OS_R_OK); //清令牌数
I21CONCLR = 0x2C;
I21CONSET = 0x60; // 设置为主机,并启动总线
if(os_sem_wait (wait_end1_sem, timeout) != OS_R_TMO)return __TRUE;
#endif
break;
case 2: //I2C2
#if USE_I2C_CTRL2 == 1
I2C2_sla = sla; // 写操作的器件地址
I2C2_buf = &dat; // 待发送的数据
I2C2_num = 1; // 发送1字节数据
I2C2_suba_en = 0; // 无子地址
while(os_sem_wait (wait_end2_sem, 0) == OS_R_OK); //清令牌数
I22CONCLR = 0x2C;
I22CONSET = 0x60; // 设置为主机,并启动总线
if(os_sem_wait (wait_end2_sem, timeout) != OS_R_TMO)return __TRUE;
#endif
break;
}
return __FALSE;
}
/*
*********************************************************************************************************
** 函数名称:IRcvByte
** 函数功能:向无子地址器件读取1字节数据。
** 入口参数:channel 通道 : 0--I2C0 1--I2C1 2--I2C2
** sla 器件地址
** dat 接收数据的变量指针
** timeout 等待时间(以系统时间衡量)
** 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
** 说 明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
*********************************************************************************************************
*/
U8 IRcvByte(U8 channel, U8 sla, U8 *dat, U16 timeout)
{
switch(channel)
{
case 0:
#if USE_I2C_CTRL0 == 1
I2C0_sla = sla+1; // 读操作的器件地址
I2C0_buf = dat;
I2C0_num = 1;
I2C0_suba_en = 0; // 无子地址
while(os_sem_wait (wait_end0_sem, 0) == OS_R_OK); //清令牌数
I20CONCLR = 0x2C;
I20CONSET = 0x60; // 设置为主机,并启动总线
if(os_sem_wait (wait_end0_sem, timeout) != OS_R_TMO)return __TRUE;
#endif
break;
case 1:
#if USE_I2C_CTRL1 == 1
I2C1_sla = sla+1; // 读操作的器件地址
I2C1_buf = dat;
I2C1_num = 1;
I2C1_suba_en = 0; // 无子地址
while(os_sem_wait (wait_end1_sem, 0) == OS_R_OK); //清令牌数
I21CONCLR = 0x2C;
I21CONSET = 0x60; // 设置为主机,并启动总线
if(os_sem_wait (wait_end1_sem, timeout) != OS_R_TMO)return __TRUE;
#endif
break;
case 2:
#if USE_I2C_CTRL2 == 1
I2C2_sla = sla+1; // 读操作的器件地址
I2C2_buf = dat;
I2C2_num = 1;
I2C2_suba_en = 0; // 无子地址
while(os_sem_wait (wait_end2_sem, 0) == OS_R_OK); //清令牌数
I22CONCLR = 0x2C;
I22CONSET = 0x60; // 设置为主机,并启动总线
if(os_sem_wait (wait_end2_sem, timeout) != OS_R_TMO)return __TRUE;
#endif
break;
}
return __FALSE;
}
/*
*********************************************************************************************************
** 函数名称 :I2C_ReadNByte
** 函数功能 :从有子地址器件任意地址开始读取N字节数据
** 入口参数 : channel 通道 : 0--I2C0 1--I2C1 2--I2C2
** sla 器件从地址
** suba_type 子地址结构 1-单字节地址 2-8+X结构 2-双字节地址
** suba 器件子地址
** s 数据接收缓冲区指针
** num 读取的个数
** timeout 等待时间(以系统时间衡量)
** 出口参数 : TRUE 操作成功
** FALSE 操作失败
*********************************************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -