配置串口部分网上教程太多了,不做复述。
利用这种方法的好处是,printf只能重定向一个串口。而这种方法可以针对不同串口写不同的函数,实现很多串口的发送数据。
可以用串口1传输日志信息,串口2传输调试信息。当不需要时,直接在相关函数里把串口发送代码注释掉就行了。
代码
H文件
#ifndef USART_PRINT_H_
#define USART_PRINT_H_
#include <stdarg.h>
#include <stdio.h>
#include "main.h"
#include "usart.h"
#define UART1_SEND_LEN 100 //建议不要大于UART1_SEND_LEN - 2个
void UART1_print(char *fmt, ...);
#endif
- 这里的
UART1_SEND_LEN
是指最多可以写入的字符数。 - 理论来说应当是
UART1_SEND_LEN - 1
,因为最后还需要一个字符串的结束符号。 - 但是实际可以传
UART1_SEND_LEN
长度的字符,这里也就是100个。但是只有UART1_SEND_LEN - 2
个是经过判断的,这里和C文件的实现有关。
C文件
#include "usart_print.h"
void UART1_print(char *fmt, ...) {
char buffer[UART1_SEND_LEN];
uint8_t i = 0;
va_list arg_ptr;
va_start(arg_ptr, fmt); // 初始化可变参数
vsnprintf(buffer, (unsigned int) (UART1_SEND_LEN), fmt, arg_ptr); // 格式化的数据写入字符串
for(i = 0; i < UART1_SEND_LEN - 1 && buffer[i] != '\0'; i++);
// while (buffer[i] != '\0') {
// i++;
// };
HAL_UART_Transmit(&huart1, (uint8_t*) buffer, i + 1, 1000);
va_end(arg_ptr);
}
- 这里利用for循环做了一个计算字符串长度的操作。
- 因为
i
是从0开始计数,所以当buffer[i] != '\0'
的条件不满足时,i
比当前字符串的实际长度要少1(在传输时’\0’最好也传输过去,所以当判断到’\0’时,'\0’并不在字符串长度之内),所以在发送串口数据时要对i
进行加一操作。 - 而当
i < UART1_SEND_LEN
这个条件不满足时,也就是没有找到'\0'
,此时i
等于UART1_SEND_LEN
,再经过后面的加一,明显越界了。所以为了方便就在判断时对UART1_SEND_LEN
进行减一操作。 - 所以实际可以传输的字符串长度是
UART1_SEND_LEN
,但是需要注意的是只有UART1_SEND_LEN -2
个字符是经过buffer[i] != '\0'
判断的。 - 被注释的部分是没有越界保护的计算字符串长度的方式,如果传输的字符没有结束符,程序就会卡在这里报错。
uint8_t
的最大数是255,所以如果想把UART1_SEND_LEN
设置的大于255,就需要把uint8_t
换成uint16_t
或者uint32_t
。- 程序中只有
for(i = 0; i < UART1_SEND_LEN - 1 && buffer[i] != '\0'; i++);
到HAL_UART_Transmit(&huart1, (uint8_t*) buffer, i + 1, 1000);
这一部分代码是可以自己修改的,其他部分基本是固定的。