📄 pcf8591ad.c
字号:
//参考程序A: PCF8591AD.C PCF8591的AD转换实验.
/*芯片PCF8951共有四个A/D输入通道:AD0,AD1,AD2,AD3,分别与四个电位器(R1,R2,R3,R4)连接,用以调节电位器的输出电压。其中AD0通道既可测量电位器输出电压,也可用于测量从J1插座输入的外接电压,须用开关J2加以选择。J4插座提供由PCF8591输出的时钟方波信号。SAA1064驱动四个数码管显示一路AD转换后得到的数据。显示格式如下表:
通道号: AD转换结果(高四位) AD转换结果(低四位)
3 E 7
函数SLA_READ(char chip_select, char channel)中的channel就是通道号选择变量.channel=0到3.本程序选定channel=3(用户可修改),用小改刀调节R4,可观察到数码管上显示的数据的变化.*/
#include <c8051f020.h> // SFR declarations
#include <intrins.h>
#define WRITE 0x00 // 写位
#define READ 0x01 // 读位
#define CHIP_B 0x70
#define SMB_START 0x08 // (MT&MR)主收发器发送起始位成功.再将从机写地址送SMB0DAT
#define SMB_RP_START 0x10 // (MT & MR)主收发器重复发送起始位成功,再将从机读地址送SMB0DAT
#define SMB_MTADDACK 0x18 // (MT)主收发器发送从地址+W成功;收到 ACK
#define SMB_MTADDNACK 0x20 // (MT) 主收发器发送从地址+W成功;收到 NACK
#define SMB_MTDBACK 0x28 //(MT)主收发器发送数据字节成功;收到ACK.
#define SMB_MRADDACK 0x40 // (MR)主收发器发送从地址+R成功;收到 ACK.
#define SMB_MRDBACK 0x50 // (MR)主收发器接收数据成功;主机发送ACK
#define SMB_MRDBNACK 0x58 // (MR)主收发器接收数据成功;主机发送NACK
char COMWRITE; //保存从地址 + R/W 位,用在 中断服务函数中
char COMREAD;
unsigned char totalnumber,sendnumber,WORD;
unsigned char INTERRUPT[20],L;
unsigned char xdata channel=3; // channel保存AD通道变量,channel=0--3.
unsigned char xdata SENDMODE; // SENDMODE=1为写(SLA_SEND),SENDMODE=0为读(SLA_READ)
bit SM_BUSY; // 在收/发过程中,SM_BUSY被置1.中断服务完成后被清为另.
unsigned char wr_data[8]; //保存写入从器件的数据
unsigned char rd_data[8]; //保存从从器件中读出的数据
void SYSCLK_Init (void);
void SMBUS_ISR (void);
char SLA_READ(char chip_select, char channel);
//channel就是通道号选择变量.channel=0到3
void SLA_SEND(char chip_select, char *wr_data, char number);
//chip_select为从器件的写地址
char temp;
char Number[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //LED数码管的字型码
void sleep_ms(unsigned int count)//延时
{
unsigned char ii,jj;
for(ii=0;ii<count;ii++)
{
for(jj=0;jj<250;jj++)
_nop_();
}
}
void MAIN (void)
{
WDTCN = 0xde; // 禁止看门狗
WDTCN = 0xad;
SYSCLK_Init(); // 系统时钟初始化
XBR0 = 0x01; // 设置P0.0为SDA,P0.1为SCL
XBR2 = 0x40; // 使能交叉开关和弱上拉
SMB0CN = 0x44; // 允许SMBus并回应低电平(AA = 1)
SMB0CR =0X0c9 ; // 设定SMBus 速率 = 100 kHz(系统时钟为11.0692MHZ)
EIE1 |= 2; // SMBus 中断使能
SM_BUSY = 0; // 释放SMBus总线
SI = 0;
EA = 1; // 开中断
while(1){
SLA_READ(0x90,channel);//(写地址WR_ADD=0x90,AD通道选择变量channel=0---3)
sleep_ms(200);
wr_data[0] = 0x00; //数组wr_data[] 中存放的数据送SAA1064
wr_data[1] = 0x17; //SAA1064的控制字
//wr_data[2] = 0x00; //第一个数码管显示通道号
wr_data[3] = 0x0; //第二个数码管熄灭
temp = rd_data[0]>>4; //AD采样数据的高四位存入temp
temp = Number[temp]; //查出temp对应的字形码
wr_data[4] = temp;
temp = rd_data[0] & 0x0f;//AD采样数据的低四位存入temp
temp = Number[temp]; //查出temp对应的字形码
wr_data[5] = temp;
SLA_SEND(CHIP_B,wr_data,0x06);
sleep_ms(200);
sleep_ms(200);
sleep_ms(200);
sleep_ms(200);
}
}
void SYSCLK_Init (void)
{
int i; // 延时计数器
OSCXCN = 0x67; // 启动外部时钟(11.0592MHZ)
for (i=0; i < 256; i++) ;
while (!(OSCXCN & 0x80)) ; // 等待晶振稳定
OSCICN = 0x88; // 选择外部晶振作为系统时钟
// 允许时钟丢失检测
}
void SLA_SEND(char chip_select, char *wr_data, char number)
{
SENDMODE=0x01;
totalnumber=number;
sendnumber=number;
while(SM_BUSY); //SMBus忙碌即等待
SM_BUSY = 1; // SMBus 忙碌标志位置1
SMB0CN = 0x44; // SMBus 使能, 回应(ACK)为低电平.
COMWRITE = (chip_select | WRITE); // COMWRITE = 7 位地址位加写位
STO = 0;
STA = 1; // 启动数据传输
while(SM_BUSY);
}
char SLA_READ(char chip_select, char channel)
{
SENDMODE=0; //SENDMODE=0,读出方式(SLA_READ)
while(SM_BUSY); // SMBus忙碌即等待
SM_BUSY = 1; // 设置忙碌标志位
SMB0CN = 0x44; // 使能SMBus, 回应(ACK)低电平 .
COMREAD = (chip_select | READ); //// COMWRITE = 7 位地址位加读位
COMWRITE = (chip_select | WRITE);
wr_data[0]=channel; //PCF8591控制字(AD通道号)---->wr_data[0]
temp =channel;
temp = Number[temp];
wr_data[2]=temp; //wr_data[2]中存入通道号,送显示在第一位数码管上
STO = 0;
STA = 1; // 启动传输
while(SM_BUSY); // 等待传输完成
return WORD; // 返回接收到的数据
}
void SMBUS_ISR (void) interrupt 7
{
switch (SMB0STA){ // 根据 SMBus 的状态字(SMB0STA)跳转
case SMB_START: //0x08
SMB0DAT = COMWRITE ; // 装入从写地址
STA = 0; // 人工清除STA
SI = 0; // 人工清除中断标志位
break;
case SMB_RP_START: //0x10
SMB0DAT = COMREAD;
STA = 0; // 人工清除STA
SI = 0; // 人工清除中断标志位
break;
case SMB_MTADDACK: //0x18
SMB0DAT = wr_data[0];
SI = 0;
break;
case SMB_MTADDNACK: //0x20
STO = 1;
STA = 1;
SI = 0;
break;
case SMB_MTDBACK: //0x28
switch (SENDMODE){ // 检查读/写标志位SENDMODE.
case 1: // SENDMODE=1(SLA_SEND)为写状态.
sendnumber--;
if(sendnumber)
SMB0DAT = wr_data[totalnumber-sendnumber];
else{
STO=1;
SM_BUSY=0;
}
break;
case 0: // SENDMODE=0(SLA_SEND)为读状态.
STO = 0;
STA = 1;
break;
default:
STO = 1;
SM_BUSY = 0;
break;
}
SI = 0;
break;
case SMB_MRADDACK: //0x40
AA = 0; // 在回应周期送NACK
SI = 0;
break;
case SMB_MRDBNACK: //0x58
rd_data[0] = SMB0DAT;
STO = 1;
SM_BUSY = 0;
AA = 1; // 设置AA=1,准备下一次传送
SI = 0;
break;
// 状态字SMB0STA无效.
default:
STO = 1;
SM_BUSY = 0;
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -