STM32HAL库笔记

使用CubeMX创建工程:

进入CubeMX,先选好芯片,配置时钟源、系统定时、时钟树和其他所需功能,设置工程文件名和保存位置(最好预先新建一个文件夹用来保存工程,最后生成工程

HAL库常用函数:

1.系统与时钟控制

复制代码
HAL_Init();                  // 初始化HAL库
SystemClock_Config();        // 系统时钟配置(通常由CubeMX生成)
HAL_Delay(uint32_t Delay);   // 毫秒级延时
HAL_GetTick();               // 获取系统时钟滴答数

2.GPIO

GPIO初始化(通常在CubeMX里配置)

复制代码
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

读写GPIO

复制代码
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
GPIO_PinState state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);(GPIO翻转函数)

3.串口通信

发送与接收:

复制代码
UART_HandleTypeDef huart1;
HAL_UART_Init(&huart1);                          // 初始化UART
HAL_UART_Transmit(&huart1, data, len, timeout);  // 阻塞式发送
HAL_UART_Receive(&huart1, data, len, timeout);   // 阻塞式接收
HAL_UART_Transmit_IT(&huart1, data, len);        // 中断发送
HAL_UART_Receive_IT(&huart1, data, len);         // 中断接收
HAL_UART_Transmit_DMA(&huart1, data, len);       // 使用DMA发送数据

回调函数:

复制代码
// UART发送完成回调(中断或DMA模式)
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) 
{
  if (huart->Instance == USART1) 
  {  
     //释放发送缓冲区或触发下一操作
  }
}

// UART接收完成回调(中断或DMA模式)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{
  if (huart->Instance == USART1) 
  {
    //重新调用 HAL_UART_Receive_IT() 以持续接收
  }
}

// UART错误回调(帧错误、噪声错误等)
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART1)
  {    
     //重新初始化UART或记录错误日志
  }
}

4.定时器(TIM)

PWM输出:

复制代码
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);         // 启动PWM
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 50); // 设置占空比

定时器中断:

复制代码
HAL_TIM_Base_Start_IT(&htim2);   // 启动定时器中断

定时器溢出中断回调:

复制代码
// 定时器溢出中断回调(周期计数完成)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 
{
  if (htim->Instance == TIM2) 
  {
    /* 定时任务处理逻辑 */
    // 例如:执行周期性任务(如LED闪烁)
  }
}

// 输入捕获完成回调(捕获到边沿信号)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) 
{
  if (htim->Instance == TIM3) 
  {
    /* 捕获值处理逻辑 */
    uint32_t capture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
  }
}

5.ADC和DAC

ADC采样:

复制代码
HAL_ADC_Start(&hadc1);                           // 启动ADC
HAL_ADC_PollForConversion(&hadc1, timeout);      // 阻塞等待转换完成
uint32_t value = HAL_ADC_GetValue(&hadc1);       // 获取采样值

ADC回调函数:

复制代码
// ADC转换完成回调(中断或DMA模式)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) 
{
  if (hadc->Instance == ADC1)
  {
    /* 采样数据处理逻辑 */
    uint32_t adc_value = HAL_ADC_GetValue(hadc);
  }
}

// ADC转换错误回调(过载、校准错误等)
void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc) 
{
  if (hadc->Instance == ADC1) 
  {
    /* 错误恢复逻辑 */
    HAL_ADC_Start_IT(hadc);  // 尝试重启ADC
  }
}

DAC输出:

复制代码
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);    // 启动DAC

SPI:

阻塞式传输:

复制代码
// 全双工阻塞式传输(发送并接收数据)
HAL_StatusTypeDef HAL_SPI_TransmitReceive(
  SPI_HandleTypeDef *hspi,      // SPI句柄(如&hspi1)
  uint8_t *pTxData,             // 发送数据缓冲区
  uint8_t *pRxData,             // 接收数据缓冲区
  uint16_t Size,                // 数据长度(字节数)
  uint32_t Timeout              // 超时时间(毫秒)
);

// 仅发送数据(阻塞式)
HAL_StatusTypeDef HAL_SPI_Transmit(
  SPI_HandleTypeDef *hspi,
  uint8_t *pData,
  uint16_t Size,
  uint32_t Timeout
);

// 仅接收数据(阻塞式)
HAL_StatusTypeDef HAL_SPI_Receive(
  SPI_HandleTypeDef *hspi,
  uint8_t *pData,
  uint16_t Size,
  uint32_t Timeout
);

中断非阻塞传输:

复制代码
// 启动全双工中断传输
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(
  SPI_HandleTypeDef *hspi,
  uint8_t *pTxData,
  uint8_t *pRxData,
  uint16_t Size
);

// 启动仅发送中断传输
HAL_StatusTypeDef HAL_SPI_Transmit_IT(
  SPI_HandleTypeDef *hspi,
  uint8_t *pData,
  uint16_t Size
);

// 启动仅接收中断传输
HAL_StatusTypeDef HAL_SPI_Receive_IT(
  SPI_HandleTypeDef *hspi,
  uint8_t *pData,
  uint16_t Size
);

DMA传输:

复制代码
// 启动全双工DMA传输
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(
  SPI_HandleTypeDef *hspi,
  uint8_t *pTxData,
  uint8_t *pRxData,
  uint16_t Size
);

// 启动仅发送DMA传输
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(
  SPI_HandleTypeDef *hspi,
  uint8_t *pData,
  uint16_t Size
);

// 启动仅接收DMA传输
HAL_StatusTypeDef HAL_SPI_Receive_DMA(
  SPI_HandleTypeDef *hspi,
  uint8_t *pData,
  uint16_t Size
);

回调函数:

复制代码
// SPI传输完成回调(中断或DMA模式)
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) 
{
  if (hspi->Instance == SPI1) 
  {  // 判断SPI实例
     /* 处理接收数据 */
     // 示例:将接收数据存入全局变量
     memcpy(rx_buffer, spi_rx_data, sizeof(spi_rx_data));
  }
}

// SPI发送完成回调
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) 
{
  /* 发送完成后的逻辑 */
  // 例如:释放发送缓冲区
}

// SPI接收完成回调
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) 
{
  /* 接收完成后的逻辑 */
}

// SPI错误回调(模式错误、CRC错误等)
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) 
{
  if (hspi->Instance == SPI1) 
  {
    /* 错误处理 */
    // 例如:重新初始化SPI
       HAL_SPI_DeInit(hspi);
       HAL_SPI_Init(hspi);
  }
}

I2C:

主模式:

复制代码
// 主模式阻塞式发送数据
HAL_StatusTypeDef HAL_I2C_Master_Transmit(
  I2C_HandleTypeDef *hi2c,      // I2C句柄(如&hi2c1)
  uint16_t DevAddress,          // 从设备地址(7位或10位)
  uint8_t *pData,               // 发送数据缓冲区
  uint16_t Size,                // 数据长度
  uint32_t Timeout              // 超时时间
);

// 主模式阻塞式接收数据
HAL_StatusTypeDef HAL_I2C_Master_Receive(
  I2C_HandleTypeDef *hi2c,
  uint16_t DevAddress,
  uint8_t *pData,
  uint16_t Size,
  uint32_t Timeout
);

// 主模式中断发送
HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(
  I2C_HandleTypeDef *hi2c,
  uint16_t DevAddress,
  uint8_t *pData,
  uint16_t Size
);

// 主模式中断接收
HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(
  I2C_HandleTypeDef *hi2c,
  uint16_t DevAddress,
  uint8_t *pData,
  uint16_t Size
);

从模式:

复制代码
// 从模式中断接收数据
HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(
  I2C_HandleTypeDef *hi2c,
  uint8_t *pData,
  uint16_t Size
);

// 从模式中断发送数据
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(
  I2C_HandleTypeDef *hi2c,
  uint8_t *pData,
  uint16_t Size
);

回调函数:

复制代码
// 主模式发送完成回调
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) 
{
  if (hi2c->Instance == I2C1) 
  {
    /* 发送完成后的逻辑 */
    // 示例:触发数据接收
    HAL_I2C_Master_Receive_IT(hi2c, DEV_ADDR, rx_data, RX_SIZE);
  }
}

// 主模式接收完成回调
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) 
{
  /* 处理接收数据 */
  // 示例:解析传感器数据
  sensor_value = (rx_data[0] << 8) | rx_data[1];
}

// 从模式发送完成回调
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c) 
{
  /* 从设备发送完成处理 */
}

// 从模式接收完成回调
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) 
{
  /* 处理主设备发送的数据 */
}

// I2C错误回调(仲裁丢失、总线错误等)
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) 
{
  if (hi2c->Instance == I2C1) 
  {
    /* 错误恢复 */
    // 示例:重新初始化I2C
    HAL_I2C_DeInit(hi2c);
    HAL_I2C_Init(hi2c);
  }
}

7.中断回调函数

复制代码
// 外部中断通用回调函数(需用户实现)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 
{
  switch (GPIO_Pin) 
  {
    case GPIO_PIN_0:  
      // 处理PA0/PB0等引脚的中断
      /* 例如:按键按下触发LED翻转 */
      HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
      break;
    case GPIO_PIN_1:  
      // 处理PA1/PB1等引脚的中断
      /* 例如:传感器信号触发数据采集 */
      Start_Sensor_Read();
      break;
    // ... 其他引脚处理
  }
}

下面是常用函数的应用(都需要在CubeMX里提前配置硬件和移植各外设驱动程序):

1.实现LED闪烁

main.c 在主函数的while循环里

复制代码
  while (1)
  {
     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
	 HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

2.简易呼吸灯

复制代码
 while (1)
  {
		for(Time=0; Time<10; Time++)
		{
			for(delay=0; delay<10;delay++)
			{
				HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
				HAL_Delay(Time);
				HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
				HAL_Delay(10-Time);
			}
		}
		for(Time=10; Time>0; Time--)
		{
			for(delay=0; delay<10;delay++)
			{
				HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
				HAL_Delay(Time);
				HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
				HAL_Delay(10-Time);
			}
		}

3.按键控制LED

复制代码
#define K1 HAL_GPIO_ReadPin(K1_GPIO_Port, K1_Pin)

 while (1)
 {
	if(K1 == 0)
	{
		HAL_Delay(10);//消抖
		if(K1 == 0)
	    {
		 while(K1 == 0);//当按键按下并被释放时改变LED电平状态
		 HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
		}
	}
 }

4.定时器软件呼吸灯

复制代码
/* USER CODE BEGIN PD */
#define LED(a) HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, (GPIO_PinState)a)
/* USER CODE END PD */

/* USER CODE BEGIN PV */
uint8_t PWM_Period;
uint8_t light;
uint8_t Flag;
uint16_t time_10us, time_10ms;
/* USER CODE END PV */

//改变占空比
void PWM_LED(void)
{
	if(Flag == 0) //从暗到亮
	{
		if(light < 100)
		{
			light++;
			if(light >= 100)
			Flag = 1;
		}
	}
	else          //从亮到暗
	{
		if(light > 0)
		{
			light--;
			if(light == 0)
			Flag = 0;
		}
	}
}

int main()
{

 /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);
  /* USER CODE END 2 */

  while (1)
  {
		if(time_10ms == 1)//每10ms改变一次占空比
		{
			time_10ms = 0;
			PWM_LED();
		}
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

}

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == htim1.Instance) //10us中断一次
	{
		time_10us++;
		if(time_10us >= 1000)    //10*1000 = 10000us = 10ms
		{
			time_10us = 0;
			time_10ms = 1;
		}
		
		PWM_Period++;
		if(PWM_Period >= 100)	//1ms 设置PWM周期
			PWM_Period = 0;
		
		if(PWM_Period < light)	//输出比较 OC
			LED(0);
		else
			LED(1);
	}
}
/* USER CODE END 4 */

5.硬件PWM呼吸灯

复制代码
/* USER CODE BEGIN PV */
uint8_t Flag;
uint16_t light;
uint8_t time_1ms, time_10ms;
/* USER CODE END PV */

int main(void)
{
   /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);
  /* USER CODE END 2 */
  

  while (1)
  {
		if(time_10ms == 1)//每10ms改变一次占空比
		{
			time_10ms = 0;
			
			if(Flag == 0)
			{
				light+=10;
				if(light >= 999)
				Flag = 1;
			}
			else
			{
				light-=10;
				if(light == 0)
				Flag = 0;
			}
			
		   __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, light);	
			
		}

}

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == htim1.Instance)     //定时器1触发中断
    {
			time_1ms++;
			if(time_1ms >= 10)
			{
				time_1ms = 0;
				time_10ms = 1;
			}
    }
}
/* USER CODE END 4 */

6.舵机控制

复制代码
/* USER CODE BEGIN PD */
#define K1 HAL_GPIO_ReadPin(K1_GPIO_Port, K1_Pin)
#define K2 HAL_GPIO_ReadPin(K2_GPIO_Port, K2_Pin)
/* USER CODE END PD */


/* USER CODE BEGIN PV */
uint8_t SG90;
/* USER CODE END PV */

/* USER CODE BEGIN 0 */
//标准的PWM信号周期为20ms,脉宽在0.5ms至2.5ms之间变化,对应0到180度的旋转角度
void SG90Angle_Set(uint8_t Angle)
{
	__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, Angle/180.0*2000+500);	
}
/* USER CODE END 0 */


int main(void)
{ 
    /* USER CODE BEGIN 2 */
	HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
    /* USER CODE END 2 */


  while (1)
  {
		
			if(K1 == 0)
			{
				if(SG90 < 180)
				SG90++;
			}
			if(K2 == 0)
			{
				if(SG90 > 0)
				SG90--;
			}
			
			SG90Angle_Set(SG90);

         }
   } 
 

}

7.烟雾传感器ADC采集

复制代码
/* USER CODE BEGIN PD */
#define MQ HAL_GPIO_ReadPin(MQ_GPIO_Port, MQ_Pin)//DO
/* USER CODE END PD */

/* USER CODE BEGIN PV */
float MQ_Value;
/* USER CODE END PV */


int main(void)
{

  /* USER CODE BEGIN 2 */
	OLED_Init();
  /* USER CODE END 2 */

while (1)
  {    
        //ADC采集的值为0-4095,对应引脚电压的0-3.3v
		HAL_ADC_Start(&hadc1);//开启ADC1采集
		if(HAL_ADC_PollForConversion(&hadc1, 999) == HAL_OK)//999为等待时间
		MQ_Value = HAL_ADC_GetValue(&hadc1)/4095.0*3.3;//把采集到的值赋给MQ_Value
		HAL_ADC_Stop(&hadc1);//关闭ADC1采集
		
		OLED_ShowString(0, 0, "气体浓度:", OLED_8X16);
		OLED_ShowFloatNum(80, 0, MQ_Value, 1, 1, OLED_8X16);
		
		OLED_ShowString(0, 16, "触发:", OLED_8X16);
		if(MQ == 0)
			OLED_ShowString(48, 16, "是", OLED_8X16);
		else
			OLED_ShowString(48, 16, "否", OLED_8X16);
		OLED_Update();
    
  }
   

 }

8.DHT11温湿度传感器

复制代码
/* USER CODE BEGIN PV */
uint16_t time_1ms, time_500ms;
//uint16_t temp, humi;
/* USER CODE END PV */

/* USER CODE BEGIN 0 */
void Sensor_Function()
{
	DHT11_Read_Data(&temp, &humi);
	
}

void Display_Function()
{
    OLED_ShowHumi(0, 16, humi);
	OLED_ShowFloatNum(0, 0, temp, 2, 1, OLED_8X16);
	
}
/* USER CODE END 0 */



int main(void)
{
   /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);  //定时器中断开始初始化
	OLED_Init();
	DHT11_Init();
  /* USER CODE END 2 */

  while (1)
  {
		if(time_500ms == 1)//每500ms采集一次
		{
			time_500ms = 0;
			Sensor_Function();
			Display_Function();
		}
  }



}

/* USER CODE BEGIN 4 */
//定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == htim1.Instance)        //定时器1触发中断
	{
		time_1ms++;
		if(time_1ms >= 500)
		{
				time_1ms= 0;
				time_500ms = 1;
		}
	}
}
/* USER CODE END 4 */

9.串口通信

复制代码
/* USER CODE BEGIN PD */
uint8_t USART2_TX_BUF[200];
#define u2_printf(...)  HAL_UART_Transmit(&huart2,USART2_TX_BUF,sprintf((char *)USART2_TX_BUF,__VA_ARGS__),0xffff)
/* USER CODE END PD */

/* USER CODE BEGIN PV */
//串口2的数据获取
uint8_t uart2_value;      //串口传的单个数据
//串口的储存数组,串口的接收时间,串口存值的数量
uint8_t uart2_buf[36],uart2_time,uart2_num;
uint8_t uart2_rx_flag;//串口的获取值的标志位
uint8_t dis_buf[36];
/* USER CODE END PV */

int main(void)
{
     /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);  //定时器中断开始初始化
	HAL_UART_Receive_IT(&huart2, &uart2_value, 1);
	OLED_Init();
    /* USER CODE END 2 */


while (1)
  {
		if(uart2_rx_flag == 1)//当接收完一帧数据
		{
			uart2_rx_flag = 0;
			
			memcpy(dis_buf, uart2_buf, sizeof(dis_buf));//把存储接收数据数组赋给定义的数组
			memset(uart2_buf, '\0', sizeof(uart2_buf));//清空存储接收数据的数组
			OLED_Clear();//清屏
		}
		
		u2_printf("Hello!");//串口发送
		OLED_ShowString(0, 0, (char *)dis_buf, OLED_8X16);//在OLED上显示接收的数据
		OLED_Update();
		HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
    /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */
//定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == htim1.Instance)        //定时器1触发中断
	{
		//定时器中串口处理过程
		if(uart2_num != 0) //串口接收到数据传来
		{
			uart2_time++;       //计时开始
			if(uart2_time >= 10)//如果接收完数据后的时间大于等于10代表一帧数据接受完成
			{
				uart2_time = 0;   
				uart2_num = 0;
				uart2_rx_flag = 1;//把接收数据标志位设为1
			}
		}
	}
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == huart2.Instance)//串口2触发中断
	{
		//获取串口2的数据,uart2_value
		HAL_UART_Receive_IT(&huart2, &uart2_value, 1);
		//将数据一个一个存储到uart2_buf中
		uart2_buf[uart2_num++] = uart2_value;		
		uart2_time = 0;//每接收存储完一个数据就开始计时
	}
}
/* USER CODE END 4 */

10.串口DMA通信

复制代码
/* USER CODE BEGIN PV */
// 串口接收缓冲区
uint8_t rx_data[256] = {0};
/* USER CODE END PV */

int main(void)
{
    /* USER CODE BEGIN 2 */
	// 使用Ex函数,接收不定长数据
	HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rx_data, sizeof(rx_data));
	// 关闭DMA传输过半中断(HAL库默认开启,但我们只需要接收完成中断)
	__HAL_DMA_DISABLE_IT(huart2.hdmarx, DMA_IT_HT);
	OLED_Init();
  /* USER CODE END 2 */



}

/* USER CODE BEGIN 4 */
// 不定长数据接收完成回调函数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
		if (huart->Instance == USART2)
		{
				// 使用DMA将接收到的数据发送回去
				HAL_UART_Transmit_DMA(&huart2, rx_data, Size);
			
				if(rx_data[0] == 0xAA && rx_data[2] == 0xBB)
				{
					if(rx_data[1] == 0x01)
						HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
					if(rx_data[1] == 0x02)
						HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
				}
			
				// 重新启动接收,使用Ex函数,接收不定长数据
				HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rx_data, sizeof(rx_data));
				// 关闭DMA传输过半中断(HAL库默认开启,但我们只需要接收完成中断)
				__HAL_DMA_DISABLE_IT(huart2.hdmarx, DMA_IT_HT);
		}
}
/* USER CODE END 4 */

11.ADC的DMA采集

复制代码
/* USER CODE BEGIN PV */
uint16_t AD_Value[2];
/* USER CODE END PV */

int main(void)
{
     /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);
	HAL_ADCEx_Calibration_Start(&hadc1);     //校准ADC
	HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, 2); //开启ADC1DMA采集   
	OLED_Init();
    /* USER CODE END 2 */

  while (1)
  {
		OLED_ShowNum(0, 0, AD_Value[0]/4095.0*100, 4, OLED_8X16);
		OLED_ShowNum(0, 32,AD_Value[1]/4095.0*100, 4, OLED_8X16);
		OLED_Update();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

}


/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == htim1.Instance)        //定时器1触发中断
    {
			static uint16_t time;
			
			time++;
			if(time >= 100)
			{
				HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
				time = 0;
			}
    }
}
/* USER CODE END 4 */

12.外部中断(测试红外传感器触发次数)

复制代码
/* USER CODE BEGIN PV */
uint16_t IR_num;
uint8_t Flag_IR;
uint8_t Flag_delay, delay_time;
/* USER CODE END PV */

int main(void)
{
    /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);
	OLED_Init();
    /* USER CODE END 2 */

 while (1)
  {
		OLED_ShowNum(0, 32, IR_num, 3, OLED_8X16);
		OLED_Update();
		HAL_Delay(3000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
    /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == htim1.Instance)   //定时器1触发中断
    {

			
			if(Flag_delay)//标志位为1时开始计时
			{
				delay_time++;
				if(delay_time >= 20)//达到指定计时条件再把标志位设为0
				Flag_delay = 0;
			}
			else
				delay_time = 0;//标志位为0就不计时
    }
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//GPIO中断回调函数
{
  if(GPIO_Pin == IR_Pin)//如果是红外传感器引脚引起GPIO中断
    {
	    if(HAL_GPIO_ReadPin(IR_GPIO_Port, IR_Pin) && Flag_delay == 0)
	    {
          IR_num++;
	      Flag_delay = 1;//当红外传感器触发1次把标志位设为1避免触发一次导致IR_num一直增加
		}
    }
}
/* USER CODE END 4 */
相关推荐
ajsbxi27 分钟前
【Java 基础】核心知识点梳理
java·开发语言·笔记
呱呱巨基44 分钟前
vim编辑器
linux·笔记·学习·编辑器·vim
新子y1 小时前
【小白笔记】普通二叉树(General Binary Tree)和二叉搜索树的最近公共祖先(LCA)
开发语言·笔记·python
聪明的笨猪猪1 小时前
Java JVM “调优” 面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
爱学习的uu1 小时前
CURSOR最新使用指南及使用思路
人工智能·笔记·python·软件工程
YuCaiH1 小时前
Linux文件处理
linux·笔记·嵌入式
小莞尔1 小时前
【51单片机】【protues仿真】基于51单片机智能窗帘系统
c语言·stm32·单片机·嵌入式硬件·物联网·51单片机
Cathy Bryant2 小时前
大模型损失函数(二):KL散度(Kullback-Leibler divergence)
笔记·神经网络·机器学习·数学建模·transformer
qq_398586542 小时前
Threejs入门学习笔记
javascript·笔记·学习
hour_go2 小时前
TCP/IP协议相关知识点
网络·笔记·网络协议·tcp/ip