⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.c

📁 ARM7(LPC2131) + FreeRTOS, 基于 Codesourcery gcc, 共10个任务, 仅占 2k RAM
💻 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 + -