打印

百为STM32开发板教程之十——I2C数字温度传感器

[复制链接]
10356|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xi_liang|  楼主 | 2013-7-23 21:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
百为STM32开发板教程之十——I2C数字温度传感器

参考资料:
百为stm32开发板光盘\其他参考资料\I2C协议-周立功.pdf
百为stm32开发板光盘\芯片数据手册\LM75A_2_cn.pdf

实验目的:读取I2C数字温度传感器LM75A的温度,并打印到串口上

主要内容:
一、了解I2C协议
二、了解STM32的I2C接口
三、研究LM75A的数据手册,了解LM75A工作原理及相关操作
四、通过STM32的I2C接口读取LM75A的温度并打印串口上

一、了解I2C协议
I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线。
1、这两线分别是串行数据线SDA和串行时钟线SCL。
2、I2C 总线上数据的传输速率在标准模式下可达100kbit/s, 在快速模式下可达400kbit/s。
3、任何连接到总线上的设备都有一个唯一的地址,主机访问从机设备之前要先发送地址选中从机。
4、I2C进行通信时由主机发送起始位开始,直到主机发送停止位时结束。
SCL 线是高电平时,SDA 线从高电平向低电平切换,这个情况表示起始条件。
SCL 线是高电平时,SDA 线由低电平向高电平切换,这个情况表示停止条件。


5、发送到SDA 线上的每个字节必须为8 位,每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。首先传输的是数据的最高位(MSB)。
6、I2C地址有7位地址和10位地址两种,我们这里只介绍7位地址的情况。主机发送完停止位后,发送的第一个字节包括7位地址,和1位读写标志位。

最后一位R/W为0时表示写,为1时表示读

二、了解STM32的I2C接口
STM32的I2C既可做主机也可做从机,我们这里只讨论STM32的I2C作为主机的情况。
STM32的I2C功能:
1、硬件产生起始位,停止位
2、状态寄存器中有“起始条件已发送”等状态标志,这些标志组合起来就成了I2C通信过程中的事件EV5,EV6,EV7,EV8等

STM32的I2C通信过程:

STM32的I2C主机发送数据过程(发送数据到LM75A):


STM32的I2C主机接收数据过程(从LM75A接收数据):


通信过程中的EV事件(仅用于STM32):
EV5:检查状态寄存器的这三位:SB:起始位(主模式),MSL:主从模式,BUSY:总线忙
EV6:主机发送时:检查状态寄存器的:BUSY:总线忙,MSL:主从模式,ADDR:地址已被发送,TxE:数据寄存器为空,TRA:发送/接收
         主机接收时:检查状态寄存器的:BUSY:总线忙,MSL:主从模式,ADDR:地址已被发送
EV8:检查状态寄存器的:TRA:发送/接收,BUSY:总线忙,MSL:主从模式,TxE:数据寄存器为空,BTF:字节发送结束
EV7:检查状态寄存器的:BUSY:总线忙,MSL:主从模式,RxNE:数据寄存器非空

要用I2C接口,首先要初始化相关的GPIO及I2C的参数:
/* tsensor.c */
void I2C_LM75_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  I2C_InitTypeDef   I2C_InitStructure;
  /* GPIOB Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
  /* 打开I2C1时钟*/
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
  /* 配置I2C1管脚: SCL and SDA */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;  //设置I2C1管脚PB6,PB7
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;  //设置为复用开漏输出
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  /* 配置PB5为上拉输入, 连接LM75A的INT管脚 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置为输入上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  I2C_DeInit(I2C1);  //xx_DeInit仅DEBUG时用
  /* I2C1 参数初始化 */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;   //设置为I2C模式,区别于SMBus模式
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //设置I2C快速模式Tlow / Thigh = 2
  I2C_InitStructure.I2C_OwnAddress1 = 0x00;  //设置I2C自身设备地址,我们这里STM32的I2C做主机用,设为0
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;  //使能ACK应答位
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;  //响应7位地址,仅作从机时用
  I2C_InitStructure.I2C_ClockSpeed = 200000;  //设置I2C时钟频率
  I2C_Init(I2C1, &I2C_InitStructure);
  /*打开I2C1 */
  I2C_Cmd(I2C1, ENABLE);
}

三、了解LM75A工作原理及相关操作
1、概述
LM75A是NXP半导体公司推出的I2C接口的数字温度传感器,它也是一个温度检测器,提供过热检测输出功能。
LM75A 可设置成工作在两种模式:正常工作模式或关断模式。我们这里只讨论正常模式。

2、LM75A管脚电路图:

百为STM32开发板上连接LM75A的电路图(STLM75M2E是另一个器件的名称,我们只要采用的是LM75A):


3、LM75A地址及寄存器
LM75A的7位地址:其中高4位固定为1001,低3位由管脚A2,A1,A0决定


LM75A 包含许多寄存器:
(1)指针寄存器,用来选择要操作的寄存器

其中最低两位B1,B0表示要操作的寄存器


(2)配置寄存器:8位寄存器,用来配置器件的工作模式

(3)温度寄存器:16位寄存器,只有其中高11位有效,存放以0.125℃为单位的温度值补码

(4)滞后寄存器(Thyst):当环境温度低于此温度的时候,LM75A将根据当前模式(比较、中断)控制OS引脚作出相应反应。
(5)过热关断阈值寄存器(Tos):当环境温度高于此温度的时候,LM75A将根据当前模式(比较、中断)控制OS引脚作出相应反应。
这两个寄存器的作用是控制OS管脚的输出。具体可以参考LM75A数据手册。

4、LM75A相关操作时序
(这里只介绍含指针字节的情况,预置指针的情况请参考LM75A数据手册)
写配置寄存器

读配置寄存器


写Tos 或Thyst 寄存器


读包含指针字节的Temp、Tos 或Thyst 寄存器


四、通过STM32的I2C接口读取LM75A的温度并打印到串口上
/* main.c */

  TempReadValue = I2C_LM75_Temp_Read();  //读取LM75A温度寄存器值
  temperature = TempReadValue*0.125;  //转换成实际的温度值
  printf("TempReadValue = %d\n\r", TempReadValue);
  printf("temperature = %.3f\n\r", temperature);

/* tsensor.c */

u16 I2C_LM75_Temp_Read(void)
{
  u32 RegValue = 0;
  /* 使能I2C1 ACK应答位(如果ACK被其他功能模块取消的话)*/
  I2C_AcknowledgeConfig(I2C1, ENABLE);
  /*----- 发送阶段-----*/
  /* 发送I2C起始条件 */
  I2C_GenerateSTART(I2C1, ENABLE);
  
  /* 等待EV5事件 */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))  /* EV5 */
  {
  }
  
  /* 发送LM75A从机地址,写操作 */
  I2C_Send7bitAddress(I2C1, LM75_Addr, I2C_Direction_Transmitter);
  
  /* 等待EV6事件 */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) /* EV6 */
  {
  }
  /* 发送温度寄存器指针值 */
  I2C_SendData(I2C1, LM75_TEMP_Reg);
  
  /* 等待EV8事件*/
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) /* EV8 */
  {
  }
  /*----- 接收阶段 -----*/
  /* 发送重复起始条件 */
  I2C_GenerateSTART(I2C1, ENABLE);
  
  /* 等待EV5事件 */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))  /* EV5 */
  {
  }
  
  /* 发送LM75A从机地址,读操作 */
  I2C_Send7bitAddress(I2C1, LM75_Addr, I2C_Direction_Receiver);
  
  /* 等待EV6事件 */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))  /* EV6 */
  {
  }
  /* 等待EV7事件 */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  /* EV7 */
  {
  }
  
  /* 接收LM75A温度值高8位 */
  RegValue = I2C_ReceiveData(I2C1) << 8;
  
  /* 取消应答位,LM75A读温度的第二个字节不需要应答位,参考LM75A的时序图 */
  I2C_AcknowledgeConfig(I2C1, DISABLE);
  
  /* 发送停止条件 */
  I2C_GenerateSTOP(I2C1, ENABLE);
  
  /* 等待EV7事件 */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  /* EV7 */
  {
  }
  
  /* 接收LM75A温度值低8位 */
  RegValue |= I2C_ReceiveData(I2C1);
  /* 返回温度值高11位 */
  return (RegValue >> 5);
}
沙发
黑非拉| | 2013-7-25 16:58 | 只看该作者
哈哈,你的这块板子有点小问题,用I2C1的PB6和PB7就不能开FSMC了,屏就不能用正常使用了(除非分时使用),小半天几乎就耗上面了。

使用特权

评论回复
板凳
黑非拉| | 2013-7-25 17:00 | 只看该作者
2.7.15 FSMC和 I2C1以及TIM4_CH2
问题描述
如果要使用FSMC功能,NADV被配置成复用输出,该信号会被默认地置位。这样就和
TIM4_CH2和I2C1的SDA信号发生冲突。
暂时解决办法
当使用FSMC的同时,不要使用TIM4_CH2。如果要使用I2C1并且封装允许,就把该功能
重映射到PB8/PB9。

使用特权

评论回复
地板
zeluo| | 2013-7-25 19:18 | 只看该作者
好资料   学习学习   顶起来  需要花点时间好好钻研钻研   谢谢了   楼主

使用特权

评论回复
5
xi_liang|  楼主 | 2013-7-26 01:18 | 只看该作者
黑非拉 发表于 2013-7-25 16:58
哈哈,你的这块板子有点小问题,用I2C1的PB6和PB7就不能开FSMC了,屏就不能用正常使用了(除非分时使用), ...

没有问题的,FSMC和I2C冲突是STM32器件本身的BUG。可以在程序里避免。

FSMC和I2C有冲突,使用I2C的时候还要把FSMC关掉,使用完后再打开:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, DISABLE);
……I2C程序……
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);

使用特权

评论回复
6
outstanding| | 2013-7-26 10:16 | 只看该作者
看过

使用特权

评论回复
7
黑非拉| | 2013-8-12 14:58 | 只看该作者
xi_liang 发表于 2013-7-26 01:18
没有问题的,FSMC和I2C冲突是STM32器件本身的BUG。可以在程序里避免。

FSMC和I2C有冲突,使用I2C的时候还 ...

这就是我所谓的“分时使用”了,哈哈:)

使用特权

评论回复
8
chuangpu| | 2013-8-12 19:25 | 只看该作者
谢谢了  楼主   需要消化消化   先顶一个   不错

使用特权

评论回复
9
xi_liang|  楼主 | 2014-5-15 23:34 | 只看该作者
STM32的I2C不能用,是之前卖STM32开发板的没搞清楚FSMC和I2C的问题,闹出来的笑话。
顶起来,让更多人看到这个问题

使用特权

评论回复
10
xi_liang|  楼主 | 2014-6-28 11:24 | 只看该作者
chuangpu 发表于 2013-8-12 19:25
谢谢了  楼主   需要消化消化   先顶一个   不错

多谢帮顶:handshake

使用特权

评论回复
11
youngme| | 2014-7-2 00:09 | 只看该作者
这样能稳定工作吗?  不会出现无限等待的问题?

使用特权

评论回复
12
xi_liang|  楼主 | 2014-7-4 13:45 | 只看该作者
youngme 发表于 2014-7-2 00:09
这样能稳定工作吗?  不会出现无限等待的问题?

还没有出现过问题。一直都很稳定。出现无限等待的估计是没处理好FSMC和I2C冲突的问题。

使用特权

评论回复
13
xi_liang|  楼主 | 2014-9-18 13:56 | 只看该作者
顶起来:victory::victory::victory:

使用特权

评论回复
14
xi_liang|  楼主 | 2014-10-19 14:33 | 只看该作者
顶起:victory::victory::victory:

使用特权

评论回复
15
Fortware| | 2014-11-9 21:37 | 只看该作者
xi_lang,请教一个问题;
买了你的百为stm32 精简版开发板(红色的那款,MCU 类型STM32F103ZET6),使用你本篇帖子里的程序编译不通过。LM75_Addr、LM75_TEMP_Reg未定义。我看了一下手册,LM75_Addr应该等于0x90,LM75_TEMP_Reg应该等于0x00。修改后,下载后一直等待事件6,不退出循环,什么原因引起的呢?(我没有使用FSMC)

使用特权

评论回复
16
xi_liang|  楼主 | 2014-11-9 22:24 | 只看该作者
Fortware 发表于 2014-11-9 21:37
xi_lang,请教一个问题;
买了你的百为stm32 精简版开发板(红色的那款,MCU 类型STM32F103ZET6),使用你本篇 ...

ST 官方DEMO里也有这个例程的,你可以参考那个

使用特权

评论回复
17
小班儿| | 2014-11-10 13:08 | 只看该作者

感谢分享。

使用特权

评论回复
18
王力斯| | 2018-10-25 20:15 | 只看该作者
感谢大神分享  顶起

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:http://baiweijishu.taobao.com/ 百为STM32开发板 兼容官方STM3210E-EVAL开发板 WM-G-MR-09 WIFI开发板

41

主题

285

帖子

10

粉丝