STM32使用模拟I2C驱动LM75A获取温度

硬件平台:STM32F103C8T6 LM75A
连线:使用PB6作为SCL PB7作为SDA 分别与LM75A连接
参考资料:LM75A数据手册
代码如下

模拟I2C

I2C.h

/*
软件模拟I2C
*/
#ifndef _I2C_H
#define _I2C_H
#include "sys.h"
#include "delay.h"
#include "usart.h"
/*
读写标志位
*/
#define Write_Flag 0
#define Read_Flag 1

/*
PB7->SDA 
PB6->SCL
*/
#define SDA_Port GPIOB
#define SDA_Pin GPIO_Pin_7
#define SCL_Port GPIOB
#define SCL_Pin GPIO_Pin_6

/*
定义SDA为输出模式
*/
void SDA_Mode_Out(void);
/*
定义SDA为输入模式
*/
void SDA_Mode_In(void);
/*
位带操作SDA,SCL高低电平以及读取SDA电平
*/
#define SCL_High PBout(6)=1
#define SCL_Low  PBout(6)=0
#define SDA_Out_High PBout(7)=1
#define SDA_Out_Low  PBout(7)=0
#define SDA_Input PBin(7)

/*
I2C基本时序电平
*/
void MyI2C_Init(void);//I2C初始化
void MyI2C_Start(void);//I2C开始信号
void MyI2C_Stop(void);//I2C停止信号
void MyI2C_Ack(void);//I2C应答信号
void MyI2C_NAck(void);//I2C非应答信号
unsigned char MyI2C_WaitAck(void);//等待应答信号
void MyI2C_WriteByte(unsigned char dat);//写数据
unsigned char MyI2C_ReadByte(void);//读数据


/*
从机通信时序
*/
void MyI2C_ReadBufAddr(unsigned char SlaveAddr, unsigned char RegAddr,unsigned char *dat,unsigned char len);
void MyI2C_ReadByteAddr(unsigned char SlaveAddr, unsigned char RegAddr,unsigned char *dat);
void MyI2C_SendByteAddr(unsigned char SlaveAddr, unsigned char RegAddr, unsigned char dat);
void MyI2C_SendBufAddr(unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *dat,unsigned char len);
#endif

I2C.c

#include "i2c.h"

void MyI2C_Init(void){//I2C初始化
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//GPIOB时钟开启
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin = SDA_Pin|SCL_Pin;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_Init(GPIOB,&GPIO_InitStruct);//初始化SDA
	GPIO_SetBits(GPIOB,SDA_Pin|SCL_Pin);//I2C总线默认为高电平
}

/*
SDA为输出
*/
void SDA_Mode_Out(void){
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin = SDA_Pin;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_Init(GPIOB,&GPIO_InitStruct);
}

/*
SDA为输入
*/
void SDA_Mode_In(void){
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin = SDA_Pin;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_Init(GPIOB,&GPIO_InitStruct);
}

/*
I2C开始信号 SCL SDA为输出模式 SDA SCL均为高电平
然后SCL高时,SDA由高到低转变
*/
void MyI2C_Start(void){//I2C开始信号
	SDA_Mode_Out();//SDA为输出
	SCL_High;
	delay_us(5);
	SDA_Out_Low;//SDA由高向低,产生开始信号
	delay_us(5);
	SCL_Low;	
}

/*
I2C停止信号 SCL SDA为输出模式
然后SCL高时,SDA由高到低转变
*/
void MyI2C_Stop(void){//I2C停止信号
  SDA_Mode_Out();//SDA为输出
  SDA_Out_Low;
	delay_us(5);
	SCL_High;
	delay_us(5);
	SDA_Out_High;
}


void MyI2C_Ack(void){//I2C应答信号
  SDA_Mode_Out();
	SDA_Out_Low;
	SCL_High;
	delay_us(4);
	SCL_Low;
	delay_us(4);
}

void MyI2C_NAck(void){//I2C非应答信号
	SDA_Mode_Out();
	SDA_Out_High;
	SCL_High;
	delay_us(4);
	SCL_Low;
	delay_us(4);
}

unsigned char MyI2C_WaitAck(void){//等待应答信号,就是检测SDA是否被拉低
    unsigned char time = 0;
		SDA_Mode_In();//SDA输入模式
	  SCL_High;
	  delay_us(4);
    while(SDA_Input){
		   time++;
			 if(time>250) {
				 MyI2C_Stop();//判断是否超时
			   return 1;//非应答
			 }
		}
    SCL_Low;
		return 0;//应答 
}

void MyI2C_WriteByte(unsigned char dat){//写入数据
   unsigned char i=0;
	  SCL_Low;
	  delay_us(4);
	//1字节有8位,每次发送一个位
	//MSB 先发最高有效位
	//每次发送数据,左移
	 for(i=0;i<8;i++){
		 SDA_Mode_Out();//发送数据,为输出模式
	   if((dat<<i)&0x80) SDA_Out_High;
		 else SDA_Out_Low;//SCL低电平期间,SDA状态改变
		 SCL_High;//SCL拉高,发送SDA
		 delay_us(4);
		 SCL_Low;//允许SDA改变状态
		 delay_us(4);
	 }
}
unsigned char MyI2C_ReadByte(void){//读取数据
	  unsigned char dat = 0;
	  unsigned char i = 0;
	  for(i=0;i<8;i++){
			SDA_Mode_In();//切换为输入模式,准备读取数据
			SCL_High;
			delay_us(4);
			dat<<=1;
			if(SDA_Input) dat |= 0x01;
			SCL_Low;
			delay_us(4);
		}
		return dat;
}









/*
从从机指定地址中读取多个数据
参数分别为从机地址 寄存器地址 读取出的数据(指针传出,推荐传入数组名) 数据长度
*/
void MyI2C_ReadBufAddr(unsigned char SlaveAddr, unsigned char RegAddr,unsigned char *dat,unsigned char len){
	unsigned char i = 0;
	
	MyI2C_Start();
	MyI2C_WriteByte(SlaveAddr|Write_Flag);
	MyI2C_WaitAck();
	MyI2C_WriteByte(RegAddr);
	MyI2C_WaitAck();
	
	MyI2C_Start();
	MyI2C_WriteByte(SlaveAddr|Read_Flag);
	MyI2C_WaitAck();
	
	for(i=0;i<len;i++){
		dat[i] = MyI2C_ReadByte();
		 if(i == len)  MyI2C_NAck();
		 else MyI2C_Ack();
	}
	MyI2C_Stop();
}

/*
从从机指定地址中读取1个数据
参数分别为从机地址 寄存器地址 读取出的数据
*/
void MyI2C_ReadByteAddr(unsigned char SlaveAddr, unsigned char RegAddr,unsigned char *dat){
	MyI2C_Start();
	MyI2C_WriteByte(SlaveAddr|Write_Flag);
	MyI2C_WaitAck();
	MyI2C_WriteByte(RegAddr);
	MyI2C_WaitAck();
	
	MyI2C_Start();
	MyI2C_WriteByte(SlaveAddr|Read_Flag);
	MyI2C_WaitAck();
	
	*dat = MyI2C_ReadByte();
	MyI2C_NAck();
	MyI2C_Stop();
}

/*
向从机指定地址发送单个字节数据
*/
void MyI2C_SendByteAddr(unsigned char SlaveAddr, unsigned char RegAddr, unsigned char dat){
	MyI2C_Start();
	MyI2C_WriteByte(SlaveAddr|Write_Flag);
	MyI2C_WaitAck();
	MyI2C_WriteByte(RegAddr);
	MyI2C_WaitAck();
	MyI2C_WriteByte(dat);
	MyI2C_WaitAck();
	MyI2C_Stop();
}

/*
向从机指定地址发送多个字节数据
*/
void MyI2C_SendBufAddr(unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *dat,unsigned char len){
	unsigned char i=0;
	MyI2C_Start();
	MyI2C_WriteByte(SlaveAddr|Write_Flag);
	MyI2C_WaitAck();
	MyI2C_WriteByte(RegAddr);
	MyI2C_WaitAck();
	for(i=0;i<len;i++){
	MyI2C_WriteByte(dat[i]);
	MyI2C_WaitAck();
	}
	MyI2C_Stop();
}

2.LM75A

LM75A.h

#ifndef _LM75A_H
#define _LM75A_H
#include "sys.h"
#include "i2c.h"
#include "delay.h"

#define LM75a_Address  0X9E
#define Write_Flag 0
#define Read_Flag 1


void LM75a_GetTemp(float *data);
void LM75a_Init(void);
#endif

2.LM75A.c

void LM75a_Init(void){
	MyI2C_Start();
	MyI2C_WriteByte(0x9E);
	MyI2C_WaitAck();
	MyI2C_WriteByte(0x00);
	MyI2C_WaitAck();
	MyI2C_Stop();
	delay_ms(100);//100ms延时
}

void LM75a_GetTemp(float *data){
	int data_temp = 0;
	unsigned char test[2];
	MyI2C_ReadBufAddr(0x9E,0x00,test,2);
	data_temp = (test[0]<<3)|(test[1]>>5);
	if(data_temp & 0x400){ //判断D10来确定温度正负 0位正 1为负
		*data = (~data_temp+1)*(-0.125f);//去反+1为补码
	}
	else{
		*data = data_temp*0.125f;
	}	
}

3.main.c文件

main.c

 #include "stm32f10x.h" //STM32头文件
 #include "sys.h"
 #include "i2c.h"
 #include "usart.h"
 #include "LM75A.h"
 float Temp;
unsigned char Test[2];
int main (void){//主程序
	RCC_Configuration(); //时钟设置
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Usart1_Init(115200);
	MyI2C_Init();
	LM75a_Init();
	while(1){
		LM75a_GetTemp(&Temp);
		printf("temp = %.2f\n",Temp);
		delay_ms(200);
	}
}

4.实验效果

1.串口
在这里插入图片描述
2.逻辑分析仪
在这里插入图片描述

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值