【第六章】STM32 / GD32 - 软件I2C读取温度传感器LM75AD

关联:STM32总结超全笔记【秋招自用】

【引言】

学习IIC通讯协议之前,我们回忆一下之前学习的第一个通信协议USART串口。

串口通信协议的特点 是串行 的、 异步 的、 半双工 通信。
  • 串行:数据位按照顺序一个接一个地被发送和接收,而不是同时传输多个数据位。
  • 异步:发送和接收数据的时钟不是同步的,发送方和接收方的时钟不需要保持同步。
  • 半双工:数据可以在两个方向上进行传输,但不能同时进行。

 【问】串口通信有几根线?

两根:TX和RX,一条收,一条发。

【IIC特点】

本章学习的IIC通信协议的特点是串行的、同步的、半双工的。

IIC是同步的,说明它必须有一条时钟线SCL,另外数据线有几条呢?

只有一条SDA数据线,所以决定了他是半双工的,来看一下图示:

如图:设备有主机STM32和若干从机,每个连接到总线的从机都有唯一的地址,任何器件也都可以作为主机,但是同一时刻只能拥有一个主机。

【问】之前在GPIO模式,讲到开漏输出的时候说到IIC特别适合开漏输出,为什么呢?

这是由IIC总线内部结构决定的,总线内部使用漏极开漏输出驱动器,所以SDA和SCL两根线都使用一个上拉电阻(上图),使用的时候就拉低为低电平,但是不能被驱动为高电平,平时为高阻态。

PS:这个上拉值有一个典型值4.7KΩ

【IIC通信协议】

【问】那么IIC的通信过程是什么样的?

一般分为四个部分:

  1. 通信开始
  2. 地址传送(通过地址选择传送数据目标)
  3. 数据传送(收发数据)
  4. 通信结束

我觉得大家可以思考一下,如果只给你两根线,一根时钟线一根数据线,条件是如此的艰难,那么要实现主机对从从机,或者是从机对主机的选择,以及数据的发送,数据的接收,甚至还需要应答机制,不然对方怎么知道数据收没收到??你会怎么做????

 【数据帧格式】

 数据帧格式,对应上方的通信过程。

 【起始和结束信号】

【应答机制】

 【数据有效性】

 【总结】

最后详细叙述一下通讯过程:

1.开始:主设备把SDA从高拉低再把SCL从高拉低,对总线上的从机说:我要开始和你们中的某个人通信了。

2.主设备发送要与之通信的从机的7位地址(一般是7位),第八位是读写位(读1写0)

3.总线上的从设备把主设备发送的地址与自己的地址比较,如果匹配:从设备将SDA拉低一位表示应答(此时从设备获得SDA的控制权,之前SDA都是主设备控制的)。如果不拉低,SDA为高就表示非应答

4.主设备发送(或接收)数据给从设备。SCL为高,读(写)数据,SCL为低,准备下一位的数据

5.数据传输完毕,从设备返回一个应答给主设备

6.停止:主设备把SCL从低拉高,再把SDA从低拉高,表示停止通信。

【软件模拟IIC】

了解了通信协议,我们具体怎么使用呢?

这里我们使用软件模拟IIC通信协议,软件模拟I2C不需要额外的硬件支持,只需要使用微控制器的GPIO引脚和软件实现即可。此外灵活性和可移植性非常高。

我们一步步来,这章使用的是GD32F1103,但其实和STM32是完全一样的。

首先我们要控制SDA和SCL的电平,就要封装一个写引脚SDA和SCL 1或0 的函数:

(IIC的引脚都宏定义了,函数基本和STM32一样的)

【起始条件】SDA从高拉低再把SCL从高拉低 

【结束条件】SCL从低拉高,再把SDA从低拉高

【应答】从设备将SDA拉表示应答

【非应答】从设备将SDA拉表示非应答

【主机发送一个字节数据给从机】

【主机读从机一个字节数据】

【主机读应答】

这个读SDA也就是把  gpio_input_bit_get  封装了一下:

 那么软件模拟IIC已经被我们封装好了,接下来做实验。

【例程11】软件IIC读取温度传感器LM75AD

首先硬件连接:  PB6 -- SCL     PB7 -- SDA

实验目的: 温度寄存器的值拿出来转化为浮点型的数值,通过串口发送到主机

 【IIC和GPIO初始化】

第一步不用想也是初始化

#define I2C_SOFT_RCU   RCU_GPIOB
#define I2C_SOFT_PORT  GPIOB
#define I2C_SOFT_SCL_PIN   GPIO_PIN_6
#define I2C_SOFT_SDA_PIN   GPIO_PIN_7

//初始化函数
void my_i2c_init(void){
    //打开IIC时钟
	rcu_periph_clock_enable(I2C_SOFT_RCU);
    
    //初始化GPIO
	gpio_init(I2C_SOFT_PORT, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, I2C_SOFT_SCL_PIN|I2C_SOFT_SDA_PIN);
	
    //GPIO引脚置1(高阻态)
	gpio_bit_set(I2C_SOFT_PORT, I2C_SOFT_SCL_PIN|I2C_SOFT_SDA_PIN);
}

【读温度寄存器的值(未转换)】

首先封装一个函数,用来向IIC总线上写入器件地址以及要用到的温度寄存器地址

uint8_t lm75a_write_addr(uint8_t id_rw, uint8_t reg_addr){
	my_i2c_start();
	my_i2c_send_byte(id_rw);
	my_i2c_read_ack();
	my_i2c_send_byte(reg_addr);
	my_i2c_read_ack();
	
	return 0;
}

然后就是读温度寄存器的值。

#define LM75A_I2C_ADDR  0x9E   //LM75A的从机地址
#define LM75A_TEMP_REG  0x00   //温度寄存器的指针地址

#define IIC_WRITE 0
#define IIC_READ 1

/***
功能:读温度寄存器的值
输入:
	uint8_t lm75a_id: lm75a的iic从机地址
	uint8_t reg:要操作的寄存器的指针
	uint8_t *p:读取结果存放的位置
	uint8_t len:寄存器的字节长度(1 or 2)
返回:无
*****/
void lm75a_read_reg(uint8_t lm75a_id, uint8_t reg, uint8_t *p, uint8_t len){
	//向iic总线上写入器件地址、指针字节
	lm75a_write_addr(lm75a_id|IIC_WRITE, reg);
	my_i2c_start();
	my_i2c_send_byte(lm75a_id|IIC_READ);
	my_i2c_read_ack();
	
	uint8_t i;
	
	for(i = 0; i < len; i++){
		*p++ = my_i2c_read_byte();
		if(i != (len-1))
			my_i2c_ack();
	}
	my_i2c_nack();
	
	my_i2c_stop();
}

详细如下图:

【读温度传感器的温度寄存器的值并转换为温度值】

// 读温度传感器的温度寄存器的值并转换为温度值
float lm75a_get_temp(void){
	float temp_result;
	//读温度寄存器值
	uint8_t byte_data[2];
	lm75a_read_reg(LM75A_I2C_ADDR, LM75A_TEMP_REG, byte_data, 2);
	
	//将温度寄存器值转为温度值
	uint16_t temp_reg = byte_data[0]<<3 | byte_data[1]>>5;
	
	if((temp_reg & 0x0400) == 0){
		temp_result = temp_reg * 0.125;
	}else{
		temp_reg = (~((temp_reg&0x03ff)-1)) & 0x03ff;    //补码到原码转换
		temp_result = temp_reg * (-0.125);
	}
	
	return temp_result;
}

 查阅数据手册,得到温度寄存器和温度值的转换方法:

判断这个寄存器的第十位是0还是1,对应着不同的计算方法:

【主函数】

lm75a_init();
	
	while(1){
		temp_result = lm75a_get_temp();
		sprintf(temp_string, "temperature is: %.3f C.\n", temp_result);
		usart0_send_string((uint8_t *)temp_string); 
		delay_1ms(1000);  //等待1s
	}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值