STM32F103C8T6使用MLX90614模块

首先说明:

1.SMBus和I2C的区别

我曾尝试用江科大的I2C底层去直接读取该模块,但是无法成功,之后AI生成的的代码也无法成功。

思来想去最大的可能就是SMBus这个协议的问题,根据百度得到的结果如下:
SMBus和I2C的区别

链接:

smbus协议_百度百科https://baike.baidu.com/item/smbus%E5%8D%8F%E8%AE%AE/56360572.个人见解(希望有知道的可以补充说明或纠错):

①SMBus协议是I2C的pro版本,对时序要求更加严格。

②特别是在超时方面,I2C可能是在SCL的对应电平下改变SDA的电平,那就能正常操作,不在意时间多久;但SMBus则是要求了SCL在对应电平下,SDA应该在什么时候做出改变,否则超时。

代码:

以下是我用STM32F103C8T6能读取到我认为正常数据的代码,若不满足读者要求,请自行微调。

若对你有帮助,请点赞收藏~

复制代码
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"

//************** 宏定义 **************
#define I2C_SCL_PIN    GPIO_Pin_6
#define I2C_SDA_PIN    GPIO_Pin_7
#define I2C_GPIO_PORT  GPIOB

#define Nack_counter   10
#define uint           unsigned int
#define uchar          unsigned char

//************** 全局变量 **************
volatile uchar DataH, DataL, Pecreg;
volatile uint temp;
//************** 函数声明 **************
void I2C_GPIO_Init(void);
void start_bit(void);
void stop_bit(void);
void send_bit(uchar bit_val);
uchar rx_byte(void);
uchar tx_byte(uchar dat_byte);
void delay_us(uint us);
uint memread(void);

//************** GPIO初始化 **************
void I2C_GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  // 使能GPIOB时钟
    
    // SCL和SDA配置为开漏输出
    GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  // 开漏输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);
    
    // 初始状态拉高
    GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN | I2C_SDA_PIN);
}

//************** 延时函数(72MHz主频)**************
void delay_us(uint us) {
    us *= 72/5;  // 72MHz下1us需要72个周期(实测需校准)
    while(us--) {
        __NOP();
    }
}

//************** I2C起始信号 **************
void start_bit(void) {
    GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
    GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
    delay_us(5);  // 保持时间≥4.7us
    
    GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
    delay_us(5);
    GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
}

//************** I2C停止信号 **************
void stop_bit(void) {
    GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
    GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
    delay_us(5);
    
    GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
    delay_us(5);
    GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
}

//************** 发送单bit **************
void send_bit(uchar bit_val) {
    if(bit_val) {
        GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
    } else {
        GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN);
    }
    
    delay_us(2);
    GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
    delay_us(5);  // SCL高电平≥4.0us
    GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
    delay_us(2);
}

//************** 接收单bit **************
uchar receive_bit(void) {
    uchar bit_val;
    
    GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN);  // 释放SDA线
    delay_us(2);
    GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
    delay_us(5);
    
    bit_val = GPIO_ReadInputDataBit(I2C_GPIO_PORT, I2C_SDA_PIN);
    
    GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN);
    delay_us(2);
    return bit_val;
}

//************** 发送单字节 **************
//void tx_byte(uchar dat_byte) {
//    uchar i, n = Nack_counter;
//    
//TX_again:
//    for(i = 0; i < 8; i++) {
//        send_bit((dat_byte & 0x80) ? 1 : 0);
//        dat_byte <<= 1;
//    }
//    
//    if(receive_bit()) {  // 检测NACK
//        stop_bit();
//        if(n--) {
//            start_bit();
//            goto TX_again;
//        }
//    }
//}

uchar tx_byte(uchar dat_byte)
{
    for(uchar i = 0; i < 8; i++) {
        send_bit((dat_byte & 0x80) ? 1 : 0);
        dat_byte <<= 1;
    }
    return !receive_bit();  // 返回1=ACK, 0=NACK
}

//************** 接收单字节 **************
uchar rx_byte(void) {
    uchar i, dat = 0;
    
    for(i = 0; i < 8; i++) {
        dat <<= 1;
        if(receive_bit()) dat |= 0x01;
    }
    
    send_bit(0);  // 发送ACK
    return dat;
}

//************** 读取温度数据 **************
//uint memread(void) {
//    start_bit();
//    tx_byte(0x00);  // MLX90614地址+写
//    tx_byte(0x07);  // 读取RAM命令
//    
//    start_bit();
//    tx_byte(0xB5);  // MLX90614地址+读
//    
//    DataL = rx_byte();
//    DataH = rx_byte();
//    Pecreg = rx_byte();
//    
//    stop_bit();
//    return (DataH << 8) | DataL;
//}
uint memread(void) {
    start_bit();
    if (!tx_byte(0xB4)) {  // 发送地址+写
        stop_bit();
        return 0xFFFF;
    }
    if (!tx_byte(0x07)) {  // 发送命令(读取RAM)
        stop_bit();
        return 0xFFFF;
    }
    
    start_bit();
    if (!tx_byte(0xB5)) {  // 发送地址+读
        stop_bit();
        return 0xFFFF;
    }
    
    DataL = rx_byte();  // 低字节
    DataH = rx_byte();  // 高字节
    Pecreg = rx_byte(); // PEC(可选)
    stop_bit();
    
    return ((DataH << 8) | DataL)*0.02 - 273.15;
}

//************** 主函数 **************
int main(void) {
    SystemInit();  // 系统时钟配置为72MHz
    I2C_GPIO_Init();
    
    while(1) {
         temp = memread();
        // 此处添加温度处理代码
        delay_us(20000);  // 延时20ms
    }
}

使用方法:

①直接copy到自己的main.c

②下载到STM32F103C8T6板子上,并保持连接。根据下面代码接线,供电3.3V

#define I2C_SCL_PIN GPIO_Pin_6

#define I2C_SDA_PIN GPIO_Pin_7
#define I2C_GPIO_PORT GPIOB

③使用debug模式查看数据,具体如下:

若点击运行后temp数据不变,则需要进行下面这一步:

相关推荐
大鼻噶喳1 小时前
使用VSCode开发MCU,FreeRTOS进Hard_Fault调试
vscode·单片机
我命由我123452 小时前
嵌入式 STM32 开发问题:烧录 STM32CubeMX 创建的 Keil 程序没有反应
c语言·开发语言·c++·stm32·单片机·嵌入式硬件·嵌入式
麦德泽特2 小时前
超高速总线CDCTL01A 芯片在机器人领域的应用解析
人工智能·嵌入式硬件·物联网·机器人·信息与通信
vicorv253 小时前
电流传感器在汽车中的应用:从BMS电池管理到电机控制的工程解析
stm32·单片机·嵌入式硬件
物联网嵌入式小冉学长3 小时前
3.TCP回响服务器实现及源码分析上
stm32·网络协议·tcp/ip·嵌入式
JINX的诅咒4 小时前
FPGA多通道卷积加速器:从零构建手写识别的硬件引擎
嵌入式硬件·fpga开发·cnn·开源
几道之旅13 小时前
零基础RT-thread第二节:按键控制
c语言·stm32
阿让啊14 小时前
Notepad++如何列选
c语言·嵌入式硬件·notepad++
Archer-15 小时前
解决STM32H7系列串口DMA发送一次卡死
stm32·单片机·嵌入式硬件
通信.萌新16 小时前
【stm32f4】ADC实验(stm32hal库)
stm32·单片机·嵌入式硬件