//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温度传感器采集温度,哪里有问题?求求求!
STM32F407中用M117温度传感器采集温度,哪里有问题?求
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
2条回答 默认 最新
关注让【道友老李】来帮你解答,本回答参考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 时序及延时设置。
解决 无用评论 打赏 举报