更新时间:2016-10-09 17:11:35人气:1014
搞这个历程差不多花了我一个周末的时间,一片小小的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));
如果经常死在这里面那你就要注意如下的问题:
我用的是3.0的库 这句是I2C_Send7bitAddress(I2C1, 0xFF, I2C_Direction_Transmitter);
红线是起始位,读写位不受0XFF控制的。
SCL SDA 要有上拉电阻,VCC与GND 间最好接个104电容滤波。
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");
PREVIOUS深圳测量精准的热电阻式温度传感器
ALWRPZ热电阻温度计、PT100温度传感器、PT100温度变送器;其原理是利用导体或半导体的电阻随温度变化这一特性。热电阻温度计的主要优点有:测量精度高,复现性好;有较大的测量范围,尤其是在低温方面;易于使用在自动测量中,也便于远距离测量。同样,热电阻也...
创意无极限,仪表大发明。今天为大家介绍一项国家发明授权专利——一种薄片型超声水表、热表、流量计用测量传感器及其使用方法。该专利由汇中仪表股份有限公司申请,并于2016年9月28日获得授权公告。内容说明本发明涉及一种薄片型超声水表、热表...