0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

STM32G0開發(fā)筆記:I2C接口軟件模擬與GXHT30溫濕度模塊

CHANBAEK ? 來源:電子技術(shù)攻城獅 ? 作者: MakerInChina.cn ? 2023-01-19 16:24 ? 次閱讀

使用Platformio平臺的libopencm3開發(fā)框架來開發(fā)STM32G0,以下使用軟件模擬I2C總線時(shí)序,并用它來讀取GXHT30溫濕度數(shù)據(jù)。

1 新建項(xiàng)目

  • 建立gxht30項(xiàng)目

PIO的Home頁面新建項(xiàng)目,項(xiàng)目名稱gxht30,選擇開發(fā)板為 MonkeyPi_STM32_G070RB,開發(fā)框架選擇libopencm3;

  • 項(xiàng)目建立完成后在src目錄下新建main.c主程序文件;
  • 修改下載和調(diào)試方式,這里開發(fā)板使用的是DAPLink仿真器,因此修改platformio.ini文件如下:
1upload_protocol = cmsis-dap
2debug_tool = cmsis-dap

2 I2C軟件模擬

2.1 文件結(jié)構(gòu)

在lib目錄新建 sw_i2c 文件夾,并新建如下文件:

2.2 sw_i2c_port.h 與底層IO讀寫相關(guān)
1/**
 2 * @file sw_i2c_port.h
 3 * @author MakerInChina (makerinchina.cn)
 4 * @brief 
 5 * @version 0.01
 6 * @date 2022-09-25
 7 * 
 8 * @copyright Copyright (c) 2022
 9 * 
10 */
11
12#ifndef _SW_I2C_PORT_HEAD_H_
13#define _SW_I2C_PORT_HEAD_H_
14
15#include 3/stm32/rcc.h>
16#include 3/stm32/gpio.h>
17
18#define    SW_I2C_SCL_CLOCK        RCC_GPIOB
19#define SW_I2C_SCL_PORT           GPIOB
20#define SW_I2C_SCL_PIN            GPIO13
21
22#define    SW_I2C_SDA_CLOCK        RCC_GPIOB
23#define SW_I2C_SDA_PORT           GPIOB
24#define SW_I2C_SDA_PIN            GPIO14
25
26#define sw_i2c_scl_high()       gpio_set(SW_I2C_SCL_PORT, SW_I2C_SCL_PIN)
27#define sw_i2c_scl_low()        gpio_clear(SW_I2C_SCL_PORT, SW_I2C_SCL_PIN)
28#define sw_i2c_sda_high()       gpio_set(SW_I2C_SDA_PORT, SW_I2C_SDA_PIN)
29#define sw_i2c_sda_low()        gpio_clear(SW_I2C_SDA_PORT, SW_I2C_SDA_PIN)
30
31#define sw_i2c_sda_input()      gpio_mode_setup(SW_I2C_SDA_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SW_I2C_SDA_PIN)
32#define sw_i2c_sda_output()     gpio_mode_setup(SW_I2C_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SW_I2C_SDA_PIN)
33
34// #define sw_i2c_delay()       delay_us(5)
35#define sw_i2c_delay()          do{                                     \\
36                                    for (int i=0; i<58; i++) {          \\
37                                        __asm__ volatile ("nop");       \\
38                                    }                                   \\
39                                }while(0)
40static bool sw_i2c_sda_get(void) 
41{
42    return (gpio_get(SW_I2C_SDA_PORT, SW_I2C_SDA_PIN) != 0) ? true:false;
43} 
44
45static void sw_i2c_port_init()
46{
47    /* 打開GPIO時(shí)鐘 */
48    rcc_periph_clock_enable(SW_I2C_SCL_CLOCK);
49    rcc_periph_clock_enable(SW_I2C_SDA_CLOCK);
50
51    /* 禁用默認(rèn)上拉,使SCL, SDA保持高阻狀態(tài), 設(shè)置為 OD 模式 */
52    gpio_mode_setup(SW_I2C_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SW_I2C_SCL_PIN);
53    gpio_mode_setup(SW_I2C_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SW_I2C_SDA_PIN);
54    gpio_set_output_options(SW_I2C_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, SW_I2C_SCL_PIN);
55    gpio_set_output_options(SW_I2C_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, SW_I2C_SDA_PIN);
56
57    /* 空閑: 拉高SCL和SDA */
58    gpio_set(SW_I2C_SCL_PORT, SW_I2C_SCL_PIN);
59    gpio_set(SW_I2C_SDA_PORT, SW_I2C_SDA_PIN);
60}
61
62#endif //!_SW_I2C_PORT_HEAD_H_

i2c時(shí)序中的延時(shí)這里使用軟件延時(shí),模擬的是 100KHz的頻率;

2.3 sw_i2c_private.h 實(shí)現(xiàn)i2c的基本時(shí)序
1/**
  2 * @file sw_i2c_private.h
  3 * @author MakerInChina (makerinchina.cn)
  4 * @brief 
  5 * @version 0.01
  6 * @date 2022-09-25
  7 * 
  8 * @copyright Copyright (c) 2022
  9 * 
 10 */
 11
 12#ifndef _SW_I2C_PRIVATE_HEAD_H_
 13#define _SW_I2C_PRIVATE_HEAD_H_
 14
 15#include "sw_i2c_port.h"
 16
 17static void i2c_start(void);
 18static void i2c_stop(void);
 19static bool i2c_wait_ack(void);
 20static void i2c_send_ack(void);
 21static void i2c_send_nack(void);
 22static void i2c_send_byte(uint8_t data);
 23static uint8_t i2c_recv_byte(bool ack);
 24
 25/**
 26 * @brief I2C總線啟動(dòng)信號
 27 */
 28static void i2c_start(void)
 29{
 30    /* 當(dāng)SCL高電平時(shí),SDA出現(xiàn)一個(gè)下跳沿表示I2C總線啟動(dòng)信號 */
 31    sw_i2c_sda_high();
 32    sw_i2c_scl_high();
 33    sw_i2c_delay();
 34    sw_i2c_sda_low();
 35    sw_i2c_delay();
 36    sw_i2c_scl_low();
 37    sw_i2c_delay();
 38}
 39
 40/**
 41 * @brief I2C總線停止信號
 42 */
 43static void i2c_stop(void)
 44{
 45    /* 當(dāng)SCL高電平時(shí),SDA出現(xiàn)一個(gè)上跳沿表示I2C總線停止信號 */
 46    sw_i2c_sda_low();
 47    sw_i2c_delay();
 48    sw_i2c_scl_high();
 49    sw_i2c_delay();
 50    sw_i2c_sda_high();
 51}
 52
 53/**
 54 * @brief 向I2C總線設(shè)備發(fā)送1個(gè)字節(jié)
 55 * @param data 等待發(fā)送的字節(jié)
 56 */
 57static void i2c_send_byte(uint8_t data)
 58{
 59    uint8_t i;
 60
 61    /* 先發(fā)送字節(jié)的高位bit7 */
 62    for (i = 0; i < 8; i++) {
 63        sw_i2c_delay();
 64        sw_i2c_scl_low();
 65
 66        if (data & 0x80) {
 67            sw_i2c_sda_high();
 68        } else {
 69            sw_i2c_sda_low();
 70        }
 71
 72        sw_i2c_delay();
 73        sw_i2c_scl_high();
 74
 75        data <<= 1;    /* 左移一個(gè)bit */
 76    }
 77}
 78
 79/**
 80 * @brief 產(chǎn)生一個(gè)時(shí)鐘,并讀取器件的ACK應(yīng)答信號
 81 * @return 返回true表示正確應(yīng)答,false表示無器件響應(yīng)
 82 */
 83static bool i2c_wait_ack(void)
 84{
 85    bool res;
 86
 87    sw_i2c_delay();
 88    sw_i2c_scl_low();
 89
 90    sw_i2c_sda_input();
 91
 92    sw_i2c_delay();
 93    sw_i2c_scl_high();    /* 驅(qū)動(dòng)SCL = 1, 此時(shí)器件會(huì)返回ACK應(yīng)答 */
 94    sw_i2c_delay();
 95    if (sw_i2c_sda_get() == false) { /* 讀取SDA口線狀態(tài) */
 96        res = true;
 97    } else {
 98        res = false;
 99    }
100    sw_i2c_scl_low();
101    sw_i2c_sda_high();    /* 釋放SDA總線 */
102    sw_i2c_sda_output();
103    sw_i2c_delay();
104
105    return res;
106}
107
108/**
109 * @brief 產(chǎn)生一個(gè)ACK信號
110 */
111static void i2c_send_ack(void)
112{
113    sw_i2c_sda_low();    /* CPU驅(qū)動(dòng)SDA = 0 */
114    sw_i2c_delay();
115    sw_i2c_scl_high();    /* CPU產(chǎn)生1個(gè)時(shí)鐘 */
116    sw_i2c_delay();
117    sw_i2c_scl_low();
118    sw_i2c_delay();
119    sw_i2c_sda_high();    /* CPU釋放SDA總線 */
120}
121
122/**
123 * @brief CPU產(chǎn)生1個(gè)NACK信號
124 */
125static void i2c_send_nack(void)
126{
127    sw_i2c_sda_high();    /* CPU驅(qū)動(dòng)SDA = 1 */
128    sw_i2c_delay();
129    sw_i2c_scl_high();    /* CPU產(chǎn)生1個(gè)時(shí)鐘 */
130    sw_i2c_delay();
131    sw_i2c_scl_low();
132    sw_i2c_delay();
133}
134
135/**
136 * @brief CPU從I2C總線設(shè)備讀取8bit數(shù)據(jù)
137 * 讀1個(gè)字節(jié),ack=1時(shí),發(fā)送ACK,ack=0,發(fā)送nACK
138 * @return
139 */
140static uint8_t i2c_recv_byte(bool ack)
141{
142    uint8_t i;
143    uint8_t value;
144
145    /* 讀到第1個(gè)bit為數(shù)據(jù)的bit7 */
146    value = 0;
147    for (i = 0; i < 8; i++) {
148        value <<= 1;
149        sw_i2c_scl_high();
150        sw_i2c_delay();
151        if (sw_i2c_sda_get()==true) {
152            value++;
153        }
154        sw_i2c_scl_low();
155        sw_i2c_delay();
156    }
157
158    if (ack) {
159        i2c_send_ack(); //發(fā)送ACK
160    } else {
161        i2c_send_nack();//發(fā)送nACK
162    }
163
164    return value;
165}
166
167#endif //!_SW_I2C_PRIVATE_HEAD_H_
2.4 sw_i2c 讀寫實(shí)現(xiàn)
1/**
  2 * @file sw_i2c.c
  3 * @author MakerInChina (makerinchina.cn)
  4 * @brief 
  5 * @version 0.01
  6 * @date 2022-09-25
  7 * 
  8 * @copyright Copyright (c) 2022
  9 * 
 10 */
 11
 12#include "sw_i2c.h"
 13#include "sw_i2c_port.h"
 14#include "sw_i2c_private.h"
 15
 16void sw_i2c_init()
 17{
 18    sw_i2c_port_init();
 19}
 20
 21/* Function to setup and execute I2C transfer request */
 22bool sw_i2c_transfer(uint8_t dev_addr, uint8_t *tx_buffer,uint16_t tx_size,uint8_t *rx_buffer,uint16_t rx_size)
 23{
 24    uint16_t i;
 25
 26    if (tx_size > 0) {
 27        /* start */
 28        i2c_start();
 29        /* address + write */
 30        i2c_send_byte(dev_addr<<1);
 31        if (i2c_wait_ack() == false) {
 32            goto error_device_nack;
 33        }
 34        /* write data */
 35        for (i=0; i36            i2c_send_byte(tx_buffer[i]);
 37            if (i2c_wait_ack() == false) {
 38                goto error_device_nack;
 39            }
 40        }
 41    }
 42    if (rx_size > 0) {
 43        /* start */
 44        i2c_start();
 45        /* address + read */
 46        i2c_send_byte(dev_addr<<1 | 1);
 47        if (i2c_wait_ack() == false) {
 48            goto error_device_nack;
 49        }
 50        /* read data */        
 51        for (i=0; i52            rx_buffer[i] = i2c_recv_byte(i+153        }
 54    }
 55    i2c_stop();
 56    return true;
 57
 58error_device_nack:
 59    i2c_stop();
 60    return false;
 61}
 62
 63// Scan the I2C bus between addresses from_addr and to_addr.
 64// On each address, call the callback function with the address and result.
 65// If result==0, address was found, otherwise, address wasn't found
 66// (can use result to potentially get other status on the I2C bus, see twi.c)
 67// Assumes Wire.begin() has already been called
 68void scan_i2c_bus(uint8_t from_addr, uint8_t to_addr, void(*callback)(uint8_t address, uint8_t result))
 69{
 70    bool rc;
 71    uint8_t dev_addr_7bit = 0;
 72
 73    for( uint8_t addr = from_addr; addr <= to_addr; addr++) {
 74
 75        /* start */
 76        i2c_start();
 77
 78        /* address + write */
 79        i2c_send_byte(addr);
 80
 81        if (i2c_wait_ack() == false) {
 82            rc = false;
 83        }else{
 84            rc = true;
 85        }
 86
 87        i2c_stop();
 88
 89        dev_addr_7bit = addr>>1;
 90
 91        callback(dev_addr_7bit, rc);
 92
 93        //dealy for sometime, 5 clk
 94        for(char i=0; i<5; i++){
 95            sw_i2c_delay();
 96        }
 97
 98        //ignore add+1, read
 99
100        addr++;
101        if(addr > to_addr){
102            break;
103        }
104
105    }
106}
  • 實(shí)現(xiàn)了數(shù)據(jù)傳輸 transfer 接口,包含了發(fā)送和接收;
  • 實(shí)現(xiàn)總線設(shè)備掃描功能,可以用于輔助調(diào)試;

3 GXHT30使用I2C

3.1 掃描設(shè)備
1void scan_i2c_cb( uint8_t addr, uint8_t result )
 2{
 3
 4    if(result == 1){
 5        printf("  scan addr[7bit]: 0x%x  found!\\r\\n",addr);
 6    }else{
 7    //    printf("scan addr:   %x not found\\r\\n",addr); //not found
 8    }
 9
10}
11
12int main(void)
13{
14    ...
15
16    printf("init i2c bus\\r\\n");
17
18    sw_i2c_init();
19
20    printf("scan device on i2c bus...\\r\\n");
21
22    scan_i2c_bus(0x02,0xfe, scan_i2c_cb);
23
24    ...
25}
3.2 讀取溫濕度數(shù)據(jù)

根據(jù)GXHT30芯片手冊實(shí)現(xiàn),這里為單次讀取:

1void gxht30_sample(float *temp, float *humi)
 2{
 3    uint8_t rd_buff[6] = {0};
 4    uint8_t cmd[2] = {0x2c, 0x06};
 5
 6    uint8_t dev_addr = 0x44;
 7
 8    //send read cmd
 9    sw_i2c_transfer(dev_addr, cmd, 2, 0, 0);
10
11    delay_ms(10);
12
13    //receive data
14    sw_i2c_transfer(dev_addr, 0,0, rd_buff, 6);
15
16    uint16_t temp_int = (uint16_t)((rd_buff[0] << 8)|(rd_buff[1]));
17    uint16_t humi_int = (uint16_t)((rd_buff[3] << 8)|(rd_buff[4]));
18
19    *temp =  -45 + (float)(175*temp_int/65535.0000);
20    *humi = 100 * (float)(humi_int /65535.0000);
21}

發(fā)送命令的波形也和預(yù)期一致;

  • 發(fā)送讀取命令 0x2c 0x06 的波形:

  • 接收數(shù)據(jù)的波形,溫度+CRC+濕度+CRC:

4 燒寫測試

4.1 連線

將開發(fā)板和溫濕度模塊的I2C引腳連接:

4.2 測試結(jié)果

可以看到讀取到0x44的設(shè)備地址,即溫濕度模塊的I2C地址,溫濕度讀取正確:

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8447

    瀏覽量

    150723
  • STM32
    +關(guān)注

    關(guān)注

    2264

    文章

    10854

    瀏覽量

    354299
  • I2C
    I2C
    +關(guān)注

    關(guān)注

    28

    文章

    1477

    瀏覽量

    123058
  • I2C總線
    +關(guān)注

    關(guān)注

    8

    文章

    386

    瀏覽量

    60791
  • 開發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    4896

    瀏覽量

    97059
收藏 人收藏

    評論

    相關(guān)推薦

    【英飛凌PSoC 6 RTT開發(fā)板試用】通過軟件和硬件I2C接口獲取數(shù)字溫濕度傳感器SHT30的數(shù)據(jù)

    本文將會(huì)分別介紹——使用軟件I2C和硬件I2C在PSoC開發(fā)板上獲取SHT30數(shù)字溫濕度傳感器的
    的頭像 發(fā)表于 07-11 09:21 ?3318次閱讀
    【英飛凌PSoC 6 RTT<b class='flag-5'>開發(fā)</b>板試用】通過<b class='flag-5'>軟件</b>和硬件<b class='flag-5'>I2C</b><b class='flag-5'>接口</b>獲取數(shù)字<b class='flag-5'>溫濕度</b>傳感器SHT<b class='flag-5'>30</b>的數(shù)據(jù)

    如何去實(shí)現(xiàn)基于AHT20溫濕度傳感器接stm32軟件I2C

    I2C通信協(xié)議是什么?其工作原理是什么?如何去實(shí)現(xiàn)基于AHT20溫濕度傳感器接stm32軟件I2C呢?
    發(fā)表于 12-10 06:46

    基于I2C硬件協(xié)議的AHT20溫濕度傳感器的數(shù)據(jù)采集

    溫濕度傳感器采集1.完成基于I2C硬件協(xié)議的AHT20溫濕度傳感器的數(shù)據(jù)采集1.1 硬件I2C軟件I2
    發(fā)表于 12-17 06:23

    SHT30溫濕度模塊怎么使用

    SHT30溫濕度模塊使用本次我們使用STM32F103C8T6最小系統(tǒng)板和STM32cubeMX來教學(xué)流程我全部寫在下面了:1、配置我們的下
    發(fā)表于 02-15 06:28

    如何去實(shí)現(xiàn)基于I2C的AHT20溫濕度傳感器的數(shù)據(jù)采集及串口輸出

    文章目錄基于I2C的AHT20溫濕度傳感器的數(shù)據(jù)采集及串口輸出一、IIC協(xié)議1. 物理層特點(diǎn)2. 協(xié)議層特點(diǎn)二、軟件I2C和硬件
    發(fā)表于 02-18 06:56

    STM32Cube_15】使用硬件I2C讀取溫濕度傳感器數(shù)據(jù)(SHT30

    本篇詳細(xì)的記錄了如何使用STM32CubeMX配置STM32L431RCT6的硬件I2C外設(shè),讀取SHT30溫濕度傳感器的數(shù)據(jù)并通過串口發(fā)送
    發(fā)表于 12-05 16:21 ?34次下載
    【<b class='flag-5'>STM32</b>Cube_15】使用硬件<b class='flag-5'>I2C</b>讀取<b class='flag-5'>溫濕度</b>傳感器數(shù)據(jù)(SHT<b class='flag-5'>30</b>)

    基于I2C下的溫濕度采集實(shí)驗(yàn)

    目錄 一、I2C相關(guān)了解及介紹1、基本介紹2、I2C 物理層3、I2C 協(xié)議層二、什么是“軟件I2C
    發(fā)表于 12-07 09:21 ?3次下載
    基于<b class='flag-5'>I2C</b>下的<b class='flag-5'>溫濕度</b>采集實(shí)驗(yàn)

    菜鳥入門9,在I2C通信協(xié)議的基礎(chǔ)上完成的溫濕度采集

    文章目錄前言一、介紹AHT20介紹I2C協(xié)議簡介軟件I2C和硬件I2C的區(qū)別二、溫濕度采集代碼部分總結(jié)前言這次本菜鳥要帶領(lǐng)大家一起學(xué)習(xí)一個(gè)芯
    發(fā)表于 12-07 10:06 ?0次下載
    菜鳥入門9,在<b class='flag-5'>I2C</b>通信協(xié)議的基礎(chǔ)上完成的<b class='flag-5'>溫濕度</b>采集

    基于I2C的AHT20溫濕度傳感器的數(shù)據(jù)采集及串口輸出

    文章目錄基于I2C的AHT20溫濕度傳感器的數(shù)據(jù)采集及串口輸出一、IIC協(xié)議1. 物理層特點(diǎn)2. 協(xié)議層特點(diǎn)二、軟件I2C和硬件
    發(fā)表于 12-23 19:43 ?5次下載
    基于<b class='flag-5'>I2C</b>的AHT20<b class='flag-5'>溫濕度</b>傳感器的數(shù)據(jù)采集及串口輸出

    STM32G0開發(fā)筆記:FreeRTOS和FreeModbus庫使用

    使用Platformio平臺的libopencm3開發(fā)框架來開發(fā)STM32G0,以下為FreeRTOS和FreeModbus庫使用。
    的頭像 發(fā)表于 01-16 14:44 ?5388次閱讀
    <b class='flag-5'>STM32G0</b><b class='flag-5'>開發(fā)筆記</b>:FreeRTOS和FreeModbus庫使用

    STM32G0開發(fā)筆記:使用FreeRTOS系統(tǒng)

    使用Platformio平臺的libopencm3開發(fā)框架來開發(fā)STM32G0,下面為使用FreeRTOS系統(tǒng)。
    的頭像 發(fā)表于 01-16 15:07 ?2290次閱讀
    <b class='flag-5'>STM32G0</b><b class='flag-5'>開發(fā)筆記</b>:使用FreeRTOS系統(tǒng)

    STM32G0開發(fā)筆記:SD卡模塊的使用方法

    使用Platformio平臺的libopencm3開發(fā)框架來開發(fā)STM32G0,下面介紹SD卡模塊的使用方法。
    的頭像 發(fā)表于 01-19 16:27 ?2162次閱讀
    <b class='flag-5'>STM32G0</b><b class='flag-5'>開發(fā)筆記</b>:SD卡<b class='flag-5'>模塊</b>的使用方法

    STM32G0開發(fā)筆記:SPI接口的基本使用

    使用Platformio平臺的libopencm3開發(fā)框架來開發(fā)STM32G0,下面介紹SPI接口的基本使用。
    的頭像 發(fā)表于 01-17 10:38 ?3006次閱讀
    <b class='flag-5'>STM32G0</b><b class='flag-5'>開發(fā)筆記</b>:SPI<b class='flag-5'>接口</b>的基本使用

    STM32G0開發(fā)筆記:串口中斷的使用

    使用Platformio平臺的libopencm3開發(fā)框架來開發(fā)STM32G0,以下為串口中斷的使用。
    的頭像 發(fā)表于 01-17 10:46 ?2251次閱讀

    STM32G0開發(fā)筆記:LED燈示例

    使用Platformio平臺的libopencm3開發(fā)框架來開發(fā)STM32G0,下面為LED燈示例。
    的頭像 發(fā)表于 01-17 10:52 ?1357次閱讀
    <b class='flag-5'>STM32G0</b><b class='flag-5'>開發(fā)筆記</b>:LED燈示例