串口中断丢包&PWM波形畸变

本文讲述了作者在使用STM32CubeIDE时遇到的挑战,如串口中断通信中的丢包问题、中断内耗时操作的误解以及PWM波形异常。作者通过反思和解决实际问题,强调了基础知识的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       写这一篇博客前我应该狠狠的反思下,为什么会犯如此低级的错误,之前在学校一直调用实验室构件,自己写相关代码,使用STM32CUBEIDE后,我反而不会写代码了。只能说基础不牢,不算一个合格的嵌入式开发工程师。

      重新用STM32CubeIDE,先上网搜索别人怎么做的。

【STM32】HAL库——串口中断通信(二)_hal_uart_rxcpltcallback-优快云博客

        好的,就是它了,按照这篇博客写了串口中断的代码,功能实现了。但是,串口接收会丢包。好的,找到F103的新Bug了,还在工作汇报上说了自己遇到的问题。领导没在意,到了第二天,总感觉哪不对,这程序还不如以前实验室程序,至少串口不会丢包。

       fuck,我居然在中断里面加了打印信息(中断里面不能使用耗时操作,这是常识,我真是把以前学的都还给老师了,吐血),还误以为HAL库的验证操作费太费时,导致串口丢包。

     还有个神奇的现象,148,149两行代码顺序不一样会出现乱码。直接原因是HAL_UART_Transmit函数的发送长度大于实际的数据长度,导致了乱码的出现。估计两个字符串的存储区域相邻,所以输出后面的字符串,真伪有待验证。

     我用之前项目的开发板做PWM demo,随机选了几个引脚,断开引脚与WIFI芯片的连接,直接作为悬空引脚进行开发。发现F103 TIM3模块PWM波形正常,TIM1 10KHz PWM波形正常,100KHz波形畸变。就很奇怪,TIM1是高级定时器,TIM3是普通定时器,有问题也应该是TIM3有问题啊。换了块板子还是这样,说明不是个别现象。回看原理图,TIM3模块我选的PWM引脚上除了0Ω电阻外,还通过100nf电容接地。无语了,这不就是个低通滤波电路吗,超过截止频率的波形,直接滤除,怪不得可以输出10KHz PWM波,不能输出100KHz。文章最后附上代码,给自己做个警醒。

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim3;

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM3_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE BEGIN 1 */
#include "stdio.h"

#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

PUTCHAR_PROTOTYPE
{

  HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
  return ch;
}
#endif
   int recvCount=0;
   uint8_t aRxBuffer[100];	//声明变量
/* USER CODE END 1 */
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
#include "stdio.h"

#ifdef __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

PUTCHAR_PROTOTYPE
{

  HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
  return ch;
}
#endif
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */


  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */

  HAL_TIM_PWM_Init(&htim3);
  HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
//  HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_2);
  HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
  HAL_UART_Transmit((UART_HandleTypeDef *)&huart1,(const uint8_t *)"start STM32F103 Test\r\n",40,1000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	 HAL_Delay(3000);

	 if(recvCount>0){
		 printf("recv array:%srecvCount %d\r\n",aRxBuffer,recvCount);
		 recvCount=0;
		 strcpy(aRxBuffer,"");
	 }
	 HAL_UART_Transmit((UART_HandleTypeDef *)&huart1,(const uint8_t *)"uart send test with interrupt\r\n",40,1000);
	 printf("duty test 50%%, 25%%\r\n");

//	 __HAL_TIM_SET_AUTORELOAD(&htim3,327);  //65535
	 __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,16);  //65535
	 __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,160);  //65535

	 __HAL_TIM_SET_AUTORELOAD(&htim1,6550);  //65535
	 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,1600);  //65535   32768 16384  49152
    /* USER CODE END WHILE */

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

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 319;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 32768;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);

}

/**
  * @brief TIM3 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 319;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART1)
  {
    HAL_UART_Receive_IT(&huart1, (uint8_t*)&aRxBuffer[recvCount],1); // ???? UART ????
    recvCount++;
  }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

<think>好的,我现在需要帮助用户了解如何通过串口控制PWM信号。首先,我需要理清楚用户的需求。用户可能是在使用微控制器(比如STM32)来实现通过串口调整PWM的参数,比如周期和占空比。根据提供的引用内容,特别是引用2和3,用户可能希望知道具体的实现步骤,包括硬件配置、软件编程以及通信协议的处理。 首先,我需要确定用户可能使用的硬件平台。引用1和2提到STM32和HAL库,所以可能需要基于STM32的解决方案。但引用3中的代码是Verilog,可能涉及FPGA,但用户的问题集中在串口控制,所以可能需要综合不同平台的方法,但用户可能更关注STM32的实现,因为引用1和2都是关于STM32的。 接下来,用户需要了解如何通过串口发送指令来调整PWM的参数。根据引用2,动态修改PWM的频率和占空比需要使用特定的HAL库函数,比如__HAL_TIM_SET_PRESCALER()、__HAL_TIM_SET_AUTORELOAD()和__HAL_TIM_SET_COMPARE()。这些函数分别用于调整预分频器、自动重装载值和比较值,从而改变周期和占空比。 然后,我需要考虑通信协议的设计。用户需要通过串口发送数据,可能采用特定的格式,比如命令+参数的方式。例如,发送“F 1000”来设置频率为1kHz,或者“D 50”来设置占空比为50%。引用3中的Verilog模块展示了如何处理周期和高电平时间,但STM32的实现方式会有所不同,需要结合定时器的配置。 另外,硬件配置部分,用户可能需要配置PWM输出的GPIO引脚,以及定时器的相关参数,如预分频、自动重装载值等。引用1中的框图说明了高级定时器的结构,需要正确配置时基单元和输出比较模式。 软件部分,用户需要初始化串口和PWM模块,并编写中断服务程序来处理接收到的串口数据。解析接收到的命令,并调用相应的HAL函数来调整PWM参数。引用2提到在代码运行时动态修改这些参数,所以需要确保在运行时能够安全地更新定时器的寄存器,可能需要考虑原子操作或临界区的保护。 此外,用户可能关心如何验证和测试这一功能,比如通过示波器观察PWM波形是否随串口指令变化,或者通过LED亮度变化来直观显示占空比的调整,如引用4所述,通过PWM控制模拟电压,进而控制LED亮度。 最后,需要考虑错误处理,比如接收到无效命令时的处理,确保系统的稳定性。同时,可能还需要考虑数据解析的准确性,比如校验和或格式检查,防止错误数据导致系统异常。 总结一下,用户的问题涉及硬件配置、通信协议设计、PWM参数动态调整以及软件实现。需要分步骤讲解每个部分,并提供代码示例和注意事项,帮助用户逐步实现功能。同时,根据引用内容,确保引用正确的函数和方法,并可能推荐使用CubeMX进行配置,简化开发流程。</think>### 通过串口控制PWM信号的实现方法 #### 一、硬件与原理基础 1. **PWM控制核心** 通过调整定时器的$预分频值(PSC)$和$自动重装载值(ARR)$控制周期,通过$比较值(CCR)$控制占空比[^1][^2]。周期公式: $$T_{PWM} = \frac{(PSC+1)(ARR+1)}{TIM\_CLK}$$ 占空比公式: $$Duty = \frac{CCR}{ARR+1} \times 100\%$$ 2. **硬件配置**(以STM32为例) - 启用定时器的PWM输出通道(如TIM1_CH1) - 配置串口通信模块(如USART1) - 连接示波器或LED验证波形输出 #### 二、软件实现步骤 1. **初始化配置**(使用CubeMX或寄存器配置) ```c // PWM初始化示例 HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // 串口初始化 HAL_UART_Receive_IT(&huart1, &rx_data, 1); ``` 2. **串口协议设计**(建议格式) | 指令类型 | 示例 | 说明 | |----------|-------------|-------------------| | 设置频率 | F:1000 | 设置PWM频率1kHz | | 设置占空比 | D:50 | 设置占空比50% | 3. **动态参数修改** ```c // 修改频率(需同时调整PSC和ARR) __HAL_TIM_SET_PRESCALER(&htim1, new_psc); __HAL_TIM_SET_AUTORELOAD(&htim1, new_arr); // 修改占空比 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, new_ccr); ``` 4. **串口中断处理** ```c void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(rx_buffer[0] == 'F') { // 解析频率值并更新PSC/ARR } else if(rx_buffer[0] == 'D') { // 解析占空比并更新CCR } HAL_UART_Receive_IT(huart, rx_buffer, 1); // 重新启用接收 } ``` #### 三、关键注意事项 1. **参数同步问题** 修改ARR时需确保$CCR \leq ARR$,否则会产生异常波形。建议使用`TIM_EGR_UG`触发更新事件: ```c htim1.Instance->EGR = TIM_EGR_UG; // 强制寄存器更新 ``` 2. **波特率匹配** 串口波特率需与上位机一致(常用115200),数据格式建议8N1 3. **防抖动处理** 在串口数据解析时添加校验机制,例如: - 帧头校验(如`$PWM`) - CRC校验 - 数值范围限制 #### 四、实验验证方法 1. 通过示波器观察波形变化 2. 连接LED观察亮度渐变 3. 使用串口调试助手发送测试指令: ``` F:2000 // 设置2kHz频率 D:75 // 设置75%占空比 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值