资讯详情

基于STM32 I2C的TMP101温度传感器的C源码

这个过程几乎花了我一个周末,一个小小的TMP101真的让我心烦意乱。最后甚至使用了示波器直接观察SDA SCL 的波形。然而,使用示波器确实纠正了我严重而低级的错误。这期间也在网上搜索过STM32 的I2C 应用 大多数人都在说 STM32 的I2C固件库写得不好,STM32硬件有问题,I2C接口不能使用等,最终的解决方案是使用软件,如51IO口软件模拟IIC时序。但我看了STM32最新的勘误表根本没有所谓的STM32的IIC硬件设计缺陷。我可不想把STM像8051一样使用32。我想使用高效的硬件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(读)不受你添加地址的影响,仅第三个参数I2C_Direction_Transmitter或I2C_Direction_Receiver的影响。我用示波器看到了这一点。 呵呵~不知道是谁把示波器CH通道打开反相...我差点怀疑STM32 硬件有问题...还有一些小曲折 唉~

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

while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));无论如何,你都会死在这里。反正我犯了很多这样的低级错误。

ac0bdc8cc79a0aeb4a13f6b3ff451ab3.png

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

红线是起始位,读写位不受0的影响XFF控制的。

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

SR一些人读完寄存器后会清理或清理硬件 也可以用 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"

u8I2c_Buf[3]="AB0";//温度存放

voidI2C_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");

}

标签: ab温度控制传感器837

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台