STM32CubeIDE(I2C)

该文详细介绍了如何在STM32F10x微控制器上使用IIC通信协议与AHT20温湿度传感器交互。首先,展示了IIC轮询模式下配置和驱动的编写,接着,过渡到使用中断优化读取流程,最后,通过DMA进一步提高传输效率,实现无阻塞的数据读取。
摘要由CSDN通过智能技术生成

目录

一、IIC轮询模式

1.1 配置

 1.2 编写AHT20驱动

1.2.1  aht20.h

1.2.2 aht20.c

二、I2C中断

2.1 打开中断

 2.2 分离读取流程

2.3 在主函数中重新编写读取流程

2.4 在i2c.c中重新定义stm32f1xx_hal_i2c.h中的两个函数

三、I2CDMA

3.1 配置DMA通道

 3.2 代码的修改


一、IIC轮询模式

1.1 配置

 不确认IIC有没有硬件上拉,保险起见,将SCL SDA的GPIO设置为上拉

1.2 编写AHT20驱动

根据AHT20手册编写初始化与读数据函数

1.2.1  aht20.h

#ifndef INC_AHT20_H_
#define INC_AHT20_H_

#include "i2c.h"


void AHT20_Init();
void AHT20_Read(float* Temperature,float* Humidity);


#endif /* INC_AHT20_H_ */

1.2.2 aht20.c

#include "aht20.h"


#define AHT20_ADDRESS 0x70

void AHT20_Init()
{
	uint8_t readBuffer;
	HAL_Delay(40);
	HAL_I2C_Master_Receive(&hi2c1,AHT20_ADDRESS,&readBuffer,1,HAL_MAX_DELAY);
	if((readBuffer& 0x80)==0x00)
	{
		uint8_t sendBuffer[3]={0xBE,0x80,0x00};
		HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);
	}
}


void AHT20_Read(float* Temperature,float* Humidity)
{
	uint8_t sendBuffer[3] = {0xAC,0x33,0x00};
	uint8_t readBuffer[6];

	HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);
	HAL_Delay(75);
	HAL_I2C_Master_Receive(&hi2c1,AHT20_ADDRESS,readBuffer,6,HAL_MAX_DELAY);

	if((readBuffer[0] & 0x80)== 0x00)
	{
		uint32_t date = 0;
		date=(((uint32_t)readBuffer[3]>>4) + ((uint32_t)readBuffer[2]<<4) + ((uint32_t)readBuffer[1]<<12));
		*Humidity = date * 100.0f/(1<<20);

		date=(((uint32_t)readBuffer[3]&0x0F)<<16) + ((uint32_t)readBuffer[4]<<8) + (uint32_t)readBuffer[5];
		*Temperature = date * 200.0f/(1<<20)-50;
	}
}

二、I2C中断

2.1 打开中断

 2.2 分离读取流程

分为测量指令 读取指令 解析 三部分

void AHT20_Measure()
{
	static uint8_t sendBuffer[3] = {0xAC,0x33,0x00};
	HAL_I2C_Master_Transmit_IT(&hi2c1, AHT20_ADDRESS, sendBuffer, 3);
}

void AHT20_Get()
{
	HAL_I2C_Master_Receive_IT(&hi2c1,AHT20_ADDRESS,readBuffer,6);
}

void AHT20_Analysis(float* Temperature,float* Humidity)
{
	if((readBuffer[0] & 0x80)== 0x00)
	{
		uint32_t date = 0;
		date=(((uint32_t)readBuffer[3]>>4) + ((uint32_t)readBuffer[2]<<4) + ((uint32_t)readBuffer[1]<<12));
		*Humidity = date * 100.0f/(1<<20);

		date=(((uint32_t)readBuffer[3]&0x0F)<<16) + ((uint32_t)readBuffer[4]<<8) + (uint32_t)readBuffer[5];
		*Temperature = date * 200.0f/(1<<20)-50;
	}
}

2.3 在主函数中重新编写读取流程

	  if(aht20State==0)
	  {
		  AHT20_Measure();
		  aht20State=1;
	  }else if(aht20State==2)
	  {
		  HAL_Delay(75);
		  AHT20_Get();
		  aht20State=3;
	  }else if(aht20State==4)
	  {
		  AHT20_Analysis(&temperature, &humidity);
		  sprintf(message,"温度�? %.1f �?, 湿度�?%.1f %%\r\n",temperature,humidity);
		  HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);

		  HAL_Delay(1000);
		  aht20State=0;
	  }

2.4 在i2c.c中重新定义stm32f1xx_hal_i2c.h中的两个函数

// 发送完成时回调
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hi2c==&hi2c1)
	{
		aht20State=2;
	}
}

void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hi2c==&hi2c1)
	{
		aht20State=4;
	}
}

三、I2CDMA

3.1 配置DMA通道

从机配置如下,DMA模式也需要开启中断。从机地址配置为0x15,7位地址加1位读写位,从机写命令就为0x2A

主机配置与从机相同,只是不配置从机地址。

 3.2 代码

从机代码

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  HAL_I2C_Slave_Receive_DMA(&hi2c3, readBuffer, 1);
  while (1)
  {
    HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);
    HAL_Delay(500);
    //HAL_I2C_Master_Transmit_DMA(&hi2c1, 0x2A, sendBuffer, sizeof(sendBuffer));
    /* USER CODE END WHILE */
  }
//I2C1_DMA_Read  callback function
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	printf("SlaveRxCpltCallback begin data: %d\r\n",readBuffer[0]);
	HAL_I2C_Slave_Receive_DMA(&hi2c3, readBuffer, 1);
}

主机代码

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    if(HAL_I2C_Master_Transmit_DMA(&hi2c1, 0x2A, sendBuffer, sizeof(sendBuffer))!=HAL_OK)
    	printf("HAL_I2C_Master_Transmit_DMA error \r\n");
    else
    	printf("sendData %d  finish \r\n",sendBuffer[0]);
    HAL_Delay(1000);
    /* USER CODE END WHILE */
  }
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
  sendBuffer[0]++;
}

四、LL库中断接收

4.1 配置

从机地址0x15,7位地址,移位后加上读写位,写指令就为0x2A

中断开启,GPIO也要最好设置为上拉

4.2 代码

开中断与数据处理

    ...
   	
    LL_I2C_EnableIT_ADDR(I2C3);
	LL_I2C_EnableIT_NACK(I2C3);
	LL_I2C_EnableIT_ERR(I2C3);
	LL_I2C_EnableIT_STOP(I2C3);

    ...

	while (1)
	{
		if(1 == Flag_I2C_FrontBackSystem)
		{
			printf("Start while !\r\n");
			allocate_task(RegisterIndex);
			Flag_I2C_FrontBackSystem = 0;
		}
		printf("data 0x%x,%d!!!!!!\r\n",RegisterMap[0],Flag_I2C_FrontBackSystem);
	}

    ...


void allocate_task(uint16_t index)
{
	switch (index)
	{
		case 0x00:
		{
			uint16_t Flag_Mode = RegisterMap[index];
			if(Flag_Mode == 0x11)
			{
				printf("IIC3 Receive 0x11\r\n");
			}
		}
			break;

		case 0x01:
		{

		}
		  break;

		default:
			break;
	}
}

在事件中断中调用回调函数

void I2C3_EV_IRQHandler(void)
{
  /* USER CODE BEGIN I2C3_EV_IRQn 0 */
	I2C_EV_Callback(I2C3);
  /* USER CODE END I2C3_EV_IRQn 0 */

  /* USER CODE BEGIN I2C3_EV_IRQn 1 */

  /* USER CODE END I2C3_EV_IRQn 1 */
}

回调函数

/*
	I2C3 Slave Function
  I2C3  set as slave device to communicate with Dothink
*/
void I2C_EV_Callback(I2C_TypeDef *I2Cx)
{
	/*Check ADDR Flag,EV1*/
	if(LL_I2C_IsActiveFlag_ADDR(I2Cx))
	{
		if(LL_I2C_GetTransferDirection(I2Cx) == LL_I2C_DIRECTION_WRITE)
		{
			Flag_I2C_Slave_Internal = 1;
			LL_I2C_ClearFlag_ADDR(I2Cx);
			LL_I2C_EnableIT_RX(I2Cx);
		}
		else if(LL_I2C_GetTransferDirection(I2Cx) == LL_I2C_DIRECTION_READ)
		{
			LL_I2C_ClearFlag_ADDR(I2Cx);
			LL_I2C_EnableIT_TX(I2Cx);
		}
		else
			LL_I2C_ClearFlag_ADDR(I2Cx);
	}

	/*Check RXNE Flag,EV2*/
	if(LL_I2C_IsActiveFlag_RXNE(I2Cx))
	{
		if(Flag_I2C_Slave_Internal == 1)
		{
			RegisterIndex = LL_I2C_ReceiveData8(I2Cx);
			Flag_I2C_Slave_Internal = 2;
		}
		else if(Flag_I2C_Slave_Internal == 2)
		{
			RegisterMap[RegisterIndex]=LL_I2C_ReceiveData8(I2Cx);
			Flag_I2C_FrontBackSystem = 1; //front back system flag
		}
	}

	/*Check NACK Flag,EV3-2*/
	if(LL_I2C_IsActiveFlag_NACK(I2Cx))
	{
		LL_I2C_ClearFlag_NACK(I2Cx);
		Flag_I2C_Slave_Internal = 0;
	}

	/*Check TXE Flag,EV3-1,EV3*/
	if(LL_I2C_IsActiveFlag_TXIS(I2Cx))
		LL_I2C_TransmitData8(I2Cx, RegisterMap[RegisterIndex++]);  //support continus read

	/*Check STOP Flag,EV4*/
	if(LL_I2C_IsActiveFlag_STOP(I2Cx))
	{
		LL_I2C_ClearFlag_STOP(I2Cx);
		if(!LL_I2C_IsActiveFlag_TXE(I2Cx))
			LL_I2C_ClearFlag_TXE(I2Cx);
		Flag_I2C_Slave_Internal = 0;
	}
}


//I2C1_DMA_Write  callback function
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}

//I2C1_DMA_Read  callback function
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
{

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhang丶&|!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值