51单片机中模拟IIC的代码编写

51单片机中模拟IIC的代码编写

一、简介以及配置
主芯片:STC51W4K32S4
引脚配置:推挽输出
IIC从设备:SHT3X温湿度传感器
通信过程:
使用code代码为0x2c 0x06,发送一次命令采集一次温湿度。
温湿度采集的通信过程
注:IIC时序图、芯片以及温湿度传感器具体介绍内容,可自行百度搜索
二、代码展示
bsp_htsensors.h

#ifndef __BSP_HTSENSORS_H
#define __BSP_HTSENSORS_H

#include "reg51.h"
#include "config.h"	
	
sbit SDA_PIN  =  P4^3;
sbit SCL_PIN	=	 P4^4;

#define SDA_TYPE                 0
#define SCL_TYPE                 1

#define HIGHLEVEL                1
#define LOWLEVEL                 0

#define I2C_ADDR                0x44                   //addr pin connected logic low

void _IOConfig_SetOutput(char _io_pin);
void _IOConfig_SetInput(char _io_pin);
void _IO_SetDigtal(char _io_digtal, char _io_pin);
unsigned char _IO_GetDigtal();
char I2C2RcvStr(unsigned char sla,unsigned char suba, unsigned char *htdata, unsigned char num);
char Get_Enviroment_T_H(float *temp, float *humi);
#endif

bsp_htsensors.c

#include "bsp_htsensors.h"
#include "stdio.h"

static void IIC_nop(void)
{
 	int i;
	for(i=0;i<500;i++);
}

//SDA P4.3    SCL P4.4 设置成推挽输出,需外接上拉电阻
void _IOConfig_SetOutput(char _io_pin)
{
	if(_io_pin == SDA_TYPE)
	{
		P4M1 &= ~0x08;                     //清零
		P4M0 |= 0x08;                      //置1
	}
	else if(_io_pin == SCL_TYPE)
	{
		P4M1 &= ~0x10;                     //清零
		P4M0 |= 0x10;                      //置1
	}
}

void _IOConfig_SetInput(char _io_pin)
{
	if(_io_pin == SDA_TYPE)
	{
		P4M1 |= 0x08;                       //置1
		P4M0 &= ~0x08;                      //清零
	}
	else if(_io_pin == SCL_TYPE)
	{
		P4M1 |= 0x10;                       //置1
		P4M0 &= ~0x10;                      //清零
	}
}

//设置输出引脚电平
void _IO_SetDigtal(char _io_digtal, char _io_pin)
{
	if(_io_pin == SDA_TYPE)
	{
		SDA_PIN = _io_digtal;
	}
	else if(_io_pin == SCL_TYPE)
	{
		SCL_PIN = _io_digtal;
	}
}

//读取引脚电平
unsigned char _IO_GetDigtal()
{
	return SDA_PIN;
}

//test------------
static int b_AckForTHIIC,b_AckForTHIIC2; 
static void TH_I2C2_Init(void)
{
	_IOConfig_SetOutput(SCL_TYPE);                //配置SCL为输出状态
	_IO_SetDigtal(HIGHLEVEL, SCL_TYPE);                   //SCL输出高电平
	IIC_nop();
	_IOConfig_SetOutput(SDA_TYPE);
	_IO_SetDigtal(HIGHLEVEL, SDA_TYPE);
	IIC_nop();
}

static void TH_I2C2_Start(void)
{
	TH_I2C2_Init();                          //初始化I2C引脚
	_IO_SetDigtal(LOWLEVEL, SDA_TYPE);                 //产生开始信号
	IIC_nop();
	_IO_SetDigtal(LOWLEVEL, SCL_TYPE);                 //SCL输出低电平
	IIC_nop();
}

static void TH_I2C2_Write(char byte)
{
	unsigned char t = 8;
	_IOConfig_SetOutput(SDA_TYPE);               /* SDA设置为输出模式*/
	do	 
	{

		if(byte&0x80)			   //无论何时都要保证SDA数据变化时,SCL为低电平,
		{
			_IO_SetDigtal(HIGHLEVEL, SDA_TYPE);
		}
		else 
		{
			_IO_SetDigtal(LOWLEVEL,SDA_TYPE);
		}
		byte<<=1;
		IIC_nop();
		_IO_SetDigtal(HIGHLEVEL, SCL_TYPE);
		IIC_nop();
		_IO_SetDigtal(LOWLEVEL, SCL_TYPE);			  //SCL由高变低
		IIC_nop();
	}while(--t!=0);

	_IO_SetDigtal(HIGHLEVEL, SDA_TYPE);			    // 设置SDA为高,已释放SDA;
	_IOConfig_SetInput(SDA_TYPE);				// 设置SDA为输入;
	IIC_nop();
	_IO_SetDigtal(LOWLEVEL, SCL_TYPE);			  //SCL由低

	IIC_nop();
	_IO_SetDigtal(HIGHLEVEL, SCL_TYPE);
	IIC_nop();

	if(_IO_GetDigtal())	
	{
		b_AckForTHIIC2=0;
	}
	else
	{
		b_AckForTHIIC2=1;        	//判断是否接收到应答信号
	}
	_IO_SetDigtal(LOWLEVEL, SCL_TYPE);
	IIC_nop();
}

static char TH_I2C2_Read()
{
	char dat = 0;
	unsigned char t;
	_IOConfig_SetInput(SDA_TYPE);/* SDA设置为输入模式*/								 
	IIC_nop();
	_IO_SetDigtal(LOWLEVEL, SCL_TYPE);/* SDA设置为输入模式*/
	IIC_nop();
	for(t=0;t<8;t++)
	{
		_IO_SetDigtal(HIGHLEVEL, SCL_TYPE);		
		dat=dat<<1;
		if(_IO_GetDigtal())
			dat=dat+1;	
		IIC_nop();		
		_IO_SetDigtal(LOWLEVEL, SCL_TYPE);
		IIC_nop();
	};
	return dat;
}

static void TH_I2C2_PutAck(char ack)
{
	_IOConfig_SetOutput(SDA_TYPE); /* SDA设置为输出模式*/
	IIC_nop();

	if(ack)
	{
		_IO_SetDigtal(HIGHLEVEL,SDA_TYPE);		
	}
	else 
	{
		_IO_SetDigtal(LOWLEVEL, SDA_TYPE);
	}	
	IIC_nop();
	_IO_SetDigtal(HIGHLEVEL, SCL_TYPE);
	IIC_nop();

	if(_IO_GetDigtal())
	{
		_IO_SetDigtal(HIGHLEVEL, SDA_TYPE);
	}
	IIC_nop();
	_IO_SetDigtal(LOWLEVEL, SCL_TYPE);
	IIC_nop();
}

static void TH_I2C2_Stop(void)
{
	_IOConfig_SetOutput(SDA_TYPE); /* SDA设置为输出模式*/
	_IO_SetDigtal(LOWLEVEL,SDA_TYPE);
	IIC_nop();
	_IO_SetDigtal(HIGHLEVEL, SCL_TYPE);
	IIC_nop();
	_IO_SetDigtal(HIGHLEVEL, SDA_TYPE);
	IIC_nop();
	IIC_nop(); //在下一次产生Start之前,要加一定的延时
	IIC_nop();

}

char I2C2RcvStr(unsigned char sla,unsigned char suba, unsigned char *htdata, unsigned char num)
{
	unsigned short i;
	
   TH_I2C2_Start();               	    //启动总线
   TH_I2C2_Write(sla);            	//发送器件地址
   if(b_AckForTHIIC2==0)return(0);

   TH_I2C2_Write(suba);            	//发送器件子地址
   if(b_AckForTHIIC2==0)return(0);

   //=====================================
   TH_I2C2_Write(0x06);            	//发送命令
   if(b_AckForTHIIC2==0)return(0);

   //===============================================

   TH_I2C2_Start();
   TH_I2C2_Write(sla+1);
   if(b_AckForTHIIC2==0)return(0);

   //==============================
   for(i=0;i<20;i++)
   {
      IIC_nop();
   }
   //==============================
   for(i=0;i<num-1;i++)
   {   
      *htdata=TH_I2C2_Read();               //发送数据
      TH_I2C2_PutAck(0);                	//发送就答位  
			htdata++;
   } 
   
   *htdata=TH_I2C2_Read();
   TH_I2C2_PutAck(1);                   	//发送非应位
   TH_I2C2_Stop();                    	//结束总线 
	 
   return(1);
}


/***************************************************************************
**	采集环境温湿度
**	temp:	环境温度
**	humi:	环境湿度
***************************************************************************/
char Get_Enviroment_T_H(float *temp, float *humi)
{
		char ret = 0;
		unsigned char ht_data[6]={0};
		unsigned int temp_env = 0;
		unsigned int humi_env = 0;
		
		ret = I2C2RcvStr((I2C_ADDR<<1), 0x2c, &ht_data, 6);
		if(ret == 1)
		{
			temp_env = ((unsigned short)ht_data[0]<<8) + ht_data[1];
			humi_env = ((unsigned short)ht_data[3]<<8) + ht_data[4];
			*temp = ((float)temp_env/65535)*172-45;
			*humi = ((float)humi_env/65535)*100;
			//printf("%.1f -- %.1f\r\n", *temp, *humi);
			return 0;
		}
		return 1;
}


模拟IIC注意事项:
1、传输数据时,SDA需在SCL保持在低电平状态方可变换,SCL在高电平时需注意SDA电平稳定,延时的主要作用就是在于此点
2、接收与发送应答与非应答信号的时序需注意
3、总线空闲状态表示为SDA、SCL电平为高

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值