关于STM32的IIC

一开始是用硬件内置的IIC来读取数据的,没有什么问题,但是不知道为什么后续断电上电之后一直没有数据,仿真看的话发现卡死在这些循环里面,我才反应过来网上一直说的硬件IIC有问题是这个。

I2C_Send7bitAddress(I2C1, (AHT20_Address << 1), I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));I2C_SendData(I2C1, 0xAC);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_SendData(I2C1, 0x33);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_SendData(I2C1, 0x00);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

由于位置原因导致数据传输异常,IIC的数据总线一直处于忙状态,没有办法检测到想要的标志位,所以直接卡在那个while循环里面出不来了。按照网上的几种解决方法,我这边都试了,没有解决问题。
后续就是断电再上电,没有工作多久就会出现这种问题,只能用程序去模拟主机发送数据来通信了。

多个IIC从机管理

参考资料:STM32上如何轻松管理多条模拟IIC总线

先说最重要的一点,这个不属于那种,只用两根线,然后不同IIC从机并联在这上面通信的情况。而是属于每个从机设备各自用两根线,但是可以通过传参的方法共用同一套驱动程序这种。

一开始的想法假如一个系统里面只有一个IIC,先写好一套IIC的驱动直接调用就行了,但是如果有两个IIC从机设备,难道要多写一套程序类似于:AHT20_I2C_Start()Digital_I2C_Start()这种?

肯定是不合适的。也不止IIC吧,类似的模块驱动程序,如果存在两套不同的设备但是要用到同一套程序,像之前我用HT8开发个人库的时候,管理GPIO的KEY,LED模块,也是用到类似的方法,核心就是同一套模块驱动程序,然后把需要管理的设备弄成可以转变成可以变成函数参数的形式。因为HT8的频率最高只有16M,调用这么多东西来实现这种做法是很不划算的,所以我打算用在主频相对较高的MCU平台。

参考程序

I2C.c

#include "stm32f10x_conf.h"
#include "common.h"
#include "I2C.h"I2C_Dev_T I2C_Dev[1] =
{[AHT20_Dev] =     {.SCL_Port = GPIOB,.SCL_Pin = GPIO_Pin_6,.SDA_Port = GPIOB,.SDA_Pin = GPIO_Pin_7,},
};void I2C_GPIO_Init()
{GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStruct.GPIO_Pin = I2C_Dev[AHT20_Dev].SCL_Pin | I2C_Dev[AHT20_Dev].SDA_Pin;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(I2C_Dev[AHT20_Dev].SCL_Port, &GPIO_InitStruct);
}void I2C_Dev_Start(I2C_Dev_T *dev)
{I2C_Dev_SDA_High(dev);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Delay);I2C_Dev_SDA_Low(dev);SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SCL_Low(dev);
}void I2C_Dev_Stop(I2C_Dev_T *dev)
{I2C_Dev_SDA_Low(dev);I2C_Dev_SCL_Low(dev);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SDA_High(dev);SysTick_Delay_us(I2C_Delay);
}void I2C_Dev_SDA_Control(I2C_Dev_T *dev, I2C_SDA_Control_T sta)
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = dev->SDA_Pin;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;if(sta == I2C_SDA_Input){GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;}else{GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;}GPIO_ResetBits(dev->SDA_Port, dev->SDA_Pin);GPIO_Init(dev->SDA_Port, &GPIO_InitStruct);
}uint8_t I2C_Dev_Check_Ack(I2C_Dev_T *dev)
{u8 check_recnt = 20;u8 flag = I2C_NACK;I2C_Dev_SCL_Low(dev);I2C_Dev_SDA_Control(dev,I2C_SDA_Input);while(check_recnt != 0){SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Bit_Delay);if(I2C_Dev_Read_SDA(dev) == I2C_ACK){flag = I2C_ACK;I2C_Dev_SCL_Low(dev);I2C_Dev_SDA_Control(dev, I2C_SDA_Output);return flag;}check_recnt -= 1;}I2C_Dev_SDA_Control(dev, I2C_SDA_Output);I2C_Dev_SCL_Low(dev);I2C_Dev_SDA_Low(dev);return flag;
}void I2C_Dev_Write_Byte(I2C_Dev_T *dev,uint8_t data)
{uint8_t index = 0x80;do{if(data & index)I2C_Dev_SDA_High(dev);elseI2C_Dev_SDA_Low(dev);SysTick_Delay_us(I2C_Bit_Delay >> 1);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Bit_Delay >> 1);I2C_Dev_SCL_Low(dev);index >>= 1;}while(index != 0);
}uint8_t I2C_Dev_Read_Byte(I2C_Dev_T *dev, I2C_Ack_Flag_T flag)
{uint8_t data = 0;uint8_t index = 0x80;I2C_Dev_SDA_Control(dev, I2C_SDA_Input);SysTick_Delay_us(I2C_Bit_Delay);do{I2C_Dev_SCL_High(dev);if(I2C_Dev_Read_SDA(dev) == 1)data |= index;index >>= 1;SysTick_Delay_us(I2C_Bit_Delay >> 1);I2C_Dev_SCL_Low(dev);SysTick_Delay_us(I2C_Bit_Delay >> 1);}while(index != 0);I2C_Dev_SDA_Control(dev, I2C_SDA_Output);I2C_Dev_SDA_High(dev);SysTick_Delay_us(I2C_Bit_Delay);if(flag == I2C_ACK){I2C_Dev_SDA_Low(dev);}SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SCL_High(dev);SysTick_Delay_us(I2C_Bit_Delay);I2C_Dev_SCL_Low(dev);return data;
}

I2C.h

#ifndef  _I2C_H_
#define _I2C_H_#include <stdint.h>#define I2C_Bit8_Write          0x00
#define I2C_Bit8_Read           0x01#define I2C_Delay               (uint16_t)200
#define I2C_Bit_Delay           (uint16_t)50#define I2C_Dev_SDA_High(dev)   ((dev->SDA_Port)->BSRR) = ((uint32_t)(dev->SDA_Pin))
#define I2C_Dev_SDA_Low(dev)    ((dev->SDA_Port)->BRR) = ((uint32_t)(dev->SDA_Pin))#define    I2C_Dev_SCL_High(dev)   ((dev->SCL_Port)->BSRR) = ((uint32_t)(dev->SCL_Pin))
#define I2C_Dev_SCL_Low(dev)    ((dev->SCL_Port)->BRR) = ((uint32_t)(dev->SCL_Pin))#define    I2C_Dev_Read_SDA(dev)   GPIO_ReadInputDataBit((dev->SDA_Port),(dev->SDA_Pin))typedef enum
{I2C_ACK = 0x00,I2C_NACK = 0x01,}I2C_Ack_Flag_T;typedef enum
{I2C_SDA_Input = 0x00,I2C_SDA_Output = 0x01,}I2C_SDA_Control_T;typedef struct
{GPIO_TypeDef *SCL_Port;uint16_t SCL_Pin;GPIO_TypeDef *SDA_Port;uint16_t SDA_Pin;}I2C_Dev_T;extern I2C_Dev_T I2C_Dev[];#define  AHT20_Dev   0x00void I2C_Dev_Start(I2C_Dev_T *dev);
void I2C_Dev_Stop(I2C_Dev_T *dev);
void I2C_Dev_SDA_Control(I2C_Dev_T *dev, I2C_SDA_Control_T sta);
uint8_t I2C_Dev_Check_Ack(I2C_Dev_T *dev);
void I2C_Dev_Write_Byte(I2C_Dev_T *dev,uint8_t data);
uint8_t I2C_Dev_Read_Byte(I2C_Dev_T *dev, I2C_Ack_Flag_T flag);#endif

AHT20.c

#include "stm32f10x_conf.h"
#include "I2C.h"
#include "AHT20.h"
#include "common.h"
#include "string.h"AHT20_Data_T AHT20_Data;void AHT20_Init()
{GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStruct.GPIO_Pin = I2C_Dev[AHT20_Dev].SCL_Pin | I2C_Dev[AHT20_Dev].SDA_Pin;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(I2C_Dev[AHT20_Dev].SCL_Port, &GPIO_InitStruct);/* 初始化数据结构体 */memset(&AHT20_Data.Rx_Humidity, 0, 3);memset(&AHT20_Data.Rx_Temperature, 0, 3);AHT20_Data.Sensor_Status = 0;AHT20_Data.CRC_Data = 0;AHT20_Data.Humidity = 0.000000;AHT20_Data.Temperature = 0.000000;
}void AHT20_Measure_Start()
{I2C_Dev_Start(&I2C_Dev[AHT20_Dev]);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], (AHT20_Slave_Address << 1) | I2C_Bit8_Write);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], 0xAC);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], 0x33);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], 0x00);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;
}void AHT20_Get_SensorData()
{I2C_Dev_Start(&I2C_Dev[AHT20_Dev]);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Write_Byte(&I2C_Dev[AHT20_Dev], (AHT20_Slave_Address << 1) | I2C_Bit8_Read);if(I2C_Dev_Check_Ack(&I2C_Dev[AHT20_Dev]) == I2C_NACK){I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);return ;}SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Sensor_Status = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Humidity[0] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Humidity[1] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Humidity[2] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Temperature[0] = AHT20_Data.Rx_Humidity[2] & 0x0F;AHT20_Data.Rx_Humidity[2] >>= 4;/*--------------------------------------------------------------*/AHT20_Data.Rx_Temperature[1] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.Rx_Temperature[2] = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_ACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/AHT20_Data.CRC_Data = I2C_Dev_Read_Byte(&I2C_Dev[AHT20_Dev], I2C_NACK);SysTick_Delay_us(I2C_Delay);/*--------------------------------------------------------------*/I2C_Dev_Stop(&I2C_Dev[AHT20_Dev]);AHT20_Data.Humidity = (AHT20_Data.Rx_Humidity[0] << 12) + (AHT20_Data.Rx_Humidity[1] << 4) + AHT20_Data.Rx_Humidity[2];AHT20_Data.Humidity = AHT20_Data.Humidity / 1048576;AHT20_Data.Temperature = (AHT20_Data.Rx_Temperature[0] << 16) + (AHT20_Data.Rx_Temperature[1] << 8) + AHT20_Data.Rx_Temperature[2];AHT20_Data.Temperature = ((AHT20_Data.Temperature * 25) / 131072) - 50;return ;
}

AHT20.h

#ifndef  _AHT20_H_
#define _AHT20_H_#define    AHT20_Slave_Address     0x38typedef struct
{uint8_t Rx_Humidity[3];uint8_t Rx_Temperature[3];uint8_t Sensor_Status;uint8_t CRC_Data;float Humidity;float Temperature;}AHT20_Data_T;extern AHT20_Data_T AHT20_Data;void AHT20_Init(void);
void AHT20_Measure_Start(void);
void AHT20_Get_SensorData(void);#endif

AHT20驱动原理

参考手册:
AHT20手册

讲道理,很久没有跟传感器打交道了,但是又不是很想用跟DS18B20这种偏简单的,有时候刷淘宝刷到这个的模块,我看了一下电路反正也简单,自己搞一个也行,主要是没有用过DFN这种封装,想练练手。而且当时IIC用的也不是很熟,或者说IIC的项目实战就是在这个模块上面展开的,算是对IIC的使用打下基础,主要是这个模块通信起来也不是太难。


但是官方手册里面读取数据这一块,我不是很明白,我都已经把IIC主机设置成读的状态了,读取传感器的那个byte之后为什么是从机发过来的应答?我自己的程序里面改成,是主机给应答,通信是正常的。

还有一个点是,按照手册提供的步骤,读取数据之前要读那个状态位,获取到传感器空闲的时候才能读数据,不然的话就证明传感器还在测量,读的数据可能是有问题的。但是因为我给了足够的延时,所以我就省略了这一步,正经开发项目的话应该要加上这个判断。

一开始我不是用STM32来当主机的,用的HT8,因为编译器不同所以我在那边用那个float变量异常小心,同时也弄明白了float类型在二进制的表达形式,稍微是有一点复杂的,但是其实不会这个也不影响使用,后面有空可以写一下心得。

注意事项

官方提供的那个手册已经写得很详细了,我这边没必要写这么多了。个人觉得需要注意的事项:
先读取到的数据是高位的,以湿度数据为例,第1byte数据读到的话要往左挪12个位,第2byte数据要挪4个位,第3byte数据只有4bit不用处理,温度的话也差不多,第1byte数据只有4bit,左移16位。

这个是仿真读到的数据,那个湿度是小数部分,要转成百分比来看的话也就是x100%的意思。

IIC驱动原理

以前初学IIC的时候觉得很复杂,那是因为找错路子了。

最开始是用两个HT8的单片机,一个模拟主机,另一个使用硬件从机模块,参考官方提供的例程,然后用示波器来看波形,现在想想那个时候居然能乱搞出点东西来真的是运气在里面的,现在让我直接在这个环境下复现一下是不太可能的

STM32F103C6T6 | 模拟IIC主机读取AHT20温湿度传感器数据相关推荐

  1. MicroPython ESP32 读取DHT11温湿度传感器数据

    MicroPython ESP32 读取DHT11温湿度传感器数据 DHT11温湿度传感器 接线说明 ESP32 ----- DHT11 3.3V ----- VCC GND ----- GND GP ...

  2. 模拟IIC读取SHT30温湿度传感器数据

    文章目录 1 i2c.c 2 i2c.h 3 crc.c 4 crc.h 1 i2c.c /*** @brief SHT30温湿度传感器相关,使用模拟IIC进行数据的读取*/#include < ...

  3. STM32F103单片机软件模拟IIC并读取TMP112数字温度传感器

    本文利用STM32F103系列单片机读取TMP112数字温度传感器的温度信息,TMP112数字传感器采用IIC总线协议通信.STM32自身含有硬件IIC资源,分别是PB6-->SCL.PB7-- ...

  4. STM32单片机硬件I2C读取AHT10温湿度传感器数据

    STM32使用硬件IIC读取AHT10温湿度传感器的数据并显示在0.96寸OLED屏上. 我用的单片机是STM32F103C8T6,程序用的是ST标准库写的. STM32使用硬件I2C读取SHTC3温 ...

  5. AHT20温湿度传感器STM32-I2C驱动,替代DHT11/DHT12/AM2320/SHT20/SHT30,IIC代码兼容AHT10/15-MEMS温湿度传感器

    AHT20是国内奥松生成的I2C接口的MEMS温湿度传感器,ADC位数为20Bit,具有体积小.精度高.成本低等优点.相较于AHT10,最显著的变化是体积由 5*4*1.6mm,缩小到 3*3*1.0 ...

  6. 基于I2C协议的AHT20温湿度传感器的数据采集

    文章目录 一.I2C相关 1.I2C总线简介 工作原理 总线特征 2.I2C协议简介 软件I2C 硬件I2C 二者比较 二.基于I2C的AHT20温湿度采集实验 AHT20简介 1.实验要求 2.实验 ...

  7. 基于I2C的AHT20温湿度传感器的数据采集

    一.I2C简介 二.软件I2C和硬件I2C 三.AHT20简介 四.基于stm32的AHT20温湿度传感器的数据采集 五.总结 一.I2C简介 I2C(芯片间)总线接口连接微控制器和串行I2C总线.它 ...

  8. STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出

    文章目录 前言 一.I2C总线通信协议 1.I2C总线 2.工作原理 3.I2C特点 4.I2C模式选择 5.软件I2C和硬件I2C 二.串口输出温湿度传感器的数据 1.核心代码分析 2.硬件实操连接 ...

  9. STM32F103基于I2C协议的AHT20温湿度传感器的数据采集

    目录 一.I2C 1.I2C 协议简介 2.I2C 物理层 3.协议层 通讯的起始和停止信号 数据有效性 响应 4. 软件I2C"和"硬件I2C 二.实现AHT20采集程序 1.A ...

最新文章

  1. pytorch笔记:policy gradient
  2. @Transactional 注解的失效场景
  3. 控制SAP Spartacus shipping address页面spinner显示的逻辑
  4. C#LeetCode刷题之#171-Excel表列序号(Excel Sheet Column Number)
  5. 洛谷 P2257 YY的GCD
  6. Visual Assist X Options 常用宏
  7. python结束线程类_Python线程指南(转)
  8. 【Computer Organization笔记13】指令流水中的结构冲突和数据冲突
  9. 一周最新示例代码回顾 (4/9–4/15)
  10. 学用计算机 关机,电脑关机命令是什么?快速关机必备(你学会了吗)
  11. PHP读取txt文件自动分成指定行数
  12. 1.2.1流动与传热的通用控制方程(OpenFOAM理论笔记系列)
  13. 自己动手编译最新Android源码及SDK
  14. win7连接远程桌面时出现黑屏的解决方法(亲测有效)——终于找到解决办法了
  15. 又发福利!日历小程序源码
  16. oracle数据库监听说法正确,Oracle数据库错题合集
  17. caffe/ windows 10 /Can't parse message of type caffe.NetParameter because it is missing required
  18. 作为建筑设计师,这8款渲染软件一定要知道
  19. 面试时,不知如何和面试官谈期望薪资
  20. 基于Java的保险管理系统

热门文章

  1. 洛谷P4383 [八省联考2018]林克卡特树lct(DP凸优化/wqs二分)
  2. 你他喵的告诉我标题怎么起!
  3. Java 行业的相关就业前景分析
  4. 引导魔女之力,征服星辰大海 升级篇: 重要事情说三遍: 升级!升级!!升满级!!! 简述: 1.本篇仅升级,涉及到的技巧全职业都可以参考; 2.考虑到萌新刚玩通关护卫者系统等级不高,故
  5. mysql 文本 挖掘_GitHub - myseve/dianping_textmining: 大众点评评论文本挖掘,包括点评数据爬取、数据清洗入库、数据分析、评论情感分析等的完整挖掘项目...
  6. 怎么给图片添加水印?教你一个图片加水印小妙招
  7. XPS如何在线转Word格式
  8. validation插件
  9. 贴片LED不良品的常见问题分析
  10. 工图怎么进行三维标注