抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

逐次逼近式AD转换器

这是一个基本原理图

首先,内部产生一个参考电压Vref,然后与要进行测量的电压Vin进行比较,如果Vref<=Vin,就产生一个“1”信号(否则产生“0”信号),并存储到N位寄存器的最高位,然重新生成参考电压信号Vref = Vref+0.5Vref,(如果前面产生的是“0”信号,则新的参考电压Vref = 0.5Vref),再与Vin比较,将比较结果(“0”或“1”存到寄存器的下一位),循环往复,直到N位寄存器全部存满数据,最后通过锁存器输出转化后的数字信号。

image-20210824143628336

比如:Vin = 3.75V, Vref = 2.5V

  1. Vref=2.5 < 3.75,因此寄存器最高位存储数据1,然后重新生成Vref = 2.5+0.5*2.5 = 3.75
  2. 此时Vref=3.75 == Vin, 返回比较结果1, 存储下来, 然后重新生成Vref = 3.75+3.75*0.5 = 5.6
  3. 此时Vref=5.6 > Vin,返回比较结果0,存储下来。。。。。
  4. 最后结果是:1100 0000

PCF8591模块

简介

PCF8591 是单电源,低功耗8 位CMOS 数据采集器件,具有4 个模拟输入、一个输出和一个串行 I2C 总线接口;

3个地址引脚A0、A1 和 A2 用于编程硬件地址,允许将最多8个器件连接至I2C总线而不需要额外硬件;

PCF8591由于其使用的简单方便和集成度高,在单片机应用系统中得到了广泛的应用。

特点:

  1. 单电源供电

  2. 工作电压:2.5 V ~ 6 V

  3. I2C总线串行输入/输出

  4. 通过3个硬件地址引脚编址

  5. 采样速率取决于 I2C 总线传输速率决定

  6. 4个模拟输入可编程为单端或差分输入

  7. 自动增量通道选择

  8. 8位逐次比较型 A/D 转换

管脚定义:

image-20210824145451094

  1. AIN0~AIN3:模拟量输入通道
  2. AOUT:模拟输出通道
  3. A0~A2:硬件设备地址
  4. VDD:电源正极
  5. VSS:电源负极
  6. VREF:参考电压输入。
  7. EXT:振荡器输入时,内部/外部的切换开关。
  8. OSC:振荡器输入/输出。
  9. SCL:I2C BUS时钟输入。
  10. SDA:I2C BUS 数据输入/输出。
  11. AGND:模拟地,模拟信号和基准电源的参考地

开发板中的PCF8591接线:

image-20210824145815414

PCF8591地址

I2C 总线系统中的每一片PCF8591 通过发送有效地址到该器件来激活。该地址包括固定部分和可编程部分

可编程部分必须根据地址引脚A0、A1 和 A2 来设置,因此I2C系统中最多可接8个PCF8591

在I2C 总线协议中地址必须是起始条件后作为第一个字节发送。

地址字节的最后一位是用于设置以后数据传输方向的读/写位(1为读操作,0为写操作)

image-20210824150249772

PCF8591控制字节

发送到 PCF8591 的第二个字节将被存储在控制寄存器,用于控制器件功能。

控制寄存器的高半字节用于允许模拟输出,以及可以将模拟输入编程为单端或差分输入。

低半字节选择一个由高半字节定义的模拟输入通道。如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加。

例子

(一)

利用I2C通信,PCF8591模数/数模转换,读取通道2电位器模拟量,通过数码管显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/*********************************************************************************
* 【作 者】: 清翔电子:向量
* 【版 本】: V1.0
* 【网 站】: http://www.qxmcu.com/
* 【淘宝店铺】: http://qxmcu.taobao.com/
* 【实验平台】: 清翔 QX-MCS51 单片机开发板
* 【外部晶振】: 11.0592mhz
* 【主控芯片】: STC89C52
* 【编译环境】: Keil μVisio4
* 【程序功能】: I2C通信,PCF8591模数/数模转换,读取通道2电位器模拟量,数码管
显示。
* 【使用说明】: 用手转动AD旁边的电位器头,数码管数值会随之变化。
**********************************************************************************/
#include <reg52.h>
#include <intrins.h>

#define PCF8591ADDR 0X90 //PCF8591地址
#define I2cRead 1 //I2C读方向位
#define I2cWrite 0 //I2C写方向位
#define CH0 0 //AD通道0
#define CH1 1 //AD通道1
#define CH2 2 //AD通道2
#define CH3 3 //AD通道3
#define DAout 0x40 //DA输出命令

#define MAIN_Fosc 11059200UL //宏定义主时钟HZ
/*====================================
使用typedef给已有数据类型取别名
====================================*/
typedef unsigned char INT8U;
typedef unsigned char uchar;
typedef unsigned char u8;

typedef unsigned int INT16U;
typedef unsigned int uint;
typedef unsigned int u16;


sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管段选
sbit SCL = P2^1; //I2C时钟总线
sbit SDA = P2^0; //I2C数据总线
uint num;//数码管显示的值
bit AckFlag;//应答标志位

//共阴数码管段选表0-9
uchar code SMGduan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};

//数码管位选码 //第1位 2位 3位 4位 5位 6位 7位 8位
uchar code SMGwei[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};//数码管位码

/*====================================
函数名 :void delay(INT16U ms)
参数 :ms,毫秒延时形参
返回值 :无
描述 :12T 51单片机自适应主时钟毫秒级延时函数
====================================*/
void delay(INT16U ms)
{
INT16U i;
do{
i = MAIN_Fosc / 96000;
while(--i); //96T per loop
}while(--ms);
}
/*====================================
函数 :void delay5us()
参数 :无
返回值 :无
描述 :12T 51单片机5微秒延时函数自适应时钟
====================================*/
void delay5us()
{
#if MAIN_Fosc == 11059200
_nop_();
#elif MAIN_Fosc == 12000000
_nop_();
#elif MAIN_Fosc == 22118400
_nop_(); _nop_(); _nop_();
#endif
}

/*====================================
函数 :display(uchar i)
参数 :i 显示变量取值0-65535
返回值 :无
描述 :数码管动态显示函数第一位显示小数点
====================================*/
//void display(uint i)
//{
// static uchar wei;
//
// P0 = 0XFF;//清除断码
// WE = 1;//打开位选锁存器
// P0 = SMGwei[wei];
// WE = 0;//锁存位选数据
//
// switch(wei)
// {
// case 0: DU = 1; P0 = SMGduan[i / 1000] | 0x80; DU = 0; break;//千位显示小数点
// case 1: DU = 1; P0 = SMGduan[i % 1000 / 100]; DU = 0; break;//显示百位
// case 2: DU = 1; P0 = SMGduan[i % 100 / 10]; DU = 0; break;//显示十位
// case 3: DU = 1; P0 = SMGduan[i % 10]; DU = 0; break;//显示个位
// }
// wei++;
// if(wei == 4)
// wei = 0;
//}

/*====================================
函数:display(INT16U Value)
参数:Value,显示值 取值0-65535
描述:共阴极数码管显示函数可显示一个字节的数
====================================*/
void display(INT16U Value) //注意由于需要显示的数大于一个字节所有形参需为int型
{
//------------------------------
DU = 0; //关闭段选
P0 = SMGduan[Value/1000]|0x80; //数码管显示千位
DU = 1; //打开段选
DU = 0; //关闭段选

WE = 0; //关闭位选
P0 = SMGwei[0]; //第一位数码管
WE = 1; //打开位选
WE = 0; //关闭位选
delay(3);
//-------------------------------
DU = 0;
P0 = SMGduan[Value%1000/100]; //显示百位
DU = 1;
DU = 0;

WE = 0;
P0 = SMGwei[1]; //第二位数码管
WE = 1;
WE = 0;
delay(3);
//-------------------------------
DU = 0;
P0 = SMGduan[Value%100/10]; //显示十位
DU = 1;
DU = 0;

WE = 0;
P0 = SMGwei[2]; //第三位数码管
WE = 1;
WE = 0;
delay(3);
//-------------------------------
DU = 0;
P0 = SMGduan[Value%10]; //显示个位
DU = 1;
DU = 0;

WE = 0;
P0 = SMGwei[3]; //第四位数码管
WE = 1;
WE = 0;
delay(3);
}

/****************************************************
IIC通信代码
****************************************************/

/*====================================
函数 :I2cStart()
参数 :无
返回值 :无
描述 :I2C总线起始信号
====================================*/
void I2cStart()
{
//时钟总线为高电平期间数据总线又高变低产生起始型号
SCL = 1;
SDA = 1;
delay5us();//状态保持5us
SDA = 0;
delay5us();//状态保持5us
}

/*====================================
函数 :I2cStop()
参数 :无
返回值 :无
描述 :I2C总线停止信号
====================================*/
void I2cStop()
{
//时钟总线为高电平期间,数据总线从高变低产生终止信号
SCL = 0;
SDA = 0;
SCL = 1;
delay5us();//状态保持5us
SDA = 1;
delay5us();//状态保持5us
}

/*====================================
函数 :ReadACK()
参数 :无
返回值 :1非应答,0应答
描述 :I2C总线读从机应答信号
====================================*/
bit ReadACK()
{
SCL = 0;//拉低时钟总线,允许从机控制SDA
SCL = 1;//拉高,读SDA
delay5us();
if(SDA)//NOACK
{
SCL = 0;
return(1);//返回1
}
else//ACK
{
SCL = 0;
return(0);//返回0
}
}

/*====================================
函数 :SendACK(bit i)
参数 :1主机发送非应答,0发送应答
返回值 :无
描述 :主机发送应答信号
====================================*/
void SendACK(bit i)
{
SCL = 0;//拉低时钟总线,允许主机控制SDA
if(i) //发非应答
SDA = 1;
else //发应答
SDA = 0;
SCL = 1; //拉高总线,让从机读SDA
delay5us();//保持5us
SCL = 0; //拉低时钟总线,允许SDA释放
SDA = 1;//释放数据总线
}

/*====================================
函数 :I2cSendByte(uchar DAT)
参数 :DAT需要发送的数据
返回值 :无
描述 :I2C发送一个字节数据
====================================*/
void I2cSendByte(uchar DAT)
{
uchar i;
for(i=0; i<8; i++) //分别写8次,每次写1位
{
SCL = 0;//拉低时钟总线,允许SDA变化
if(DAT & 0x80)//先写数据最高位
SDA = 1; //写1
else
SDA = 0; //写0
SCL = 1; //拉高时钟,让从机读SDA
DAT <<= 1; //为发送下一位左移1位
}
SCL = 0; //拉低时钟总线,允许SDA释放
SDA = 1;//释放数据总线
}

/*====================================
函数 :Pcf8591DA(uchar Ctrl, DAT)
参数 :Ctrl 8591控制字节,DAT 要写入的数据
返回值 :无
描述 :PCF8591数字量转模拟量输出
====================================*/
//void Pcf8591DA(uchar Ctrl, DAT)
//{
// I2cStart();//I2C起始信号
// I2cSendByte(PCF8591ADDR + I2cWrite);//发送器件地址加读写方向位
// if(ReadACK()) //读从机应答
// AckFlag = 1; //NOACK
// else
// AckFlag = 0; //ACK
// I2cSendByte(Ctrl);//发送控制字节
// if(ReadACK())//读从机应答
// AckFlag = 1; //NOACK
// else
// AckFlag = 0; //ACK
// I2cSendByte(DAT);//发送一字节数据
// if(ReadACK())//读从机应答
// AckFlag = 1; //NOACK
// else
// AckFlag = 0; //ACK
// I2cStop(); //I2C停止信号
//}


/*====================================
函数 :I2cReadByte()
参数 :无
返回值 :返回读出的一字节数据
描述 :I2C总线读一字节数据
====================================*/
uchar I2cReadByte()
{
uchar i, DAT;
for(i=0; i<8; i++)//分别读8次,每次读一位
{
DAT <<= 1; //数据左移1位,准备接收一位
SCL = 0; //拉低时钟总线,允许从机控制SDA变化
SCL = 1; //拉高时钟总线,读取SDA上的数据
if(SDA)
DAT |= 0X01;//为1则写1,否则不行执行写1,通过左移补0
}
return(DAT); //返回读出的数据
}

/*====================================
函数 :PCF8591Read(uchar Ctrl)
参数 :Ctrl 8591控制字节
返回值 :AD转出的数字量
描述 :读指定通道的输入的模拟量专为数字量
====================================*/
uchar PCF8591Read(uchar Ctrl)
{
uchar DAT;
I2cStart();//I2C起始信号
I2cSendByte(PCF8591ADDR + I2cWrite);//发送器件地址加读写方向位
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(Ctrl);//发送控制字节
ReadACK();//读从机应答
I2cStart();//再次产生I2C起始信号
I2cSendByte(PCF8591ADDR + I2cRead);//发送器件地址加读写方向位 读
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
DAT = I2cReadByte();//读一字节
SendACK(1);//主机发送非应答
I2cStop(); //I2C停止信号
return(DAT);//返回读出数据

}

void main()//main函数自身会循环
{
while(1)
{
num = (PCF8591Read(CH2) * 19.53 + 0.5);//读AD通道2,电位器值
// 5000mv/256约等于等于19.53 ,加0.5是小数四舍五入接近实际转换精度
display(num); //数码管显示函数
delay(5);
}
}

(二)

使用I2C通信,PCF8591模数/数模转换,读取通道0光敏模拟量,输出模拟量控制LED10亮度变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
/*********************************************************************************
* 【作 者】: 清翔电子:向量
* 【版 本】: V1.0
* 【网 站】: http://www.qxmcu.com/
* 【淘宝店铺】: http://qxmcu.taobao.com/
* 【实验平台】: 清翔 QX-MCS51 单片机开发板
* 【外部晶振】: 11.0592mhz
* 【主控芯片】: STC89C52
* 【编译环境】: Keil μVisio4
* 【程序功能】: I2C通信,PCF8591模数/数模转换,读取通道0光敏模拟量,输出模拟量控制LED10
* 【使用说明】: 随着环境光线的变强LED10亮度增加,环境光变弱LED10亮度变暗
需要用跳线帽把DEN和DOUT短接(默认已短接)
**********************************************************************************/
#include <reg52.h>
#include <intrins.h>

#define uint unsigned int
#define uchar unsigned char
#define PCF8591ADDR 0X90 //PCF8591硬件地址
#define I2cRead 1 //I2C读方向位
#define I2cWrite 0 //I2C写方向位
#define CH0 0 //AD通道0
#define CH1 1 //AD通道1
#define CH2 2 //AD通道2
#define CH3 3 //AD通道3
#define DAout 0x40 //DA输出命令

sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管段选
sbit SCL = P2^1; //I2C时钟总线
sbit SDA = P2^0; //I2C数据总线
uchar num;//数码管显示的值
bit AckFlag;//应答标志位

//共阴数码管段选表0-9
uchar code SMGduan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
//数码管位选码
uchar code SMGwei[] = {0xfe, 0xfd, 0xfb};

/*====================================
函数 : delay(uint z)
参数 :z 延时毫秒设定,取值范围0-65535
返回值 :无
描述 :12T/Fosc11.0592M毫秒级延时
====================================*/
void delay(uint z)
{
uint x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}

/*====================================
函数 :display(uchar i)
参数 :i 显示数值,取值范围0-255
返回值 :无
描述 :三位共阴数码管动态显示
====================================*/
void display(uchar i)
{
static uchar wei;
P0 = 0XFF;//清除断码
WE = 1;//打开位选锁存器
P0 = SMGwei[wei];
WE = 0;//锁存位选数据
switch(wei)
{
case 0: DU = 1; P0 = SMGduan[i / 100]; DU = 0; break;
case 1: DU = 1; P0 = SMGduan[i % 100 / 10]; DU = 0; break;
case 2: DU = 1; P0 = SMGduan[i % 10]; DU = 0; break;
}
wei++;
if(wei == 3)
wei = 0;
}
//定时器0初始化
void timer0Init()
{
EA = 1; //打开总中断
ET0 = 1;//打开定时器0中断
TR0 = 1; //启动定时器0
TMOD |= 0X01; //定时器工作模式1,16位定时模式
TH0 = 0xED;
TL0 = 0xFF; //定时5ms
}
/****************************************************
IIC通信代码
****************************************************/

/*====================================
函数 :delay5us()
参数 :无
返回值 :无
描述 :5us延时函数
====================================*/
void delay5us()
{
_nop_();
}

/*====================================
函数 :I2cStart()
参数 :无
返回值 :无
描述 :I2C总线起始信号
====================================*/
void I2cStart()
{
//时钟总线为高电平期间数据总线又高变低产生起始型号
SCL = 1;
SDA = 1;
delay5us();//状态保持5us
SDA = 0;
delay5us();//状态保持5us
}

/*====================================
函数 :I2cStop()
参数 :无
返回值 :无
描述 :I2C总线停止信号
====================================*/
void I2cStop()
{
//时钟总线为高电平期间,数据总线从高变低产生终止信号
SCL = 0;
SDA = 0;
SCL = 1;
delay5us();//状态保持5us
SDA = 1;
delay5us();//状态保持5us
}

/*====================================
函数 :ReadACK()
参数 :无
返回值 :1非应答,0应答
描述 :I2C总线读从机应答信号
====================================*/
bit ReadACK()
{
SCL = 0;//拉低时钟总线,允许从机控制SDA
SCL = 1;//拉高,读SDA
delay5us();
if(SDA)//NOACK
{
SCL = 0;
return(1);//返回1
}
else//ACK
{
SCL = 0;
return(0);//返回0
}
}

/*====================================
函数 :SendACK(bit i)
参数 :1主机发送非应答,0发送应答
返回值 :无
描述 :主机发送应答信号
====================================*/
void SendACK(bit i)
{
SCL = 0;//拉低时钟总线,允许主机控制SDA
if(i) //发非应答
SDA = 1;
else //发应答
SDA = 0;
SCL = 1; //拉高总线,让从机读SDA
delay5us();//保持5us
SCL = 0; //拉低时钟总线,允许SDA释放
SDA = 1;//释放数据总线
}

/*====================================
函数 :I2cSendByte(uchar DAT)
参数 :DAT需要发送的数据
返回值 :无
描述 :I2C发送一个字节数据
====================================*/
void I2cSendByte(uchar DAT)
{
uchar i;
for(i=0; i<8; i++) //分别写8次,每次写1位
{
SCL = 0;//拉低时钟总线,允许SDA变化
if(DAT & 0x80)//先写数据最高位
SDA = 1; //写1
else
SDA = 0; //写0
SCL = 1; //拉高时钟,让从机读SDA
DAT <<= 1; //为发送下一位左移1位
}
SCL = 0; //拉低时钟总线,允许SDA释放
SDA = 1;//释放数据总线
}

/*====================================
函数 :Pcf8591DA(uchar Ctrl, DAT)
参数 :Ctrl 8591控制字节,DAT 要写入的数据
返回值 :无
描述 :PCF8591数字量转模拟量输出
====================================*/
void Pcf8591DA(uchar Ctrl, DAT)
{
I2cStart();//I2C起始信号
I2cSendByte(PCF8591ADDR + I2cWrite);//发送器件地址加读写方向位
if(ReadACK()) //读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(Ctrl);//发送控制字节
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(DAT);//发送一字节数据
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cStop(); //I2C停止信号
}


/*====================================
函数 :I2cReadByte()
参数 :无
返回值 :返回读出的一字节数据
描述 :I2C总线读一字节数据
====================================*/
uchar I2cReadByte()
{
uchar i, DAT;
for(i=0; i<8; i++)//分别读8次,每次读一位
{
DAT <<= 1; //数据左移1位,准备接收一位
SCL = 0; //拉低时钟总线,允许从机控制SDA变化
SCL = 1; //拉高时钟总线,读取SDA上的数据
if(SDA)
DAT |= 0X01;//为1则写1,否则不行执行写1,通过左移补0
}
return(DAT); //返回读出的数据
}

/*====================================
函数 :PCF8591Read(uchar Ctrl)
参数 :Ctrl 8591控制字节
返回值 :AD转出的数字量
描述 :读指定通道的输入的模拟量专为数字量
====================================*/
uchar PCF8591Read(uchar Ctrl)
{
uchar DAT;
I2cStart();//I2C起始信号
I2cSendByte(PCF8591ADDR + I2cWrite);//发送器件地址加读写方向位
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(Ctrl);//发送控制字节
ReadACK();//读从机应答
I2cStart();//再次产生I2C起始信号
I2cSendByte(PCF8591ADDR + I2cRead);//发送器件地址加读写方向位 读
if(ReadACK())//读从机应答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
DAT = I2cReadByte();//读一字节
SendACK(1);//主机发送非应答
I2cStop(); //I2C停止信号
return(DAT);//返回读出数据

}

void main()//main函数自身会循环
{
timer0Init();//定时器0初始化
while(1)
{
EA = 0;//屏蔽中断
num = PCF8591Read(CH0);//读AD通道0,光敏值
Pcf8591DA(DAout, ~num);//把光敏转出的数字量取反,输出模拟量控制LED10
EA = 1;//开中断
delay(5);
}
}

//定时器0中断函数
void timer0() interrupt 1
{
TH0 = 0xED;
TL0 = 0xFF; //定时5ms
display(num); //数码管显示函数
}

评论