原来是阿龙呀! 2025-02-10 11:16 采纳率: 0%
浏览 36

STM32F407中用M117温度传感器采集温度,哪里有问题?求

//PB10_I2C2_SCL
//PB11_I2C2_SDA

void M117_init(void)
{
    GPIO_InitTypeDef gpioConfig;
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
//    GPIO_ConfigStructInit(&gpioConfig);
    /* M117B GPIO configuration */
    gpioConfig.GPIO_Mode = GPIO_Mode_AF;// 复用功能
    gpioConfig.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    gpioConfig.GPIO_Speed = GPIO_Speed_100MHz;
    gpioConfig.GPIO_OType = GPIO_OType_OD; // 开漏输出
    gpioConfig.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOB, &gpioConfig);
    
    // 配置引脚复用为I2C
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2);
    //启动传输状态(S)-当SCL为高电平时,SDA由高电平转换为低电平
    GPIO_SetBits(GPIOB, GPIO_Pin_10);//设置为高电平,保证启动传输状态
    GPIO_SetBits(GPIOB, GPIO_Pin_11);
}
//写SCL拉高
void M117_I2C_W_SCL_H(void)
{
    GPIO_SetBits(GPIOB, GPIO_Pin_10);//设置为高电平
    delay_us(4);
}
//写SCL拉低
void M117_I2C_W_SCL_L(void)
{
    GPIO_ResetBits(GPIOB, GPIO_Pin_10);//设置为低电平
    delay_us(4);
}
//写SDA拉高
void M117_I2C_W_SDA_H(void)
{
    GPIO_SetBits(GPIOB, GPIO_Pin_11);//设置为高电平
    delay_us(4);
}
//写SDA拉低
void M117_I2C_W_SDA_L(void)
{
    GPIO_ResetBits(GPIOB, GPIO_Pin_11);//设置为低电平
    delay_us(4);
}
//读取SDA电平状态
uint8_t M117_I2C_R_SDA(void)
{
    uint8_t BitValue;
    BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
    delay_us(4);
    return BitValue;
}
//除了停止信号 其他的结束 SCL 都为低电平
//函数:起始条件 当 SCL 为高电平,SDA 由高到低
void M117_I2C_Start(void)
{
    M117_I2C_W_SDA_H(); //保险起见先释放 SDA,如果原来是高也不影响
    M117_I2C_W_SCL_H();
    M117_I2C_W_SDA_L();
    M117_I2C_W_SCL_L();
}
//函数:终止条件 当 SCL 为高电平,SDA 由低到高
void M117_I2C_Stop(void)
{
    M117_I2C_W_SDA_L();
    M117_I2C_W_SCL_H();
    M117_I2C_W_SDA_H();
}
//函数:发送一个字节 SCL 低,主机将数据位放到 SDA(由高到低),拉高
// SCL 高,从机在 SCL 高时读取数据位,循环八次,发送一个字节
void M117_I2C_SendByte(uint8_t Byte)
{
    uint8_t i;
    for (i = 0; i < 8; i ++)
    {
        if(Byte & (0x80 >> i))//检查 Byte 中的第 i 位是否为 1 拉高  0x80-1000 0000 右移i位,检查每一位
        {    
            M117_I2C_W_SDA_H();
        }
        else //不为1 拉低
        {
            M117_I2C_W_SDA_L();
        }
        M117_I2C_W_SCL_H(); //SCL拉高,从机会立即读取数据位
        M117_I2C_W_SCL_L();// 将 SCL 线设置为低电平,完成一个时钟周期
    }
}
//函数:接收一个字节 SCL 低,从机将数据位放到 SDA(由高到低),拉高
// SCL 高,主机在 SCL 高时读取数据位,循环八次,接收一个字节(主机接收之前需要释放 SDA)
uint8_t M117_I2C_ReceiveByte(void)
{
    uint8_t i, Byte = 0x00;
    M117_I2C_W_SDA_H(); //切换成输入状态,主机释放 SDA,防止从机干扰
    for (i = 0; i < 8; i ++)
    {
        M117_I2C_W_SCL_H(); //SCL拉高,主机会立即读取数据位
        if (M117_I2C_R_SDA() == 1)
        {
            Byte |= (0x80 >> i);//一1000 0000   0x80 >> 1---0100 0000   二1100 0000   0x80 >> 2---0010 0000  三1110 0000   0x80 >> 3--- 0001 0000  四1111 0000 五1111 1000   六1111 1100 
        }
        M117_I2C_W_SCL_L();//SCL 读取数据位后,拉低,之后从机就会将下一个数据位放到 SDA,循环 8 次
    }
    return Byte;
}
//数据 1 非应答
//数据 0 应答
//函数:发送应答 SCL 低,主机将应答位放到 SDA(由高到低),拉高
// SCL 高,从机在 SCL 高时读取应答位,发送一位
void M117_I2C_SendAck(uint8_t AckBit)
{
    //函数进来 SCL 默认为低电平
    if(AckBit==1)
    {
        M117_I2C_W_SDA_H(); // 发送 ACK
    }
    else
    {
        M117_I2C_W_SDA_L();// 发送 NACK 
    }
    M117_I2C_W_SCL_H(); //释放 SCL 后,从机会立即读取数据位
    M117_I2C_W_SCL_L();//将 SCL 线设置为低电平,完成一个时钟周期
}
//函数:接收应答 SCL 低,从机将应答位放到 SDA(由高到低),拉高
// SCL 高,主机在 SCL 高时读取应答位,接收 1 位(主机接收之前需要释放 SDA)
uint8_t M117_I2C_ReceiveAck(void)
{
    //函数进来 SCL 默认为低电平
    uint8_t AckBit;
    M117_I2C_W_SDA_H(); //将 SDA 线设置为高电平,切换 SDA 为输入状态,//主机释放 SDA,防止从机干扰
    M117_I2C_W_SCL_H(); //将 SCL 线设置为高电平,释放 SCL 后,主机会立即读取数据位
    AckBit = M117_I2C_R_SDA();//读取 SDA 线的状态 ACK 或 NACK
    M117_I2C_W_SCL_L();//SCL 读取数据位后,拉低,之后从机就会将下一个数据位放到应答位,进入下一个时序单元
    return AckBit;
}

//1、M117/ M117Z/M117W I2C 地址固定为 0x44;
//2、M117B I2C 地址固定为 0x45。
//传感器上电后进入空闲状态,如要启动温度测量,主机必须发出 Convert Temperature 指令。
//经过转换时间后,产生的 16 位温度数据被存储在暂存器的 2 个字节的温度寄存器中

// 启动温度测量
void M117_Start_Measurement(void)
{
    M117_I2C_Start();  
    M117_I2C_SendByte(0x44 << 1); // 发送写命令,地址左移1位,最低位为0表示写
    M117_I2C_SendByte(0xCC); // 发送启动测量命令的高字节
    M117_I2C_SendByte(0x44); // 发送启动测量命令的低字节
    M117_I2C_Stop();
}

// 读取温度数据
uint16_t M117_Read_Temperature(void)
{
    uint16_t temperature = 0;
//    uint8_t data[2];
        uint8_t lsb = 0, msb = 0;

    M117_I2C_Start();
    M117_I2C_SendByte(0x44 << 1 | 0x01); // 发送读取命令,地址左移1位,最低位为1表示读取
    msb = M117_I2C_ReceiveByte(); // 读取温度高字节
    M117_I2C_SendAck(0); // 发送ACK
    lsb = M117_I2C_ReceiveByte(); // 读取温度低字节
    M117_I2C_SendAck(1); // 发送NACK
    M117_I2C_Stop();

    temperature = (msb << 8) | lsb; // 合并高低字节
    return temperature;
}

// 处理温度数据
void M117_Handle(void)
{
    uint16_t raw_temperature;
    float temperature;

    M117_Start_Measurement(); // 启动温度测量
    delay_ms(10); // 等待测量完成

    raw_temperature = M117_Read_Temperature(); // 读取温度数据

    // 解析温度数据
    if (raw_temperature & 0x8000) 
        {
        // 负数处理
        raw_temperature = -(0x10000 - raw_temperature);
    }
    temperature = 40 + ((float)raw_temperature / 256.0); // 计算温度

    printf("Raw Temperature: %d\r\n", raw_temperature);
    printf("Temperature: %.1f°C\r\n", temperature);
}

在STM32F407开发板中实现M117温度传感器采集温度,哪里有问题?求求求!
  • 写回答

2条回答 默认 最新

  • 道友老李 JWE233286一种基于机器视觉的水表指针读数识别及修正的方法 专利发明者 2025-02-10 11:16
    关注
    让【道友老李】来帮你解答,本回答参考gpt编写,并整理提供,如果还有疑问可以点击头像关注私信或评论。
    如果答案让您满意,请采纳、关注,非常感谢!
    ### 问题解答:I2C协议的实现 I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,广泛应用于微控制器和各种外设之间的连接。以下是基于 STM32 微控制器的 I2C 通信的实现代码示例,该代码包含了 I2C 的初始化、读取与写入操作等。

    1. I2C初始化

    在初始化 I2C 硬件之前,我们需要配置相应的 GPIO 引脚,以便将其设置为 I2C 的复用功能。引脚 PB10 为 SCL(时钟线),引脚 PB11 为 SDA(数据线)。

    #include "stm32f4xx_gpio.h"
    #include "stm32f4xx_rcc.h"
    void M117_init(void) {
        GPIO_InitTypeDef gpioConfig;
        
        // 使能GPIOB时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
        
        // GPIO配置
        gpioConfig.GPIO_Mode = GPIO_Mode_AF; // 复用功能
        gpioConfig.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; // SCL和SDA
        gpioConfig.GPIO_Speed = GPIO_Speed_100MHz; // 设置速度
        gpioConfig.GPIO_OType = GPIO_OType_OD; // 开漏输出
        gpioConfig.GPIO_PuPd = GPIO_PuPd_UP; // 上拉配置
        GPIO_Init(GPIOB, &gpioConfig); // 初始化GPIO
        
        // 配置引脚复用为I2C
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2);
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2);
        
        // 启动时,SCL和SDA均为高电平
        GPIO_SetBits(GPIOB, GPIO_Pin_10);
        GPIO_SetBits(GPIOB, GPIO_Pin_11);
    }
    

    2. I2C操作函数

    2.1 启动和停止条件 I2C 通信中的启动和停止条件是非常重要的。启动条件是在 SCL 为高电平时,SDA 从高电平拉低;停止条件是在 SCL 为高电平时,SDA 从低电平拉高。

    void M117_I2C_Start(void) {
        M117_I2C_W_SDA_H(); // 释放SDA
        M117_I2C_W_SCL_H(); // SCL高
        M117_I2C_W_SDA_L(); // SDA拉低
        M117_I2C_W_SCL_L(); // SCL拉低
    }
    void M117_I2C_Stop(void) {
        M117_I2C_W_SDA_L(); // SDA拉低
        M117_I2C_W_SCL_H(); // SCL拉高
        M117_I2C_W_SDA_H(); // SDA拉高
    }
    

    2.2 发送字节 发送一个字节时,需要在每次发送数据位后调整 SCL 线的状态。

    void M117_I2C_SendByte(uint8_t Byte) {
        for (uint8_t i = 0; i < 8; i++) {
            if (Byte & (0x80 >> i)) {
                M117_I2C_W_SDA_H(); // 如果当前位为1
            } else {
                M117_I2C_W_SDA_L(); // 如果当前位为0
            }
            M117_I2C_W_SCL_H(); // 拉高 SCL
            M117_I2C_W_SCL_L(); // 拉低 SCL
        }
    }
    

    2.3 接收字节 接收字节的过程与发送字节类似,但在接收过程中需要保证 SDA 是输入状态。

    uint8_t M117_I2C_ReceiveByte(void) {
        uint8_t Byte = 0;
        M117_I2C_W_SDA_H(); // 释放 SDA
        for (uint8_t i = 0; i < 8; i++) {
            M117_I2C_W_SCL_H(); // 拉高 SCL
            if (M117_I2C_R_SDA() == 1) {
                Byte |= (0x80 >> i); // 根据 SDA 状态设置 Byte
            }
            M117_I2C_W_SCL_L(); // 拉低 SCL
        }
        return Byte; // 返回接收到的字节
    }
    

    3. 代码总结

    以上代码实现了基本的 I2C 通信协议,包括初始化 GPIO、发送和接收字节等操作。通过调用这些函数,可以实现更复杂的 I2C 设备通信。

    4. 使用案例

    在实际应用中,可以通过调用 M117_init() 函数来初始化 I2C,随后可以使用 M117_I2C_Start() 开启通信、M117_I2C_SendByte()M117_I2C_ReceiveByte()进行数据传输,最后使用 M117_I2C_Stop() 结束通信。

    注意事项:

    • 确保在使用之前适当地配置和连接 I2C 设备。
    • 根据具体硬件要求适时调整 I2C 时序及延时设置。
    评论

报告相同问题?

问题事件

  • 创建了问题 2月10日