I2C C程序
I2C总线AT24C02存储器读写程序
write_byte(date);//在芯片第address位置写date.
respons();//写完后调用应答函数
stop();//I2C结束时钟函数
}
uchar read_add(uchar address)
{
uchar date;
{ start();//I2C开始时钟函数
write_byte(0xa0);//at24c02的固定地址A,1010,AO-A3都接地都为0。
respons();//写完后调用应答函数
write_byte(address);//确定从at24c02的第address位置写数据。
aa=k;
ee=aa*2200;
if(D4==0)
{
delay (100);
if(D4==1)
{
aa++;
delay (1);
init();//写直址,最后低位应为0。
write_add(2,aa);//23为at24c02内部储存地址,0xaa为写到23地址的数据。
#include <reg52.h>
#define uint unsigned int //定义unsigned int 为uint
#define uchar unsigned char //定义unsigned char 为uchar
#define uchar unsigned char //定义unsigned char 为uchar
delay (1);
k=read_add(2);//送到P1口显示。//从23地址读数据
I2C总线AT24C01读写程序(汇编和C)
NOP
NOP
MOV C,SDA
RLC A
CLR SCL
DJNZ B,I2C_RECEIVE8IT_A
RET
C语言写的24C01 单字节读写程序
LCALL I2C_SEND8BIT
LCALL I2C_ACK
JC I2C_READ_A ;=1,表示无确认,再次发送
MOV A,Address
LCALL I2C_SEND8BIT
LCALL I2C_ACK
unsigned char i2c_read(unsigned char Address)
{
unsigned char c;
do{
i2c_start();
i2c_send8bit(0xA0);
}while(i2c_ack()); //=1,表示无确认,再次发送
; 24C01存储器I2C总线实验 汇编语言例子
; =======================================================
SDA EQU P2.0
SCL EQU P2.1
i2c_write(地址,数据),写一个字节
=======================================================*/
void i2c_write(unsigned char Address,unsigned char Data)
{
do{
I2C总线AT24C01读写程序(汇编和C)
--------------------------------------------------------------------------------
I2C_周立功标准驱动程序_c代码
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.************************************************************************ ********************************/。
I2C通信原理及程序详细讲解
I2C通信原理及程序详细讲解I2C(Inter-Integrated Circuit)是一种串行通信协议,常用于连接微控制器、传感器和其他外部设备。
I2C通信协议由荷兰飞利浦公司于1982年开发,它使用两根信号线(SDA和SCL)进行数据传输。
I2C通信协议采用主从结构,一个主设备(如微控制器)可以连接多个从设备(如传感器)。
主从设备之间通过SDA和SCL线进行数据传输。
SDA线是双向数据线,用于传输数据,SCL线是时钟线,用于同步数据传输。
I2C通信协议中,设备的地址是一个重要概念。
每个设备都有一个唯一的地址,通过该地址可以选择和通信特定的设备。
地址由7个位组成,其中最高位是固定的,并取决于设备是主设备还是从设备。
如果最高位为0,则表示该设备是主设备;如果最高位为1,则表示该设备是从设备。
通过以下步骤,让我们详细了解如何在I2C总线上进行通信。
1.初始化I2C总线:在程序开始时,需要初始化I2C总线。
这通常包括初始化SDA和SCL引脚,设置时钟频率等。
具体的初始化步骤取决于使用的硬件和软件环境。
2.发送开始信号:开始信号表示I2C数据传输的开始。
它由主设备发送,并且SDA线从高电平转为低电平时发出。
发送开始信号后,SDA线上的数据将被解释为地址数据。
3.发送设备地址:主设备发送一个包含设备地址和读/写位(R/W)的数据字节。
设备地址是唯一的,并且由主设备选择。
读/写位指示从设备是要读取数据还是写入数据。
4.等待从设备响应:主设备发送设备地址后,会等待从设备的响应。
从设备将响应一个应答位(ACK)来确认地址接收成功。
如果收到ACK位,则继续进行下一步,否则可能是设备未连接或通信错误。
5.发送数据:主设备发送数据给从设备。
数据可以是命令、配置或实际数据,具体取决于应用场景。
发送数据的方式是将每个数据字节传输到SDA线上,并在每个数据字节后发送一个ACK位。
6.接收数据:从设备将数据发送给主设备。
数据可以是传感器读数、存储器数据等。
i2c标准库的读写函数实现
I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,用于在多个设备之间进行数据传输。
实现I2C通信的库可以根据不同的硬件平台和编程语言而有所差异,下面是一个简单的C语言示例,展示了如何使用标准库函数进行I2C的读写操作。
在示例中,我们假设已经初始化了I2C接口并设置了正确的通信速率。
示例使用的C语言标准库函数为`i2c_read()`和`i2c_write()`,这里的函数只是简单地演示读写一个字节的数据。
在实际应用中,您可能需要根据设备和需求进行更复杂的读写操作。
```c#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <linux/i2c-dev.h>#define I2C_DEVICE_ADDRESS 0x20#define I2C_BUS_PATH "/dev/i2c-1"int main() {int i2c_fd;unsigned char i2c_data[2];// 打开I2C设备i2c_fd = open(I2C_BUS_PATH, O_RDWR);if (i2c_fd < 0) {perror("Failed to open I2C device");return -1;}// 设置I2C设备地址if (ioctl(i2c_fd, I2C_SLAVE, I2C_DEVICE_ADDRESS) < 0) {perror("Failed to set I2C slave address");return -1;}// 写入数据到I2C设备i2c_data[0] = 0x01; // 设置寄存器地址i2c_data[1] = 0xAA; // 设置数据if (write(i2c_fd, i2c_data, 2) != 2) {perror("Failed to write data to I2C device");return -1;}// 从I2C设备读取数据i2c_data[0] = 0x01; // 设置寄存器地址if (write(i2c_fd, i2c_data, 1) != 1) {perror("Failed to write register address to I2C device");return -1;}if (read(i2c_fd, i2c_data, 1) != 1) {perror("Failed to read data from I2C device");return -1;}printf("Received data: 0x%02x\n", i2c_data[0]);// 关闭I2C设备close(i2c_fd);return 0;}```。
I2C操作序2-C程序(包含2 4C02和24C512)
SCL=1;
nop();
SDA=0;
nop();
SCL=0; //SCL need to hold on low
}
//***************************
{
SDA=1;
SCL=1;
Txmt_Progress=0;
ACK_Error=1; //no success
}
else //if SDA=0 the ACK right
{
SCL=0;
Txmt_Progress=0;
SCL=1; //A rising edge in SCL to read SDA
nop();
if(SDA)
Data_G=Data_G|0x01;
else
Data_G=Data_G&0xFE;
SCL=0;
}
return Data_G; //return the result
void IsActive(void)
{
SlaveActive=0;
while(!SlaveActive) //if not Active,check it again
IsSlaveActive();
}
//************************************
nop(); //if SDA=0,then send ACK
SCL=1;
nop();
SCL=0; //need to set low when ACK is ok
模拟I2C从机程序
SCL BIT P1.0SDA BIT P1.1;----------------------------ORG 0RESET:SETB SCLSETB SDACALL I2C_WAITSTART ;等待起始信号CALL I2C_RXBYTE ;接收地址数据CLR CCALL I2C_TXACK ;回应ACKSETB C ;读/写 IDATA[80H - FFH] RRC A ;读/写位->CMOV R0,A ;地址送入R0JC READDATA ;C=1(读) C=0(写) WRITEDATA:CALL I2C_RXBYTE ;接收数据MOV @R0,A ;写入IDATAINC R0 ;地址+1CLR CCALL I2C_TXACK ;回应ACKCALL I2C_WAITSTOP ;等待停止信号JMP RESETREADDATA:MOV A,@R0INC R0CALL I2C_TXBYTE ;发送IDATA数据CALL I2C_RXACK ;接收ACKCALL I2C_WAITSTOP ;等待停止信号JMP RESET;----------------------------;等待起始信号;----------------------------I2C_WAITSTART:JNB SCL,$ ;等待时钟->高JB SDA,$ ;等待数据线下降沿JB SCL,$ ;等待时钟->低RET;----------------------------;等待结束信号;----------------------------I2C_WAITSTOP:JNB SCL,$ ;等待时钟->高JNB SDA,$ ;等待数据线上升沿RET;----------------------------;发送ACK/NAK信号;----------------------------第 1 页I2C_TXACK:MOV SDA,C ;送ACK数据JNB SCL,$ ;等待时钟->高JB SCL,$ ;等待时钟->低SETB SDA ;发送完成RET;----------------------------;接收ACK/NAK信号;----------------------------I2C_RXACK:SETB SDA ;准备读数据JNB SCL,$ ;等待时钟->高MOV C,SDA ;读取ACK信号JB SCL,$ ;等待时钟->低RET;----------------------------;接收一字节数据;----------------------------I2C_RXBYTE:MOV R7,#8 ;8位计数RXNEXT:JNB SCL,$ ;等待时钟->高MOV C,SDA ;读取数据口RLC A ;保存数据JB SCL,$ ;等待时钟->低DJNZ R7,RXNEXT ;收下一位RET;----------------------------;发送一字节数据;----------------------------I2C_TXBYTE:MOV R7,#8 ;8位计数TXNEXT:RLC A ;移出数据位MOV SDA,C ;数据送数据口JNB SCL,$ ;等待时钟->高JB SCL,$ ;等待时钟->低DJNZ R7,TXNEXT ;送下一位RET;----------------------------END第 2 页。
51单片机模拟I2C总线的C语言实现
51单⽚机模拟I2C总线的C语⾔实现I2C(Inter-Integrated Circuit)总线是⼀种由PHILIPS公司开发的两线式串⾏总线,⽤于连接微控制器及其外围设备。
I2C总线产⽣于在80年代,最初为⾳频和视频设备开发,如今主要在服务器管理中使⽤,其中包括单个组件状态的通信。
例如管理员可对各个组件进⾏查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。
可随时监控内存、硬盘、⽹络、系统温度等多个参数,增加了系统的安全性,⽅便了管理。
⼀、I2C总线特点 I2C总线最主要的优点是其简单性和有效性。
由于接⼝直接在组件之上,因此I2C总线占⽤的空间⾮常⼩,减少了电路板的空间和芯⽚管脚的数量,降低了互联成本。
总线的长度可⾼达25英尺,并且能够以10Kbps的最⼤传输速率⽀持40个组件。
I2C总线的另⼀个优点是,它⽀持多主控 (multimastering), 其中任何能够进⾏发送和接收的设备都可以成为主总线。
⼀个主控能够控制信号的传输和时钟频率。
当然,在任何时间点上只能有⼀个主控。
⼆、I2C总线⼯作原理2.1、总线的构成及信号类型I2C 总线是⼀种串⾏数据总线,只有⼆根信号线,⼀根是双向的数据线SDA,另⼀根是时钟线SCL。
在CPU与被控IC之间、IC与IC之间进⾏双向传送,最⾼传送速率100kbps。
各种被控制电路均并联在这条总线上,但就像电话机⼀样只有拨通各⾃的号码才能⼯作,所以每个电路和模块都有唯⼀的地址,在信息的传输过程中,I2C总线上并接的每⼀模块电路既是主控器(或被控器),⼜是发送器(或接收器),这取决于它所要完成的功能。
CPU发出的控制信号分为地址码和控制量两部分,地址码⽤来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对⽐度、亮度等)及需要调整的量。
这样,各控制电路虽然挂在同⼀条总线上,却彼此独⽴,互不相关。
2.2、位的传输SDA 线上的数据必须在时钟的⾼电平周期保持稳定数据线的⾼或低电平状态只有在SCL 线的时钟信号是低电平时才能改变。
I2C的C代码
#include<reg51.h>#define uchar unsigned char#define uint unsigned int#define write_ADD 0xa0#define read_ADD 0xa1uchar a;sbit SDA=P2^0;sbit SCL=P2^1;void SomeNop(); //短延时void init(); //初始化void check_ACK(void);void I2CStart(void);void I2cStop(void);void write_byte(uchar dat);//写字节void delay(uint z);uchar read_byte(); //读字节void write(uchar addr,uchar dat); //指定地址写uchar read(uchar addr); //指定地址读bit flag; //应答标志位void main(){init();write_add(5,0xaa); //向地址5写入0xaadelay(10); //延时,否则被坑呀P1=read_add(5); //读取地址5的值while(1);}//************************************************************ ***************void delay()//简单延时函数{ ;; }//************************************************************ ***************void start() //开始信号 SCL在高电平期间,SDA一个下降沿则表示启动信号{sda=1; //释放SDA总线delay();scl=1;delay();sda=0;delay();}//************************************************************ ***************void stop() //停止 SCL在高电平期间,SDA一个上升沿则表示停止信号{sda=0;delay();scl=1;delay();sda=1;delay();}//************************************************************ ***************void respons() //应答 SCL在高电平期间,SDA被从设备拉为低电平表示应答{uchar i;scl=1;delay();//至多等待250个CPU时钟周期while((sda==1)&&(i<250))i++;scl=0;delay();}//************************************************************ ***************void init()//总线初始化将总线都拉高一释放总线发送启动信号前,要先初始化总线。
完整的I2C 模拟总线 C 程序
if ( I2C_SDA )
i2c_ack=1;
else
i2c_ack=0;
I2C_SCL = 0;
delay(1);
}
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
// 读取 24xx 一字节数据 ‥‥‥‥‥‥‥
nop();
// delay(2); // 延迟 47uSec
}
// nop();
I2C_SCL = 0;
nop();
//-------
SDAIO = 1;
I2C_SDA = 1;
//-------
delay(1);
I2C_SCL=1;
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
// I2C 模拟总线
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
//-----------
unsigned char dfefer[8];
delay(1);
I2C_SCL = 0;
}
// }
}
stop_i2c();
}
//‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
/**********END**************/
// 程序结束
// SCLIO = 0;
nop();
I2C_SDA = 1;
nop();
I2C_SCL = 1;
delay(1); // 24LCxx 要求建立时间大于 Delay40uSec
I2C程序(AT24C1024)测试通过的
_nop_();
}
//*********************************************
//从机接收一位数据应答0
//*********************************************
voidACK(void)
{
SDA=0;
_nop_();
void write_byte(uchar ch)
{
uchar i, n=8;//向SDA发送一个字节数据,8位
for(i=0;i<n;i++)
{
if((ch&0x80)==0x80)
{//若要发送的位为1,则SDA=1
SDA=1;
SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL=0;
_nop_();
_nop_();
_nop_();
SDA=1;
_nop_();
}
//*********************************************
{
receive_data[i]=read_byte();//读出来的数据存到receivedata[]数组中
if(i==15)//是否读完,未读完全部数据,则应答0
NoACK();
else
ACK();
}//停止总线
stop();
}
void main()
STM32用GPIO模拟IIC(I2C)通讯C语言源码 实测可用
/******************************************************************************
*
* Function Name : I2C_NoAck
* Description : Master Send No Acknowledge Single
SDA_IN();//SDA 设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
Delay_us(I2C_Delayus);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
Delay_us(I2C_Delayus);
}
return receive;
IIC_SDA=(dat&0x80)>>7; dat<<=1; Delay_us(I2C_Delayus); //对 TEA5767 这三个延时都是必须的 IIC_SCL=1; Delay_us(I2C_Delayus); IIC_SCL=0; Delay_us(I2C_Delayus); } IIC_RecvACK(); #endif } //************************************** //从 IIC 总线接收一个字节数据 //************************************** u8 IIC_RecvByte(void) { #ifdef BMI160 u8 i=8; u8 ReceiveByte=0;
if(!IIC_RecvACK()){IIC_Stop();return FALSE;} IIC_SendByte((u8) REG_Address); //设置低起始地址 IIC_RecvACK(); IIC_Start(); IIC_SendByte(SlaveAddress+1); IIC_RecvACK();
I2C模拟程序
2.1 虚拟I2C总线汇编程序软件包2.1.1 概述为了非常方便地对I2C从器件进行快速的、正确的读写操作,我们为此而设计出虚拟I2C总线操作平台软件包。
本软件包是主方式下的虚拟I2C总线软件包,只要用户给子程序提供几个主要的参数,即可轻松地完成任何I2C总线外围器件的应用程序设计。
2.1.2I2C串行总线I2C总线是PHILIPS公司推出的芯片间串行数据传输总线,2根线(SDA、SCL)即可实现完善的全双工同步数据传送,能够十分方便地地构成多机系统和外围器件扩展系统。
I2C器件是把I2C的协议植入器件的I/O接口,使用时器件直接挂到I2C总线上,这一特点给用户在设计应用系统带来了极大的便利。
I2C器件无须片选信号,是否选中是由主器件发出的I2C从地址决定的,而I2C器件的从地址是由I2C总线委员会实行统一发配。
我们推出的I2C总线的操作平台软件包,只要你给出器件从地址[,子地址(注:PCF8574无子地址)],即可进行字节读,字节写,多字节读,多字节写,能够非常方便地使用I2C器件,无须你介入底层的I2C操作协议。
2.1.3汇编软件包说明此软件包是用在单主I2C总线上,硬件接口是SDA,SCL,使用MCU的I/O口来模拟SDA/SCL总线。
设计有/无子地址的子程序是根据I2C器件的特点,目的在于将地址和数据彻底分开。
软件包的接口界面为:IRDBYTE (无子地址)读单字节数据(现行地址读)IWRBYTE (无子地址)写单字节数据(现行地址写)IRDNBYTE (有子地址)读N字节数据IWRNBYTE (有子地址)写N字节数据说明:现行地址读/写即专指无子地址的器件,不给定子地址的读/写操作。
;平台占用内部资源:R0,R1,R2,R3,ACC,Cy。
;使用前须定义变量:SLA 器件从地址,SUBA器件子地址,NUMBYTE读/写的字节数,位变量ACK ;使用前须定义常量:SDA 、SCL 总线位,MTD 发送数据缓冲区首址,MRD 接收数据缓冲区首址;(※子程序出口参数ACK为0时表示从器件无应答)2.1.4软件包清单;--------------------------------------------------------------------------------------------------------;VI2C_ASM.ASM;I2C 软件包的底层子程序,使用前要定义好SCL和SDA。
I2C总线及其驱动程序
SDA SCL 起始 信号 static void __zyI2cAckSend (void) { __ZY_I2C_SDA = 0; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 1; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 0; } 1 2 8 9 应答 信号 1 2 8 9 非应答 信号 停止 信号
1 0 1 0 1 0 1 0
MSB LSB
主机
MSB
LSB
从机
接收一个字节的数据
程序示例
static unsigned char __zyI2cByteReceive(void) { unsigned char ucRt; unsigned char i; // 接收数据 i = 8; do { ucRt = (ucRt << 1) + __zyI2cBitReceive(); } while (--i != 0); }
空闲时SDA状态未知, 需手动拉低
发送重复起始信号
在I2C总线忙时,产生起始条件,以改变数据收发方向。
SDA(I/O) SDA
80C51
SCL(I/O)
I2C从机
SCL
static void __zyI2cStartSend (void) { __ZY_I2C_SDA = 1; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 1; __ZY_I2C_DELAY(); __ZY_I2C_SDA = 0; __ZY_I2C_DELAY(); __ZY_I2C_SCL = 0; }
从机具有I2C地址,内部寄存器均对应具体地址 主机对从机的操作即对寄存器的读写操作
初始化
读操作
i2cc语言编程实例
I2C语言编程实例I2C是一种用于短距离通信的串行通信协议。
在嵌入式系统中,I2C总线被广泛使用于芯片之间的通信。
本示例将展示如何使用I2C 总线进行通信。
1. 初始化I2C总线在开始使用I2C总线之前,必须先初始化它。
初始化步骤包括设置时钟频率、启用I2C中断等。
下面是一个初始化I2C总线的示例代码:```c// 初始化I2C总线void init_i2c(void) {// 设置I2C时钟频率为100kHzI2C_SetClockRate(100000);// 启用I2C中断I2C_EnableInterrupts(I2C1, I2C_IT_ERR | I2C_IT_TCR | I2C_IT_TC);// 初始化I2C1I2C_Init(I2C1, I2C1_PSC_16, I2C1_DRR_OPEN, I2C1_DUTY_ONE_SHOT, I2C1_滤波_ENABLED, I2C1_低电平触发_DISABLED, 384);}```2. 设置从设备地址和读写位在通信过程中,从设备地址和读写位是必不可少的。
从设备地址用于指定从设备的位置,而读写位则用于指示数据传输的方向。
下面是一个设置从设备地址和读写位的示例代码:```c// 设置从设备地址和读写位void set_slave_address(uint8_t address, uint8_t read_write) { // 设置从设备地址I2C_WriteData(I2C1, address << 1 | read_write);}```3. 发送数据发送数据的过程包括设置从设备地址和读写位、发送起始信号、发送数据、发送停止信号等步骤。
下面是一个发送数据的示例代码:```c// 发送数据void send_data(uint8_t data) {// 设置从设备地址和读写位set_slave_address(0x50, I2C_READ);// 发送起始信号I2C_GenerateSTART(I2C1, ENABLE);// 等待起始信号发送完成while (!I2C_GetFlagStatus(I2C1, I2C1_FLAG_SB)) {}// 发送从设备地址和读写位I2C_SendData(I2C1, data);// 等待数据发送完成while (!I2C_GetFlagStatus(I2C1, I2C1_FLAG_TXIS)) {}// 清除发送数据标志位I2C_ClearFlag(I2C1, I2C1_FLAG_TXIS);// 发送停止信号I2C_GenerateSTOP(I2C1, ENABLE);}```4. 接收数据接收数据的过程包括设置从设备地址和读写位、发送起始信号、接收数据、发送停止信号等步骤。
I2C协议—24C08读写操作源程序
I2C协议—24C08读写操作源程序以下是I2C协议中24C08的读写操作的源程序示例:```c++#include <Wire.h>#define EEPROM_ADDRESS 0x50 // EEPROM的I2C地址void setuWire.begin(; // 初始化I2C总线Serial.begin(9600); // 初始化串口通信void loodelay(1000);//写入数据到EEPROMbyte dataToWrite = 150; // 要写入的数据writeData(0x0000, dataToWrite); // 写入数据到EEPROM的地址0//从EEPROM读取数据byte readData = readData(0x0000); // 从EEPROM的地址0读取数据Serial.println(readData); // 打印读取到的数据void writeData(unsigned int address, byte data)//发送开始信号到EEPROMWire.beginTransmission(EEPROM_ADDRESS);//发送写命令和地址到EEPROMWire.write((int)(address >> 8)); // 发送高8位地址Wire.write((int)(address & 0xFF)); // 发送低8位地址//发送数据到EEPROMWire.write(data);//发送停止信号到EEPROM,完成写入操作Wire.endTransmission(;//等待写入完成delay(10);byte readData(unsigned int address)//发送开始信号到EEPROMWire.beginTransmission(EEPROM_ADDRESS);//发送读命令和地址到EEPROMWire.write((int)(address >> 8)); // 发送高8位地址Wire.write((int)(address & 0xFF)); // 发送低8位地址//发送重启信号到EEPROM,进行读操作Wire.endTransmission(false);//请求1个字节的数据Wire.requestFrom(EEPROM_ADDRESS, 1);//检查是否有接收到数据if (Wire.available()byte data = Wire.read(; // 读取数据return data;}return 0; // 如果没有接收到数据,则返回0```上述源程序使用Arduino的Wire库实现了24C08 EEPROM的读写操作。
单片机控制的I2C总线高频头程序
DELAY(DELAY_TIME)
{
/*发送完一个字节后检验设备的应答信号*/
SDA=1;
SCL=1;
DELAY(DELAY_TIME);
}
}
/***********************************主程序*********************************/
void main()
{
system_init(); //系统初始化
//Start-C2-ACK-05-ACK-8A-CE-ACK-ACK-A4-ACK-STOP
}
I2C_Start();//I2C总线开始
WriteI2CByte(ADD);
ChAck();
WriteI2CByte(DB1);
ChAck();
WriteI2CByte(DB2);
SEND_1();
else
SEND_0();
}
void system_init(void)//系统初始化
{
SCON = 0x50; //串口方式1,允许接收
PCON= 0x80; // SMOD=1, 波特率加倍
if(NDB>471 && NDB<863) PB=0X30; //频段计算
WriteI2CByte(PB); //频段控制
ChAck();
I2C_Stop(); //I2C总线停止
delay_ms(100);
}
F0=SDA;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
}
for(;number!=0;number--) //循环,逐个字节发送
{
Write8Bit(*Wdata); //写一个字节
TestAck(); //应答检查
if(E0==1)
{
NACK=1; //若非应答表明器件错误或已坏,置错误标志位NACK
SDA=(bit)(n&0x80);
SCL=1;
DELAY5US
SCL=0;
SDA=0;
n=n<<1;
}
}
void WriteI2C(uchar *Wdata,uchar RomAddress,uchar number) // 写n个字节数据子程序
return;
}
Start(); //重新启动
Write8Bit(ReadDeviceAddress); //写入器件的寻址地址
TestAck(); //应答检查
if(E0==1)
{
NACK=1; //若非应答表明器件错误或已坏,置错误标志位NACK
return;
if(SDA==1) //如果SDA为1,表明非应答,置位非应答标志E0
E0=1;
SCL=0;
}
void Write8Bit(uchar n) //写一个字节数据子程序,n为待发送的数据
{
uchar i;
for(i=8;i>0;i--)
{
模拟I2C程序设计
#define uchar unsigned char
#define DELAY5US _nop_(); _nop_(); _nop_(); _nop_(); //延时5us
#define WriteDeviceAddress 0xa0 //写I2C外围器件的寻址地址
}
*RamAddress=Read8Bit(); //读入最后一个字节数据
NoAck(); //非应答
Stop();
{
SDA=0;
SCL=1;
DELAY5US
SDA=1;
DELAY5US
SCL=0;
}
void Ack(void) //发送应答位子程序
{
SDA=0;
SCL=1;
DELAY5US
SCL=0;
SDA=1;
}
void NoAck(void) //发送非应答位子程序
return;
}
Wdata++; //指针增加,指向下一个数据
}
Stop(); //全部发送完则停止
}
uchar Read8Bit(void) //读一个字节数据子程序
{
uchar temp,rbyte=0;
for(temp=8;temp>0;temp--)
}
while(bytes!=1) //循环读入字节数据
{
*RamAddress=Read8Bit(); //读入一个字节
Ack(); //应答
RamAddress++; //地址指针递增
bytes--; //待读入数据个数递
sbit SDA = P1^0; //模拟数据线
sbit SCL = P1^1; //模拟时钟线
void Start(void) //启动I2C总线子函数
{
SDA=1;
SCL=1;
DELAY5US
SDA=0;
DELAY5US
SCL=0;
}
void Stop(void) //停止I2C总线数据传送子函数
{ //RamAddresБайду номын сангаас为接收数据缓冲区的首地址,RomAddress为待I2C外围器件的数据读取首地址,bytes为写字节的个数
Start(); //启动
Write8Bit(WriteDeviceAddress); //写入器件的寻址地址
TestAck(); //应答检查
if(E0==1)
{
NACK=1; //若非应答表明器件错误或已坏,置错误标志位NACK
return;
}
Write8Bit(RomAddress); //写入I2C器件内部数据的读取首地址
TestAck(); //应答检查
if(E0==1)
{
NACK=1; //若非应答表明器件错误或已坏,置错误标志位NACK
{
SDA=1;
SCL=1;
DELAY5US
SCL=0;
SDA=0;
}
void TestAck(void) //应答位检查子程序,若检测不到非应答信号,置位E0
{
SDA=1;
SCL=1;
E0=0;
_nop_(); //短延时
{ //*Wdata为待发送数据的首地址,RomAddress为待I2C外围器件的数据写入首地址,number为写字节的个数
Start(); //启动
Write8Bit(WriteDeviceAddress); //写入器件的寻址地址
TestAck(); //应答检查
if(E0==1)
{
NACK=1; //若非应答表明器件错误或已坏,置错误标志位NACK
return;
}
Write8Bit(RomAddress); //写入I2C器件的数据存储首地址
TestAck(); //应答检查
if(E0==1)
{
NACK=1; //若非应答表明器件错误或已坏,置错误标志位NACK
{
SDA=1;
SCL=1;
_nop_(); //短延时
rbyte=rbyte<<1;
rbyte=rbyte|((uchar)(SDA));
SCL=0;
}
return(rbyte);
}
void ReadI2C(uchar *RamAddress,uchar RomAddress,uchar bytes) // 读n个字节数据子程序
#define ReadDeviceAddress 0xa1 //读I2C外围器件的寻址地址
//注:写I2C外围器件的寻址地址为器件的地址,读为器件地址加1
uchar E0; //非应答信号标志位
uchar NACK=0; //错误标志位
//**************************修改硬件时要修改的部分********************************