⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcf8591ad.c

📁 C8051F系列单片机外围电路功能模块程序
💻 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 + -