基于STM32 I2C的TMP101溫度傳感器的C源碼
心得:
本文引用地址:http://m.butianyuan.cn/article/201612/325217.htm函數(shù)I2C_CheckEvent ()這個(gè)典型的用法是
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
如果經(jīng)常死在這里面那你就要注意如下的問題:
- GPIO口的模式一定要是GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//開漏復(fù)用功能
- 保證的你的接線正確且速度合適。比如:SCL SDA要有上拉電阻 4K7是典型值,100K的速度最好
- I2C_Send7bitAddress()發(fā)送要是8位數(shù) 例如你的7位地址是1001001 你不能寫成0X49正確的是0x92或者是0x93最后的讀寫位是0(寫)還是1(讀)不受你添地址的影響,僅受第3個(gè)參數(shù)I2C_Direction_Transmitter或I2C_Direction_Receiver的影響。這點(diǎn)我是用了示波器才看出來的 呵呵~不知道是誰把示波器CH2通道打開了反相........我差點(diǎn)就懷疑STM32 硬件有問題.....又出現(xiàn)了一些小曲折 唉~
- 最后細(xì)心寫程序 比如I2C_Send7bitAddress(I2C1, 0x92, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));這樣話如論如何你都會(huì)死在這里的。反正我是出了不少這種低級(jí)錯(cuò)誤的。
我用的是3.0的庫 這句是I2C_Send7bitAddress(I2C1, 0xFF, I2C_Direction_Transmitter);
紅線是起始位,讀寫位不受0XFF控制的。
SCL SDA 要有上拉電阻,VCC與GND 間最好接個(gè)104電容濾波。
串口出溫度。
再說說 STM32的固件庫.....唉~確實(shí)比較另類不過ST的工程師好人做到底了一個(gè)庫讓人輕松一截子 請(qǐng)先看
最頭大的 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的狀態(tài),不同的位組合產(chǎn)生多種情況 汗~~~這個(gè)確實(shí)有創(chuàng)意。
好在ST的工程師總結(jié)好了各種情況 我也推薦大家直接看庫函數(shù)是怎么寫的不要只看那個(gè)數(shù)據(jù)手冊(cè)...
#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 每個(gè)都有中斷的。這太多了我也記不下.....總結(jié)一下吧 之說簡(jiǎn)單常用的的主模式
起始標(biāo)志I2C_EVENT_MASTER_MODE_SELECT
地址寫標(biāo)志 I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED
數(shù)據(jù)寫標(biāo)志I2C_EVENT_MASTER_BYTE_TRANSMITTED
地址讀標(biāo)志I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED
數(shù)據(jù)讀標(biāo)志I2C_EVENT_MASTER_BYTE_RECEIVED
SR1中有些讀了寄存器就清了或硬件清零 也可以用 I2C_ClearFlag
注意:標(biāo)志位DUALF, SMBHOST, SMBDEFAULT, GENCALL, TRA, BUSY,MSL, TXE和RXNE不能被本函數(shù)清除
好了再看看TMP101 的手冊(cè) 挺簡(jiǎn)單的。 其實(shí)TMP101對(duì)I2C的時(shí)序要求并不嚴(yán)格,應(yīng)答、非應(yīng)答、中止都可省略。
網(wǎng)上找的
SHUT DOWN 就是省電啊 less than 1μA 夠省吧。F1 與F 0 是報(bào)警溫度次數(shù)。
TM 報(bào)警極性.POL 也是報(bào)警的 咱先不管.....
這個(gè)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的時(shí)鐘
/* 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;// 開漏復(fù)用功能
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//設(shè)置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;//使能應(yīng)答(ACK)
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//應(yīng)答7位地址
I2C_InitStructure.I2C_ClockSpeed = 100000;//100K速度
I2C_Cmd(I2C1, ENABLE);
I2C_Init(I2C1, &I2C_InitStructure);
/*允許1字節(jié)1應(yīng)答模式*/
I2C_AcknowledgeConfig(I2C1, ENABLE);
}
/***************************************************
**函數(shù)名:I2C_ReadTmp
**功能:讀取tmp101的2個(gè)字節(jié)溫度
***************************************************/
void I2C_ReadTmp(void)
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));/*檢測(cè)總線是否忙 就是看 SCL 或SDA是否為 低 */
/*允許1字節(jié)1應(yīng)答模式*/
I2C_AcknowledgeConfig(I2C1, ENABLE);
/* 發(fā)送起始位 */
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /*EV5,主模式*/
/*發(fā)送器件地址(寫)*/
I2C_Send7bitAddress(I2C1, 0x92, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/*發(fā)送Pointer Register*/
I2C_SendData(I2C1, 0X00);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));/*數(shù)據(jù)已發(fā)送*/
/*起始位*/
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/*發(fā)送器件地址(讀)*/
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);//最后一位后要關(guān)閉應(yīng)答的
I2C_GenerateSTOP(I2C1, ENABLE);//發(fā)送停止位
/*● 為了在收到最后一個(gè)字節(jié)后產(chǎn)生一個(gè)NACK脈沖,在讀倒數(shù)第二個(gè)數(shù)據(jù)字節(jié)之后(在倒數(shù)第二個(gè)RxNE事件之后)必須清除ACK位。
● 為了產(chǎn)生一個(gè)停止/重起始條件,軟件必須在讀倒數(shù)第二個(gè)數(shù)據(jù)字節(jié)之后(在倒數(shù)第二個(gè)RxNE事件之后)設(shè)置STOP/START位。
● 只接收一個(gè)字節(jié)時(shí),剛好在EV6之后(EV6_1時(shí),清除ADDR之后)要關(guān)閉應(yīng)答和停止條件的產(chǎn)生位。*/
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* EV7 */
I2c_Buf[1]= I2C_ReceiveData(I2C1);
/* Decrement the read bytes counter */
/*再次允許應(yīng)答模式*/
I2C_AcknowledgeConfig(I2C1, ENABLE);
}
/*************************************************
**函數(shù)名:void I2C_InitTmp(void)
**功能:初始化TMP101
*************************************************/
void I2C_InitTmp(void)
{
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* 發(fā)送器件地址(寫)*/
I2C_Send7bitAddress(I2C1, 0X92, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/*發(fā)送Pointer Register*/
I2C_SendData(I2C1, 0X01);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* 寫Configuration Register 12位溫度 連續(xù)轉(zhuǎn)換*/
I2C_SendData(I2C1, 0XFE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1, ENABLE);
}
//測(cè)試用 使用之前要先調(diào)用I2C_InitTmp 初始化TMP101
void I2C_Test(void)
{
char a[8]=" ";
u32 temp;
float tmp;
I2C_ReadTmp();//讀溫度
temp=I2c_Buf[0];//轉(zhuǎn)換溫度
temp=temp<<4;
temp=temp|I2c_Buf[1]>>4;
tmp=(temp/16.0);/*僅處理了正的溫度 負(fù)溫度取反后加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("rn");
}
評(píng)論