tiny6410的IIC裸机驱动

时间:2022-07-02 03:53:45

  IIC即Inter-IntegratedCircuit(集成电路总线),是一种多向控制总线,由飞利浦半导体公司在八十年代初设计,主要是用来连接整体电路(ICS)。在IIC中,多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实施数据传输的控制源,这种方式简化了信号传输总线。I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。

 一IIC协议

   IIC的总线协议规定:从设备采用7位地址,D7~D1作为从设备的地址,D0作为数据传输方向(0表示主设备向从设备写入数据,1表示主设备想从设备读出数据)。每次主设备广播出去的地址,所有从设备都会接收到并和自己的地址进行比对。IIC的从设备地址分为固定部分和用户自定义部分,D7~D4由厂商生产时就已经确定,D3~D1有用户自己确定,这里的实验是在IIC上挂载AT24C02(eeprom),其D3~D1接地,由其芯片手册以确定其读取地址为0xa1,发送地址为0xa0。tiny6410的IIC裸机驱动

    IIC发送过程主要有三个重要阶段:

   发送:在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低时为开始信号。

tiny6410的IIC裸机驱动

  结束:在时钟线SCL保持高电平期间,数据线SDA上的电平被释放,被拉高时为结束信号

tiny6410的IIC裸机驱动

应答:发送器每发送一个字节,就在时钟脉冲的第9位释放数据线,由接收器反馈一个应答信号,应答信号为低电平是定义为有效。

tiny6410的IIC裸机驱动


  二 IIC编程实现

  IIC的编程实验分为四部分,分别是iic初始化,读/写和测试。

相关寄存器:

IICCON:该寄存器主要涉及到IIC的应答信号是能(bit7),以及SCL的时钟频率(bit6和bit[3:0])。bit6确定其分频系数,由于SCL的频率规定为小于1000KHz,所以这次实验中IICCLK = PCLK /16,bit[3:0]确定最终的值,这次实验中bit[3:0]的值为0xf,所以最终频率值为IICCLK/(IICCON[3:0]+1).
计算公式:(PCLK=66.5Hz)

IICCLK = PCLK /16;
tiny6410的IIC裸机驱动

Tx clock = IICCLK/(IICCON[3:0]+1).=66.5/(16*16)*1M=255859.375HZ.

IICSTAT:该寄存器的bit[7:6]确定主从机的工作模式,bit[4]使能串行输出
tiny6410的IIC裸机驱动

tiny6410的IIC裸机驱动

IICDS:发送或者接受数据寄存器

tiny6410的IIC裸机驱动
初始化:结合s3c6410的操作手册,主要涉及到IIC相关寄存器的初始化和IIC数据线与时钟线的io初始化;

tiny6410的IIC裸机驱动

数据的发送这要结合芯片at24c02的数据手册和s3c6410的数据手册上的流程图

tiny6410的IIC裸机驱动tiny6410的IIC裸机驱动

读数据:在结合流程图的同时要特别注意两个地方的操作,在图中以画出。

tiny6410的IIC裸机驱动

tiny6410的IIC裸机驱动

下面是本次实验的总代码:

#define IICDS (*(volatile unsigned char*)0x7F00400C)
#define IICSTAT (*(volatile unsigned char*)0x7F004004)
#define IICCON (*(volatile unsigned char*)0x7F004000)
//相关IO定义
#define GPBCON (*(volatile unsigned long*)0x7F008020)
#define GPBPUD (*(volatile unsigned long*)0x7F008028)
#define slavew_addr 0xa0//从机的发送地址
#define slaver_addr 0xa1//从机的接收地址
void delay(int timer)
{
int i;
while(timer--)
for(i=0;i<100;i++)
;
}
/*****
函数名:void IIC_init(void)
功能:初始化IIC相关的硬件
参数说明:无
返回值:无
时间:2017/7/11
*****/
void IIC_init(void)
{
//初始化中断相关寄存器()


//初始化相关IO
GPBCON |=(0x22<<20);
GPBPUD &=~(0xf<<9);
//1 如果需要将主机当作iic的从设备时,将其地址写入到IICADD中这里我们的cpu做主机所以不需要配置。

//2设置IICCON寄存器
//2.1 使能中断
IICCON |=(1<<5);
//2.2 定义SCL时钟(时钟频率小于1000khz)
IICCON &=~(1<<6);
IICCON &=~(0Xf<<0);
IICCON |=(0xf<<0);
//3设置IICSTAT为使能串行输出状态
IICSTAT |=(1<<4);
//应答信号的产生
IICCON |=(1<<7);
//清除相应的中断标志位,注意,这一位在接受或者发送完成时都要清零。
IICCON &=~(1<<4);
}
/*****
函数名:void IIC_read(unsigned char *buf,unsigned char daddr,int length)
功能:初始化IIC相关的硬件
参数说明:buf->存放接收到的数据,daddr读数据的地址,lengt读取数据的长度
返回值:无
时间:2017/7/11
*****/
void IIC_read(unsigned char *buf,unsigned char daddr,int length)
{
int j;
unsigned char unused;
//在eeprom芯片手册上有一段是写操作,所以这里要配置成主机发送模式
IICSTAT |=(0b10<<6);
//tab 写入从机地址
IICDS=slavew_addr;
IICCON &=~(1<<4);

IICSTAT=0xf0;

//tab2 等待应答-----发送完成产生中断,IICCON&(1<<4))==0表示数据发送完成
while((IICCON&(1<<4))==0)
{
delay(100);
}
//tab3 写入字节地址
IICDS=daddr;
//注意清除中断标志位
IICCON &=~(1<<4);
//tab4 等待应答
while((IICCON&(1<<4))==0)
{
delay(100);
}

//1 配置为主机接收模式
IICSTAT &=~(0b11<<6);
IICSTAT |=(0b10<<6);
//2 写入从机地址到IICDS
IICDS=slaver_addr;
IICCON &=~(1<<4);
//3 写入0X0B到IICSTAT
IICSTAT=0Xb0;
while((IICCON&(1<<4))==0)//在接收前会产生一次中断,如果该penging寄存器为1说明中断产生开始接收数据了
delay(100);
while((IICCON&(1<<4))==0)//在接收前会产生一次中断,如果该penging寄存器为1说明中断产生开始接收数据了
delay(100);
//不知道为什么,EEPROM每次在读数据时独到的第一个数据常常是无效数据,所以应该丢掉
unused=IICDS;
IICCON &= ~(1<<4);
//在接受数据前会产生中断所以这里需要等待中断的产生。
while((IICCON&(1<<4))==0)
delay(100);
//4 接受IICDS的数据(从机地址)的数据
for(j=0;j<length;j++)
{
//从eepro芯片手册观察到如果接受数据结束 ,最后会产生非应答信号。
if(j==(length-1))
IICCON &=~(1<<7);
buf[j]=IICDS;
//5 产生应答信号同时清楚相应的pending寄存器
IICCON &=~(1<<4);
while((IICCON&(1<<4))==0)//在接收前会产生一次中断,如果该penging寄存器为1说明中断产生开始接收数据了
delay(100);
}
//6 停止结接受数据,写入0X90到IICSTAT
IICSTAT=0x90;

//7 清楚pengding相应位
IICCON &= ~(1<<4);
//8 结束

}
/*****
函数名:void IIC_write(unsigned char sbuf,unsigned char daddr)
功能:IIC发送数据
参数说明:buf->存放要发送到的数据,daddr读数据的地址,lengt读取数据的长度
返回值:无
时间:2017/7/11
*****/
void IIC_write(unsigned char sbuf,unsigned char daddr)
{
//1主机发送模式
IICSTAT |=(0b10<<6);
//2 写从机地址到IICDS
IICDS=slavew_addr;
IICCON &= ~(1<<4);
//3 写入0xf0到IICSTAT
IICSTAT=0xf0;
//4 等待应答
while((IICCON&(1<<4))==0)//在接收前会产生一次中断,如果该penging寄存器为1说明中断产生开始接收数据了
delay(100);
//tab 写入字节地址
IICDS=daddr;
IICCON &= ~(1<<4);
//等待应答
while((IICCON&(1<<4))==0)//在接收前会产生一次中断,如果该penging寄存器为1说明中断产生开始接收数据了
delay(100);
//5 开始发送数据,一次发送一个字节
IICDS=sbuf;
IICCON &= ~(1<<4);
//5 等待应答并清除中断标志位
while((IICCON&(1<<4))==0)//在接收前会产生一次中断,如果该penging寄存器为1说明中断产生开始接收数据了
delay(100);
//6 写入0XD0到IICSTAT
IICSTAT=0xd0;
//7 清除中断标志位
IICCON &= ~(1<<4);
//8 等待结束
delay(100);
}

void IIC_test(void)
{
int i;
unsigned char sbuf[256];
unsigned char dbuf[256];
printf("befor read:---->\n");
for(i=0;i<256;i++)
{
sbuf[i] = i+1;
dbuf[i] = 0;
}
for(i=0;i<256;i++)
{
if(i%8==0)
printf("\r\n");
printf("dbuf[%d]=%d\t\t",i,dbuf[i]);
}
printf("there is dbug 1\n");
for(i=0;i<256;i++)
IIC_write(sbuf[i],i);
printf("after read:\n");
IIC_read(dbuf,0,256);
printf("there is dbug 2\n");
for(i =0; i<256;i++)
{
if(i%8==0)
printf("\r\n");

printf("%d\t",dbuf[i]);
}
}