📄 i2c.c
字号:
/*
*==================================================================================================
* 文件名称 : I2CINT.c
* 功能说明 : LPC2000硬件I2C中断方式软件包。
* 使用说明 : 主程序要配置好I2C总线接口(I2C引脚功能和I2C中断,并已使能I2C主模式)
*==================================================================================================
*/
#include "i2c.h"
#include "bsp.h"
#include "lpc213_4x.h"
volatile unsigned char i2c_sla; // I2C器件从地址
volatile unsigned long i2c_suba; // I2C器件内部子地址
volatile unsigned char i2c_suba_w; // I2C子地址宽度(字节数)
volatile unsigned char i2c_suba_en; // 子地址控制: 0-无或已处理 1-读 2-写
volatile unsigned char *i2c_buf; // 数据缓冲区指针
volatile unsigned long i2c_num; // 要读/写的数据个数
volatile unsigned char i2c_end; // I2C总线结束标志: 结束总线是置1
/*
*--------------------------------------------------------------------------------------------------
*--------------------------------------------------------------------------------------------------
*/
void I2C_Init(void)
{
PINSEL0 = (PINSEL0&0xFFFFFF0F)|0x50; // 配置P0.2为SCL, P0.3为SDA
I20SCLH = (Fpclk/Fi2c+1)/2; // 配置I20C时钟频率(100kbps)
I20SCLL = (Fpclk/Fi2c+0)/2;
}
/*
*--------------------------------------------------------------------------------------------------
* 函数名称: I2SendByte()
* 函数功能: 向无子地址器件发送1字节数据。
* 入口参数: sla 器件地址
* dat 要发送的数据
* 出口参数: 返回值为0时表示出错,为1时表示操作正确。
* 说明: 使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
*--------------------------------------------------------------------------------------------------
*/
unsigned char I2SendByte(unsigned char sla, unsigned char dat)
{
i2c_sla = sla; // 写操作的器件地址
i2c_buf = &dat; // 待发送的数据
i2c_num = 1; // 发送1字节数据
i2c_suba_en = 0; // 无子地址
i2c_end = 0;
I20CONCLR = 0x2C;
I20CONSET = 0x60; // 设置为主机,并启动总线
while (i2c_end==0) ;
if (i2c_end==1) return(1);
else return(0);
}
/*
*--------------------------------------------------------------------------------------------------
* 函数名称:I2RecvByte()
* 函数功能:向无子地址器件读取1字节数据。
* 入口参数:sla 器件地址
* dat 接收数据的变量指针
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
*--------------------------------------------------------------------------------------------------
*/
unsigned char I2RecvByte(unsigned char sla, unsigned char *dat)
{
i2c_sla = sla + 1; // 读操作的器件地址
i2c_buf = dat;
i2c_num = 1;
i2c_suba_en = 0; // 无子地址
i2c_end = 0;
I20CONCLR = 0x2C;
I20CONSET = 0x60; // 设置为主机,并启动总线
while (i2c_end==0) ;
if (i2c_end==1) return(1);
else return(0);
}
/*
*--------------------------------------------------------------------------------------------------
* 函数名称: i2c_ReadNByte()
* 函数功能: 从有子地址器件任意地址开始读取N字节数据
* 入口参数: sla 器件从地址
* suba_type 子地址结构 1-单字节地址 2-双字节地址 3-8+X结构
* suba 器件子地址
* s 数据接收缓冲区指针
* num 读取的个数
* 出口参数: TRUE 操作成功
* FALSE 操作失败
*--------------------------------------------------------------------------------------------------
*/
unsigned char I2C_ReadNByte(unsigned char sla, unsigned char suba_type, unsigned long suba, unsigned char *s, unsigned long num)
{
//if ((num<1)||(num>16)) return (0);
if (num<1) return (0);
if (suba_type==_1BYTE_SUBA) {
i2c_sla = sla + 1; // 读器件的从地址,R=1
i2c_suba = suba; // 器件子地址
i2c_suba_w = 1; // 器件子地址为1字节
}
if (suba_type==_2BYTE_SUBA) {
i2c_sla = sla + 1; // 读器件的从地址,R=1
i2c_suba = suba; // 器件子地址
i2c_suba_w = 2; // 器件子地址为2字节
}
if (suba_type==_8XBIT_SUBA) {
i2c_sla = sla+((suba>>7)&0x0E)+1; // 读器件的从地址,R=1
i2c_suba = suba&0x00FF; // 器件子地址
i2c_suba_w = 1; // 器件子地址为8+x
}
i2c_buf = s; // 数据接收缓冲区指针
i2c_num = num; // 要读取的个数
i2c_suba_en = 1; // 有子地址读
i2c_end = 0;
I20CONCLR = (1<<5)|(1<<3)|(1<<2); // 清除STA,SI,AA标志位
I20CONSET = (1<<6)|(1<<5); // 使能I2C总线, 置位STA
while (i2c_end==0) {;} // 等待I2C操作完成
if (i2c_end==1) return (1);
else return (0);
}
/*
*--------------------------------------------------------------------------------------------------
* 函数名称: i2c_WriteNByte()
* 函数功能: 向有子地址器件写入N字节数据
* 入口参数: sla 器件从地址
* suba_type 子地址结构 1-单字节地址 2-双字节地址 3-8+X结构
* suba 器件内部物理地址
* *s 将要写入的数据的指针
* num 将要写入的数据的个数
* 出口参数: TRUE 操作成功
* FALSE 操作失败
*--------------------------------------------------------------------------------------------------
*/
unsigned char I2C_WriteNByte(unsigned char sla, unsigned char suba_type, unsigned long suba, unsigned char *s, unsigned long num)
{
if (num<1) return (0);
if (suba_type==_1BYTE_SUBA) {
i2c_sla = sla; // 读器件的从地址
i2c_suba = suba; // 器件子地址
i2c_suba_w = 1; // 器件子地址为1字节
}
if (suba_type==_2BYTE_SUBA) {
i2c_sla = sla; // 读器件的从地址
i2c_suba = suba; // 器件子地址
i2c_suba_w = 2; // 器件子地址为2字节
}
if (suba_type==_8XBIT_SUBA) {
i2c_sla = sla+((suba>>7)&0x0E); // 读器件的从地址
i2c_suba = suba&0x00FF; // 器件子地址
i2c_suba_w = 1; // 器件子地址为8+X
}
i2c_buf = s; // 数据
i2c_num = num; // 数据个数
i2c_suba_en = 2; // 有子地址写操作
i2c_end = 0;
I20CONCLR = (1<<5)|(1<<3)|(1<<2); // 清除STA,SI,AA标志位
I20CONSET = (1<<6)|(1<<5); // 置位I2CEN,STA标志位
while (i2c_end==0) {;} // 等待I2C操作完成
if (i2c_end==1) return (1);
else return (0);
}
/*
*--------------------------------------------------------------------------------------------------
* 函数名称: __irq IRQ_I2C()
* 函数名次: 硬件I2C中断服务程序。
* 入口参数: 无
* 出口参数: 无
* 说明 : 注意处理子地址为2字节的情况。
*--------------------------------------------------------------------------------------------------
*/
void I2C_ISR(void) __attribute__ ((interrupt("IRQ")));
void I2C_ISR(void)
{
switch (I20STAT & 0xF8) {
case 0x08: // 已发起始条件(主发和主收均有)
if (i2c_suba_en==1) { // 有子地址读操作
I20DAT = i2c_sla&0xFE;// 装入SLA+W
} else {
I20DAT = i2c_sla; // 装入SLA+R
}
I20CONCLR = 0x28; // 清STA,SI位
break;
case 0x10: //已发重复起始条件(主发和主收均有)
I20DAT = i2c_sla; // 重起总线后, 装入SLA+R
I20CONCLR = 0x28; // 清STA,SI位
break;
case 0x18:
case 0x28: // 已发I20DAT中的数据, 且已接收ACK
if (i2c_suba_en==0) {
if (i2c_num > 0) {
I20DAT = *i2c_buf++;
I20CONCLR = 0x28; // 清SI,STA
i2c_num --;
} else { // 没有数据发送了, 停止总线
I20CONSET = 0x10; // STO
I20CONCLR = 0x28; // 清SI,STA
i2c_end = 1; // 总线已经停止
}
}
if(i2c_suba_en==1) { // 若是指定子地址读,则重启总线
if (i2c_suba_w==2) {
I20DAT = ((i2c_suba>>8)&0x00FF);
I20CONCLR = 0x28; // 清SI,STA
i2c_suba_w--;
break;
}
if(i2c_suba_w==1) {
I20DAT = (i2c_suba & 0xFF);
I20CONCLR = 0x28; // 清SI,STA
i2c_suba_w--;
break;
}
if (i2c_suba_w==0) {
I20CONSET = 0x20;
I20CONCLR = 0x08;
i2c_suba_en = 0; // 子地址己处理
break;
}
}
if (i2c_suba_en==2) { // 指定子地址写,子地址尚未指定,则发送子地址
if (i2c_suba_w > 0) {
if (i2c_suba_w==2) {
I20DAT = ((i2c_suba>>8)&0x00FF);
I20CONCLR = 0x28;
i2c_suba_w--;
break;
}
if (i2c_suba_w==1) {
I20DAT = (i2c_suba&0xFF);
I20CONCLR = 0x28;
i2c_suba_w --;
i2c_suba_en = 0;
break;
}
}
}
break;
case 0x40: // 已发SLA+R, 已收ACK
if (i2c_num <= 1) { // 如果是最后一个字节
I20CONCLR = 0x04; // 下次发NACK(AA=0)
} else {
I20CONSET = 0x04; // 下次发ACK(AA=1)
}
I20CONCLR = 0x28; // 清SI,STA
break;
case 0x20: // 已发SLA+W, 已收NACK
case 0x30: // 已发I20DAT中的数据, 已收NACK
case 0x38: // 在SLA+R/W或数据字节中丢失仲裁
case 0x48: // 已发SLA+R, 已收NACK
I20CONCLR = 0x28;
i2c_end = 0xFF;
break;
case 0x50: // 已收数据节,已返回ACK
*i2c_buf++ = I20DAT;
i2c_num--;
if (i2c_num==1) { // 收最后一节
I20CONCLR = 0x2C; // 清STA,SI,AA
} else {
I20CONSET = 0x04; // 下次发ACK(AA=1)
I20CONCLR = 0x28; // 清STA,SI
}
break;
case 0x58: // 已收数据节,已返回NACK
*i2c_buf++ = I20DAT; // 读最后一节数据
I20CONSET = 0x10; // 结束总线(STO=1)
I20CONCLR = 0x28; // 清STA,SI
i2c_end = 1;
break;
default: break;
}
VICVectAddr = 0x00;
}
/*=============================================<EOF>=============================================*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -