编译能过,但没烧录试
4
- admin管理员2小时前
/* * 板子: Generic STM32F4 series -> STM32F407VGT6 * HSE: 12MHz, 系统时钟: 168MHz * * 功能说明: * 1. SoftSerial (PA9 TX, PA10 RX) - 115200bps, 接CH340 Type-C, 调试和监控 (软件串口) * 2. USART2 (PA2 TX, PA3 RX) - 300bps, 接井下设备 (硬件串口) * 3. USART1 (PB6 RX, PB7 TX, PB5 EN) - RS485通信 (硬件串口) * 注意:PB6/PB7是USART1的默认复用引脚 * 4. PA0/PA1 差分输入捕获 - 测量脉冲宽度 * * 通信流转: * - RS485接收 -> SoftSerial输出 + USART2转发 * - SoftSerial接收 -> RS485发送 * - USART2接收 -> RS485发送 */ #include <Arduino.h> #include <SoftwareSerial.h> // ==================== 系统配置 ==================== #define SYS_CLOCK_HZ 168000000UL // 系统时钟168MHz #define APB1_CLOCK_HZ 42000000UL // APB1时钟42MHz #define APB2_CLOCK_HZ 84000000UL // APB2时钟84MHz // ==================== 定时器配置 ==================== #define TIMER_CLOCK_HZ 84000000UL // TIM2时钟84MHz #define PRESCALER 41 // 预分频 (84M/(41+1)=2MHz) #define TIMER_STEP_US 0.5f // 计数步长 0.5μs // ==================== 波特率配置 ==================== #define SOFT_SERIAL_BAUDRATE 115200 // 软件串口调试口 (高速) #define USART1_BAUDRATE 4800 // RS485通信 #define USART2_BAUDRATE 300 // 井下设备 // ==================== 引脚定义 ==================== // 软件串口: PA9(TX), PA10(RX) - 115200bps CH340 (软件模拟) // USART1: PB6(RX), PB7(TX), PB5(EN) - RS485 (硬件) // USART2: PA2(TX), PA3(RX) - 300bps 井下设备 (硬件) // ==================== 软件串口定义 ==================== SoftwareSerial softSerial(PA10, PA9); // RX, TX (注意:SoftwareSerial参数顺序是RX, TX) // ==================== 全局变量 ==================== // 脉冲捕获相关 volatile uint32_t last_capture_ch1 = 0; volatile uint32_t last_capture_ch2 = 0; volatile bool new_capture_ready_ch1 = false; volatile bool new_capture_ready_ch2 = false; volatile uint32_t overflow_count_ch1 = 0; volatile uint32_t overflow_count_ch2 = 0; volatile uint32_t pulse_width_ticks_ch1 = 0; volatile uint32_t pulse_width_ticks_ch2 = 0; // RS485控制 volatile bool rs485_tx_mode = false; // ==================== 中断处理函数 ==================== #ifdef __cplusplus extern "C" { #endif // TIM2_CH1/CH2 捕获中断 (PA0, PA1) __attribute__((weak)) void TIM2_IRQHandler(void) { // 处理CH1捕获中断 (PA0) if (TIM2->SR & TIM_SR_CC1IF) { TIM2->SR &= ~TIM_SR_CC1IF; uint32_t current_capture = TIM2->CCR1; // 计算脉冲宽度(考虑溢出) if (overflow_count_ch1 > 0 || current_capture < last_capture_ch1) { uint32_t period = TIM2->ARR + 1; pulse_width_ticks_ch1 = (period - last_capture_ch1) + current_capture + (overflow_count_ch1 - 1) * period; } else { pulse_width_ticks_ch1 = current_capture - last_capture_ch1; } overflow_count_ch1 = 0; last_capture_ch1 = current_capture; new_capture_ready_ch1 = true; } // 处理CH2捕获中断 (PA1) if (TIM2->SR & TIM_SR_CC2IF) { TIM2->SR &= ~TIM_SR_CC2IF; uint32_t current_capture = TIM2->CCR2; if (overflow_count_ch2 > 0 || current_capture < last_capture_ch2) { uint32_t period = TIM2->ARR + 1; pulse_width_ticks_ch2 = (period - last_capture_ch2) + current_capture + (overflow_count_ch2 - 1) * period; } else { pulse_width_ticks_ch2 = current_capture - last_capture_ch2; } overflow_count_ch2 = 0; last_capture_ch2 = current_capture; new_capture_ready_ch2 = true; } // 处理更新事件(溢出) if (TIM2->SR & TIM_SR_UIF) { TIM2->SR &= ~TIM_SR_UIF; overflow_count_ch1++; overflow_count_ch2++; // 超时保护 if (overflow_count_ch1 > 1000) { overflow_count_ch1 = 0; last_capture_ch1 = TIM2->CCR1; new_capture_ready_ch1 = false; } if (overflow_count_ch2 > 1000) { overflow_count_ch2 = 0; last_capture_ch2 = TIM2->CCR2; new_capture_ready_ch2 = false; } } } // USART1 (RS485) 接收中断处理 __attribute__((weak)) void USART1_IRQHandler(void) { if (USART1->SR & USART_SR_RXNE) { uint8_t data = USART1->DR; // 转发到软件串口 (调试口) softSerial.write(data); // 转发到USART2 (井下设备) while (!(USART2->SR & USART_SR_TXE)); USART2->DR = data; } } #ifdef __cplusplus } #endif // ==================== 软件串口发送函数 (调试口) ==================== void soft_serial_send_char(char c) { softSerial.write(c); } void soft_serial_send_string(const char* str) { softSerial.print(str); } void soft_serial_send_uint32(uint32_t value) { char buffer[16]; utoa(value, buffer, 10); soft_serial_send_string(buffer); } void soft_serial_send_float(float value, int decimals) { char buffer[32]; dtostrf(value, 1, decimals, buffer); soft_serial_send_string(buffer); } void soft_serial_send_hex(uint8_t value) { char hex[] = "0123456789ABCDEF"; soft_serial_send_char(hex[value >> 4]); soft_serial_send_char(hex[value & 0x0F]); } void soft_serial_send_buffer(uint8_t* buf, uint16_t len) { for (uint16_t i = 0; i < len; i++) { soft_serial_send_char(buf[i]); } } // ==================== USART2 发送函数 (300bps井下设备) ==================== void usart2_send_char(char c) { while (!(USART2->SR & USART_SR_TXE)); USART2->DR = c; } void usart2_send_buffer(uint8_t* buf, uint16_t len) { for (uint16_t i = 0; i < len; i++) { usart2_send_char(buf[i]); } } // ==================== RS485 控制函数 ==================== void rs485_set_mode(bool tx_mode) { rs485_tx_mode = tx_mode; if (tx_mode) { // 发送模式:使能发送,禁用接收 digitalWrite(PB5, HIGH); // 等待使能稳定 delayMicroseconds(10); } else { // 接收模式:使能接收,禁用发送 digitalWrite(PB5, LOW); // 等待使能稳定 delayMicroseconds(10); } } // ==================== USART1 (RS485) 发送函数 ==================== void usart1_send_char(char c) { while (!(USART1->SR & USART_SR_TXE)); USART1->DR = c; } void usart1_send_buffer(uint8_t* buf, uint16_t len) { rs485_set_mode(true); // 切换到发送模式 for (uint16_t i = 0; i < len; i++) { usart1_send_char(buf[i]); } // 等待发送完成 while (!(USART1->SR & USART_SR_TC)); rs485_set_mode(false); // 切换回接收模式 } // ==================== 初始化软件串口 (PA9, PA10) ==================== void init_soft_serial() { // 初始化SoftwareSerial,波特率115200 softSerial.begin(SOFT_SERIAL_BAUDRATE); // 配置引脚模式(SoftwareSerial会自动配置,但手动配置更可靠) // PA9 (TX) - 输出 pinMode(PA9, OUTPUT); // PA10 (RX) - 输入 pinMode(PA10, INPUT); // 等待稳定 delay(100); } // ==================== 初始化USART1 (RS485) ==================== void init_usart1_rs485() { // 启用USART1时钟 (APB2) RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // 配置PB6为复用功能 (RX) GPIOB->MODER &= ~GPIO_MODER_MODER6_Msk; GPIOB->MODER |= GPIO_MODER_MODER6_1; // 复用功能 GPIOB->AFR[0] &= ~GPIO_AFRL_AFSEL6_Msk; GPIOB->AFR[0] |= (7 << GPIO_AFRL_AFSEL6_Pos); // AF7 = USART1 // 配置PB7为复用功能 (TX) GPIOB->MODER &= ~GPIO_MODER_MODER7_Msk; GPIOB->MODER |= GPIO_MODER_MODER7_1; // 复用功能 GPIOB->AFR[0] &= ~GPIO_AFRL_AFSEL7_Msk; GPIOB->AFR[0] |= (7 << GPIO_AFRL_AFSEL7_Pos); // AF7 = USART1 // 配置PB5为485使能控制 (输出) GPIOB->MODER &= ~GPIO_MODER_MODER5_Msk; GPIOB->MODER |= GPIO_MODER_MODER5_0; // 输出模式 GPIOB->OTYPER &= ~GPIO_OTYPER_OT5; // 推挽输出 GPIOB->ODR &= ~GPIO_ODR_OD5; // 初始为接收模式 // 配置USART1: 4800, 8N1 USART1->BRR = APB2_CLOCK_HZ / USART1_BAUDRATE; USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; // 使能发送、接收和接收中断 USART1->CR1 |= USART_CR1_UE; // 使能USART1接收中断 NVIC_SetPriority(USART1_IRQn, 2); NVIC_EnableIRQ(USART1_IRQn); } // ==================== 初始化USART2 (300bps井下设备) ==================== void init_usart2() { // 启用USART2时钟 (APB1) RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // 配置PA2为复用功能 (TX) GPIOA->MODER &= ~GPIO_MODER_MODER2_Msk; GPIOA->MODER |= GPIO_MODER_MODER2_1; // 复用功能 GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL2_Msk; GPIOA->AFR[0] |= (7 << GPIO_AFRL_AFSEL2_Pos); // AF7 = USART2 // 配置PA3为复用功能 (RX) GPIOA->MODER &= ~GPIO_MODER_MODER3_Msk; GPIOA->MODER |= GPIO_MODER_MODER3_1; // 复用功能 GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL3_Msk; GPIOA->AFR[0] |= (7 << GPIO_AFRL_AFSEL3_Pos); // AF7 = USART2 // 配置USART2: 300, 8N1 (低速通信) USART2->BRR = APB1_CLOCK_HZ / USART2_BAUDRATE; USART2->CR1 = USART_CR1_TE | USART_CR1_RE; // 使能发送和接收 USART2->CR1 |= USART_CR1_UE; // 使能USART } // ==================== 初始化TIM2差分输入捕获 ==================== void init_timer2_capture() { // 启用TIM2时钟 (APB1) RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // ===== 配置PA0为TIM2_CH1 (捕获通道1) ===== GPIOA->MODER &= ~GPIO_MODER_MODER0_Msk; GPIOA->MODER |= GPIO_MODER_MODER0_1; // 复用功能 GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL0_Msk; GPIOA->AFR[0] |= (1 << GPIO_AFRL_AFSEL0_Pos); // AF1 = TIM2 // ===== 配置PA1为TIM2_CH2 (捕获通道2) ===== GPIOA->MODER &= ~GPIO_MODER_MODER1_Msk; GPIOA->MODER |= GPIO_MODER_MODER1_1; // 复用功能 GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL1_Msk; GPIOA->AFR[0] |= (1 << GPIO_AFRL_AFSEL1_Pos); // AF1 = TIM2 // ===== 配置TIM2 ===== TIM2->PSC = PRESCALER; // 预分频 41 TIM2->ARR = 0xFFFFFFFF; // 32位自动重载最大值 // ===== 配置通道1 (PA0) ===== TIM2->CCMR1 &= ~TIM_CCMR1_CC1S_Msk; TIM2->CCMR1 |= (1 << TIM_CCMR1_CC1S_Pos); // CC1输入, IC1映射到TI1 TIM2->CCMR1 &= ~(TIM_CCMR1_IC1F_Msk | TIM_CCMR1_IC1PSC_Msk); TIM2->CCMR1 |= (0 << TIM_CCMR1_IC1PSC_Pos); // 无预分频 TIM2->CCMR1 |= (0 << TIM_CCMR1_IC1F_Pos); // 无滤波 // ===== 配置通道2 (PA1) ===== TIM2->CCMR1 &= ~TIM_CCMR1_CC2S_Msk; TIM2->CCMR1 |= (1 << TIM_CCMR1_CC2S_Pos); // CC2输入, IC2映射到TI2 TIM2->CCMR1 &= ~(TIM_CCMR1_IC2F_Msk | TIM_CCMR1_IC2PSC_Msk); TIM2->CCMR1 |= (0 << TIM_CCMR1_IC2PSC_Pos); // 无预分频 TIM2->CCMR1 |= (0 << TIM_CCMR1_IC2F_Pos); // 无滤波 // ===== 配置捕获边沿 ===== // 通道1: 上升沿捕获 TIM2->CCER &= ~TIM_CCER_CC1P_Msk; TIM2->CCER |= TIM_CCER_CC1E_Msk; // 通道2: 上升沿捕获 TIM2->CCER &= ~TIM_CCER_CC2P_Msk; TIM2->CCER |= TIM_CCER_CC2E_Msk; // ===== 使能中断 ===== TIM2->DIER |= TIM_DIER_CC1IE; // 通道1捕获中断 TIM2->DIER |= TIM_DIER_CC2IE; // 通道2捕获中断 TIM2->DIER |= TIM_DIER_UIE; // 更新中断(溢出) // 设置NVIC中断优先级并启用 NVIC_SetPriority(TIM2_IRQn, 1); NVIC_EnableIRQ(TIM2_IRQn); // 清除中断标志 TIM2->SR &= ~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_UIF); // 启动定时器 TIM2->CR1 |= TIM_CR1_CEN; } // ==================== 格式化和输出脉冲宽度 ==================== void output_pulse_width(uint32_t ticks, float step_us, const char* channel_name) { float width_us = ticks * step_us; float width_ms = width_us / 1000.0f; soft_serial_send_string(channel_name); soft_serial_send_string(": "); soft_serial_send_uint32(ticks); soft_serial_send_string(" ticks = "); soft_serial_send_float(width_us, 2); soft_serial_send_string(" us ("); soft_serial_send_float(width_ms, 3); soft_serial_send_string(" ms)"); // 对于串口信号,计算对应的波特率 if (width_us > 0) { float baud_rate = 1000000.0f / width_us; // 如果是单bit脉宽 soft_serial_send_string(" (~"); soft_serial_send_float(baud_rate, 0); soft_serial_send_string(" bps)"); } soft_serial_send_string("\r\n"); } // ==================== setup ==================== void setup() { // 初始化软件串口 (PA9, PA10) - 调试口 115200bps init_soft_serial(); // 初始化硬件串口 init_usart1_rs485(); // RS485 (PB6/PB7) - 4800bps init_usart2(); // 井下设备 (PA2/PA3) - 300bps // 初始化定时器捕获 init_timer2_capture(); // 延时等待稳定 delay(100); // 设置RS485为接收模式 rs485_set_mode(false); // ===== 发送启动信息到软件串口 ===== soft_serial_send_string("\r\n"); soft_serial_send_string("================================================\r\n"); soft_serial_send_string("STM32F407 Multi-Serial & Pulse Measurement\r\n"); soft_serial_send_string("================================================\r\n"); soft_serial_send_string("System Clock: "); soft_serial_send_uint32(SYS_CLOCK_HZ); soft_serial_send_string(" Hz\r\n"); soft_serial_send_string("\r\n"); soft_serial_send_string("Serial Ports:\r\n"); soft_serial_send_string(" SoftSerial: PA9/PA10, 115200bps (Debug - Software)\r\n"); soft_serial_send_string(" USART1: PB6/PB7, 4800bps (RS485 - Hardware)\r\n"); soft_serial_send_string(" USART2: PA2/PA3, 300bps (Downhole - Hardware)\r\n"); soft_serial_send_string("\r\n"); soft_serial_send_string("RS485 Control:\r\n"); soft_serial_send_string(" TX: PB7, RX: PB6, EN: PB5\r\n"); soft_serial_send_string(" Mode: "); soft_serial_send_string(rs485_tx_mode ? "TX" : "RX"); soft_serial_send_string("\r\n"); soft_serial_send_string("\r\n"); soft_serial_send_string("Pulse Capture (TIM2):\r\n"); soft_serial_send_string(" CH1: PA0, CH2: PA1 (Differential)\r\n"); soft_serial_send_string(" Clock: 84MHz, Prescaler: 41, Step: 0.5us\r\n"); soft_serial_send_string("================================================\r\n"); soft_serial_send_string("\r\n"); soft_serial_send_string("Waiting for data...\r\n\r\n"); } // ==================== loop ==================== void loop() { // ===== 1. 处理RS485接收数据 (已在中断中自动转发) ===== // USART1接收中断已经将数据转发到SoftSerial和USART2 // ===== 2. 处理软件串口接收 (调试口 -> RS485) ===== if (softSerial.available()) { char c = softSerial.read(); // 转发到RS485 (USART1) usart1_send_buffer((uint8_t*)&c, 1); // 单字符发送,内部会控制485使能 // 可选:回显到软件串口 // soft_serial_send_char(c); } // ===== 3. 处理USART2接收 (井下设备 -> RS485) ===== if (USART2->SR & USART_SR_RXNE) { char c = USART2->DR; // 转发到RS485 (USART1) usart1_send_buffer((uint8_t*)&c, 1); // 可选:转发到调试口监控 // soft_serial_send_char(c); } // ===== 4. 处理脉冲捕获结果 ===== // 通道1 (PA0) if (new_capture_ready_ch1) { new_capture_ready_ch1 = false; output_pulse_width(pulse_width_ticks_ch1, TIMER_STEP_US, "CH1(PA0)"); } // 通道2 (PA1) if (new_capture_ready_ch2) { new_capture_ready_ch2 = false; output_pulse_width(pulse_width_ticks_ch2, TIMER_STEP_US, "CH2(PA1)"); } // 小延时防止过度占用CPU delayMicroseconds(100); } - 暂无回复