STC12驱动PCF8575

一、简介

PCF8575是一个I/O扩展芯片,德州仪器的芯片。有3个硬件地址引脚寻址,也就是说这个芯片可以设置8个IIC器件地址;芯片工作电压2.5V~5.5V,具有16位准双向输入/输出(I/O)端口(P07-P00、P17-P10)。当我们在做嵌入式开发时,MCU接口不够用可以考虑使用这一款芯片扩展,详细查看相关芯片手册。
请添加图片描述
淘宝有这一款模块售卖,我使用的经验总结是:使用IO扩展模块当输出时,必须加上拉电阻。上拉电阻选择是1K-10K之间就行了。不然驱动的电压很低!

二、例程

备注:使用例程编译的时候会出现警告,已经检查过警告原因是没有调用函数,不影响功能运行。不用理会即可。
例程1:使用STC12使端口持续高低电平切换

//
//PCF8575控制电平和读取电平
//作者:小途
//时间:2022年2月17日
//

#include <STC12C5A60S2.h>
#include <intrins.h>

#define uchar unsigned char
#define uint unsigned int

//常用数据宏定义
#define MAIN_Fosc		11059200L	//宏定义主时钟HZ
//#define MAIN_Fosc		12000000L

//当A0 A1 A2 为000时
#define PCF8575_READ_ADDRESS 0x41		//IIC总线从机8位读地址
#define PCF8575_WRITEADDRESS 0x40		//IIC总线从机8位写地址

/*I2C硬件接口定义*/
sbit SCL = P3^2;		//I2C时钟总线
sbit SDA = P3^3;		//I2C数据总线

/*I2C常用变量宏定义*/
#define I2cRead 		1			//I2C读方向位
#define I2cWrite 		0			//I2C写方向

/*全局变量定义*/
bit AckFlag;	//应答标志位
uchar PCF8575_LVal,PCF8575_HVal;

//基于STC12单片机1ms延时函数
//函数说明:内部调用
static void Delay1ms()
{
	# if MAIN_Fosc == 11059200L
	//晶振11.0592MHz
	unsigned char i, j;

	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
	
	#elif MAIN_Fosc == 12000000L
	//晶振12.000000MHZ
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 12;
	j = 168;
	do
	{
		while (--j);
	} while (--i);
	
	#endif
	
}

//基于STC12单片机1us延时函数
//函数说明:内部调用
static void Delaym1us()
{
	# if MAIN_Fosc == 11059200L
	//晶振11.0592MHz
	_nop_();
	
	#elif MAIN_Fosc == 12000000L
	//晶振12.000000MHZ
	_nop_();
	_nop_();
	
	#endif
}



//基于STC12单片机ms延时函数
//函数说明:外部调用
void Delay_ms(uint time)
{
	int i;
	for(i=0; i<time; i++)
	{
		Delay1ms();
	}
}

//基于STC12单片机us延时函数
//函数说明:外部调用
void Delay_us(uint time)
{
	int i;
	for(i=0; i<time; i++)
	{
		Delaym1us();
	}
}

//I2C延时5us函数
void I2cDelay_5us(void)
{
	Delay_us(5);
}

//I2C总线起始信号
void I2cStart(void)
{
	SCL = 1;
	SDA = 1;
	I2cDelay_5us();//状态保持5us
	SDA = 0;
	I2cDelay_5us();//状态保持5us
}

//I2C总线停止信号
void I2cStop(void)
{
	SCL = 0;
	SDA = 0;
	SCL = 1;
	I2cDelay_5us();//状态保持5us
	SDA = 1;
	I2cDelay_5us();//状态保持5us
}

/********************************
 *函数名称:ReadACK(void)
 *函数输入:无
 *函数返回:1非应答,0应答
 *函数说明:I2C总线读从机应答信号
 ********************************/
bit ReadACK(void)
{
	uint i;
	
	SCL = 0;//拉低时钟总线,允许从机控制SDA
	SCL = 1;//拉高,读SDA
	I2cDelay_5us();
	while((SDA==1) && (i<250))//等待SDA应答,或者超过时间默认应答
		i++;
	SCL = 0;
	I2cDelay_5us();
	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
	I2cDelay_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;			//释放数据总线
}


/*====================================
函数	:I2cReadByte()
参数	:无
返回值	:返回读出的一字节数据
描述	:I2C总线读一字节数据
====================================*/
uchar I2cReadByte(void)
{
	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); //返回读出的数据
}

/*=========================================
 *函数名称:PCF8575Read(uchar dat)
 *函数输入:要控制硬件的数据(16位)
 *函数返回:无
 *函数说明:控制PCF引脚
 *=========================================*/
void PCF8575Read(uchar dat1, uchar dat2)
{
	bit AckTemp=1;
	
	I2cStart();//发送启动位
	I2cSendByte(PCF8575_WRITEADDRESS);//发送地址
	AckTemp=ReadACK();//接收应答
	I2cSendByte(dat1);//控制P0.0-P0.7
	AckTemp=ReadACK();//接收应答
	I2cSendByte(dat2);//控制P1.0-P1.7
	AckTemp=ReadACK();//接收应答
	I2cStop();
}


void PCF8575_Read()
{
	bit AckTemp = 1;
	
	I2cStart();//发送启动位
	I2cSendByte(PCF8575_READ_ADDRESS);//发送地址位
	AckTemp=ReadACK();//接收应答
	PCF8575_LVal = I2cReadByte();//接收1个字节(P0.0-P0.7)
	SendACK(0);//发送应答位
	PCF8575_HVal = I2cReadByte();//接收1个字节(P1.0-P1.7)
	SendACK(1);//发送非应答位
	I2cStop();
}

void main()
{
	PCF8575Read(0xff,0xff);//上电复位将PCF8575的电平拉高
	while(1)
	{
		
		//使控制的led闪烁
		Delay_ms(1000);
		PCF8575Read(0xff,0xff);
		Delay_ms(1000);
		PCF8575Read(0x00,0x00);
		
		
	}
}

例程2:使用STC12读取PCF8575端口电平,通过串口发送当前电平状态

#include <STC12C5A60S2.h>
#include <intrins.h>

//数据类型重定义
#define uchar unsigned char
#define uint unsigned int

//常用数据宏定义
#define MAIN_Fosc		11059200L	//宏定义主时钟HZ
//#define MAIN_Fosc		12000000L

//当A0 A1 A2 为000时
//IIC总线从机8位读地址
//IIC总线从机8位写地址
//#define PCF8575_READ_ADDRESS 0x41
//#define PCF8575_WRITEADDRESS 0x40

/*I2C常用变量宏定义*/
#define I2cRead 		1			//I2C读方向位
#define I2cWrite 		0			//I2C写方向


//IO管脚定义
sbit SDA = P0^7;//I2C时钟总线
sbit SCL = P0^6;//I2C数据总线
sbit INT0 = P3^2;//按键中断引脚


//全局变量定义
uchar PCF8575_LVal;
uchar PCF8575_HVal;

//基于STC12单片机1ms延时函数
//函数说明:内部调用
static void Delay1ms()
{
	# if MAIN_Fosc == 11059200L
	//晶振11.0592MHz
	unsigned char i, j;

	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
	
	#elif MAIN_Fosc == 12000000L
	//晶振12.000000MHZ
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 12;
	j = 168;
	do
	{
		while (--j);
	} while (--i);
	
	#endif
	
}

//基于STC12单片机1us延时函数
//函数说明:内部调用
static void Delaym1us()
{
	# if MAIN_Fosc == 11059200L
	//晶振11.0592MHz
	_nop_();
	
	#elif MAIN_Fosc == 12000000L
	//晶振12.000000MHZ
	_nop_();
	_nop_();
	
	#endif
}



//基于STC12单片机ms延时函数
//函数说明:外部调用
void Delay_ms(uint time)
{
	int i;
	for(i=0; i<time; i++)
	{
		Delay1ms();
	}
}

//基于STC12单片机us延时函数
//函数说明:外部调用
void Delay_us(uint time)
{
	int i;
	for(i=0; i<time; i++)
	{
		Delaym1us();
	}
}

// 发送I2C启动位
void I2C_Start(void)
{
	SDA=1; 
	SCL=1; 
	Delay_us(2);
	SDA=0; 
	Delay_us(2);
	SCL=0;
	Delay_us(2);
}

// 发送I2C停止位
void I2C_Stop(void)
{
	SDA=0;
	SCL=1;
	Delay_us(2);
	SDA=1;
	Delay_us(2);
	SCL=0;
	Delay_us(2);
}

// 发送BIT0  
void I2C_Send_Bit_0(void)
{
	SDA=0;
	SCL=1;
	Delay_us(2);
	SCL=0;
	Delay_us(2);
}

// 发送BIT1 
void I2C_Send_Bit_1(void)
{
	SDA=1;
	SCL=1;
	Delay_us(2);
	SCL=0;
	Delay_us(2);
}

// 接收应答信号
bit I2C_Check_Ack(void)
{
	SDA=1;
	SCL=1;
	Delay_us(2);
	F0=SDA;
	Delay_us(2);
	SCL=0;
	Delay_us(2);
	if(F0==1) return 1;

	return 0;
}

// 发送应答信号
void I2C_Ack()
{
	SDA=0;
	SCL=1;
	Delay_us(2);
	SDA=0;
	Delay_us(2);
	SCL=0;
	Delay_us(2);
}

void I2C_NoAck()
{
	SDA=1;
	SCL=1;
	Delay_us(2);
	SDA=1;
	Delay_us(2);
	SCL=0;
	Delay_us(2);
}

// 写一个字节
void I2C_Write8Bit(unsigned char I2C_data)
{
	unsigned char i;

	for(i=0;i<8;i++)
	{
		if((I2C_data<<i)&0x80)
				I2C_Send_Bit_1();
			else
				I2C_Send_Bit_0();
	}
}

// 接收一个字节
unsigned char I2C_Read8Bit(void)
{
	unsigned char I2C_data=0,i;

	for(i=0;i<8;i++)
	{
		SDA=1;    
		SCL=1;    
		Delay_us(2);
		F0=SDA;
		Delay_us(2);
		SCL=0;
		if(F0==1)
		{
			I2C_data=I2C_data<<1;
			I2C_data=I2C_data|0x01;
		}
		else
			I2C_data=I2C_data<<1;
	}
	return I2C_data;
}

// 控制PCF8575引脚电平
void PCF8575_Wirte(unsigned char addr, unsigned int val)
{
  	bit AckTemp=1;
  
  	I2C_Start();
  	I2C_Write8Bit(0x40|(addr<<1));
  	I2C_Check_Ack();
  	I2C_Write8Bit(val);                   
  	I2C_Check_Ack();
  	I2C_Write8Bit(val>>8);                 
  	I2C_Check_Ack();
  	I2C_Stop();
}

// 读出PCF8575引脚电平
void PCF8575_Read(unsigned char addr)
{    
	bit AckTemp=1;

	I2C_Start();
	I2C_Write8Bit(0x41|(addr<<1));
	AckTemp=I2C_Check_Ack();
	PCF8575_LVal=I2C_Read8Bit();
	I2C_Ack();
	PCF8575_HVal=I2C_Read8Bit();
	I2C_NoAck();
	I2C_Stop();
}


//串口初始化,晶振11.0592,波特率9600
void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x04;		//独立波特率发生器时钟为Fosc,即1T
	BRT = 0xDC;		//设定独立波特率发生器重装值
	AUXR |= 0x01;		//串口1选择独立波特率发生器为波特率发生器
	AUXR |= 0x10;		//启动独立波特率发生器
	
	EA = 1;//开总中断
	ES = 1;//开串口中断
}

//向串口发送一个字符
void putchar(char ch)
{
	SBUF = ch;
	while(!TI);TI = 0;
}

void main()
{
	UartInit();//串口初始化
	
	PCF8575_Wirte(0,0xffff); // 让PCF8575的所有IO口输出高电平
	
	while(1)
	{
		Delay_ms(100);
		PCF8575_Read(0); // 读PCF8575引脚电平 
		putchar(PCF8575_LVal); // 把P0.0~P0.7的电平字节发送到串口
		putchar(PCF8575_HVal); // 把P1.0~P1.7的电平字节发送到串口
	}
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小明n.n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值