前言

调试设备时往往需要有一个高效简单的printf函数帮助追踪错误日志、运行状态,DSP开发也不例外

介绍

自带printf如果是按照stm32的方式通过自定义fputc来实现的话,它是可以打印字符串的,但是一旦自定义数值格式输出就报错(Interrupt_illegalOperationHandler)

1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include "driverlib/sci.h"

int fputc(int c, register FILE *stream)
{
SCI_writeCharBlockingNonFIFO(SCIA_BASE, (uint16_t)c);
while(SCI_getTxFIFOStatus(SCIA_BASE) != SCI_FIFO_TX0);
return c;
}

配置SCI

使用sysconfig配置SCIA串口引脚、参数,SCIA对应的是板子分配的默认串口:RXDTXD分别对应GPIO43GPIO42

img

自定义printf

自定义打印函数实现,分别实现dsp_putchar、dsp_puts、print_int、print_float、dsp_printf几个函数

dsp_putchar

通过SCI发送单个字符,和标准库putchar对应

1
2
3
4
void dsp_putchar(char c) {
SCI_writeCharBlockingNonFIFO(SCIA_BASE, (uint16_t)c);
while(SCI_getTxFIFOStatus(SCIA_BASE) != SCI_FIFO_TX0);
}

dsp_puts

通过SCI发送字符串,和标准库puts对应

1
2
3
4
5
void dsp_puts(const char *str) {
while(*str) {
dsp_putchar(*str++);
}
}

将整数转换为字符并输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void print_int(int32_t num) {
char buffer[12]; // 足够保存32位整数
int i = 0;
int is_negative = 0;

// 特殊处理0
if(num == 0) {
dsp_putchar('0');
return;
}

// 处理负数
if(num < 0) {
is_negative = 1;
num = -num;
}

// 转换整数到字符
while(num > 0) {
buffer[i++] = '0' + (num % 10);
num /= 10;
}

// 如果是负数,添加负号
if(is_negative) {
dsp_putchar('-');
}

// 反向输出字符
while(i > 0) {
dsp_putchar(buffer[--i]);
}
}

将浮点数转换为字符并输出(带2位小数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void print_float(float num, int decimal_places) {
// 处理负数
if(num < 0) {
dsp_putchar('-');
num = -num;
}

// 提取整数部分
int32_t integer_part = (int32_t)num;
print_int(integer_part);

// 小数点
dsp_putchar('.');

// 处理小数部分
float fractional_part = num - integer_part;
int i;
for(i = 0; i < decimal_places; i++) {
fractional_part *= 10;
int digit = (int)fractional_part;
dsp_putchar('0' + digit);
fractional_part -= digit;
}
}

dsp_printf

简单的格式化打印函数 - 支持 %d, %f, %s, %c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void dsp_printf(const char *format, ...) {
va_list args;
va_start(args, format);

while(*format) {
// 处理格式化标记
if(*format == '%') {
format++;

// 根据格式化类型处理参数
switch(*format) {
case 'd': case 'i': // 整数
print_int(va_arg(args, int));
break;

case 'f': // 浮点数
print_float(va_arg(args, double), 2); // 默认2位小数
break;

case 's': // 字符串
dsp_puts(va_arg(args, char*));
break;

case 'c': // 字符
dsp_putchar(va_arg(args, int)); // 注意:char参数被提升为int
break;

case '%': // 百分号
dsp_putchar('%');
break;

default: // 未知格式
dsp_putchar('%');
dsp_putchar(*format);
}
} else {
// 普通字符直接输出
dsp_putchar(*format);
}

format++;
}

va_end(args);
}

格式化数据

测试用例:用dsp_printf生成sin(x), cos(x), sin(x)*cos(x), cos(x)*cos(x)波形,%f表示浮点数、%d表示整形数据,%s表示字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 打印表头
dsp_printf("Angle,Sin(x),Cos(x),Sin(x)*Cos(x),Cos(x)*Cos(x)\r\n");

// 生成三角函数数据
float angle = 0.0f; // 角度(度)
float angleRad; // 角度(弧度)
float sinVal, cosVal; // sin(x)和cos(x)值
float sinCosVal, cosSquareVal; // sin(x)*cos(x)和cos(x)*cos(x)值

for(;;) {
// 每15度输出一次数据
while(angle <= 360.0f)
{
// 转换为弧度
angleRad = angle * 0.01745329f; // 0.01745329 = π/180

// 计算三角函数值
sinVal = sin(angleRad);
cosVal = cos(angleRad);
sinCosVal = sinVal * cosVal;
cosSquareVal = cosVal * cosVal;

// 使用指定格式输出数据:"%f,%f,%f,%f\n"
dsp_printf("%f,%f,%f,%f\r\n", sinVal, cosVal, sinCosVal, cosSquareVal);

// 角度增加15度
angle += 15.0f;

// 延时,避免输出太快
DEVICE_DELAY_US(10000); // 延时100ms
}
angle = 0;
}

数据可视化

使用vofa+工具显示FireWater的自定义格式的串口数据流

img

总结

自定义dsp_printf更加高效,更加自由,依赖体积更小,无需关心stack大小限制


© 2025 hywing 使用 Stellar 创建
总访问 113701 次 | 本页访问 326