天天看點

STM32F0 I2C 驅動光感子產品 GY30(BH1750FVI)

最近因為工程需要,需要使用光感子產品BH1750FVI,使用STM32F030F4。本來打算移植店主給的51代碼,但移植後發現無法調通,正好STM32F0系列的I2C還未調通過,于是打算用這個子產品來練手。

STM32 F0跟F3系列的自帶I2C庫跟F1最大的不通就是多了個 I2C_Timing,其他的差別不大。

至于這個 I2C_Timing 怎麼得出的,我們需要去ST官網下載下傳相關的一個XLS檔案,查找方式建議先通過搜尋 STM32F0 I2C來找到文檔,文檔中有工具的編号,我們就可以通過編号來直接下載下傳了(釋出文章時是 STSW-STM32126)。

用法可以參考官方社群文檔:

http://www.stmcu.org/module/forum/thread-571931-1-1.html

好,下面進入正題。(本文章完全了解需要一些I2C基礎)

I2C配置

代碼:

void I2C_BH175()
{
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef I2C_InitStructure;

    RCC_I2CCLKConfig(RCC_I2C1CLK_SYSCLK);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);  //使能GPIOA的時鐘
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);  //使能I2C1的時鐘

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_4);//配置PA9成第4功能引腳 SCL
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_4);//配置PA10成第4功能引腳  SDA

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//這個我覺得影響不大,隻要是推挽模式這個可以換成NOPULL
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost;//這個地方網上很多同志換成了I2C_Mode_I2C,應該也是沒問題的。這裡寫成SMBusHost是因為他作為主機
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;//模拟信号濾波
    I2C_InitStructure.I2C_DigitalFilter = ;//數字信号濾波
    I2C_InitStructure.I2C_OwnAddress1 = ;//主機位址(就是本機位址,沒做過從機的I2C是以不太清楚)
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//ACK
    I2C_InitStructure.I2C_Timing = ;//這個需要用那個軟體來計算
    I2C_Init(I2C1, &I2C_InitStructure);
    I2C_Cmd(I2C1, ENABLE);
}
           

I2C 發送與接收

這裡隻用了 I2C_TransferHandling,I2C_SendData,I2C_GenerateSTOP,I2C_ReceiveData 這三個函數。

第一個函數的作用可以認為是傳輸中報頭的設定。

比如:

I2C_TransferHandling(I2C1,SlaveAddress,1,I2C_SoftEnd_Mode,I2C_Generate_Start_Write)

首先,這裡面的 1 代表需要接收的位元組數。

I2C_SoftEnd_Mode 代表我們需要手動發送STOP信号,即 I2C_GenerateSTOP。還有Auto模式可以自動發送STOP,在讀取了設定的數字後發送STOP結束通信。

I2C_Generate_Start_Write 顧名思義,生成SlaveAddress後面那一位 R/W。并且理所當然,還有I2C_Generate_Start_Read。

好,說的差不多了,上代碼。

void Single_Write_BH1750(uint8_t REG_Data)
{
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//檢測是否總線忙
    I2C_TransferHandling(I2C1,SlaveAddress,,I2C_SoftEnd_Mode,I2C_Generate_Start_Write);
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXIS) == RESET);// 檢測發送
    I2C_SendData(I2C1,REG_Data);
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TC) == RESET);
    I2C_GenerateSTOP(I2C1,ENABLE);
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);//是否停止
}
           
uint16_t Read_BH1750()
{
    uint16_t Recev = ;//光強為16位。先發送高8後低8
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);//IF BUSY
    I2C_TransferHandling(I2C1,SlaveAddress+,,I2C_AutoEnd_Mode,I2C_Generate_Start_Read);//這裡設定後就不需要 I2C_GenerateSTOP 了
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);
    Recev |= I2C_ReceiveData(I2C1);Recev<<=;
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);
    Recev |= I2C_ReceiveData(I2C1);
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);
    return Recev;
}
           

其實回過頭來看很簡單。有的時候我們就是卡在某一個位置,可能是我們的馬虎,也可能是其他一些奇奇怪怪的原因。但隻要不放棄,我們一定能得出答案,得出想要的結果。

繼續閱讀