您的位置 首页 编程

根据STM32 I2C的TMP101温度传感器的C源码

搞这个历程差不多花了我一个周末的时间,一片小小的TMP101确实让我破费脑筋。最后甚至使用了示波器直接观察SDA SCL 的波形。不过示波器的使用确实纠正我一个严重且低级的错误。这期间也在网上搜过

  搞这个进程差不多花了我一个周末的时刻,一片小小的TMP101的确让我花费脑筋。最终乃至运用了示波器直接调查SDA SCL 的波形。不过示波器的运用的确纠正我一个严峻且初级的过错。这期间也在网上搜过STM32 的I2C 运用 大多都是在说 STM32 的I2C固件库写的烂、STM32的硬件有问题、I2C接口没法用等等,最终处理方法都是用软件像51那样用IO口软件模仿IIC时序。但我看了STM32最新的勘误表,底子没有所谓STM32的IIC硬件规划缺点。我可不想把STM32用的像8051相同。我要用高效的硬件I2C并且要用ST官方库来完成~!

  心得:

  函数 I2C_CheckEvent () 这个典型的用法是

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

  假如常常死在这里边那你就要留意如下的问题:

  GPIO口的形式必定要是GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏复用功用

  确保的你的接线正确且速度适宜。比方:SCL SDA要有上拉电阻 4K7是典型值,100K的速度最好

  I2C_Send7bitAddress()发送要是8位数 例如你的7位地址是1001001 你不能写成0X49正确的是0x92或者是0x93最终的读写位是0(写)仍是1(读)不受你添地址的影响,仅受第3个参数I2C_Direction_Transmitter或I2C_Direction_Receiver的影响。这点我是用了示波器才看出来的 呵呵~不知道是谁把示波器CH2通道打开了反相……..我差点就置疑STM32 硬件有问题…..又呈现了一些小弯曲 唉~

  最终仔细写程序 比方 I2C_Send7bitAddress(I2C1, 0x92, I2C_Direction_Receiver);

  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));这样话如论怎样你都会死在这里的。横竖我是出了不少这种初级过错的。

  

 

  我用的是3.0的库 这句是I2C_Send7bitAddress(I2C1, 0xFF, I2C_Direction_Transmitter);

  红线是开始位,读写位不受0XFF操控的。

  

 

  SCL SDA 要有上拉电阻,VCC与GND 间最好接个104电容滤波。

  

 

  串口出温度。

  再说说 STM32的固件库…..唉~的确比较特殊不过ST的工程师好人做究竟了一个库让人轻松一截子 请先看

  最头大的 I2C_CheckEvent

  flag1 = I2Cx->SR1;

  flag2 = I2Cx->SR2;

  flag2 = flag2 << 16;

  /* Get the last event value from I2C status register */

  lastevent = (flag1 | flag2) & FLAG_Mask;

  //lastevent = (flag1 | flag2) & I2C_EVENT;

  /* Check whether the last event is equal to I2C_EVENT */

  if (lastevent == I2C_EVENT )

  {

  /* SUCCESS: last event is equal to I2C_EVENT */

  status = SUCCESS;

  }

  else

  {

  /* ERROR: last event is different from I2C_EVENT */

  status = ERROR;

  }

  return status;

  看得出STM32 便是靠SR1 与SR2 来判别各种IIC的状况,不同的位组合发生多种状况 汗~~~这个的确有构思。

  好在ST的工程师总结好了各种状况 我也引荐我们直接看库函数是怎样写的不要只看那个数据手册…

  #define I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED ((uint32_t)0x00060082) /* TRA, BUSY, TXE and ADDR flags */

  #define I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED ((uint32_t)0x00020002) /* BUSY and ADDR flags */

  #define I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED ((uint32_t)0x00860080) /* DUALF, TRA, BUSY and TXE flags */

  #define I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED ((uint32_t)0x00820000) /* DUALF and BUSY flags */

  #define I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED ((uint32_t)0x00120000) /* GENCALL and BUSY flags */

  #define I2C_EVENT_SLAVE_BYTE_RECEIVED ((uint32_t)0x00020040) /* BUSY and RXNE flags */

  还有很多………EVx 每个都有间断的。这太多了我也记不下…..总结一下吧 之说简略常用的的主形式

  开始 标志 I2C_EVENT_MASTER_MODE_SELECT

  地址写标志 I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED

  数据写标志 I2C_EVENT_MASTER_BYTE_TRANSMITTED

  地址读标志 I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED

  数据读标志 I2C_EVENT_MASTER_BYTE_RECEIVED

  SR1中有些读了寄存器就清了或硬件清零 也可以用 I2C_ClearFlag

  留意:标志位DUALF, SMBHOST, SMBDEFAULT, GENCALL, TRA, BUSY,MSL, TXE和RXNE不能被本函数铲除

  好了再看看TMP101 的手册 挺简略的。 其实TMP101对I2C的时序要求并不严厉,应对、非应对、间断都可省掉。

  网上找的

 

  SHUT DOWN 便是省电啊 less than 1μA 够省吧。F1 与F 0 是报警温度次数。

  

 

  TM 报警极性.POL 也是报警的 咱先不论…..

  这个STM32 进程没有凭借DMA 与间断。

  #include "STM32Lib\\stm32f10x.h"

  #include "hal.h"

  u8 I2c_Buf[3]="AB0";//温度寄存

  void I2C_Configuration(void)

  {

  I2C_InitTypeDef I2C_InitStructure;

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); //开I2C的时钟

  /* PB6,7 SCL and SDA */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏复用功用

  GPIO_Init(GPIOB, &GPIO_InitStructure);

  I2C_DeInit(I2C1);

  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //设置I2C为I2C形式

  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //I2C快速形式Tlow / Thigh = 2 便是拉扯SCL 凹凸电平比

  I2C_InitStructure.I2C_OwnAddress1 = 0x30; //STM32本身地址

  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能应对(ACK)

  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //应对7位地址

  I2C_InitStructure.I2C_ClockSpeed = 100000; //100K速度

  I2C_Cmd(I2C1, ENABLE);

  I2C_Init(I2C1, &I2C_InitStructure);

  /*答应1字节1应对形式*/

  I2C_AcknowledgeConfig(I2C1, ENABLE);

  }

  /***************************************************

  **函数名:I2C_ReadTmp

  **功用:读取tmp101的2个字节温度

  ***************************************************/

  void I2C_ReadTmp(void)

  {

  while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); /*检测总线是否忙 便是看 SCL 或SDA是否为 低 */

  /*答应1字节1应对形式*/

  I2C_AcknowledgeConfig(I2C1, ENABLE);

  /* 发送开始位 */

  I2C_GenerateSTART(I2C1, ENABLE);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /*EV5,主形式*/

  /*发送器材地址(写)*/

  I2C_Send7bitAddress(I2C1, 0x92, I2C_Direction_Transmitter);

  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  /*发送Pointer Register*/

  I2C_SendData(I2C1, 0X00);

  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); /*数据已发送*/

  /*开始位*/

  I2C_GenerateSTART(I2C1, ENABLE);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  /*发送器材地址(读)*/

  I2C_Send7bitAddress(I2C1, 0x92, I2C_Direction_Receiver);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

  /* 读Temperature Register*/

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* EV7 */

  I2c_Buf[0]= I2C_ReceiveData(I2C1);

  I2C_AcknowledgeConfig(I2C1, DISABLE); //最终一位后要封闭应对的

  I2C_GenerateSTOP(I2C1, ENABLE); //发送中止位

  /*● 为了在收到最终一个字节后发生一个NACK脉冲,在读倒数第二个数据字节之后(在倒数第二个RxNE事情之后)有必要铲除ACK位。

  ● 为了发生一个中止/重开始条件,软件有必要在读倒数第二个数据字节之后(在倒数第二个RxNE事情之后)设置STOP/START位。

  ● 只接纳一个字节时,刚好在EV6之后(EV6_1时,铲除ADDR之后)要封闭应对和中止条件的发生位。*/

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* EV7 */

  I2c_Buf[1]= I2C_ReceiveData(I2C1);

  /* Decrement the read bytes counter */

  /*再次答应应对形式*/

  I2C_AcknowledgeConfig(I2C1, ENABLE);

  }

  /*************************************************

  **函数名:void I2C_InitTmp(void)

  **功用:初始化TMP101

  *************************************************/

  void I2C_InitTmp(void)

  {

  I2C_GenerateSTART(I2C1, ENABLE);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  /* 发送器材地址(写)*/

  I2C_Send7bitAddress(I2C1, 0X92, I2C_Direction_Transmitter);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  /*发送Pointer Register*/

  I2C_SendData(I2C1, 0X01);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  /* 写Configuration Register 12位温度 接连转化*/

  I2C_SendData(I2C1, 0XFE);

  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  I2C_GenerateSTOP(I2C1, ENABLE);

  }

  //测试用 运用之前要先调用I2C_InitTmp 初始化TMP101

  void I2C_Test(void)

  {

  char a[8]=" ";

  u32 temp;

  float tmp;

  I2C_ReadTmp(); //读温度

  temp=I2c_Buf[0]; //转化温度

  temp=temp<<4;

  temp=temp|I2c_Buf[1]>>4;

  tmp=(temp/16.0); /*仅处理了正的温度 负温度取反后加1 再按正温度处理*/

  a[0]=(char)tmp/10+48;

  a[1]=(char)tmp%10+48;

  a[2]=’.’;

  a[3]=(char)((int)(tmp*10)%10+48);

  a[4]=(char)((int)(tmp*100)%10+48);

  a[5]=(char)((int)(tmp*1000)%10+48);

  a[6]=’C’;

  USART1_Puts(a); //USART 出温度

  USART1_Puts("\r\n");

  }

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/biancheng/298555.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部