51单片机AD转换pcf8591+数码管显示+Proteus仿真二

51单片机AD转换pcf8591+数码管显示+Proteus仿真二


📝实例代码1

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
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit sda=P2^0; //自定义由普通IO口模拟I2C
sbit scl=P2^1;
sbit dm=P2^6; //段锁存
sbit wm=P2^7;
uchar code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

void Delay(uint n)
{
uint i,j;
for(i=n;i>0;i--)
for(j=110;j>0;j--);
}

void delay() //延时几微秒。延时函数在很多函数里都要用它。至少要大于4.7us
{;;} //当你把这个函数写在用它这个函数的前面就不用声明了

void init() //初始化总线。将总线都拉高以释放
{
scl=1;
delay(); //I2C总线使用时一般都要延时5us左右
sda=1;
delay();
}

void start() //启始信号。 时钟信号为高电平期间,数据总线产生下降沿。
{ //为什么要下降沿,且sda先要为1。因为先要保证数据线为空才能工作
sda=1; //先释放数据总线。高电平释放
delay();
scl=1;
delay();
sda=0;
delay();
}

void stop()
{
sda=0; //先要有工作状态才能释放,sda=0时在工作状态
delay();
scl=1;
delay();
sda=1; //释放数据总线
delay();
}

void respons() //应答函数
{
uchar i=0;
scl=1; //每个字节发送完后的第九个时钟信号的开始
delay();
while((sda==1)&&(i<255)) //此处i的定义使用了uchar.只要填一个小于255的就行
i++; //此处的sda是从机的
scl=0; //表示主器件默认从器件已经收到而不再等待。不再等待之后,时钟的高电平过了就是低电平,所以scl=0
//此时第酒个时钟信号结束
}

void writebyte(uchar d) //写一字节,每次左移一位
{
uchar i,temp;
temp=d;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0; //数据传输期间要想sda可变,先把时钟拉低。此处要给sda赋值
delay();
sda=CY; //CY为左移移入PSW寄存器中的的CY位。
delay();
scl=1; //sda有数据了。保持数据稳定
delay();
}
scl=0; //此处是写数据,是属于数据传输过程中。只有在时钟信号为低电平期间
delay(); //数据总线才可以变化。
sda=1; //所以要想释放数据总线,就必须先把时钟拉低
delay();
/\*此处释放总线写在末尾是因为调用它时,前面有起始函数释放了总线\*/
}

uchar readbyte()
{
uchar i,k;
scl=0;
delay();
sda=1;
delay();
/\*此处释放总线放在前面是因为一般都是先写后读,保险起见,释放一下总线\*/
for(i=0;i<8;i++)
{
scl=1; //一个时钟信号的开始
delay();
k=(k<<1)|sda; //实质是把sda的数据,最先传来的放在最高位,依次往下排
scl=0; //一个时钟信号结束
delay();
}
return k;
}

void display(uchar bai,uchar shi,uchar ge)
{
dm=1;
P0=table[bai]; //显示第一位
dm=0;
P0=0xff; //消隐
wm=1;
P0=0xfe;
wm=0;
P0=0x00; //消除仿真乱码
Delay(5);

dm=1;
P0=table[shi]; //显示第二位
dm=0;
P0=0xff; //消隐
wm=1;
P0=0xfd;
wm=0;
P0=0x00; //消除仿真乱码
Delay(5);

dm=1;
P0=table[ge]; //显示第三位
dm=0;
P0=0xff; //消隐
wm=1;
P0=0xfb;
wm=0;
P0=0x00; //消除仿真乱码
Delay(5);
}

/\*void write(uchar addr,uchar dat)
{
start(); //初始化
writebyte(0x90); //调用写一字节函数.PCF8591为1001。此处是给从机发送写信号(最低位是0)
respons(); //调用应答函数让从机应答
writebyte(addr); //写入地址
respons(); //每写一字节都要应答
writebyte(dat);
respons();
stop();
}\*/

uchar read(uchar addr)
{
uchar dat;
start();
writebyte(0x90); //从此处的发送地址和方向位0到从机
respons(); //此处的从机产生应答。属于“伪写”。用于确定和哪台机子通信
writebyte(addr);
respons();
start();
writebyte(0x91); //从此处开始,从机向主机写数据。读的方向位为1
respons();
dat=readbyte();
stop();
return dat; //读得的数据要返回
}

void main()
{
uchar ge,shi,bai,n;
init();
while(1)
{
n=read(0x00); //此处是读取内存的不同位置。至于从哪儿开始应该没要求
ge=n%10;
shi=n%100/10;
bai=n/100;
display(bai,shi,ge);
}
}


📚程序源码资源链接1

1
2
3
链接:https://pan.baidu.com/s/1zCTCHAllhSIEDCIuf5Z9Ng 
提取码:w37p

📝示例代码二

  • 🎬Proteus仿真效果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
//摘要:
//四位数码管显示采集的电位器AD(代码值)
//Designed by Cache.Lee 2013.11.15

#include "STC12C5A60S2.h"
#include <I2C.H>

#define uchar unsigned char
#define uint unsigned int

#define PCF8591 0x90 //PCF8591 地址

#define THCO 0xf8 //11.0592MHZ晶振
#define TLCO 0xcb //定时2ms时间常数值

unsigned char Data_Buffer[4]={1,2,3,4};
uchar code Duan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x76};

sbit P24=P2^4; //四个数码管的位码口定义
sbit P25=P2^5;
sbit P26=P2^6;
sbit P27=P2^7;


bit flag=0;


bit DACconversion(unsigned char sla,unsigned char c, unsigned char Val);
bit ISendByte(unsigned char sla,unsigned char c);
unsigned char IRcvByte(unsigned char sla);
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void main(void) //主程序
{
unsigned int v;
unsigned char AD_CHANNEL=1;
unsigned int D[5]={0,0,0,0,255};

TMOD=0x11; //设置定时器0工作模式,16位计数模式
TH0=THCO;
TL0=TLCO;
TR0=1; //启动定时器
ET0=1; //使能定时器中断
EA=1; //开总中断

while(1)
{
if(flag==1)
{flag=0;

ISendByte(PCF8591,0x01);
v=IRcvByte(PCF8591);

Data_Buffer[0]=0;//高位显示0,因为8位ADC最大值:255,第四位用不上
Data_Buffer[1]=v/100%10;
Data_Buffer[2]=v/10%10;
Data_Buffer[3]=v%10;
}
}
}


void timer0() interrupt 1 //定时器中断服务子程序
{
static unsigned int count=0;//软计时变量定义
static unsigned char Bit=0; //静态变量,退出程序后,值保留

TH0=THCO;
TL0=TLCO;

Bit++;
if(Bit>=4)Bit=0;
P2|=0xf0; //先关位码
P0=Duan[Data_Buffer[Bit]]; //开段码
switch(Bit) //送位码
{
case 0: P24=0;break;
case 1: P25=0;break;
case 2: P26=0;break;
case 3: P27=0;break;
}

count++;
if(count>=250) //半S时间到
{
count=0;
flag=1;
}
}


/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
DAC 变换, 转化函数
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
bit DACconversion(unsigned char sla,unsigned char c, unsigned char Val)
{
Start\_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(c); //发送控制字节
if(ack==0)return(0);
SendByte(Val); //发送DAC的数值
if(ack==0)return(0);
Stop\_I2c(); //结束总线
return(1);
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
ADC发送字节[命令]数据函数
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
bit ISendByte(unsigned char sla,unsigned char c)
{
Start\_I2c(); //启动总线
SendByte(sla+1); //发送器件地址+1
if(ack==0)return(0);
SendByte(c); //发送数据
if(ack==0)return(0);
Stop\_I2c(); //结束总线
return(1);
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
ADC读字节数据函数 8位AD.DA转换器
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
unsigned char IRcvByte(unsigned char sla)
{ unsigned char c;

Start\_I2c(); //启动总线
SendByte(sla+1); //发送器件地址
if(ack==0)return(0);
c=RcvByte(); //读取数据0

Ack\_I2c(1); //发送非就答位
Stop\_I2c(); //结束总线
return(c);
}


📚工程源码二

1
2
3
4
复制这段内容后打开百度网盘手机App,操作更方便哦
链接: https://pan.baidu.com/s/1xLGKhSgExyTDmE-OW6g2ZQ
提取码: dsde