stm的HAL库的这个函数HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)的原理是什么

时间: 2025-07-24 17:21:16 浏览: 25
<think>我们正在讨论的是STM32 HAL库中的UART传输函数,特别是阻塞式发送函数HAL_UART_Transmit。根据引用[3],这个函数的原型是: HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) 它的作用是以阻塞模式发送大量数据。下面我将详细解释其工作原理。 ### 函数参数 1. **huart**: 指向UART_HandleTypeDef结构的指针,该结构包含了UART的配置信息(如波特率、字长、停止位等)和操作状态。 2. **pData**: 指向要发送的数据缓冲区的指针。 3. **Size**: 要发送的数据字节数。 4. **Timeout**: 超时时间(单位为毫秒),表示函数在发送数据时最多等待的时间。如果设置为HAL_MAX_DELAY(0xFFFFFFFF),则函数会一直等待直到发送完成。 ### 函数工作流程 1. **检查状态和参数有效性**: - 检查huart是否为NULL,pData是否为NULL,Size是否为0。 - 检查UART是否已初始化(huart->gState是否为HAL_UART_STATE_READY)。 - 检查是否已经有传输在进行(避免重入)。 2. **设置状态为“忙”**: - 将huart->gState设置为HAL_UART_STATE_BUSY_TX,表示UART正在发送数据。 3. **启动传输**: - 使能UART的发送相关中断(如发送数据寄存器空中断,即TXE),但注意阻塞模式并不依赖中断来发送数据,而是使用轮询方式。 4. **循环发送数据**: - 函数进入一个循环,每次循环发送一个字节,直到发送完Size个字节或超时。 - 对于每个字节: a. 等待发送数据寄存器为空(即TXE标志置位),表示可以写入下一个字节。在等待过程中,如果超过Timeout时间,则返回HAL_TIMEOUT。 b. 将下一个字节写入UART的数据寄存器(DR),硬件会自动将其发送出去。 5. **等待最后一个字节发送完成**: - 在发送完所有字节后,需要等待传输完成(TC标志置位),以确保最后一个字节已经发送完毕(包括停止位)。同样,这里也会检查超时。 6. **清除状态并返回**: - 发送完成后,将状态恢复为HAL_UART_STATE_READY。 - 返回HAL_OK表示发送成功,或者HAL_TIMEOUT表示超时。 ### 关键点 - **阻塞模式**:函数在发送数据期间会一直占用CPU,直到所有数据发送完毕或超时。在此期间,程序不能执行其他任务。 - **超时机制**:如果硬件出现问题(如线路断开导致无法发送),函数会在超时后返回,避免程序永久阻塞。 - **直接操作寄存器**:函数通过轮询状态标志(TXE和TC)并写入数据寄存器(DR)来发送数据,不依赖中断。 ### 示例代码 ```c // 发送字符串"Hello"(包括5个字符) uint8_t data[] = "Hello"; HAL_StatusTypeDef status = HAL_UART_Transmit(&huart1, data, 5, 1000); // 超时设为1000ms if (status == HAL_OK) { // 发送成功 } else if (status == HAL_TIMEOUT) { // 超时错误 } ``` ### 时序分析 假设波特率为115200bps,则每个位的时间为$T_{bit} = \frac{1}{115200} \approx 8.68 \mu s$。发送一个字节(包括起始位、8个数据位、停止位,共10位)需要的时间为: $$ T_{byte} = 10 \times T_{bit} \approx 86.8 \mu s $$ 发送n个字节的时间大约为$n \times T_{byte}$。例如,发送100个字节大约需要8.68ms。 ### 注意事项 1. **阻塞时间**:在高速率或大数据量传输时,阻塞时间可能较长,影响实时性。此时可考虑使用中断(HAL_UART_Transmit_IT)或DMA(HAL_UART_Transmit_DMA)方式。 2. **超时设置**:超时时间应大于预计发送时间。若使用HAL_MAX_DELAY,则需确保硬件正常,否则程序可能死等。 3. **状态管理**:在发送过程中,UART的状态为“忙”,此时不能启动另一次发送,否则会返回错误。 ### 与TI的DL_UART_transmitDataBlocking对比 - 相似点:都是阻塞式发送,单次调用发送一个字节(但HAL_UART_Transmit可发送多个字节)。 - 不同点:HAL_UART_Transmit通过循环发送多个字节,并提供了超时机制;而DL_UART_transmitDataBlocking一次只发送一个字节,没有超时参数。 ### 相关问题 1. 如何避免HAL_UART_Transmit的阻塞对实时任务的影响? 2. 在STM32 HAL库中,如何配置UART使用DMA进行数据传输? 3. 当UART发送超时时,可能的原因有哪些? 4. HAL_UART_Transmit函数在发送过程中是否可被中断打断? 5. 如何利用HAL_UART_Transmit发送浮点数或结构体数据? [^1]: STM32hal库学习(F1)-串口UART [^3]: STM32F0 HAL----USART</think>### STM32 HAL库中 `HAL_UART_Transmit` 函数工作原理详解 `HAL_UART_Transmit` 是 STM32 HAL 库中用于**阻塞式串口数据发送**的核心函数。它会将数据完全发送后才返回,确保数据传输的可靠性。以下是其详细工作原理: #### 函数原型 ```c HAL_StatusTypeDef HAL_UART_Transmit( UART_HandleTypeDef *huart, // UART句柄指针 uint8_t *pData, // 待发送数据缓冲区 uint16_t Size, // 发送数据长度(字节) uint32_t Timeout // 超时时间(毫秒) ); ``` #### 工作流程 1. **参数校验阶段**: ```c if((huart->gState != HAL_UART_STATE_READY) || (pData == NULL) || (Size == 0)) { return HAL_ERROR; // 检查UART状态/数据有效性 } ``` 2. **状态锁定**: ```c huart->gState = HAL_UART_STATE_BUSY_TX; // 标记UART为发送忙状态 ``` 3. **数据发送循环**: ```c while(Size > 0) { // 等待发送寄存器就绪(TXE标志) if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, Timeout) != HAL_OK) return HAL_TIMEOUT; // 超时处理 // 写入数据到数据寄存器 huart->Instance->DR = (*pData++ & 0xFF); Size--; } ``` 4. **等待传输完成**: ```c // 等待传输完成标志(TC标志) if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, Timeout) != HAL_OK) return HAL_TIMEOUT; ``` 5. **状态恢复**: ```c huart->gState = HAL_UART_STATE_READY; // 恢复就绪状态 return HAL_OK; ``` #### 关键机制解析 1. **阻塞式发送**: - 函数会**持续占用CPU**直到所有数据发送完成或超时 - 发送期间程序无法执行其他任务(实时性要求高的场景需谨慎) 2. **超时控制**: - 超时时间计算公式:$T_{\text{max}} = \frac{\text{字节数} \times 10 \text{位}}{\text{波特率}}$ - 例如115200bps发送100字节:$T_{\text{max}} = \frac{100 \times 10}{115200} \approx 8.7\text{ms}$ 3. **状态标志检测**: | 标志位 | 含义 | 检测时机 | |--------|------|----------| | TXE | 发送数据寄存器空 | 写入新数据前 | | TC | 传输完成 | 所有数据发送后 | 4. **硬件寄存器操作**: ```c huart->Instance->DR = data; // 实际数据写入硬件寄存器 ``` 数据写入DR寄存器后由UART外设自动完成串行化发送[^1] #### 典型使用示例 ```c // 发送字符串"Hello World" uint8_t msg[] = "Hello World!\r\n"; HAL_StatusTypeDef status = HAL_UART_Transmit( &huart1, // UART1句柄 msg, // 数据缓冲区 sizeof(msg)-1, // 数据长度(排除结束符) 100 // 超时100ms ); if(status == HAL_OK) { // 发送成功处理 } else if(status == HAL_TIMEOUT) { // 超时错误处理 } ``` #### 与其它发送方式的对比 | 特性 | `HAL_UART_Transmit` | `HAL_UART_Transmit_IT` | `HAL_UART_Transmit_DMA` | |------|----------------------|------------------------|--------------------------| | 阻塞性 | 阻塞 | 非阻塞 | 非阻塞 | | CPU占用 | 高 | 中 | 低 | | 实现机制 | 轮询等待 | 中断驱动 | DMA传输 | | 适用场景 | 短数据/调试输出 | 中等长度数据 | 大数据流传输 | #### 注意事项 1. **状态管理**: - 发送前需确保 `huart->gState == HAL_UART_STATE_READY` - 禁止在中断服务程序中调用(可能引起死锁) 2. **超时设置建议**: ```c #define SAFE_TIMEOUT (2 * (Size * 10000) / BaudRate) // 2倍安全系数 ``` 3. **物理传输完成**: - 函数返回仅表示数据写入硬件寄存器 - 实际物理传输需要额外时间:$T_{\text{phy}} = \frac{\text{停止位+数据位}}{\text{波特率}}$ 4. **错误处理**: - 超时返回 `HAL_TIMEOUT` - 参数错误返回 `HAL_ERROR` - UART硬件错误返回 `HAL_BUSY` > 对于115200bps波特率,发送1KB数据约需87ms阻塞时间。在实时系统中,建议使用DMA传输(`HAL_UART_Transmit_DMA`)避免长时间阻塞[^3]。 --- ### 相关问题 1. 如何避免 `HAL_UART_Transmit` 在实时系统中的阻塞问题? 2. `HAL_UART_Transmit_IT` 中断发送模式的工作原理是什么? 3. 使用DMA进行UART数据传输需要哪些特殊配置? 4. 如何实现STM32串口的不定长数据接收? 5. UART传输中出现数据丢失的可能原因及排查方法? [^1]: STM32hal库学习(F1)-串口UART [^2]: 关于stm32 hal库usart HAL_UART_Transmit_IT函数解析 [^3]: STM32F0 HAL----USART [^4]: STM32Cube HAL库串口总结
阅读全文

相关推荐

/** ****************************************************************************** * @file usart.c * @brief This file provides code for the configuration * of the USART instances. ****************************************************************************** * @attention * *
© Copyright (c) 2022 CSTX. * All rights reserved.
* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * leigong opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "usart.h" /* USER CODE BEGIN 0 */ #include "stdio.h" #include "string.h" uint8_t rxConut = 0; //数据长度 uint8_t regConut = 0; uint16_t USART_RX_STA=0; //接收状态标记 uint16_t USART2_RX_STA=0; uint8_t USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节. uint8_t USART2_RX_BUF[USART_REC_LEN]; __align(8) char usart_txBuff[USART_REC_LEN]; //字节对齐缓冲区 #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ /** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */ HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); return ch; } //usart2的printf() void USART2_printf(char *fmt,...) { uint32_t i,length; va_list ap; va_start(ap,fmt); vsprintf(usart_txBuff,fmt,ap); va_end(ap); length=strlen((const char*)usart_txBuff); while((USART2->ISR&0x40)==0); for(i=0;i<length;i++) { USART2->TDR=usart_txBuff[i]; while((USART2->ISR&0x40)==0); } } /* USER CODE END 0 */ UART_HandleTypeDef huart1; UART_HandleTypeDef huart2; /* USART1 init function */ 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; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK) { Error_Handler(); } if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART1_Init 2 */ /* USER CODE END USART1_Init 2 */ } /* USART2 init function */ void MX_USART2_UART_Init(void) { /* USER CODE BEGIN USART2_Init 0 */ /* USER CODE END USART2_Init 0 */ /* USER CODE BEGIN USART2_Init 1 */ /* USER CODE END USART2_Init 1 */ huart2.Instance = USART2; huart2.Init.BaudRate = 9600; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1; huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART2_Init 2 */ /* USER CODE END USART2_Init 2 */ } void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* USART1 clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /**USART1 GPIO Configuration PB7 ------> USART1_RX PB6 ------> USART1_TX */ GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF0_USART1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ } else if(uartHandle->Instance==USART2) { /* USER CODE BEGIN USART2_MspInit 0 */ /* USER CODE END USART2_MspInit 0 */ /* USART2 clock enable */ __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART2 GPIO Configuration PA2 ------> USART2_TX PA3 ------> USART2_RX */ GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF1_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART2 interrupt Init */ HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART2_IRQn); /* USER CODE BEGIN USART2_MspInit 1 */ /* USER CODE END USART2_MspInit 1 */ } } void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) { if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspDeInit 0 */ /* USER CODE END USART1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART1_CLK_DISABLE(); /**USART1 GPIO Configuration PB7 ------> USART1_RX PB6 ------> USART1_TX */ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7|GPIO_PIN_6); /* USART1 interrupt Deinit */ HAL_NVIC_DisableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspDeInit 1 */ /* USER CODE END USART1_MspDeInit 1 */ } else if(uartHandle->Instance==USART2) { /* USER CODE BEGIN USART2_MspDeInit 0 */ /* USER CODE END USART2_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART2_CLK_DISABLE(); /**USART2 GPIO Configuration PA2 ------> USART2_TX PA3 ------> USART2_RX */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3); /* USART2 interrupt Deinit */ HAL_NVIC_DisableIRQ(USART2_IRQn); /* USER CODE BEGIN USART2_MspDeInit 1 */ /* USER CODE END USART2_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ void USART_Interupt_Enable(void) { __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //空闲中断使能 __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE); //接收中断使能 __HAL_UART_CLEAR_IDLEFLAG(&huart1); __HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE); //空闲中断使能 __HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE); //接收中断使能 __HAL_UART_CLEAR_IDLEFLAG(&huart2); } //void USART1_IdleCallback(uint8_t*pData,uint16_t len) //{ // while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET); // HAL_UART_Transmit(&huart2,pData,len,1000); //} //void USART2_IdleCallback(uint8_t*pData,uint16_t len) //{ // while(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_TC)!=SET); // HAL_UART_Transmit(&huart1,pData,len,1000); //} /*串口中断处理函数*/ void USER_UartHandler(UART_HandleTypeDef* huart) { uint8_t res = 0; static uint8_t OnPow = 1,OnPow2 = 1; if(huart->Instance == USART1) { //接收中断 if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE)!=RESET) { HAL_UART_Receive(&huart1,&res,1,1000); //将数据放入缓冲区 if(rxConut<USART_REC_LEN) { USART_RX_BUF[rxConut]=res; rxConut++; } USART_RX_STA = REC_WAIT ; __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_RXNE); } //空闲中断 if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)!=RESET) { //一帧数据接收完成 if(OnPow) { USART_RX_STA = REC_WAIT ; OnPow = 0; }else {USART_RX_STA = REC_OK;} //USART1_IdleCallback(USART_RX_BUF,rxConut); rxConut =0; __HAL_UART_CLEAR_IDLEFLAG(&huart1); } }else if(huart->Instance == USART2) { //接收中断 if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_RXNE)!=RESET) { HAL_UART_Receive(&huart2,&res,1,1000); //将数据放入缓冲区 if(rxConut<USART_REC_LEN) { USART2_RX_BUF[rxConut]=res; rxConut++; regConut++; } USART2_RX_STA = REC_WAIT ; __HAL_UART_CLEAR_FLAG(&huart2,UART_FLAG_RXNE); } //空闲中断 if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE)!=RESET) { //一帧数据接收完成 if(OnPow2) { USART2_RX_STA = REC_WAIT ; OnPow2 = 0; }else {USART2_RX_STA = REC_OK;} //USART2_IdleCallback(USART2_RX_BUF,rx2Conut); rxConut =0; __HAL_UART_CLEAR_IDLEFLAG(&huart2); } } } //发送len个字节. //buf:发送区首地址 //len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节) void CS_Reg_Send_Data(unsigned char *buf,unsigned char len) { unsigned char t; while((USART2->ISR&0x40)==0); for(t=0;t<len;t++) //循环发送数据 { USART2->TDR=buf[t]; while((USART2->ISR&0x40)==0); } regConut=0; memset(USART2_RX_BUF,0,USART_REC_LEN); } //查询接收到的数据 //buf:接收缓存首地址 //len:读到的数据长度 void cstx_reg_Receive_Data(unsigned char *buf,unsigned char *len) { unsigned char rxlen=regConut; unsigned char i=0; *len=0; //默认为0 if(USART2_RX_BUF[0]==0XC1)//接收到了数据,且接收完成了 { for(i=0;i<rxlen;i++) { buf[i]=USART2_RX_BUF[i]; } *len=regConut; //记录本次数据长度 } // regConut=0; //清零 memset(USART2_RX_BUF,0,USART_REC_LEN); } /* USER CODE END 1 */ /************************ (C) COPYRIGHT CSTX *****END OF FILE****/ 这是我的串口模块

/** ****************************************************************************** * File Name : USART.c * Description : This file provides code for the configuration * of the USART instances. ****************************************************************************** * @attention * *
© Copyright (c) 2020 STMicroelectronics. * All rights reserved.
* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "usart.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ UART_HandleTypeDef huart1; UART_HandleTypeDef huart2; /* USART1 init function */ void MX_USART1_UART_Init(void) { 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(); } } /* USART2 init function */ void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 9600; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } } void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* USART1 clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ } else if(uartHandle->Instance==USART2) { /* USER CODE BEGIN USART2_MspInit 0 */ /* USER CODE END USART2_MspInit 0 */ /* USART2 clock enable */ __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /**USART2 GPIO Configuration PA2 ------> USART2_TX PD6 ------> USART2_RX */ GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* USER CODE BEGIN USART2_MspInit 1 */ /* USER CODE END USART2_MspInit 1 */ } } void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) { if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspDeInit 0 */ /* USER CODE END USART1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART1_CLK_DISABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); /* USER CODE BEGIN USART1_MspDeInit 1 */ /* USER CODE END USART1_MspDeInit 1 */ } else if(uartHandle->Instance==USART2) { /* USER CODE BEGIN USART2_MspDeInit 0 */ /* USER CODE END USART2_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART2_CLK_DISABLE(); /**USART2 GPIO Configuration PA2 ------> USART2_TX PD6 ------> USART2_RX */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2); HAL_GPIO_DeInit(GPIOD, GPIO_PIN_6); /* USER CODE BEGIN USART2_MspDeInit 1 */ /* USER CODE END USART2_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ #include <stdio.h> // 使用HAL库实现的fputc函数 int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY); return ch; } // 如果希望支持__io_putchar格式(针对GCC编译器) #ifdef __GNUC__ int __io_putchar(int ch) { return fputc(ch, stdout); } #endif /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 以上是usart.c中的代码

/* USER CODE BEGIN Header */ /** ****************************************************************************** * File Name : freertos.c * Description : Code for freertos applications ****************************************************************************** * @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 "FreeRTOS.h" #include "task.h" #include "main.h" #include "cmsis_os.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "usart.h" #include "gpio.h" #include "tim.h" #include <string.h> #include <stdio.h> /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define MOTOR_PWM_MAX 19999 // PWM最大值 (Period - 1) #define MOTOR_PWM_MIN 0 // PWM最小值 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Variables */ struct uart3_rx_t { int num,ok,en; uint8_t data[28]; int class; float score; int x1,y1,x2,y2; uint8_t datarx; }uart3_rx; struct uart2_rx_t { int num,ok,en; uint8_t data[3]; int shexiangtou_en; int manzaijianche_en; int dangban_en; int youhailaji_en; int chuyulaji_en; int kehuishou_en; int qitalaji_en; uint8_t datarx; }uart2_rx; struct pingmu_tx_t { int manzai,ok,en; int class; float score; int x1,y1,x2,y2; }pingmu_tx; osThreadId motorTaskHandle; osThreadId motor2TaskHandle; osThreadId manzaiTaskHandle; osThreadId txTaskHandle; // 新增:电机控制和超声波测距任务句柄 osThreadId motorControlTaskHandle; // 电机控制任务句柄 osThreadId ultrasonicTaskHandle; // 超声波测距任务句柄 // 新增:超声波测距变量 float ultrasonic1_distance = 0.0f; // 超声波1测量距离 (cm) float ultrasonic2_distance = 0.0f; // 超声波2测量距离 (cm) // 新增:舵机状态跟踪变量 typedef enum { SERVO_IDLE = 0, // 舵机空闲状态(在原位) SERVO_WORKING = 1, // 舵机正在执行分类动作 SERVO_RETURNING = 2 // 舵机正在回到原位 } ServoState_t; volatile ServoState_t servoState = SERVO_IDLE; // 舵机状态 volatile uint32_t servoWorkStartTime = 0; // 舵机工作开始时间 // 新增:电机启动停止延时控制变量 volatile uint32_t motor1_startConditionStartTime = 0; // 电机1启动条件开始时间 volatile uint32_t motor2_startConditionStartTime = 0; // 电机2启动条件开始时间 volatile uint8_t motor1_startConditionActive = 0; // 电机1启动条件是否激活 volatile uint8_t motor2_startConditionActive = 0; // 电机2启动条件是否激活 volatile uint32_t motor1_stopConditionStartTime = 0; // 电机1停止条件开始时间 volatile uint32_t motor2_stopConditionStartTime = 0; // 电机2停止条件开始时间 volatile uint8_t motor1_stopConditionActive = 0; // 电机1停止条件是否激活 volatile uint8_t motor2_stopConditionActive = 0; // 电机2停止条件是否激活 // 电机当前状态 volatile uint8_t motor1_running = 0; // 电机1是否正在运行 volatile uint8_t motor2_running = 0; // 电机2是否正在运行 /* USER CODE END Variables */ osThreadId defaultTaskHandle; osSemaphoreId motorHandle; osSemaphoreId motor2Handle; osSemaphoreId rxlubancatHandle; osSemaphoreId rxpingmuHandle; osSemaphoreId bujingdianjiHandle; osSemaphoreId manzaiSignalHandle; /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN FunctionPrototypes */ int fun (int a,int b, int c); //_Noreturn void motorTask(void const * argument); _Noreturn void motor2Task(void const * argument); //_Noreturn void bujingdianjiTask(void const * argument); _Noreturn void manzaiTask(void const * argument); _Noreturn void txTask(void const * argument); // 新增:电机控制和超声波测距任务函数声明 _Noreturn void motorControlTask(void const * argument); // 核心电机控制任务 _Noreturn void ultrasonicTask(void const * argument); // 超声波测距任务 /* USER CODE END FunctionPrototypes */ void StartDefaultTask(void const * argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /* GetIdleTaskMemory prototype (linked to static allocation support) */ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); /* USER CODE BEGIN GET_IDLE_TASK_MEMORY */ static StaticTask_t xIdleTaskTCBBuffer; static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) { *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; *ppxIdleTaskStackBuffer = &xIdleStack[0]; *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* place for user code */ } /* USER CODE END GET_IDLE_TASK_MEMORY */ /** * @brief FreeRTOS initialization * @param None * @retval None */ void MX_FREERTOS_Init(void) { /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* USER CODE BEGIN RTOS_MUTEX */ osMutexDef(uartMutex); osMutexId uartMutexHandle = osMutexCreate(osMutex(uartMutex)); /* USER CODE END RTOS_MUTEX */ /* Create the semaphores(s) */ /* definition and creation of motor */ osSemaphoreDef(motor); motorHandle = osSemaphoreCreate(osSemaphore(motor), 1); /* definition and creation of motor2 */ osSemaphoreDef(motor2); motor2Handle = osSemaphoreCreate(osSemaphore(motor2), 1); /* definition and creation of rxlubancat */ osSemaphoreDef(rxlubancat); rxlubancatHandle = osSemaphoreCreate(osSemaphore(rxlubancat), 1); /* definition and creation of rxpingmu */ osSemaphoreDef(rxpingmu); rxpingmuHandle = osSemaphoreCreate(osSemaphore(rxpingmu), 1); osSemaphoreDef(manzaiSignal); manzaiSignalHandle = osSemaphoreCreate(osSemaphore(manzaiSignal), 1); /* definition and creation of bujingdianji */ osSemaphoreDef(bujingdianji); bujingdianjiHandle = osSemaphoreCreate(osSemaphore(bujingdianji), 1); /* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ /* USER CODE END RTOS_SEMAPHORES */ HAL_UART_Receive_IT(&huart1, (uint8_t *)&uart3_rx.datarx, 1); HAL_UART_Receive_IT(&huart6, (uint8_t *)&uart2_rx.datarx, 1); HAL_NVIC_SetPriority(USART1_IRQn, 6, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); HAL_NVIC_SetPriority(USART6_IRQn, 6, 0); HAL_NVIC_EnableIRQ(USART6_IRQn); /* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */ /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Create the thread(s) */ /* definition and creation of defaultTask */ osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128); defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ // osThreadDef(motorTask, motorTask, osPriorityNormal, 0, 128); // 添加舵机初始化 //__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 1300); // 舵机1初始位置 //__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 2030); // 舵机2初始位置 // HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); // 启动PWM输出 // HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2); // servoState = SERVO_IDLE; // 设置初始状态 // motorTaskHandle = osThreadCreate(osThread(motorTask), NULL); // 保留现有的舵机控制任务 osThreadDef(motor2Task, motor2Task, osPriorityAboveNormal, 0, 128); motor2TaskHandle = osThreadCreate(osThread(motor2Task), NULL); // 保留现有的满载检测任务 osThreadDef(manzaiTask, manzaiTask, osPriorityNormal, 0, 128); manzaiTaskHandle = osThreadCreate(osThread(manzaiTask), NULL); // 保留现有的串口屏通讯任务 osThreadDef(txTask, txTask, osPriorityNormal, 2, 128); txTaskHandle = osThreadCreate(osThread(txTask), NULL); // 新增:电机控制任务 osThreadDef(motorControlTask, motorControlTask, osPriorityNormal, 0, 256); motorControlTaskHandle = osThreadCreate(osThread(motorControlTask), NULL); // 新增:超声波测距任务 osThreadDef(ultrasonicTask, ultrasonicTask, osPriorityLow, 0, 256); ultrasonicTaskHandle = osThreadCreate(osThread(ultrasonicTask), NULL); /* USER CODE END RTOS_THREADS */ } /* USER CODE BEGIN Header_StartDefaultTask */ /** * @brief Function implementing the defaultTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartDefaultTask */ void StartDefaultTask(void const * argument) { /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ for(;;) { xSemaphoreTake(rxpingmuHandle,portMAX_DELAY); switch (uart2_rx.data[1]) { case 1: uart2_rx.shexiangtou_en=0; break; case 0: uart2_rx.shexiangtou_en=1; break; case 3: uart2_rx.manzaijianche_en=0; break; case 2: uart2_rx.manzaijianche_en=1; break; case 4: uart2_rx.dangban_en=0; break; case 5: uart2_rx.dangban_en=1; break; case 6: uart2_rx.youhailaji_en=0; break; case 7: uart2_rx.youhailaji_en=1; break; case 8: uart2_rx.chuyulaji_en=0; break; case 9: uart2_rx.chuyulaji_en=1; break; case 10: uart2_rx.kehuishou_en=0; break; case 11: uart2_rx.kehuishou_en=1; break; case 12: uart2_rx.qitalaji_en=0; break; case 13: uart2_rx.qitalaji_en=1; break; default: break; } osDelay(100); } /* USER CODE END StartDefaultTask */ } /* Private application code --------------------------------------------------*/ /* USER CODE BEGIN Application */ /* _Noreturn void motorTask(void const * argument) { for(;;) { xSemaphoreTake(motorHandle,portMAX_DELAY); // __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,1410); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,1500); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,1000); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_3,1000); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_4,1000); osDelay(1000); xSemaphoreGive(motor2Handle); xSemaphoreTake(motorHandle,portMAX_DELAY); // __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,1050); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,1500); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,1500); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_3,1500); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_4,1500); osDelay(1000); } } */ // 保留现有的舵机控制任务 - 增加状态跟踪 _Noreturn void motor2Task(void const * argument) { // 上电首次执行初始化动作 __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 1300); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 2030); osDelay(500); // 确保舵机到位 servoState = SERVO_IDLE; for(;;) { xSemaphoreTake(motor2Handle, portMAX_DELAY); // 🎯 设置舵机工作状态 servoState = SERVO_WORKING; //servoWorkStartTime = HAL_GetTick(); switch (uart3_rx.class) { case 0: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,1300); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,2430); break; case 1: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,1300); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,1570); break; case 2: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,2000); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,2430); break; case 3: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,2000); osDelay(500); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,1570); break; default: __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,1300); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,2030); break; } osDelay(1000); // 执行分类动作的延时 // 🎯 设置舵机回到原位状态 servoState = SERVO_RETURNING; __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,1300); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,2030); osDelay(1000); // 回到原位的延时 // 🎯 设置舵机空闲状态 servoState = SERVO_IDLE; } osDelay(10); } // 保留现有的满载检测任务 _Noreturn void manzaiTask(void const * argument) { for(;;) { osDelay(100); if(HAL_GPIO_ReadPin(load1_GPIO_Port,load1_Pin)==0 || HAL_GPIO_ReadPin(load2_GPIO_Port,load2_Pin)==0 || HAL_GPIO_ReadPin(load3_GPIO_Port,load3_Pin)==0 || HAL_GPIO_ReadPin(load4_GPIO_Port,load4_Pin)==0) { pingmu_tx.manzai=1; //xSemaphoreGive(rxlubancatHandle); xSemaphoreGive(manzaiSignalHandle); // 使用独立信号量 } xSemaphoreTake(manzaiSignalHandle, portMAX_DELAY); // 等待满载信号 } } // 保留现有的串口屏通讯任务 _Noreturn void txTask(void const * argument) { int num=0; const char manzaidata[]={0x74,0x30,0x2E,0x74,0x78,0x74,0x3D,0x22,0xC0,0xAC,0xBB, 0xF8,0xC2,0xFA,0xD4,0xD8,0x22,0xff,0xff,0xff}; // const char kongdata[]={0x74,0x30,0x2E,0x74,0x78,0x74,0x3D,0x22,0x20,0x22,0xff,0xff,0xff}; char play[]={0x70,0x6C,0x61,0x79,0x20,0x30,0x2C,0x30,0x2C,0x30}; unsigned char aa[2]={0}; const char start[]={0x64,0x61,0x74,0x61,0x30,0x2E ,0x69 ,0x6E ,0x73 ,0x65 ,0x72 ,0x74 ,0x28 ,0x22 }; const char end[]={0x22,0x29,0xff,0xff,0xff}; const char end2[]={0xff,0xff,0xff}; //塑料 const char data1[]={0x5E,0xCD,0xC1,0xB6,0xB9,'\0'}; //白色瓶 const char data2[]={0x5E ,0xB0 ,0xD7 ,0xC2 ,0xDC ,0xB2 ,0xB7 ,'\0'}; //红色瓶 const char data3[]={0x5E ,0xBA ,0xFA ,0xC2 ,0xDC ,0xB2 ,0xB7 ,'\0'}; //纸片 const char data4[]={0x5E ,0xD6 ,0xBD ,0xB1 ,0xAD ,'\0'}; //石头 const char data5[]={0x5E ,0xCA ,0xAF ,0xCD ,0xB7 ,'\0'}; //玻片 const char data6[]={0x5E ,0xB4,0xC9 ,0xC6 ,0xAC ,'\0'}; //5号电池 const char data7[]={0x5E ,0x35 ,0xBA ,0xC5 ,0xB5 ,0xE7 ,0xB3 ,0xD8 ,'\0'}; //1号电池 const char data8[]={0x5E ,0x31 ,0xBA ,0xC5 ,0xB5 ,0xE7 ,0xB3 ,0xD8 ,'\0'}; //有害垃圾 const char data10[]={0x5E ,0xD3 ,0xD0 ,0xBA ,0xA6 ,0xC0 ,0xAC ,0xBB ,0xF8 ,0x5E,'\0'}; //厨余垃圾 const char data11[]={0x5E ,0xB3 ,0xF8 ,0xD3 ,0xE0 ,0xC0 ,0xAC ,0xBB ,0xF8 ,0x5E,'\0'}; //可回收垃圾 const char data12[]={0x5E ,0xBF ,0xC9 ,0xBB ,0xD8 ,0xCA ,0xD5 ,0xC0 ,0xAC ,0xBB ,0xF8 ,0x5E,'\0'}; //其他垃圾 const char data13[]={0x5E ,0xC6 ,0xE4 ,0xCB ,0xFB ,0xC0 ,0xAC ,0xBB ,0xF8 ,0x5E,'\0'}; const char* data[]={data8,data4,data7,data5,data6,data2,data3,data1,data1,data1,data1}; uart2_rx.manzaijianche_en=0; uart2_rx.shexiangtou_en=1; for(;;) { xSemaphoreTake(rxlubancatHandle,portMAX_DELAY); if(uart3_rx.ok && uart2_rx.shexiangtou_en ==1 ){ uart3_rx.ok=0; HAL_GPIO_TogglePin(led0_GPIO_Port,led0_Pin); uart3_rx.class = uart3_rx.data[1] - 0x30; xSemaphoreGive(motor2Handle); // 触发舵机动作 uart3_rx.class=uart3_rx.data[1]-0x30; if(uart3_rx.class<0 || uart3_rx.class>9) uart3_rx.class=11; aa[1]=num%10+0x30; aa[0]=num/10+0x30; HAL_UART_Transmit(&huart6, (uint8_t *) start,sizeof(start),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); switch (uart3_rx.class) { case 0: case 2: HAL_UART_Transmit(&huart6, (uint8_t *) data[uart3_rx.class], strlen(data[uart3_rx.class]),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) data10, strlen(data10),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end, sizeof(end),0xFFFF); play[7]=0x30; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); break;//有害垃圾 case 5: case 6: case 7: HAL_UART_Transmit(&huart6, (uint8_t *) data[uart3_rx.class], strlen(data[uart3_rx.class]),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) data11, strlen(data11),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end, sizeof(end),0xFFFF); play[7]=0x31; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); break;//厨余垃圾 case 1: HAL_UART_Transmit(&huart6, (uint8_t *) data[uart3_rx.class], strlen(data[uart3_rx.class]),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) data12, strlen(data12),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end, sizeof(end),0xFFFF); play[7]=0x32; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); break;//可回收垃圾 case 3: case 4: HAL_UART_Transmit(&huart6, (uint8_t *) data[uart3_rx.class], strlen(data[uart3_rx.class]),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) data13, strlen(data13),0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *)aa, 2,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end, sizeof(end),0xFFFF); play[7]=0x33; HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); break;//其他垃圾 default: break; } //xSemaphoreGive(motor2Handle); num++; if(num>99)num=0; osDelay(2000); } if(pingmu_tx.manzai==1 && uart2_rx.manzaijianche_en==1){ //HAL_UART_Transmit(&huart6, (uint8_t *) manzaidata, 20,0xFFFF),pingmu_tx.manzai=0; HAL_UART_Transmit(&huart6, manzaidata, sizeof(manzaidata), 100); play[7]=0x34; HAL_UART_Transmit(&huart6, play, 10, 100); HAL_UART_Transmit(&huart6, end2, sizeof(end2), 100); //HAL_UART_Transmit(&huart6, (uint8_t *) play, 10,0xFFFF); //HAL_UART_Transmit(&huart6, (uint8_t *) end2, sizeof(end2),0xFFFF); pingmu_tx.manzai=0; osDelay(2000); } } } // ========== 🎯 新增:电机控制任务 ========== // 功能:控制两个电机的PWM速度,与舵机控制分开 // 电机1:PA6 (TIM3_CH1) // 电机2:PA7 (TIM3_CH2) _Noreturn void motorControlTask(void const * argument) { uint32_t tickCounter = 0; // 延迟启动 osDelay(1000); for(;;) { // 电机现在由超声波任务自动控制,这里只做周期性检查 if(tickCounter % 50 == 0) { // 可以在这里添加电机状态检查逻辑 } tickCounter++; osDelay(100); } } // ========== 🎯 新增:超声波测距函数 ========== // 简化版本,避免任务阻塞,返回距离值(cm*10) int32_t measureDistanceInt(GPIO_TypeDef* trig_port, uint16_t trig_pin, GPIO_TypeDef* echo_port, uint16_t echo_pin) { volatile uint32_t count = 0; volatile uint32_t time_count = 0; // 1. 确保Trig引脚为低电平 HAL_GPIO_WritePin(trig_port, trig_pin, GPIO_PIN_RESET); // 短暂延时 for(volatile int i = 0; i < 1000; i++) __NOP(); // 2. 发送10μs触发脉冲 HAL_GPIO_WritePin(trig_port, trig_pin, GPIO_PIN_SET); // 10μs延时 @168MHz for(volatile int i = 0; i < 1680; i++) __NOP(); HAL_GPIO_WritePin(trig_port, trig_pin, GPIO_PIN_RESET); // 3. 等待Echo上升沿,超时保护 // count = 0; while(HAL_GPIO_ReadPin(echo_port, echo_pin) == GPIO_PIN_RESET) { count++; if(count > 300000) { return -1; // 等待上升沿超时 } } // 4. 测量Echo高电平持续时间 time_count = 0; while(HAL_GPIO_ReadPin(echo_port, echo_pin) == GPIO_PIN_SET) { time_count++; if(time_count > 500000) { return -2; // 高电平持续过长 } } // 5. 计算距离 int32_t distance_x10 = (time_count * 50) / 1000; // 6. 范围检查:1-100cm if(distance_x10 < 10 || distance_x10 > 1000) { return -3; // 超出合理范围 } return distance_x10; } // ========== 🎯 新增:超声波测距任务 ========== // 真实测距版本,控制电机运行,与舵机同步,不使用USART1发送 _Noreturn void ultrasonicTask(void const * argument) { uint32_t counter = 0; int32_t distance1, distance2; for(;;) { // 测量超声波模块1 (PB2->PD8) distance1 = measureDistanceInt(GPIOB, GPIO_PIN_2, GPIOD, GPIO_PIN_8); // 间隔300ms避免干扰 osDelay(300); // 测量超声波模块2 (PB3->PD9) distance2 = measureDistanceInt(GPIOB, GPIO_PIN_3, GPIOD, GPIO_PIN_9); // ========== 🎯 电机控制逻辑 - 与舵机同步 + 启动停止延时500ms ========== uint32_t currentTime = HAL_GetTick(); // ========== 电机1控制逻辑 ========== if(distance1 > 100 && servoState == SERVO_IDLE) { // distance1是cm*10,所以100表示10cm // 满足启动条件 motor1_stopConditionActive = 0; // 清除停止条件 motor1_stopConditionStartTime = 0; if(motor1_running == 0) { // 电机未运行,需要启动(延时500ms) if(motor1_startConditionActive == 0) { // 刚开始满足启动条件,记录时间 motor1_startConditionActive = 1; motor1_startConditionStartTime = currentTime; } else { // 已经在启动条件中,检查是否已经持续500ms if((currentTime - motor1_startConditionStartTime) >= 500) { // 启动条件持续500ms,真正启动电机 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 6000); // PA6, 30%速度 motor1_running = 1; motor1_startConditionActive = 0; } } } else { // 电机已运行,继续运行 motor1_startConditionActive = 0; // 清除启动条件 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 6000); // PA6, 30%速度 } } else { // 满足停止条件 motor1_startConditionActive = 0; // 清除启动条件 motor1_startConditionStartTime = 0; if(motor1_running == 1) { // 电机正在运行,需要停止(延时500ms) if(motor1_stopConditionActive == 0) { // 刚开始满足停止条件,记录时间 motor1_stopConditionActive = 1; motor1_stopConditionStartTime = currentTime; } else { // 已经在停止条件中,检查是否已经持续500ms if((currentTime - motor1_stopConditionStartTime) >= 500) { // 停止条件持续500ms,真正停止电机 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 停止 motor1_running = 0; motor1_stopConditionActive = 0; } } } else { // 电机已停止,保持停止状态 motor1_stopConditionActive = 0; // 清除停止条件 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 确保停止 } } // ========== 电机2控制逻辑 ========== if(distance2 > 100 && servoState == SERVO_IDLE) { // distance2是cm*10,所以100表示10cm // 满足启动条件 motor2_stopConditionActive = 0; // 清除停止条件 motor2_stopConditionStartTime = 0; if(motor2_running == 0) { // 电机未运行,需要启动(延时500ms) if(motor2_startConditionActive == 0) { // 刚开始满足启动条件,记录时间 motor2_startConditionActive = 1; motor2_startConditionStartTime = currentTime; } else { // 已经在启动条件中,检查是否已经持续500ms if((currentTime - motor2_startConditionStartTime) >= 500) { // 启动条件持续500ms,真正启动电机 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 6000); // PA7, 30%速度 motor2_running = 1; motor2_startConditionActive = 0; } } } else { // 电机已运行,继续运行 motor2_startConditionActive = 0; // 清除启动条件 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 6000); // PA7, 30%速度 } } else { // 满足停止条件 motor2_startConditionActive = 0; // 清除启动条件 motor2_startConditionStartTime = 0; if(motor2_running == 1) { // 电机正在运行,需要停止(延时500ms) if(motor2_stopConditionActive == 0) { // 刚开始满足停止条件,记录时间 motor2_stopConditionActive = 1; motor2_stopConditionStartTime = currentTime; } else { // 已经在停止条件中,检查是否已经持续500ms if((currentTime - motor2_stopConditionStartTime) >= 500) { // 停止条件持续500ms,真正停止电机 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); // 停止 motor2_running = 0; motor2_stopConditionActive = 0; } } } else { // 电机已停止,保持停止状态 motor2_stopConditionActive = 0; // 清除停止条件 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0); // 确保停止 } } counter++; osDelay(1200); // 每1.5秒测量一次 } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Prevent unused argument(s) compilation warning */ // UNUSED(huart); /* NOTE: This function Should not be modified, when the callback is needed, the HAL_UART_TxCpltCallback could be implemented in the user file */ BaseType_t xHigherPriorityTaskWoken = pdFALSE; if(huart ->Instance == USART6){ if(uart2_rx.datarx== 0x70) uart2_rx.num=0; uart2_rx.data[uart2_rx.num]=uart2_rx.datarx; uart2_rx.num++; if(uart2_rx.num>2){ uart2_rx.num=0; if(uart2_rx.data[2]==0x71){ uart2_rx.ok=1; xSemaphoreGiveFromISR(rxpingmuHandle, &xHigherPriorityTaskWoken); } } HAL_UART_Receive_IT(&huart6, (uint8_t *)&uart2_rx.datarx, 1); } if(huart ->Instance == USART1){ HAL_GPIO_TogglePin(led1_GPIO_Port,led1_Pin); if(uart3_rx.datarx=='@') uart3_rx.num=0; uart3_rx.data[uart3_rx.num]=uart3_rx.datarx; uart3_rx.num++; if(uart3_rx.num>=28){ uart3_rx.num=0; if(uart3_rx.data[27]==']'){ uart3_rx.ok=1; xSemaphoreGiveFromISR(rxlubancatHandle, &xHigherPriorityTaskWoken); } uart3_rx.num = 0; // 重置缓冲区 } HAL_UART_Receive_IT(&huart1, (uint8_t *)&uart3_rx.datarx, 1); } portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } /* USER CODE END Application */ 此程序中串口六无法发送数据至串口屏是为什么,该怎么解决

最新推荐

recommend-type

开发界面语义化:声控 + 画图协同生成代码.doc

开发界面语义化:声控 + 画图协同生成代码.doc
recommend-type

LABVIEW与三菱PLC通信:实现数据批量读写的高效库解决方案

如何通过LabVIEW与三菱PLC建立高效的通信桥梁,实现数据批量读写。首先概述了LabVIEW和三菱PLC的基本概念及其在工业自动化中的重要性。接着重点讲解了利用Modbus RTU协议构建通信连接的具体步骤和技术细节,包括初始化通信、发送读写请求、处理响应数据和关闭连接等功能。文中还提供了一个简化的代码示例,展示了如何在LabVIEW环境中实现这一过程。最后对这项技术进行了总结和展望,强调其在提高数据交互效率方面的潜力以及未来的广泛应用前景。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是那些熟悉LabVIEW或三菱PLC的人士。 使用场景及目标:适用于需要频繁进行数据交互的工业控制系统,如生产线监控、设备状态监测等场合。主要目的是提升数据传输的速度和可靠性,从而优化整个系统的运行效率。 阅读建议:读者可以通过本文深入了解LabVIEW与三菱PLC通信的实现方法,掌握批量数据读写库的设计思路,并将其应用于实际工程项目中。建议边阅读边尝试动手实践相关代码,以便更好地理解和吸收所学知识。
recommend-type

欧姆龙PLC NJ系列模切机程序:高级伺服运动与张力控制的应用实例

欧姆龙PLC NJ系列模切机项目的编程细节及其关键技术。主要内容涵盖12轴EtherCAT总线伺服运动控制,包括回零、点动、定位和速度控制;张力控制采用PID算法并进行收放卷径计算;隔膜自动纠偏控制利用模拟量数据平均化处理;同步运动控制实现凸轮表追剪和裁切;以及结构化编程和ST语言功能块的使用。项目结构规范,注释详尽,有助于理解和维护代码。通过本项目的学习,可以掌握PLC高端复杂应用的实际操作技能。 适合人群:从事工业自动化领域的工程师和技术人员,特别是对PLC编程和伺服运动控制有浓厚兴趣的人群。 使用场景及目标:适用于需要深入了解PLC编程技巧和自动化控制系统原理的技术人员。目标是提升编程能力和对复杂自动化系统的工作机制的理解。 其他说明:本文不仅提供具体的编程指导,还强调了项目管理和代码规范的重要性,为读者提供了全面的学习体验。
recommend-type

大班主题性区域活动计划表.doc

大班主题性区域活动计划表.doc
recommend-type

高校教研室工作计划.doc

高校教研室工作计划.doc
recommend-type

Python程序TXLWizard生成TXL文件及转换工具介绍

### 知识点详细说明: #### 1. 图形旋转与TXL向导 图形旋转是图形学领域的一个基本操作,用于改变图形的方向。在本上下文中,TXL向导(TXLWizard)是由Esteban Marin编写的Python程序,它实现了特定的图形旋转功能,主要用于电子束光刻掩模的生成。光刻掩模是半导体制造过程中非常关键的一个环节,它确定了在硅片上沉积材料的精确位置。TXL向导通过生成特定格式的TXL文件来辅助这一过程。 #### 2. TXL文件格式与用途 TXL文件格式是一种基于文本的文件格式,它设计得易于使用,并且可以通过各种脚本语言如Python和Matlab生成。这种格式通常用于电子束光刻中,因为它的文本形式使得它可以通过编程快速创建复杂的掩模设计。TXL文件格式支持引用对象和复制对象数组(如SREF和AREF),这些特性可以用于优化电子束光刻设备的性能。 #### 3. TXLWizard的特性与优势 - **结构化的Python脚本:** TXLWizard 使用结构良好的脚本来创建遮罩,这有助于开发者创建清晰、易于维护的代码。 - **灵活的Python脚本:** 作为Python程序,TXLWizard 可以利用Python语言的灵活性和强大的库集合来编写复杂的掩模生成逻辑。 - **可读性和可重用性:** 生成的掩码代码易于阅读,开发者可以轻松地重用和修改以适应不同的需求。 - **自动标签生成:** TXLWizard 还包括自动为图形对象生成标签的功能,这在管理复杂图形时非常有用。 #### 4. TXL转换器的功能 - **查看.TXL文件:** TXL转换器(TXLConverter)允许用户将TXL文件转换成HTML或SVG格式,这样用户就可以使用任何现代浏览器或矢量图形应用程序来查看文件。 - **缩放和平移:** 转换后的文件支持缩放和平移功能,这使得用户在图形界面中更容易查看细节和整体结构。 - **快速转换:** TXL转换器还提供快速的文件转换功能,以实现有效的蒙版开发工作流程。 #### 5. 应用场景与技术参考 TXLWizard的应用场景主要集中在电子束光刻技术中,特别是用于设计和制作半导体器件时所需的掩模。TXLWizard作为一个向导,不仅提供了生成TXL文件的基础框架,还提供了一种方式来优化掩模设计,提高光刻过程的效率和精度。对于需要进行光刻掩模设计的工程师和研究人员来说,TXLWizard提供了一种有效的方法来实现他们的设计目标。 #### 6. 系统开源特性 标签“系统开源”表明TXLWizard遵循开放源代码的原则,这意味着源代码对所有人开放,允许用户自由地查看、修改和分发软件。开源项目通常拥有活跃的社区,社区成员可以合作改进软件,添加新功能,或帮助解决遇到的问题。这种开放性促进了技术创新,并允许用户根据自己的需求定制软件。 #### 7. 压缩包子文件的文件名称列表 文件名称列表中的“txlwizard-master”可能指的是TXLWizard项目的主版本库或主分支。这个名称表明了这是项目源代码的中心点,其他开发者会从这个主分支拉取代码进行合作开发或部署。以“-master”结尾通常是版本控制系统中表示主要开发线路的常见约定,例如Git中的master(现在更常被称为main)分支。 通过这些知识点的详细解释,我们可以看到TXLWizard不仅是一个用于生成TXL文件的工具,它还整合了一系列的功能,使得电子束光刻掩模的设计工作更为高效和直观。同时,作为一个开源项目,它能够借助社区的力量不断进步,为用户带来更多的便利和创新。
recommend-type

【创新图生成:扣子平台的技术前沿与创新思维】:引领图像生成技术的新潮流

# 1. 扣子平台的图像生成技术概述 在当今数字化时代,图像生成技术正成为推动技术创新和社会变革的关键力量。扣子平台正是这一技术革新的代表。本章将对扣子平台的图像生成技术进行一个全面概述,探究它如何将理论技术转化为实际应用,并带来显著的社会影响。 扣子平台运用了先进的图像生成技术,将现实世界和数字空间无缝融合,打造了沉浸式的视觉体验。其技术的核心是通过高度复杂的算法模型,快速生成高质
recommend-type

海康威视机器视觉工程师考核

<think>好的,我现在需要帮助用户了解海康威视机器视觉工程师的考核内容和要求。根据用户提供的引用资料,特别是引用[1]和[2],里面提到了考核素材包分为初级和中级,涵盖理论、算法、应用案例等。首先,我要整理这些信息,确保结构清晰,符合用户要求的格式。 接下来,我需要确认素材包的具体内容,比如初级和中级的不同点。引用[2]提到初级包含基础理论、算法实现和实际案例,中级则增加复杂算法和项目分析。这部分需要分点说明,方便用户理解层次。 另外,用户可能想知道如何准备考核,比如下载素材、学习顺序、模拟考核等,引用[2]中有使用说明和注意事项,这部分也要涵盖进去。同时要注意提醒用户考核窗口已关闭,
recommend-type

Linux环境下Docker Hub公共容器映像检测工具集

在给出的知识点中,我们需要详细解释有关Docker Hub、公共容器映像、容器编排器以及如何与这些工具交互的详细信息。同时,我们会涵盖Linux系统下的相关操作和工具使用,以及如何在ECS和Kubernetes等容器编排工具中运用这些检测工具。 ### Docker Hub 和公共容器映像 Docker Hub是Docker公司提供的一项服务,它允许用户存储、管理以及分享Docker镜像。Docker镜像可以视为应用程序或服务的“快照”,包含了运行特定软件所需的所有必要文件和配置。公共容器映像指的是那些被标记为公开可见的Docker镜像,任何用户都可以拉取并使用这些镜像。 ### 静态和动态标识工具 静态和动态标识工具在Docker Hub上用于识别和分析公共容器映像。静态标识通常指的是在不运行镜像的情况下分析镜像的元数据和内容,例如检查Dockerfile中的指令、环境变量、端口映射等。动态标识则需要在容器运行时对容器的行为和性能进行监控和分析,如资源使用率、网络通信等。 ### 容器编排器与Docker映像 容器编排器是用于自动化容器部署、管理和扩展的工具。在Docker环境中,容器编排器能够自动化地启动、停止以及管理容器的生命周期。常见的容器编排器包括ECS和Kubernetes。 - **ECS (Elastic Container Service)**:是由亚马逊提供的容器编排服务,支持Docker容器,并提供了一种简单的方式来运行、停止以及管理容器化应用程序。 - **Kubernetes**:是一个开源平台,用于自动化容器化应用程序的部署、扩展和操作。它已经成为容器编排领域的事实标准。 ### 如何使用静态和动态标识工具 要使用这些静态和动态标识工具,首先需要获取并安装它们。从给定信息中了解到,可以通过克隆仓库或下载压缩包并解压到本地系统中。之后,根据需要针对不同的容器编排环境(如Dockerfile、ECS、Kubernetes)编写配置,以集成和使用这些检测工具。 ### Dockerfile中的工具使用 在Dockerfile中使用工具意味着将检测工具的指令嵌入到构建过程中。这可能包括安装检测工具的命令、运行容器扫描的步骤,以及将扫描结果集成到镜像构建流程中,确保只有通过安全和合规检查的容器镜像才能被构建和部署。 ### ECS与Kubernetes中的工具集成 在ECS或Kubernetes环境中,工具的集成可能涉及到创建特定的配置文件、定义服务和部署策略,以及编写脚本或控制器来自动执行检测任务。这样可以在容器编排的过程中实现实时监控,确保容器编排器只使用符合预期的、安全的容器镜像。 ### Linux系统下的操作 在Linux系统下操作这些工具,用户可能需要具备一定的系统管理和配置能力。这包括使用Linux命令行工具、管理文件系统权限、配置网络以及安装和配置软件包等。 ### 总结 综上所述,Docker Hub上的静态和动态标识工具提供了一种方法来检测和分析公共容器映像,确保这些镜像的安全性和可靠性。这些工具在Linux开发环境中尤为重要,因为它们帮助开发人员和运维人员确保他们的容器映像满足安全要求。通过在Dockerfile、ECS和Kubernetes中正确使用这些工具,可以提高应用程序的安全性,减少由于使用不安全的容器镜像带来的风险。此外,掌握Linux系统下的操作技能,可以更好地管理和维护这些工具,确保它们能够有效地发挥作用。
recommend-type

【扣子平台图像艺术探究:理论与实践的完美结合】:深入学习图像生成的艺术

# 1. 图像艺术的理论基础 艺术领域的每一个流派和技巧都有其理论基础。在图像艺术中,理论基础不仅是对艺术表现形式的认知,也是掌握艺术创作内在逻辑的关键。深入理解图像艺术的理论基础,能够帮助艺术家们在创作过程中更加明确地表达自己的艺术意图,以及更好地与观众沟通。 图像艺术的理论