stm32使用rs485进行串口调试

rs485收发数据:

在上一篇中完成:

https://blog.csdn.net/bling_bling_bui/article/details/149027288?spm=1001.2014.3001.5501https://blog.csdn.net/bling_bling_bui/article/details/149027288?spm=1001.2014.3001.5501

重定向printf到USART2 

main.c中添加以下代码,将printf重定向到USART2:

/* USER CODE BEGIN Includes */
#include <stdio.h>  // 添加标准输入输出库
/* USER CODE END Includes */

/* USER CODE BEGIN 0 */
// 重定向printf到USART2
int __io_putchar(int ch) {
    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

// 可选:如果需要scanf,重定向输入
int __io_getchar(void) {
    uint8_t ch;
    HAL_UART_Receive(&huart2, &ch, 1, HAL_MAX_DELAY);
    return ch;
}
/* USER CODE END 0 */

封装带方向控制的printf函数

由于485需要手动控制方向引脚,需要封装一个安全的printf函数:

/* USER CODE BEGIN PFP */
// 封装安全的485打印函数
void RS485_Printf(const char *format, ...) {
    va_list args;
    va_start(args, format);

    // 临时缓冲区(根据需求调整大小)
    char buffer[128];
    int len = vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    if (len > 0) {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // 发送模式
        HAL_UART_Transmit(&huart2, (uint8_t *)buffer, len, HAL_MAX_DELAY);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // 接收模式
    }
}
/* USER CODE END PFP */

 使用示例

int main(void) {
    // 初始化代码...
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // 初始为接收模式

    while (1) {
        RS485_Printf("Temperature: %.1f\r\n", 25.5); // 自定义封装函数
        // 或者直接使用printf(需确保方向控制已处理)
        printf("Hello 485!\r\n"); // 需配合重定向
        HAL_Delay(1000);
    }
}

 关键注意事项

  1. 方向控制时序

    每次调用printfHAL_UART_Transmit前,必须切换为发送模式(CON=低电平),发送完成后立即切回接收模式(CON=高电平)。
  2. 缓冲区大小

    RS485_Printf中的临时缓冲区(如char buffer[128])需根据实际数据长度调整,避免溢出。
  3. 中断安全

    如果在中断中使用printf,需确保方向控制不会被其他中断打断。
  4. 格式化支持

    vsnprintf支持完整的printf格式化(如%f%d),但需在工程选项中启用浮点数支持:Project > Properties > C/C++ Build > Settings > Tool Settings > MCU Settings > Enable float with printf (-u _printf_float)

完整代码

//rs485.c
#include "string.h"
#include "rs485.h"
#include "main.h"
#include <stdio.h>  // 添加标准输入输出库
#include <stdarg.h>  // 用于 va_list, va_start, va_end
#include <string.h>
#define RS485_TX_BUFFER_SIZE  128  // 发送缓冲区大小

volatile uint8_t rs485_tx_buf[128];
volatile uint8_t rs485_tx_busy = 0;

uint8_t rxBuffer[50];
volatile uint8_t usart2_tx_complete = 0; // 发送完成标志
 
extern DMA_HandleTypeDef hdma_usart2_rx;
extern UART_HandleTypeDef huart2;

//// 重定向printf到USART2
//int __io_putchar(int ch) {
//    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
//    return ch;
//}

//// 可选:如果需要scanf,重定向输入
//int __io_getchar(void) {
//    uint8_t ch;
//    HAL_UART_Receive(&huart2, &ch, 1, HAL_MAX_DELAY);
//    return ch;
//}


void RS485_Printf(const char *format, ...) {
    if (rs485_tx_busy) {
        return; // 或加入队列等待
    }

    va_list args;
    va_start(args, format);
    int len = vsnprintf((char *)rs485_tx_buf, sizeof(rs485_tx_buf), format, args);
    va_end(args);

    if (len > 0) {
        rs485_tx_busy = 1;
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // 发送模式
        HAL_UART_Transmit_DMA(&huart2, (uint8_t *)rs485_tx_buf, len); // DMA发送
    }
}

uint8_t RS485_IsBusy(void) {
    return rs485_tx_busy;
}

void RS485_Send(uint8_t *data, uint16_t size) {
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // 发送模式
    usart2_tx_complete = 0;  	  
    HAL_UART_Transmit_DMA(&huart2, data, size); // 非阻塞发送
}


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart == &huart2) {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // 发送完成后切接收模式
        usart2_tx_complete = 1;  rs485_tx_busy = 0; // 标记发送完成
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart == &huart2) {
        RS485_Send(rxBuffer, 3); // 回传数据
        HAL_UART_Receive_DMA(&huart2, rxBuffer, 3); // 重启接收
			
    }
}	

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
    if (huart == &huart2) {
			 RS485_Send(rxBuffer, Size); // 回传数据
			HAL_UARTEx_ReceiveToIdle_DMA(&huart2, rxBuffer, sizeof(rxBuffer));
			__HAL_DMA_DISABLE_IT(&hdma_usart2_rx,DMA_IT_HT);
		}
}
//rs485.h
#ifndef __RS485_H
#define __RS485_H
 
#include "stdint.h"
void RS485_Printf(const char *format, ...);
uint8_t RS485_IsBusy(void);
 void RS485_Send(uint8_t *data, uint16_t size) ;

#endif

使用测试:

while (1) {
    RS485_Printf("Temperature: %.1f\r\n", 25.5f); 
    HAL_Delay(1000); // 避免频繁发送
}

现象:

调试助手显示收到    Temperature: 25.5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值