i2c芯片的驱动程序(汇编)
- 格式:doc
- 大小:31.50 KB
- 文档页数:5
51单片机的I2C底层驱动程序(IO口模拟)/*Title:I2C for 80C51Author:yuyouliang51单片机(本人使用STC89C52单片机,12T模式)的I2C驱动程序,使用逻辑分析仪对该协议进行分析,发现波形比较美观,SCL 的频率在70KHz左右(11.0592M晶振),低于标准的100K,可以适应大多数的I2C器件。
如果感觉速度过快或过慢,可以自行修改延时。
希望可以给读者一个参考,给读者一些帮助!*//*i2c.h文件 */#ifndef __I2C_H_#define __I2C_H_sbit SCL = P2^1;sbit SDA = P2^0;void start_i2c(); //启动I2C总线:SCL高电平期间,SDA由高变低void stop_i2c(); //停止I2C总线:SCL高电平期间,SDA由低变高void send_i2c(unsigned char c); //主机发送一个字节,先发送最高位unsigned char receive_i2c(); //主机接收一个字节,先接收最高位void master_ack(bit ack); //主机非应答信号(填参数0)或应答信号(填参数1)void slave_ack(); //等待从机应答信号#endif/* i2c.c文件 */#include#include#include#define nop() _nop_()void start_i2c() //启动I2C总线:SCL高电平期间,SDA由高变低{SDA=1;SCL=1;nop();nop();nop();nop();SDA=0;SCL=0;}void stop_i2c() //停止I2C总线,SCL高电平期间,SDA由低变高{SDA=0;SCL=1;nop();nop();nop();nop();SDA=1;}void slave_ack() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。
ARM : at91-sam9x5ekLinux内核:linux-2.6.39时钟芯片:rx8025 SA/NB第一种方法:Rx8025驱动程序在该linux内核中已经包含,路径为:drivers/rtc/rtc-rx8025.c所以在内核中增加驱动只需要配置即可:1.执行make ARCH=arm menuconfig 进入菜单选项,选择RTC配置,选中EPSONRX-8025SA/NB,同时一定要去掉cpu自带的时钟。
2.i2c support 需要选中I2C Hardware Bus support中GPIO-based bitbanging I2C,否则,即使rtc驱动正确,也不能使用,提示:drivers/rtc/hctosys.c: unable to open rtc device (rtc0)。
问题源自,驱动配置正确,I2C驱动没有加载正确,udevd不能创建rtc0设备节点3.在arch/arm/mach-at91/board-sam9x5ek.c中添加信息,注意此处的name名称要与驱动程序中id_table中的名称保持一致。
而在linux某些匹配机制中,设备名称是与驱动名称相一致。
如果名称不能正确匹配,系统是不会执行probe函数的。
另外需要注意的是i2c地址,手册上给出的地址一般都是带有读写位的,而程序中的地址需要把最后一位的读写位去掉,取前面的7位。
Rx8025的地址为0x64,相应的程序中的地址应该为0x32。
否则会提示对寄存器的操作失败。
4.驱动正确配置后,生成相应的文件/dev/i2c-0/dev/rtc0/sys/bus/i2c/drivers/rtc-rx8025/sys/bus/i2c/drivers/0-0032。
24LC65 I2C EEPROM字节读写驱动程序[龙啸九天] [786次] 01-3-24 下午07:54:15/*————————————————————〖说明〗24LC65 I2C EEPROM字节读写驱动程序,芯片A0-A1-A2要接VCC。
现缺页写、页读,和CRC校验程序。
以下程序经过50台验证,批量的效果有待考察。
为了安全起见,程序中很多NOP是冗余的,希望读者能进一步精简,但必须经过验证。
51晶振为11.0592MHz〖文件〗24LC65.c ﹫2001/03/23〖作者〗龙啸九天 c51@ <a href= target=_blank></a> 〖修改〗修改建议请到论坛公布 <a href= target=_blank></a> 〖版本〗V1.00A Build 0323—————————————————————*/#define SDA P0_0#define SCL P0_1/*----------------------------------------------------------------------------调用方式:write_8bit(uchar ch) ﹫2001/03/23函数说明:内函数,私有,用户不直接调用。
------------------------------------------------------------------------------*/write_8bit(uchar ch){uchar i=8;SCL=0;_nop_();_nop_();_nop_();_nop_();_nop_();while (i--){SDA=(bit)(ch&0x80);_nop_();_nop_();_nop_();_nop_();_nop_();ch<<=1;SCL=1;_nop_();_nop_();_nop_();_nop_();_nop_();SCL=0;_nop_();_nop_();_nop_();_nop_();_nop_();}_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}/*--------------------------------------------------------------------------------调用方式:void ACK(void) ﹫2001/03/23函数说明:内函数,私有,用户不直接调用。
I2C_周立功标准驱动程序_c代码1. /****************************************Copyright(c)**************************************************2. ** 广州周立功单片机发展有限公司3. ** 研究所4. ** 产品一部5. **6. **7. **8. **--------------文件信息--------------------------------------------------------------------------------9. **文件名: I2c.c10. **创建人: 陈明计11. **最后修改日期: 2003年7月21日12. **描述: μCOS-II下LPC210x的I2c主模式底层驱动 13. **14. **--------------历史版本信息----------------------------------------------------------------------------15. ** 创建人: 陈明计16. ** 版本: v1.017. ** 日期: 2003年7月8日18. ** 描述: 原始版本19. **20. **------------------------------------------------------------------------------------------------------21. ** 修改人: 陈明计22. ** 版本: v1.123. ** 日期: 2003年7月21日24. ** 描述: 根据正式文档更改寄存器名25. **26. **--------------当前版本修订------------------------------------------------------------------------------27. ** 修改人:28. ** 日期:29. ** 描述:30. **31. **------------------------------------------------------------------------------------------------------32.************************************************************************ ********************************/33.34. #define IN_I2C35. #include "config.h"36. static uint8 *I2cBuf;37. static OS_EVENT *I2cSem;38. static OS_EVENT *I2cMbox;39. static int16 I2cNbyte;40. static uint8 I2cAddr;41.42. #define I2C_WRITE_END 1 /* 写完成 */ 43. #define I2C_READ_END 2 /* 读完成 */ 44. #define I2C_NOT_GET_BUS 4 /* 丢失仲裁 */ 45. #define I2C_ACK_ERR 8 /* 接收ACK错误 */46.47.48./*********************************************************************** **********************************49. ** 函数名称: I2cInit50. ** 功能描述: 初始化I2c(主模式)51. ** 输入: FI2c:I2c总线频率52. **53. ** 输出:TRUE :成功54. ** FALSE:失败55. ** 全局变量: I2cSem,I2cMbox56. ** 调用模块: OSSemCreate57. **58. ** 作者: 陈明计59. ** 日期: 2003年7月8日60. **-------------------------------------------------------------------------------------------------------61. ** 修改人: 陈明计62. ** 日期: 2003年7月10日63. **-------------------------------------------------------------------------------------------------------64. ** 修改人: 陈明计65. ** 日期: 2003年7月21日66. **------------------------------------------------------------------------------------------------------67.************************************************************************ ********************************/68. uint8 I2cInit(uint32 FI2c)69. {70. VICIntEnClr = 1 << 9; /* 禁止能I2c中断 */ 71. if (FI2c <= 400000)72. {73. PINSEL0 = (PINSEL0 & 0xffffff0f) | 0x50; /* 选择管脚为I2c */ 74. I2CONCLR = 0x6C; /* 清除控制寄存器 */ 75. I2SCLH = (Fpclk / FI2c + 1) / 2; /* 设置高电平时间 */ 76. I2SCLL = (Fpclk / FI2c) / 2; /* 设置低电平时间 */ 77. I2cSem = OSSemCreate(1); /* 信号量用于互斥操作总线 */ 78.I2cMbox = OSMboxCreate(NULL); /* 消息邮箱用于中断向任务传递操作结果 */79. if (I2cMbox == NULL)80. {81. return FALSE;82. }83. if (I2cSem != NULL)84. {85. return TRUE;86. }87. }88. return FALSE;89. }90.91./*********************************************************************** **********************************92. ** 函数名称: __I2cWrite93. ** 功能描述: 读I2C,但不发送STOP信号94. ** 输入: Addr:从机地址95. ** Data:将要写的数据96. ** 写的数据数目97. ** 输出:发送的数据字节数98. **99. ** 全局变量: I2cAddr,I2cNbyte,I2cBuf100. ** 调用模块: OSMboxPend101. **102. ** 作者: 陈明计103. ** 日期: 2003年7月8日104. **-------------------------------------------------------------------------------------------------------105. ** 修改人: 陈明计106. ** 日期: 2003年7月21日107. **------------------------------------------------------------------------------------------------------108.************************************************************************ ********************************/109. uint8 __I2cWrite(uint8 Addr, uint8 *Data, int16 NByte) 110. { 111. uint8 err;112. unsigned int Rt;113.114. I2cAddr = Addr & 0xfe; /* 存储发送地址 */ 115. I2cNbyte = NByte; /* 存储写字节数 */ 116. I2cBuf = Data; /* 存储写的数据的指针 */ 117.I2CONSET = 0x24; /* 设置为主机,并启动总线 */ 118.119. Rt = (unsigned int) OSMboxPend(I2cMbox, 0, &err); /* 等待操作结束 */ 120. return Rt;121. }122.123.124./*********************************************************************** **********************************125. ** 函数名称: I2cWrite126. ** 功能描述: 向I2C从器件写数据127. ** 输入: Addr:从机地址128. ** Data:指向将要写的数据的指针129. ** NByte:写的数据数目130. ** 输出:发送的数据字节数131. **132. ** 全局变量: I2cSem,I2cNbyte133. ** 调用模块: OSSemPend,__I2cWrite,OSSemPost134. **135. ** 作者: 陈明计136. ** 日期: 2003年7月8日137. **-------------------------------------------------------------------------------------------------------138. ** 修改人: 陈明计139. ** 日期: 2003年7月10日140. **-------------------------------------------------------------------------------------------------------141. ** 修改人: 陈明计142. ** 日期: 2003年7月21日143. **------------------------------------------------------------------------------------------------------144.************************************************************************ ********************************/145. uint16 I2cWrite(uint8 Addr, uint8 *Data, int16 NByte) 146. {147. uint8 err;148.149. OSSemPend(I2cSem, 0, &err);150.151. I2CONCLR = 0x6C;152. I2CONSET = 0x40; /* 使能I2c */ 153. VICIntEnable = 1 << 9; /* 使能I2c中断 */ 154.155. if (__I2cWrite(Addr, Data, NByte) == I2C_WRITE_END) 156. { 157. I2CONSET = 1 << 4; /* 发送停止信号 */ 158. I2CONCLR = 0x28; /* 清除标志 */ 159. }160.161. VICIntEnClr = 1 << 9; /* 禁止能I2c中断 */ 162.163. OSSemPost(I2cSem);164. return (NByte - I2cNbyte);165. }166.167./*********************************************************************** **********************************168. ** 函数名称: I2cRead169. ** 功能描述: 从I2c从器件读数据170. ** 输入: Addr:从机地址171. ** Ret:指向返回数据存储位置的指针172. ** Eaddr:扩展地址存储位置173. ** EaddrNByte:扩展地址字节数,0为无174. ** ReadNbyte:将要读取的字节数目175. ** 输出:已读取的字节数176. **177. ** 全局变量: I2cSem,I2cAddr,I2cNbyte,I2cBuf178. ** 调用模块: OSSemPend,__I2cWrite,OSMboxPend,OSSemPost 179. ** 180. ** 作者: 陈明计181. ** 日期: 2003年7月8日182. **-------------------------------------------------------------------------------------------------------183. ** 修改人: 陈明计184. ** 日期: 2003年7月21日185. **------------------------------------------------------------------------------------------------------186.************************************************************************ ********************************/187. int16 I2cRead(uint8 Addr, uint8 *Ret, uint8 *Eaddr, int16 EaddrNByte, int16 ReadNbyte)188. {189. uint8 err;190.191. OSSemPend(I2cSem, 0, &err);192.193. I2CONCLR = 0x6C;194. I2CONSET = 0x40; /* 使能I2c */ 195. VICIntEnable = 1 << 9; /* 使能I2c中断 */ 196.197. if (EaddrNByte > 0)198. {199. if (__I2cWrite(Addr, Eaddr, EaddrNByte) != I2C_WRITE_END) 200. {201. return -1;202. }203. }204.205. I2cAddr = Addr | 0x01; /* 存储发送地址 */ 206. I2cNbyte = ReadNbyte; /* 存储读字节数 */ 207. I2cBuf = Ret; /* 存储读到的数据 */ 208. I2CONCLR = 0x28;209. I2CONSET = 0x24; /* 设置为主机,并启动总线 */ 210. VICIntEnable = 1 << 9; /* 使能I2c中断 */ 211.212. OSMboxPend(I2cMbox, 0, &err); /* 等待操作结束 */ 213.214. VICIntEnClr = 1 << 9; /* 禁止能I2c中断 */ 215.OSSemPost(I2cSem);216. return (ReadNbyte - I2cNbyte);217. }218.219.220./*********************************************************************** **********************************221. ** 函数名称: I2c_Exception222. ** 功能描述: I2c中断服务程序223. ** 输入: 无224. **225. ** 输出: 无226. **227. ** 全局变量: I2cAddr,I2cBuf,I2cNbyte,I2cMbox228. ** 调用模块: OSMboxPost229. **230. ** 作者: 陈明计231. ** 日期: 2003年7月8日232. **-------------------------------------------------------------------------------------------------------233. ** 修改人: 陈明计234. ** 日期: 2003年7月21日235. **------------------------------------------------------------------------------------------------------236.************************************************************************ ********************************/237. void I2c_Exception(void)238. {239. OS_ENTER_CRITICAL();240. switch(I2STAT & 0xf8)241. {242. case 0x08: /* 已发送起始条件,与0x18相同处理 */ 243. // break;244. case 0x10: /* 已发送重复起始条件 */ 245. I2DAT = I2cAddr; /* 发送地址 */ 246. I2CONCLR = 0x28; /* 清除标志 */ 247. break;248. case 0x18: /* 已发送SLA+W,并已接收应答 */ 249. I2DAT =*I2cBuf++;250. I2cNbyte--;251. I2CONCLR = 0x28; /* 清除标志 */ 252. break;253. case 0x28: /* 已发送I2C数据,并接收到应答 */ 254. if (I2cNbyte > 0)255. {256. I2DAT = *I2cBuf++;257. I2cNbyte--;258. I2CONCLR = 0x28; /* 清除标志 */ 259. }260. else261. {262. OSMboxPost(I2cMbox, (void *)I2C_WRITE_END); 263. VICIntEnClr =1 << 9; /* 禁止能I2c中断 */ 264. }265. break;266. case 0x20: /* 已发送SLA+W;已接收非ACK, 与0x48处理相同 */ 267. // break;268. case 0x30: /* 已发送I2DAT中的数据字节;已接收非ACK, 与0x48处理相同 */269. // break;270. case 0x48: /* 已发送SLA+R;已接收非ACK */271. I2CONSET = 1 << 4; /* 发送停止信号 */ 272. OSMboxPost(I2cMbox, (void *)I2C_ACK_ERR); 273. I2CONCLR = 0x28; /* 清除标志 */ 274. break;275. case 0x38: /* 在SLA+R/W或数据字节中丢失仲裁 */ 276. OSMboxPost(I2cMbox, (void *)I2C_NOT_GET_BUS); 277. I2CONCLR = 0x28; /* 清除标志 */ 278. break;279. case 0x40: /* 已发送SLA+R;已接收ACK */ 280. if (I2cNbyte <= 1) 281. {282. I2CONCLR = 1 << 2; /* 下次发送非应答信号 */ 283. }284. else285. {286. I2CONSET= 1 << 2; /* 下次发送应答信号 */ 287. }288. I2CONCLR = 0x28; /* 清除标志 */ 289. break;290. case 0x50: /* 已接收数据字节;已发送ACK */ 291. *I2cBuf++ =I2DAT; /* 接收数据 */ 292. I2cNbyte--;293. if (I2cNbyte <= 1)294. {295. I2CONCLR = 1 << 2; /* 下次发送非应答信号 */ 296. }297. I2CONCLR = 0x28; /* 清除标志 */ 298. break;299. case 0x58: /* 已接收数据字节;已返发送ACK */ 300. *I2cBuf =I2DAT; /* 接收数据 */ 301. I2cNbyte--;302. I2CONSET= 1 << 4; /* 结束总线 */ 303. OSMboxPost(I2cMbox, (void *)I2C_READ_END); 304. I2CONCLR = 0x28; /* 清除标志 */ 305. break;306. default:307. I2CONCLR = 0x28; /* 清除标志 */ 308. break;309. }310.311. VICVectAddr = 0; /* 通知中断控制器中断结束 */ 312.OS_EXIT_CRITICAL();313. }314./*********************************************************************** **********************************315. ** End Of File316.************************************************************************ ********************************/。
//......................................//名称: PCF8574(A).c I2C扩展8位I/O芯片的接口程序//编程: 不详//日期: 20111025////发现问题请指点,谢谢!//......................................//CPU: 89C55 11.0592MHz//环境:KeilC51 V8.01//引脚定义://CPU_P2.0--- P CF8574X_SC L 时钟// CP U_P2.1 ---PCF8574X_SDA 数据//CPU_P2.2 --- PC F8574X_INT中断//......................................#incl ude <Publi c.h>#incl ude <Intri ns.h>#inc lude"dela y_s.h"#in clude "pcf8574.h"//PCF8574(A)芯片指令的定义#defi ne PC F8574_WRIT E 0x40 //器件地址= 0111 A2 A1 A0r/w#defin e PCF8574_READ0x41//器件地址= 0111 A2 A1A0 r/w#de finePCF8574A_W RITE0x70//器件地址= 0111 A2 A1A0 r/w#de finePCF8574A_R EAD 0x71 //器件地址= 0111 A2 A1 A0 r/w#de fineP CF8574X_R EGIST ER_AD DR_MA X 7 //器件内部寄存器地址的最大值//内部函数s tatic void i2c_star t_con d(voi d);s tatic void i2c_stop_cond(void);st aticuchar i2c_read_byte(void);sta tic u chari2c_r ead_b yte_n ack(v oid);stat ic vo id i2c_wr ite_b yte(u charda);//============================================================== ===============//接口调用函数部分//*******************************************************//序号:// HD_PC F8574X_S01//功能://读出芯片的复位状态// is_pcf8574a=1 是A芯片// ad d_of_part器件的子地址 0~3//输出://端口的数据//********************************************************uch ar PC F8574X_rea d_io(uchar is_p cf8574a, u charadd_o f_par t){uchar i;i2c_s tart_cond();i f(is_pcf8574a !=0){i2c_wr ite_b yte(P CF8574A_RE AD |((add_of_pa rt <<1) &0x0E));//器件地址=0111 A2 A1 A0 r/w}else{i2c_write_byte(PCF8574_R EAD |((add_of_p art <<1) &0x0E));//器件地址=0100 A2 A1A0 r/w}i =i2c_re ad_by te_na ck();//顺序读的方式读出一个字节i2c_st op_co nd();ret urn(i);}//*******************************************************//序号:// H D_PCF8574X_S02//功能://写数据到I/O端口//输入://is_pcf8574a =1 是A芯片//add_of_p art:器件的子地址 0~7//dat:写入的字节//输出: // 无//********************************************************voidPCF8574X_w rite_io(uc har i s_pcf8574a, uch ar ad d_of_part, ucha r dat){i2c_s tart_cond();i f(is_pcf8574a !=0){i2c_wr ite_b yte(P CF8574A_WR ITE |((add_of_p art <<1) &0x0E)); //器件地址=0111A2 A1 A0 r/wel se{i2c_wri te_by te(PC F8574_WRIT E |((add_o f_par t <<1) &0x0E));//器件地址=0100 A2 A1 A0 r/w}i2c_write_byte(dat);i2c_st op_co nd();}//==============//内部调用函数部分//==============//----------------------------------------------//I2C发启始条件:时钟线为高时数据线发生下降沿跳变//----------------------------------------------sta tic v oid i2c_st art_c ond(v oid){CO DE_SC L_LOW;_D ELAY_NOP3;COD E_SDA_HIGH;_D ELAY_NOP3;COD E_SCL_HIGH;_D ELAY_NOP3;COD E_SDA_LOW;_DE LAY_N OP3;}//----------------------------------------//I2C 发结束条件:时钟线为高时数据线发生上升沿跳变//----------------------------------------st aticvoidi2c_s top_c ond(v oid){CO DE_SC L_LOW;_D ELAY_NOP3;COD E_SDA_LOW;_DE LAY_N OP3;CODE_SCL_HIGH;_DE LAY_N OP3;CODE_SDA_HIGH;_DE LAY_N OP3;}//----------------------------------------// I2C 读取一个中间字节的数据//----------------------------------------/*stat ic uc har i2c_re ad_by te(vo id){uch ar i;uch ar da=0;for(i =0;i<8;i++){da <<=1; //传输的数据高位在前C ODE_S CL_LO W;_DELA Y_NOP3;CODE_SCL_H IGH;//时钟为高时读数据//N OP3;if(JUDG E_PCF8574X_SDA) da++;}CODE_SCL_LOW;_DEL AY_NO P3;CODE_SDA_L OW; //发送应答位_DELA Y_NOP3;C ODE_S CL_HI GH;_DELA Y_NOP3;C ODE_S CL_LO W;_DELAY_NOP3;CO DE_SD A_HIG H;r eturn(da);}*///----------------------------------------// I2C读取一个结尾字节的数据//----------------------------------------stat ic uc har i2c_re ad_by te_na ck(vo id){uch ar i;uch ar da =0;for(i =0; i<8; i++){da<<=1;CO DE_SC L_LOW;_DELAY_NOP3;C ODE_S CL_HI GH;//NOP3;i f(JUD GE_PC F8574X_SDA) da++;}COD E_SCL_LOW;_DE LAY_N OP3;CODE_SDA_HIGH;_DE LAY_N OP3;CODE_SCL_HIGH;_DE LAY_N OP3;CODE_SCL_LOW;retu rn( d a );}//----------------------------------------// I2C 写入一个字节的数据//----------------------------------------stat ic vo id i2c_wri te_by te(uc har d a ){uch ar i;for(i =0; i<8; i++){COD E_SCL_LOW;if(da&0x80){COD E_SDA_HIGH;}el se{CODE_SDA_L OW;}CODE_SCL_H IGH;da<<=1;}CODE_SCL_L OW; //第8个SCL下降沿,写入8位数据_DELA Y_NOP3;C ODE_S DA_HI GH;_DELA Y_NOP3;C ODE_S CL_HI GH;}//============================================================== ===============//End O f Fil e。
I2C设备驱动介绍I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接并使多个外部设备与主控制器进行通信。
在嵌入式系统中,I2C设备驱动起着至关重要的作用,负责将操作系统与I2C总线上的设备进行通信,促进数据的传输和交互。
1.初始化:驱动程序需要初始化I2C控制器,包括设置时钟频率、地址范围等。
2.设备注册:设备驱动需要在操作系统中注册I2C设备,以便操作系统能够识别和管理设备。
3.读写操作:驱动程序需要实现读写设备寄存器的功能,包括发送开始和停止信号、以及发送、接收数据等。
4.错误处理:驱动程序需要处理I2C通信过程中可能出现的错误,例如传输失败、设备无响应等情况。
5.中断处理:驱动程序需要支持I2C设备的中断机制,以便及时处理设备的状态变化或数据传输完成的中断信号。
6.电源管理:驱动程序需要支持设备的电源管理功能,包括设备的唤醒、睡眠等操作。
7.设备控制:驱动程序需要实现设备特定的控制功能,例如设置传感器的采样率、配置设备的工作模式等。
8. 虚拟文件系统接口:在Linux系统中,驱动程序通常通过虚拟文件系统接口(如/dev)与用户空间进行交互,提供读写设备寄存器的功能。
1.确定设备:首先,开发者应该确定需要驱动的I2C设备。
这可能包括传感器、EEPROM、显示器等。
2.确定硬件连接:确定I2C设备与主控制器之间的硬件连接和电气特性。
这包括设备的I2C地址、I2C总线上的物理接口等。
3.编写驱动程序:在操作系统中,开发者可以根据设备的文档或芯片厂商提供的驱动程序框架,编写自己的I2C设备驱动程序。
驱动程序需要实现上述提到的功能,并且根据设备的特点进行相应的适配和优化。
4.编译和测试:完成驱动程序的编写后,需要将其编译成与操作系统内核匹配的模块或静态链接库。
然后,通过加载驱动模块或重新编译内核来使驱动程序生效。
最后,进行测试,确保驱动程序在各种场景下的正常运行。
1,module_init(ft5306_touch_init);2,static int __init ft5306_touch_init(void)a)i2c_add_driver(&ft5306_touch_driver);3,static struct i2c_driver ft5306_touch_driver(就是向系统注册一些程序,在系统规定的时机执行)a).probe = ft5306_touch_probe,注册检测程序和一些初始化信息,检测是否准备好程序(开机时执行)b).remove = ft5306_touch_remove,基本不执行,只在卸载c).suspend = ft5306_touch_suspend(#ifndef CONFIG_HAS_EARLYSUSPEND)注册挂起程序(休眠时执行)d).resume = ft5306_touch_resume(#ifndef CONFIG_HAS_EARLYSUSPEND)注册唤醒程序(唤醒时执行)4,f t5306_touch_probe,检测是否准备好a)ft5306_touch_phys_init,初始化b)input_register_device(input_dev);,注册设备c)request_irq()。
申请中断号,只是注册但不执行d)INIT_WORK(&touch_work.work, ft5306_touch_worker);完成结构初始化工作,为将工作提交到工作队列做准备,即为顶半部准备好work_struct结构体。
只是完成初始化,但不执行e)register_early_suspend(&ft5306_touch_early_suspend_desc);在这里注册唤醒及休眠管理函数(#ifdef CONFIG_HAS_EARLYSUSPEND)f)ft5306_virtual_keys_init(),虚拟按键初始化程序,这就是虚拟按键程序的入口5,如果不做任何操作,则进入休眠状态。
i2c芯片的驱动程序(汇编)本文对AT24系列存贮器和AT89系列单片机的特征及总线状态作为介绍,并以AT24C01与AT89C2051为例详细描述了通用存贮器IC卡的工作原理及用单片机对其进行读写操作的基本电路连接和软件编程方法。
通用存贮器IC卡是由通用存贮器芯片封装而成的,由于它的结构和功能简单,生产成本低,使用方便,因此在各领域都得到了广泛的应用。
目前用于IC卡的通用存贮器芯片多为E2PROM,其常用的协议主要有两线串行连接协议(I2C)和三线串行链接协议,其中比较常用的是ATMEL公司生产的AT24系列芯片。
以该系列中的AT24C01为例,它具有1k的存贮容量,适用于2V~5V的低电压/标准电压的操作,具有低功耗和高可靠性等优点。
而AT89C2051虽是ATMEL公司89系列单片机的低档型,但它具有2k的FLASHROM(可重编闪速存贮器)、128×8位内部RAM及全静态操作方式,同样也具有低功耗和较强的功能。
下面以AT24C2051为例,对通用存贮器IC卡的工作原理及基本电路连线作一介绍,该线路简单,使用灵活,能可靠地对通用存贮器IC卡进行读写。
2 硬件特性2.1 AT24系列存贮器的特性AT24系列存贮器芯片采用CMOS工艺制造,内置有高压泵,可在单电压供电条件下工作。
其标准封装为8脚DIP封装形式,各引脚的功能说明如下:SCL:串行时钟。
在该脚的上升沿时,系统将数据输入到每个EEPROM器件,在下降沿时输出。
SDA:串行数据。
该引脚为开漏极驱动,可双向传送数据。
A0、A1、A2:器件/页面寻址。
为器件地址输入端。
在AT24C01/02中,该引脚被硬连接。
Vcc:一般输入+5V的工作电压。
图1是符合ISO7816-2标准的IC卡的触点图。
对于AT24系列通用存贮器IC卡来说,通常只需使用四个触点。
AT24C01的内部组态为128个8位字节,而对随机字寻址则需要一个7位地址。
2.2 总线状态及时序A24C01的SCL及SDA两总线可通过一个电阻上拉为高电平,SDA上的数据仅在SCL为低电平时周期才能改变。
当SCL为高电平时,SDA的改变表示“开始”和“停止”状态。
此时,所有地址和数据字都以8位串行码方式输入输出EEPROM。
开始状态:SCL为高电平时,SDA由高电平转入低电平。
该命令必须在其它命令前执行。
停止状态:SCL为高电平时,SDA由低电平转入高电平。
该命令可终止所有通讯。
确认:相同总线上的设备在收到数据后,以置SDA为低电平的方式对其进行确认。
2.3 器件寻址AT24系列EEPROM在开始状态后需紧接一个8位器件地址,以进行应读写操作。
设备寻址码的高4位为1、0、1、0,对于AT24C01/02,寻址码高4位后面的三位是器件寻址码,与它们的硬连线管脚相对应。
最低应是读写选择位,置0时可激发读操作。
具体的格式如下:1010A2A1A0R/W2.4 AT89C2051芯片AT89C2051是MCS-51产品的兼容型,它具有2k的FLASHROM、128字节ROM,15根I/O引线、两个16位定时/计数器、一个五向量两级中断结构、一个全双工串行口、一个精密模拟比较器以及片内振荡电路和时钟电路。
它的P1口和P3口是双向I/O口,其中P1.2~P1.7、P3.0~P3.5和P3.7带有内部上拉电阻。
在AT89C2051用作输入端时,将首先向引脚写“1”而使内部M OS管截止以便引脚处于悬浮状态,从而可获得高阻抗输入。
图2为通用存贮器IC卡的基本电路连接图。
3 读写操作软件当系统采用6MHz晶体振荡器时所定义的I/O口线及器件地址如下:SCL BIT P1.7SDA BIT P1.6DEVICEAD_W DATA 10100000B ;写卡器件地址DEVICEAD_R DATA 10100001B ;读卡器件地址3.1 开始条件(START_IC)在开始条件下,当SCL为高电平时,SDA由高转为低。
程序如下:START_IC:CLR SCL;SCL低电平时才允许SDA更改NOP ;加入空指令延时以确保信号可靠NOPSETB SDANOPNOPSETB SCLNOPNOPCLR SDANOPNOPCLR SCLNOPRET3.2 停止条件(STOP_C)在停止条件下,当SCL为高电平时,SDA由低转为高。
程序如下:STOP_IC:CLR SCLNOPNOPCLR SDANOPNOPSETB SCLNOPNOPSETB SDANOPNOPCLR SCLNOPNOPCLR SDARET3.3 确认信号(ACK_IC)在接收方应答下,每收到一字节后便将SDA电平拉低,程序如下:ACK_IC:CLR SCLNOPNOPCLR SDANOPNOPSEIB SCLNOPNOPCLR SCLNOPSETB SDANOPRET3.4 写一字节数据到IC卡(WR_BYTE)在下列程序中,参数A表示源数据,R5表示字节位数。
WR_BYTE:MOV R5,#08 ;一字节8位数据CLR SCLNOPNOPWR_BYTE1:RLC A ;带进位位左移,A.8->CMOV SDA,C ;SCL低电平时改变SDA上的数据NOPSETB SCL ;拉高SCL把数据发送出去NOPNOPCLR SCLNOPNOPDJNZ R5,WR_BYTE1;依次发送A中的8位数据SETB SDASETB SCLJB SDA,$ ;等待IC卡确认信号CLR SCLNOPRET此子程序的主要作用是按照定义的时序,顺序左移A中一字节8位数据,并通过引脚传送出去。
当一字节发完后,等待IC卡发回的确认信号。
3.5 从IC卡读一字节(RD+BYTE)从IC卡中读一字节的源程序如下:RD_BYTE:MOV R5,#08SETB SDA ;设备SDA为读状态CLR A ;清空A寄存器RD_BTYE1:MOV C,SDA ;读一位数据到进位位RLC A ;左移数据到A.0SETB SCLNOPNOPCLR SCLNOPNOPDJNZ R5,RD_BYTE1;依次读出8位数据到A中RET ;无应答信号利用该程序可将读出的数据存放在A中。
需要注意的是:读数据的器件不是通过确认状态来应答的,而是随后产生一个停止状态。
3.6 字节写入模式写数据(WRITE_BYTE)下列程序中的参数为:R6= =目的地址,A= =数据;数据如下:WRITE_BYTE:PUSH ACC ;保存A中的数据LCALL START_IC ;发开始信号MOV A,#DEVICEAD_W;写入器件地址LCAL WR_BYTEMOV A,R6 ;写入字节地址LCALL WR_BYTEPOP ACC ;恢复A中数据LCALL WR_BYTE ;写入数据LCALL STOP_ICRET在收到8位数据后,EEPROM将通过SDA来回送确认信号,而传送设备必须用停止状态来终止写操作。
这时,EEPROM将进入一个内时固定存贮器的写入周期并且禁止在此其间的所有输入,直到写操作完成后才对通讯应答。
其写入周期可自定义,最大为10ms。
3.7 页面写入模式写数据(WRITE_PAGE)以下程序中的参数为P0= =源指针,R6= =目的地址,R7= =页面长度。
WRITE_PAGE:LCALL START_ICMOV A,#DEVICEAD_WLCALL WR_BYTEMOV A,R6LCALL WR_BYTEWRITE_PAGE1:MOV A,@R0LCALL WR_BYTEINC R0DJNZ R7,WRITE_PAGE1LCALL STOP_ICRETAT24C01/02可利用上述程序进行8字节的页面写入,它的操作类似于写字节。
不同的是,它无需在第一个字节送出后才以停止状态,不同在收到确认信号后,再传送7个字节的数据码,最后以停止状态来终止页面写序列。
AT24C04/08/16的页面为16字节。
3.8 立即地址读模式(READ_BYTEC)立即地址读模式读一字节数据的程序如下:READ_BYTEC:LCALL START_ICMOV A,#DEVICEAD_RLCALL WR_BYTELCALL RD_BYTE ;读出默认地址数据LCALL STOP_IC ;发停止状态应答RET该程序执行后,其内部数据字地址指针将保持在上次读写操作访问的最后一个地址,并按1递增且在芯片上电期间一直有效。
只有当地址为页面的最末时,下次访问才滚动到该页面的首地址。
3.9 随机地址读模式(READ_BYTER)在下列程序中,R6= =源地址,程序如下:READ_BYTER:LCALL START_ICMOV A,#DEVICEAD_W ;执行空字节写序列LCALL WR_BYTE ;载入数据地址MOV A,R6LCALL WR_BYTELCALL START_ICMOV A,#DEVICEAD_R ;立即地址读取LCALL WR_BYTELCALL DR_BYTELCALL STOP_ICRET读操作模式需要一个字节写序列载入数据地址。
在器件和数据地址写入并得到确认后,将再产生另一个开始条件,并送出读操作器件的地址,同时激发一个立即地址读取。
3.10 顺序地址读取(READ_BYTES)在下列程序中:R0= =目的指针;R7= =数据长度,程序如下:READ+BYTES:LCALL START_ICMOV A,#DEVICEAD_RLCALL WR_BYTEREAD_BYTES2:LCALL RD_BYTEMOV @R0,A ;存放数据到目的地址INC R0DJNZ R7,READ_BYTES1LCALL STOP_IC ;读写指定长度后停止RETREAD_BYTES1:LCALL ACK_IC ;收到数据后发确认信号SJMP READ_BYTES2其中顺序读取由立即寻址读或随机地址读激发,并在收到一字节数据后发确认信号应答。
当读数器件以停止状态应答时,操作被终止。
4 总结该系统结构简单,在实际运行时具有很高的可靠性,同时具有一定的可扩展性,并可通过单片机的串行口经电平转换后直接与计算机相连,以进行数据通讯。
另外,也可根据需要连接到其它引脚或卡座触点,如果适当改进电路和程序,还可读写加密卡和CPU卡等。