/*
* I2C.c
*
* Created on: 2017-9-4
* Author: 代忠
* function: implment i2c function
*/
#include "includes.h"
/********************************************************************
*以下为24C0X 系列的EEROM操作函数
*******************************************************************/
#define __IIC24C0x_h__
#include "includes.h"
#include "system.h"
#include "delay.h"
#include "altera_avalon_pio_regs.h"
#define false 0
#define true 1
/******************************************************************************
* 功能:读取SDA数据线上的数据
* 入口参数:无
* 返回值:返回数据线上的电平情况
*/
alt_u8 SDA_READ(void)
{
return IORD_ALTERA_AVALON_PIO_DATA(SDA_BASE);//读取I2C总线数据线上的数据信息
}
/********************************************************************
*功能:I2C总线初始化函数,在main函数中应该先调用该函数对i2C总线进行相关的初始化工作
*入口参数:无
*返回值:无
********************************************************************/
void I2C_init(void)
{
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,0);
delay(1);
I2C_stop();
}
/********************************************************************
*功能:I2C总线产生起始信号函数
*入口参数:无
*返回值:无
********************************************************************/
void I2C_start(void)
{
//设置数据信号线的工作方式为输出模式
IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE,1);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,1);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE,0);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,0);//保持时钟信号线
delay(1);
}
/********************************************************************
*功能:I2C总线产生停止信号
*入口参数:无
*返回值:无
********************************************************************/
void I2C_stop(void)
{
IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE,1);//设置数据信号线的工作方式为输出模式
IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE,0);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,1);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE,1);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,0);
delay(1);//保持时钟信号线
}
/********************************************************************
*功能:I2C总线上写入1个字节的数据
*入口参数:待写入的数据
*返回值:无
********************************************************************/
alt_u8 I2C_sendByte(alt_u8 I2C_data)
{
alt_u8 i;
alt_u8 ack;
IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE,1);//设置数据信号线的工作方式为输出模式
for (i=0;i<8;i++)
{
if(I2C_data & 0x80)
IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE,1);
else
IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE,0);
I2C_data = I2C_data << 1;
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,1);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,0);
}
delay(1);
IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE,0);//设置数据信号线的工作方式为输入模式
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,1);
delay(1);
if (IORD_ALTERA_AVALON_PIO_DATA(SDA_BASE)&0x0001)//等待从器件应答
ack = 0;
else
ack = 1;
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,0);
return ack; //返回从器件所发送应答信号进行取反返回
}
/********************************************************************
*I2C总线上读取一个字节的内容
********************************************************************/
alt_u8 I2C_receiveByte(void)
{
alt_u8 I2C_data = 0x00;
alt_u8 i;
IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE,0);//设置数据信号线的工作方式为输入模式
for (i=0;i<8;i++)
{
delay(1);
I2C_data *= 2; //接受到的数据进行相关的左移
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,1);
delay(1);
if (IORD_ALTERA_AVALON_PIO_DATA(SDA_BASE)&0x0001)
{
I2C_data++;
}
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,0);
}
return (I2C_data);
}
/********************************************************************
*I2C总线上向从器件写入器件地址和从寄存器地址
********************************************************************/
void I2C_issue_add(alt_u8 chipAdd,alt_u16 subAdd)
{
alt_u8 low_add;
alt_u8 wd = 0;
low_add = subAdd; //24C04有两页的一个地址空间,此处为计算地址空间位于那一页,详情参观24C04的datasheet
subAdd >>= 7;
wd = subAdd & 0x02; //计算位于那一页
wd |= chipAdd;
I2C_start();
I2C_sendByte(wd);
I2C_sendByte(low_add);
}
/********************************************************************
*I2C总线等待从器件内部完成写操作
********************************************************************/
void I2C_waitforwrite(alt_u8 chip)
{
alt_u8 ack;
do
{
I2C_start();
ack = I2C_sendByte(chip);
}while (!ack);
}
/********************************************************************
*将指针地址buf中的数据想入到器件chipAdd中的 s_add处
*写入数据的地址是连续写的,连续所写的内容最多为4个
********************************************************************/
void I2C_write_block(alt_u8 chipAdd,alt_u16 S_add,alt_u8 n_buf,alt_u8 *buf)
{
alt_u8 i;
I2C_issue_add(chipAdd,S_add);
for (i=0;i<n_buf;i++)
{
I2C_sendByte(*(buf+i));
}
I2C_stop();
//I2C_waitforwrite(chipAdd);
}
/********************************************************************
* 从EEROM中寄存器地址为S_add出读取n_buf个数据信息,存放于buf指针里面
********************************************************************/
void I2C_read_block(alt_u8 chipAdd,alt_u16 S_add,alt_u8 n_buf,alt_u8 *buf)
{
alt_u8 i;
alt_u8 rd=0;
I2C_issue_add(chipAdd,S_add);
S_add >>= 7;
rd = S_add & 0x02; //地址页计算
rd |= chipAdd;
rd |= 0x01; //进行读写位置位
I2C_start(); //重新产生启动信号,详情请参观I2C协议读取EEROM协议手册
I2C_sendByte(rd);
for (i=0;i<n_buf-1;i++)
{
*(buf+i) = I2C_receiveByte();
delay(1);
IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE,1);
IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE,0); //应答是否需要连续读取数据
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,1);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE,0);
delay(1);
IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE,1);
}
*(buf+i) = I2C_receiveByte();
I2C_stop();
}