1 /*************************此部分为I2C总线的驱动程序*************************************/
2
3 #include<reg52.h>
4 #include <intrins.h>
5
6 //#define NOP() _nop_() /* 定义空指令 */
7 #define _Nop() _nop_() /*定义空指令*/
8
9
10 sbit SCL=P2^1; //I2C 时钟
11 sbit SDA=P2^0; //I2C 数据
12
13 bit ack; /*应答标志位*/
14
15
16 //起动总线函数
17 extern void Start_I2c();
18
19 //结束总线函数
20 extern void Stop_I2c();
21
22 //应答子函数
23 extern void Ack_I2c(bit a);
24
25 //字节数据发送函数
26 extern void SendByte(unsigned char c);
27
28 /*******************************************************************
29 起动总线函数
30 函数原型: void Start_I2c();
31 功能: 启动I2C总线,即发送I2C起始条件.
32 ********************************************************************/
33 void Start_I2c()
34 {
35 SDA=1; /*发送起始条件的数据信号*/
36 _Nop();
37 SCL=1;
38 _Nop(); /*起始条件建立时间大于4.7us,延时*/
39 _Nop();
40 _Nop();
41 _Nop();
42 _Nop();
43 SDA=0; /*发送起始信号*/
44 _Nop(); /* 起始条件锁定时间大于4μs*/
45 _Nop();
46 _Nop();
47 _Nop();
48 _Nop();
49 SCL=0; /*钳住I2C总线,准备发送或接收数据 */
50 _Nop();
51 _Nop();
52 }
53
54 /*******************************************************************
55 结束总线函数
56 函数原型: void Stop_I2c();
57 功能: 结束I2C总线,即发送I2C结束条件.
58 ********************************************************************/
59 void Stop_I2c()
60 {
61 SDA=0; /*发送结束条件的数据信号*/
62 _Nop(); /*发送结束条件的时钟信号*/
63 SCL=1; /*结束条件建立时间大于4μs*/
64 _Nop();
65 _Nop();
66 _Nop();
67 _Nop();
68 _Nop();
69 SDA=1; /*发送I2C总线结束信号*/
70 _Nop();
71 _Nop();
72 _Nop();
73 _Nop();
74 }
75
76 /*******************************************************************
77 字节数据发送函数
78 函数原型: void SendByte(UCHAR c);
79 功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
80 此状态位进行操作.(不应答或非应答都使ack=0)
81 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
82 ********************************************************************/
83 void SendByte(unsigned char c)
84 {
85 unsigned char BitCnt;
86
87 for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/
88 {
89 if((c<<BitCnt)&0x80)SDA=1; /*判断发送位*/
90 else SDA=0;
91 _Nop();
92 SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/
93 _Nop();
94 _Nop(); /*保证时钟高电平周期大于4μs*/
95 _Nop();
96 _Nop();
97 _Nop();
98 SCL=0;
99 }
100
101 _Nop();
102 _Nop();
103 SDA=1; /*8位发送完后释放数据线,准备接收应答位*/
104 _Nop();
105 _Nop();
106 SCL=1;
107 _Nop();
108 _Nop();
109 _Nop();
110 if(SDA==1)ack=0;
111 else ack=1; /*判断是否接收到应答信号*/
112 SCL=0;
113 _Nop();
114 _Nop();
115 }
116
117 /*******************************************************************
118 字节数据接收函数
119 函数原型: UCHAR RcvByte();
120 功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
121 发完后请用应答函数应答从机。
122 ********************************************************************/
123 unsigned char RcvByte()
124 {
125 unsigned char retc;
126 unsigned char BitCnt;
127
128 retc=0;
129 SDA=1; /*置数据线为输入方式*/
130 for(BitCnt=0;BitCnt<8;BitCnt++)
131 {
132 _Nop();
133 SCL=0; /*置时钟线为低,准备接收数据位*/
134 _Nop();
135 _Nop(); /*时钟低电平周期大于4.7μs*/
136 _Nop();
137 _Nop();
138 _Nop();
139 SCL=1; /*置时钟线为高使数据线上数据有效*/
140 _Nop();
141 _Nop();
142 retc=retc<<1;
143 if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */
144 _Nop();
145 _Nop();
146 }
147 SCL=0;
148 _Nop();
149 _Nop();
150 return(retc);
151 }
152
153 /********************************************************************
154 应答子函数
155 函数原型: void Ack_I2c(bit a);
156 功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
157 ********************************************************************/
158 void Ack_I2c(bit a)
159 {
160
161 if(a==0)SDA=0; /*在此发出应答或非应答信号 */
162 else SDA=1;
163 _Nop();
164 _Nop();
165 _Nop();
166 SCL=1;
167 _Nop();
168 _Nop(); /*时钟低电平周期大于4μs*/
169 _Nop();
170 _Nop();
171 _Nop();
172 SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/
173 _Nop();
174 _Nop();
175 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· 语音处理 开源项目 EchoSharp
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 使用 Dify + LLM 构建精确任务处理应用