📄 drivereeprom.c
字号:
/*
* Copyright (c) 2006,深圳国人通信网优中心软件开发部
* All rights reserved.
*
* 文件名:DriverEeprom.c
*
* 版本号:V1.0
*
* 创建日期:2006年3月20日
*
* 摘 要:ARM自带的I2C0驱动程序
*
* 作 者:段斌
*
*
* 修改人:
*
* 修改日期:
*
* 修改摘要:
*/
#define EEPROM_GLOBE
#include "..\include\DriverEeprom.h"
#if(SOURCE_VER == TEST_SOURCE_IIC) //??????????????????????????????????????????????????????
#define BEEP 1 << 7 //P0.7控制BEEP,低电平蜂鸣
#endif
/**********************************************************
** 函数名称:
** 功能说明: eprom初始化
** 输入参数: u32_Fi2c 设置I2C的时钟值,单位HZ
** 输出参数: 无
** 返 回 值: 无
** 引用函数:
** 创 建 人: 段斌
** 创建时间:2006-03-17
***********************************************************/
void I2cInit(UINT32 u32_Fi2c)
{
#if(SOURCE_VER == TEST_SOURCE_IIC) //??????????????????????????????????????????????????????
UINT32 i;
UCHAR8 data_buf[32];
#endif
if (u32_Fi2c > 400000) //I2C的最大速率400K
u32_Fi2c = 400000;
PINSEL0 = (PINSEL0 & (~0xF0)) | 0x50; // 不影响其它管脚连接,pinsel05:4对应SCL值01,pinsel07:6对应SDA值01
I2SCLH = (Fpclk/u32_Fi2c + 1) / 2; // 设定I2C时钟
I2SCLL = (Fpclk/u32_Fi2c)/2;
I2CONCLR = 0x2C; //清除AA,SI,STA位
I2CONSET = 0x40; // 使能主I2C,即设置I2EN位
// 设置I2C中断允许
VICIntSelect = 0x00000000; // 设置所有通道为IRQ中断
VICVectCntl1 = (0x20 | 0x09); // I2C通道分配到IRQ slot1,次高优先级,0x09为I2C0对应中断编号
VICVectAddr1 = (int32)IRQ_I2C0; //设置I2C中断向量
VICIntEnable = VICIntEnable | (1 << 9); //使能I2C0中断,0x09为I2C0对应中断编号
//IRQEnable(); //打开中断
#if(SOURCE_VER == TEST_SOURCE_IIC) //??????????????????????????????????????????????????????
IO0DIR = IO0DIR | BEEP; // 设置蜂鸣器控制口输出
IO0SET = IO0SET | BEEP; //先关闭蜂鸣器
//I2cInit(100000); //I2C初始化,100K
for (i=0; i<10; i++)
{
data_buf[i] = i + '0'; //数据0~9,转换成ASCII码
}
I2C_WriteNByte(AT24C16, X_ADD_8_SUBA, 0x00, data_buf, 10);//往起始地址0x00开始写入10个数据
DelayNS(10);
for (i=0; i<10; i++) //清零数据缓冲区,防止出错
{
data_buf[i] = 0;
}
I2C_ReadNByte(AT24C16, X_ADD_8_SUBA, 0x00, data_buf, 10); //读回刚才写入的数据
for (i=0; i<10; i++) //判断读回的数据是否正确
{
if (data_buf[i] != (i + '0'))
{
while (1)
{
IO0SET = BEEP; //出错,连续蜂鸣
DelayNS(20);
IO0CLR = BEEP;
DelayNS(20);
}
}
}
//正确,蜂鸣一次
IO0CLR = BEEP;
DelayNS(50);
IO0SET = BEEP;
while (1);
#endif
}
/*
**********************************************************************************************************
** 函数名称:ISendByte()
** 函数功能:向无子地址器件发送1字节数据。
** 入口参数:sla 器件地址
** dat 要发送的数据
** 出口参数:返回值为0时表示出错,为1时表示操作正确。
** 说明: 使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
*********************************************************************************************************
*/
UCHAR8 ISendByte(UCHAR8 sla, UCHAR8 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);
}
}
/*
*********************************************************************************************************
** 函数名称:IRcvByte()
** 函数功能:向无子地址器件读取1字节数据。
** 入口参数:sla 器件地址
** dat 接收数据的变量指针
** 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
** 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
*********************************************************************************************************
*/
UCHAR8 IRcvByte(UCHAR8 sla, UCHAR8 *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);
}
/*
*********************************************************************************************************
** 函数名称 :I2C_ReadNByte()
** 函数功能 :从有子地址器件任意地址开始读取N字节数据
** 入口参数 : sla 器件从地址
** suba_type 子地址结构 1-单字节地址 3-8+X结构 2-双字节地址
** suba 器件子地址
** s 数据接收缓冲区指针
** num 读取的个数
** 出口参数 : TRUE 操作成功
** FALSE 和I2C_ADDR_ERRO 操作失败
** 创 建 人: 段斌
** 创建时间:2006-03-20
*********************************************************************************************************
*/
UCHAR8 I2C_ReadNByte (UCHAR8 sla, UINT32 suba_type, UINT32 suba, UCHAR8 *s, UINT32 num)
{
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; /* 有子地址读 */
I2C_end = 0;
if((I2C_num == 0) || ((I2C_suba + I2C_num)>0x800))//超过0x800,即2K范围
{
return(I2C_ADDR_ERRO);
}
/* 清除STA,SI,AA标志位 */
I2CONCLR = (1 << 2)| /* AA */
(1 << 3)| /* SI */
(1 << 5); /* STA */
/* 置位STA,启动I2C总线 */
I2CONSET = (1 << 5)| /* STA */
(1 << 6); /* I2CEN */
/* 等待I2C操作完成 */
//// while (I2C_end == 0)
//// { }
if (I2C_end == 1)
return (TRUE);
else
return (FALSE);
}
return (FALSE);
}
/*
*********************************************************************************************************
** 函数名称 :I2C_WriteNByte()
** 函数功能 :向有子地址器件写入N字节数据
** 入口参数 : sla 器件从地址
** suba_type 子地址结构 1-单字节地址 3-8+X结构 2-双字节地址
** suba 器件内部物理地址
** *s 将要写入的数据的指针
** num 将要写入的数据的个数
** 出口参数 : TRUE 操作成功
** FALSE 和I2C_ADDR_ERRO 操作失败
** 创 建 人: 段斌
** 创建时间:2006-03-20
*********************************************************************************************************
*/
UCHAR8 I2C_WriteNByte(UCHAR8 sla, UCHAR8 suba_type, UINT32 suba, UCHAR8 *s, UINT32 num)
{
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; /* 有子地址,写操作*/
I2C_end = 0;
if((I2C_num == 0) || ((I2C_suba + I2C_num)>0x800))//超过0x800,即2K范围
{
return(I2C_ADDR_ERRO);
}
/* 清除STA,SI,AA标志位 */
I2CONCLR = (1 << 2)| /* AA */
(1 << 3)| /* SI */
(1 << 5); /* STA */
/* 置位STA,启动I2C总线 */
I2CONSET = (1 << 5)| /* STA */
(1 << 6); /* I2CEN*/
/* 等待I2C操作完成 */
/// /while (I2C_end == 0)
//// { }
if (I2C_end == 1)
return (TRUE);
else
return (FALSE);
}
return (FALSE);
}
/*
*********************************************************************************************************
** 函数名称 :__irq IRQ_I2C()
** 函数名次 :硬件I2C中断服务程序,按照全局变量的设置进行操作及设置软件标志
** 入口参数 :无
** 出口参数 :无
** 说明 :注意处理子地址为2字节的情况。
** 创 建 人: 段斌
** 创建时间:2006-03-20
*********************************************************************************************************
*/
void __irq IRQ_I2C0(void)
{
switch (I2STAT & 0xF8) /* 读取I2C状态寄存器I2DAT */
{
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 */
I2C_end = 1; /* 总线已经停止 */
}
}
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 0x38: /* 在SLA+R/W或数据字节中丢失仲裁 */
case 0x48: /* 已发送SLA+R,已接收非应答 */
{
I2CONCLR = 0x28;
I2C_end = 0xFF;
}
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;
I2C_end = 1;
}
break;
default:
break;
}
VICVectAddr = 0x00; /* 中断处理结束 */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -