S3C2440之IIC

33 篇文章 1 订阅

IIC个人感觉驱动的中断步骤还是挺麻烦的,

要按照步骤流程来,程序如下:

/******************************
*文件名:IIC.c				  *
*功能:   AT24C02底层驱动	  *
*创建者: 潘星宇				  *
*最后修改:2013.03.20		  *
*备注:						  *
*							  *
*******************************/
#include "IIC.h"

static U8 _iicData[IICBUFSIZE];		//IIC数据缓冲区 
static volatile int _iicDataCount;	//IIC数据计数器它是保证数据地址和数据值发送完了	 
static volatile int _iicStatus;		//IIC状态标志
static volatile int _iicMode;		//IIC模式变量
static int _iicPt;					//IIC读数据计数器,用于修改读回的数据缓冲区的地存放在址

/**************************************************************************
***** 函数名: IIC_init(void)
***** 功  能: IIC初始化
***** 参  数: 无
***** 返回值: 无
***** 创建者:	
***** 创建时间:
***** 最后更新: 
****************************************************************************/
void IIC_init(void)
{
	/*第一步:功能选择 GPE15:IICSDA , GPE14:IICSCL。禁止内部上拉*/
	//rGPECON = 0xa0000000; // 1010 GPE15:IICSDA , GPE14:IICSCL
	rGPECON &= 0x0fffffff; 
	rGPECON |= 0xa0000000;  // 1010 GPE15:IICSDA , GPE14:IICSCL
	/*第二步:将中断函数地址送给IIC中断向量地址,pISR_IIC:IIC中断服务程序地址寄存器  IicInt为IIC中断服务函数名*/
	pISR_IIC = (unsigned)IicInt;

	/*第三步:让IIC中断源有效(IIC中断源使能)*/ 
	rINTMSK &= ~(BIT_IIC); //~(0x1<<27)

	/***********************************************************************
	***IICCON[7]:IIC总线应答使能位             
	***IICCON[6]:IIC总线传输时钟预定标器源时钟选择位,
	             0:IICCLK = fPCLK /16 ; 1: IICCLK = fPCLK/512 
	***IICCON[5]:IIC总线接收发送中断使能位0:无效即禁止中断  1:有效,允许中断     
	***IICCON[4]:IIC总线接收发送中断挂起标志
	             1 中断挂起(读)恢复IIC传输(写),	 
	             0无中断挂起(读) N/A(写); 
				 //中断标记,此位用来标识是否有IIC中断发生,读出为0时表示没有中断发生,
				 //读出为1时表示有中断发生。当此位为1时,SCL线被拉低,此时所有IIC传输停止;
				 //如果要继续传输,需写入0清除它。
	***IICCON[3:0]:IIC总线传输时钟预写器,Tx clock = IICCLK/(IICCON[3:0]+1) 与IICCON[6]有关 
	*******************************************************************/ 
	/*Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, 
	Transmit clock value Tx clock=IICCLK/16
	If PCLK 50.7MHz, IICCLK = 3.17MHz, Tx Clock = 0.198MHz */
	//第四步:设置IICCON寄存器,ACK信号使能,16分频时钟,TX/RX中断允许,继续传输,预分频系数为16。
	rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);//IICCON[4]上电为0,所以不需要设置
	/* 第五步:设置本机当从机时的地址,2440在IIC空闲的情况下通常配置为从机模式*/ 
	rIICADD  = 0x10;             

	/**************************************************************************** 
	***IICSTAT[7:6] 00:  从接收模式  01:  从发送模式  
	                10:  主接收模式  11: 主发送模式 

	***IICSTAT[5]   IIC总线忙状态位   0:(读)不忙,(写)停止信号生成;       
	1:(读)忙 (写)开始信号输出.在开始信号后,IICDS中的数据自动被传输。
					 
	***IICSTAT[4] IIC总线数据输出使能位。       
	0:无效Rx/Tx     1:有效Rx/Tx 

	***IICSTAT[3] IIC总线仲裁过程状态标志位     
	0:总线仲裁成功  1:在串行IO中总线仲裁失败 

	***IICSTAT[2] IIC总线address-as-slave状态标志位:
	当检测到开始或停止条件,该位被清除; 
	1:收到的从设备地址和IICADD中的地址匹配 。

	***IICSTAT[1] IIC总线地址0状态标志位.     
	0:当检测到开始或停止条件,该位被清除; 	                                            
	1:收到的从地址是00000000b 

	***IICSTAT[0] IC总线最后收到位状态标志位;  
	0:最后收到位是0(收到ACK); 1:最后收到位是1(未收到ACK)         	                                              
	****************************************************************************/ 
	//第六步:IIC总线数据输出使能位,允许发送,接收数据
	rIICSTAT = 0x10;              ///*输出使能*/ 0001 0000

	/****************************************************************************
	****IICLC[2]:IIC总线滤波器使能位 
	****IICLC[0:1]:IIC总线SDA线延时长度选择位  
	    00:  0 clocks  01:  5 clocks 10:  10 clocks  11: 15 clocks   
	****************************************************************************/
	//第七步:IICLC  IIC数据经过滤波,且延时5个时钟    ???
	rIICLC = (1<<2)|(1);  /* 一般配置为5或15个时钟就可以了*/  
	//IICLC[2]表示将1个pclk时钟周期内SDA信号跳变两次就滤除,不处理,
    //IICLC[1:0]表示将SDA数据线上的数据保持几个pclk时钟周期
}


/**************************************************************************
***** 函数名: Wr24C080(void)
***** 功  能: 写一个字节到AT24C08
***** 参  数: slvAddr 从机地址	addr内部子地址	data要写的数据
***** 返回值: 无 
***** 创建者:	
***** 创建时间:
***** 最后更新: 
***Wr24C080(0xa0,(U8)i,i);
****************************************************************************/
void Wr24C080(U32 slvAddr,U32 addr,U8 data)
{
	U32 i = 0;
	/*第一步:设置标志位:设置IIC模式,主发送,仅是一个标志位,(设置两个标志、将要写入数据,写入那个地址暂存)*/
	_iicMode      = WRDATA;	 //(1)

	/*数据索引设置为0*/
	_iicPt        = 0;		 

	/*把从机内部地址存放到_iicData[0]*/	//芯片内部地址
	_iicData[0]   = (U8)addr;
	
	/*把要写入的数据存放到_iicData[1]*/ 
	_iicData[1]   = data;	  

	/*写数据模式总共要发送三个字节数据:从机地址,从机内部地址和要
	写入的数据。所以在此阶段下要进入三个次中断服务程序,所以设置为2,
	因为下面判断是以while (_iicDataCount!=-1);为判断条件的*/
	_iicDataCount = 2;		 

	/*第二步:写入芯片地址(即丛机地址),0xa0 把从设备地址写入IICDS*/
	//IICDS寄存器的位[7:0],保存的是要发送或已经接收的数据
	rIICDS   = slvAddr;      
	//第三步:设置为主机模式及发起发送信号及允许中断
	/*设置为主机模式,发送起始信号*/ //IICSTAT[7:6]为10即为主机发送器模式
	rIICSTAT = 0xf0; //1111 0000 IICSTAT[5]=1发出起始信号,IICSTAT[4]=1,使能接收/发送功能。

	///*第四步:等待发送完成,数据发送完毕,然后就进入中断服务函数
	//(进入中断三次才可能等于-1)*/

	while (_iicDataCount!=-1)
	{	
		i++;
		if (i>80000000)
		{
			break;
		}
	}
}


/**************************************************************************
***** 函数名: Rd24C080(void)
***** 功  能: 写一个字节到AT24C08
***** 参  数: slvAddr 从机地址	addr内部子地址
***** 返回值: 读取的数据U8
***** 创建者:	
***** 创建时间:
***** 最后更新: 
****************************************************************************/
U8 Rd24C080(U32 slvAddr,U32 addr)
{	
	U32 i = 0;
	//第一步:设置相关标志位
	_iicMode      = SETRDADDR; //4设置IIC模式,写地址,仅是一个标志位
	_iicPt        = 0;		   //数据索引设置为0
	_iicData[0]   = (U8)addr;  //把设置字地址存放到_iicData[0]
	_iicDataCount = 1;		   //计数器设置为 1
	rIICDS   = slvAddr;		   //0xa0  把从设备地址写入IICDS

	/*第二步:设置为主机模式,发送起始信号*/
	rIICSTAT = 0xf0;           

	/* 发送开始信号后IIC就会把前面装入rIICDS中的从机地址发送出去,
	当从机地址发送完成后,进入中断服务程序,在中断服务程序执行
	_iicDataCount,_iicDataCount值变为0,同时把_iicData[0](这时里面的数据
	实际上是24C08的内部的地址)送给rIICDS,恢复IIC传输,退出中断服务程序。
	当发送完成后再次进入中断服务程序, 在中断服务程序执行_iicDataCount,
	_iicDataCount值变为-1,退出中断服务程序.
	*/
	/*第三步:等待发送完毕,如果发送完成,进入中断函数,等待把从机地址和从机内部地址发送完成(进入中断2次才可能等于-1)*/
	while (_iicDataCount!=-1);	 //该步:发送芯片地址,发送芯片内部地址
	//第四步:将写变成读,并且重新设置相应标志位
	/*设置为取数据模式*/
	_iicMode      = RDDATA;	 //3
	_iicPt        = 0;

	/*取数据模式上还要再发一次从机地址加读方向位,这会产生一次中断,
	读指定单元的数据也会产生一次中断。所以在此阶段下要进入两次中断
	服务程序,的以设置为1,因为下面判断是以_iicDataCount!=-1为判断条件的*/
	_iicDataCount = 1;

	/*把从机地址装入数据寄存器*/
	rIICDS        = slvAddr;

	/*发送起始信号,配置为主接收模式*/
	rIICSTAT      = 0xb0;  //1011             

	/*恢复IIC传输*/
	rIICCON       = 0xaf;               //Resumes IIC operation.

	/*第五步:等待把数据读取回来*/
	while (_iicDataCount!=-1)
	{
		i++;
		if (i>80000000)
		{
			break;
		}
	}

	/*第六步:把数据存放到data指向的单元中*/
	return(_iicData[0]);
}


/**************************************************************************
***** 函数名: IicInt(void)
***** 功  能: IIC中断服务程序
***** 参  数: 无
***** 返回值: 无 
***** 创建者:	
***** 创建时间:
***** 最后更新: 
****************************************************************************/
void __irq IicInt(void)
{
	U32 iicSt,i;

	/*进入中断后第一步:清中断标志*/
	rSRCPND = BIT_IIC; //(0x1<<27) 为1清除中断屏蔽,即中断来了进行处理     
	rINTPND = BIT_IIC; //(0x1<<27) 为1允许中断 
	//第二步:判定是否正常(IICST=IICSTAT),当出现如下4种情况也可以进入中断,一般用不到。
	//根据需要可以添加如下四种设置,该程序没用到
	if (iicSt & 0x8){} //当仲裁失败
	if (iicSt & 0x4){} //当接收到的从机地址与IICADD中的相同
	if (iicSt & 0x2){} //当接收到从机地址是 0000000b
	if (iicSt & 0x1){} //当没有接收到应答信号

	switch (_iicMode)  //判定是处理那一种阶段:读、写、写地址三种
	{

	/*处于读数据模式*/
	case RDDATA:   //3
		if ((_iicDataCount--)==0)   //0,
		{
			/*读取接收到的数据*/
			_iicData[0] = rIICDS;

			/*配置为发送停止信号,主接收模式*/
			rIICSTAT = 0x90;   //1001

			/*恢复IIC总线传输,以便把停止信号发送出去*/
			rIICCON  = 0xaf;

			/*延时一会,等待停止信号有效,但不能太长*/
			delay(1);       
			       
			//Too long time...
			//The pending bit will not be set after issuing stop condition.
			break;
		}

		/*如果是最后一个数据,重启IIC传输,但禁止发送应答信号*/
		if ((_iicDataCount)==0)
		{
			/*重启支IIC传输,但不再发送应答信号*/
			rIICCON = 0x2f;  //0010 1111
		}              

	   	/*如果不是最后一个数据*/
		else
		{
			/*如果不是最后一个数据,重启支IIC传输,同时允许发送应答信号*/
			rIICCON = 0xaf;         
		}
		break;

    /*处于写数据模式*/
	case WRDATA:  //1
		/*如果已经是最后一个数据*/
		if ((_iicDataCount--)==0)	 //2,1,0
		{
			/*配置为发送停止信号,主发送模式*/
			rIICSTAT = 0xd0;  //1101 0000  写IICSTAT[5]此位时0:发出P信号(结束信号)

			/*恢复IIC总线传输,以便把停止信号发送出去*/
			rIICCON  = 0xaf;   //1010 1111           

			/*延时一会,等待停止信号有效,但不能太长*/
			for (i=0;i<100;i++);         //Wait until stop condtion is in effect.

			//Too long time...
			//The pending bit will not be set after issuing stop condition.
			break;
		}

		/*把下一个要发送的数据写入到数据寄存器中*/
		rIICDS = _iicData[_iicPt++];        //_iicData[0] has dummy.

		/*延时,直到IICSCL时钟线上跳,时间可以适当放宽*/
		for (i=0;i<10;i++);                 //for setup time until rising edge of IICSCL

		/*恢复IIC传输*/
		rIICCON = 0xaf;                     //resumes IIC operation.
		break;

	/*处于写地址模式*/
	case SETRDADDR:
		/*如果已经是最后一个数据*/
		if ((_iicDataCount--)==0)  //0,-1
		{
			break; //IIC operation is stopped because of IICCON[4]
		}

		/*把一个个要发送的数据放入到数据寄存器中*/
		rIICDS = _iicData[_iicPt++];

		/*延时,直到IICSCL时钟线上跳,时间可以适当放宽*/
		for (i=0;i<10;i++);                

		/*恢复IIC传输*/
		rIICCON = 0xaf;    //1010 1111
		   
		break;

	default:
		break;
	}
}


按照程序中每一步来执行就没有问题了,这个IIC用来控制一个EEPROM的。

头文件如下:

#ifndef IIC_H
#define IIC_H
#include <string.h>
#include "2440addr.h"
#include "def.h"
#include "IIC.h"
#include "UART.h"
#include "common_functions.h"

#define WRDATA      (1)
#define POLLACK     (2)
#define RDDATA      (3)
#define SETRDADDR   (4)

#define IICBUFSIZE 0x20

#define EEPROM_ADDRESS   0xa0	  //EEPROM地址

#define IIC_DATA_ADDRESS 0xff     //用于储存判断是否校准过触摸屏的数据的地址
#define IIC_DATA         0xf0     //用于判断是否校准过触摸屏的数据的值
#define PLUS 0x00                 //正数
#define MINUS 0x01				  //负数

//以下0~6为校准用的参数储存地址 
#define TOUCH_01_ADDRESS  0x00	  //最高8位
#define TOUCH_02_ADDRESS  0x01	  //次高8位
#define TOUCH_03_ADDRESS  0x02	  //次低8位
#define TOUCH_04_ADDRESS  0x03	  //最低8位

#define TOUCH_10_ADDRESS  0x10	  //参数1
#define TOUCH_11_ADDRESS  0x11	  
#define TOUCH_12_ADDRESS  0x12	  
#define TOUCH_13_ADDRESS  0x13	  

#define TOUCH_20_ADDRESS  0x20	  //参数2
#define TOUCH_21_ADDRESS  0x21	  
#define TOUCH_22_ADDRESS  0x22	  
#define TOUCH_23_ADDRESS  0x23	  

#define TOUCH_30_ADDRESS  0x30	  //参数3
#define TOUCH_31_ADDRESS  0x31	  
#define TOUCH_32_ADDRESS  0x32	  
#define TOUCH_33_ADDRESS  0x33	  

#define TOUCH_40_ADDRESS  0x40	  //参数4
#define TOUCH_41_ADDRESS  0x41	  
#define TOUCH_42_ADDRESS  0x42	  
#define TOUCH_43_ADDRESS  0x43	  
 
#define TOUCH_50_ADDRESS  0x50	  //参数5
#define TOUCH_51_ADDRESS  0x51	  
#define TOUCH_52_ADDRESS  0x52	  
#define TOUCH_53_ADDRESS  0x53	  

#define TOUCH_60_ADDRESS  0x60	  //参数6
#define TOUCH_61_ADDRESS  0x61	  
#define TOUCH_62_ADDRESS  0x62	  
#define TOUCH_63_ADDRESS  0x63	  

#define DOOR_PASSWOR1_1   0x70	  //用户账号1密码存储区域
#define DOOR_PASSWOR1_2   0x71
#define DOOR_PASSWOR1_3   0x72
#define DOOR_PASSWOR1_4   0x73
#define DOOR_PASSWOR1_5   0x74
#define DOOR_PASSWOR1_6   0x75

#define DOOR_PASSWOR2_1   0x80	  //用户账号2密码存储区域
#define DOOR_PASSWOR2_2   0x81
#define DOOR_PASSWOR2_3   0x82
#define DOOR_PASSWOR2_4   0x83
#define DOOR_PASSWOR2_5   0x84
#define DOOR_PASSWOR2_6   0x85

#define DOOR_PASSWOR3_1   0x90	  //用户账号3密码存储区域
#define DOOR_PASSWOR3_2   0x91
#define DOOR_PASSWOR3_3   0x92
#define DOOR_PASSWOR3_4   0x93
#define DOOR_PASSWOR3_5   0x94
#define DOOR_PASSWOR3_6   0x95
/**************************************************************************
***** 函数名: IIC_init(void)
***** 功  能: IIC初始化
***** 参  数: 无
***** 返回值: 无
***** 创建者:	
***** 创建时间:
***** 最后更新: 
****************************************************************************/
extern void IIC_init(void);

/**************************************************************************
***** 函数名: Wr24C080(void)
***** 功  能: 写一个字节到AT24C08
***** 参  数: slvAddr 从机地址	addr内部子地址	data要写的数据
***** 返回值: 无 
***** 创建者:	
***** 创建时间:
***** 最后更新: 
***Wr24C080(0xa0,(U8)i,i);
****************************************************************************/
extern void Wr24C080(U32 slvAddr,U32 addr,U8 data);

/**************************************************************************
***** 函数名: Rd24C080(void)
***** 功  能: 写一个字节到AT24C08
***** 参  数: slvAddr 从机地址	addr内部子地址
***** 返回值: 读取的数据U8
***** 创建者:	
***** 创建时间:
***** 最后更新: 
****************************************************************************/
extern U8 Rd24C080(U32 slvAddr,U32 addr);

/**************************************************************************
***** 函数名: IicInt(void)
***** 功  能: IIC中断服务程序
***** 参  数: 无
***** 返回值: 无 
***** 创建者:	
***** 创建时间:
***** 最后更新: 
****************************************************************************/
extern void __irq IicInt(void);
#endif

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值