IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32 IIC LM75B -> 正文阅读

[嵌入式]STM32 IIC LM75B


零、参考资料:

IIC协议图解
韦东山 STM32通信模拟 I2C
韦东山 STM32通信硬件 I2C
51 IIC程序
串行总线I2C
STM32 IIC详解 有动图


软件IIC

一、IIC程序:

0、数据有效性

在SCL高电平的时候采样,也就是有效。低电平的时候切换数据。
在这里插入图片描述

1、端口定义和端口初始化

?软件IIC的本质就是通过GPIO的输入与输出功能,来模拟实现硬件IIC的功能,按照时序图规定的通信协议进行模拟通信。

//--------------------------------IIC端口定义----------------  					   			   
#define SCL_Clr() GPIO_ResetBits(GPIOB,GPIO_Pin_8)//SCL   置0
#define SCL_Set() GPIO_SetBits(GPIOB,GPIO_Pin_8)   //置1

#define SDA_Clr() GPIO_ResetBits(GPIOB,GPIO_Pin_9)//SDA  置0
#define SDA_Set() GPIO_SetBits(GPIOB,GPIO_Pin_9)  //置1
#define SDA_Read() GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)  //读取IO口外部电平状态

?端口初始化,SCL时钟引脚只有输出功能,而SDA数据引脚既有输出功能,又有输入功能。STM32的GPIO的输入输出不能共用,因此需要在SDA引脚在不同输入输出功能时候,分别初始化为推挽输出浮空输入


void SCL_GPIO_Init(void)   //将SCL引脚配置为推挽输出
{
 	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能B端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOB, &GPIO_InitStructure);	  //初始化
 	GPIO_SetBits(GPIOB,GPIO_Pin_8);
}


void SDA_GPIO_Out_Init(void)  //将SDA引脚配置为推挽输出
{
 	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能B端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOB, &GPIO_InitStructure);	  //初始化
 	GPIO_SetBits(GPIOB,GPIO_Pin_9);
}

void SDA_GPIO_Read_Init(void)  //将SDA引脚配置为 浮空输入
{
 	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能B端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 		 //浮空输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOB, &GPIO_InitStructure);	  //初始化
 	GPIO_SetBits(GPIOB,GPIO_Pin_9);
}

void IIC_Init(void)  //初始化IIC接口
{
  SCL_GPIO_Init();
  SDA_GPIO_Out_Init();
  //SDA_GPIO_Read_Init();
}

2、IIC总线启动和停止条件

时序图
在这里插入图片描述

void IIC_Start(void)
{
	SDA_GPIO_Out_Init();  //SDA引脚配置为推挽输出模式
	
    SDA_Set();  //置1
	SCL_Set();  //置1
	delay_us(6);
	SDA_Clr();  //置0
	delay_us(6);
	SCL_Clr();  //置0
}


void IIC_Stop(void)
{
	SDA_GPIO_Out_Init();  //SDA引脚配置为推挽输出模式
	
	SDA_Clr();  //置0
	SDA_Set();  //置1
	delay_us(6);  //延时时间自定义
	SDA_Set();  //置1
	delay_us(6);
}


3、IIC发送与等待应答

时序图
https://img-blog.csdnimg.cn/20200827205254442.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzOTM1MDIw,size_16,color_FFFFFF,t_70#pic_center


//-------------------------------主机通过IIC发送应答----------------------------//
void IIC_SendAck(unsigned char ackbit)   
{
	SDA_GPIO_Out_Init();   //SDA引脚配置为推挽输出模式
	
	SCL_Clr();  //置0    //在SCL为0时改变SDA
	if(ackbit ==1)   // 0:应答,1:非应答
		SDA_Set();  //置1
	else if(ackbit == 0) 	
		SDA_Clr();  //置0
  
	delay_us(6);
	
	SCL_Set();  //置1 
	delay_us(6);
	SCL_Clr();  //置0
	SDA_Set();  //置1
	delay_us(6);
}


//-----------------------------IIC等待从机应答-----------------------------//
unsigned char IIC_WaitAck(void) 
{
   unsigned char ackbit = 0;
	
   SDA_GPIO_Read_Init(); //将SDA引脚配置为 浮空输入
	
   SCL_Set();  //置1  
   delay_us(6);
   ackbit = SDA_Read();
   SCL_Clr();  //置0
   delay_us(6);
	
   return ackbit;
}

Notes:
?●在开始和停止条件之间从发送机到接收机传输的数据字节数不受限制。
?●每个八位数据字节后跟一个应答位。
?●应答位是发送器将总线置为高电平,而来自主机的SCL也产生与应答有关的额外时钟脉冲。
?●被寻址的从机接收机必须在接收到每个字节后产生一个应答。同样,主机必须在接收到从机发送机中移出的每个字节后产生应答。
?●应答的设备必须在应答时钟脉冲期间拉低SDA线,以使SDA线在应答时钟脉冲的高电平期间稳定为低电平。
?●主接收机必须通过不在从机时钟输出的最后一个字节上生成应答,向发射机发送数据结束信号。在这种情况下,发送机必须将数据线保持为高电平,以使主机能够产生停止条件。

4、通过I2C总线发送和接收数据

?●具体的通信格式和芯片有关,仅介绍发送和接收单个字节。

//-------------------------通过I2C总线发送数据------------------------//
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    SDA_GPIO_Out_Init();  //SDA引脚配置为推挽输出模式
	
    for(i=0; i<8; i++)
    {
	   SCL_Clr();  //置0           //在SCL为0时改变SDA
	   delay_us(6);
       if(byt & 0x80) 	SDA_Set();  //置1
       else 	SDA_Clr();  //置0
       delay_us(6);
	   SCL_Set();  //置1  
       byt <<= 1;
       delay_us(6);
    }
	  SCL_Clr();  //置0 
}



//-----------------------从I2C总线上接收数据-----------------------------//
unsigned char IIC_RecByte(void)
{
    unsigned char i, da = 0;
	
	SDA_GPIO_Read_Init(); //将SDA引脚配置为 浮空输入
	
    for(i=0; i<8; i++)
    {   
	    SCL_Set();  //置1          //高电平时进行数据读取
        delay_us(6);
	    da <<= 1;
    	if(SDA_Read()) da |= 1;
	    SCL_Clr();  //置0
	    delay_us(6);
    }
    return da;    
}

Notes:
?●所有的SDA 信号变化都要在SCL 时钟为低电平时进行,除了开始和结束标志。
?●I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
在这里插入图片描述
?●I2C总线上进行一次数据传输的通信格式,即I2C总线的完整时序。
?●当主控器接收数据时,在最后一个数据字节,必须发送一个非应答信号,使受控器释放数据线,以便主控器产生一个停止信号来终止总线的数据传送。
在这里插入图片描述


二、应用-LM75B:

?●恩智浦和TI好像都有类似的芯片。
NXP
TI

unsigned int LM75BD_ReadTemp(void)
{
	unsigned char High_temp = 0;
	unsigned char Low_temp  = 0;	
	unsigned int temp = 0;
	
	unsigned char ack = 0;  //应答信号检查
	
	IIC_Start();  //总线开启
	
	IIC_SendByte(0x90);  //发送写命令+设备地址  写操作
	ack = IIC_WaitAck(); //等待从机发送应答
	if(ack == 1)  //从机未产生应答
	{
		OLED_ShowString(5,30,"ERROR 1 ack",12,1);  //OLED显示错误
		ack = 0;
	}
	
    IIC_SendByte(0x00);     //发送寄存器地址  温度寄存器的地址 0x00
	ack = IIC_WaitAck();
	if(ack == 1) 
	{
		OLED_ShowString(5,40,"ERROR 2 ack",12,1);
		ack = 0;
	}
	
    IIC_Start();  //再次开启总线 改变传输方向
	
	IIC_SendByte(0x91);  //地址字节 读操作
	ack = IIC_WaitAck();
	if(ack == 1) 
	{
		OLED_ShowString(5,50,"ERROR 3 ack",12,1);
		ack = 0;
	}
	
	High_temp = IIC_RecByte();   //接收高字节
	IIC_SendAck(0);   //还未接收完,接收设备主机产生应答 
	Low_temp  = IIC_RecByte();  //接收低字节
	IIC_SendAck(1);      //已经接收完,接收设备主机产生非应答 
    IIC_Stop();  //总线停止
	
	temp = ((High_temp<<8) | Low_temp);
	
	return (temp>>5);  //低五位 为无效数据,由数据手册可知
}

void LM75BD_Init(void)
{
	 ui_temperature = LM75BD_ReadTemp();
	
	 if( (ui_temperature & 0x8000) == 0x8000)  //负数
	 {
		 ui_temperature &= 0x7fff;
		 sprintf((char *)puc_temp_Buf,"temperature:-%7.3f",(float)ui_temperature*0.125);
	 }
	 else if( (ui_temperature & 0x8000) == 0)  //正数
	 {
		 sprintf((char *)puc_temp_Buf,"temperature:%7.3f",(float)ui_temperature*0.125);
	 }
	 
	 OLED_ShowString(5,20,puc_temp_Buf,12,1);
 }





void LM75BD_Temp_Proc(void)
{
   if( ui_LM75BD_flag >= 200)   //在定时器中递加,控制温度读取频率
	 {
		 ui_LM75BD_flag = 0;
		 	
         ui_temperature = LM75BD_ReadTemp();
		 
		 if( (ui_temperature & 0x8000) == 0x8000)  //负数
		 {
		   ui_temperature &= 0x7fff;
		   sprintf((char *)puc_temp_Buf,"temperature:-%7.3f",(float)ui_temperature*0.125);
		 }
		 else if( (ui_temperature & 0x8000) == 0)  //正数
		 {
		   sprintf((char *)puc_temp_Buf,"temperature:%7.3f",(float)ui_temperature*0.125);
		 }
    
	   OLED_ShowString(5,20,puc_temp_Buf,12,1);
	 }
	
}


三、时序图示波器测试:

?●对照时序图,可以在波形图上找出启动和停止条件,以及应答和八个数据传输时钟。
在这里插入图片描述
在这里插入图片描述



硬件IIC

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-12-09 11:49:55  更:2021-12-09 11:52:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 1:17:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码