常见BUG调试

一.串口把0X0A默认为换行符,会莫名其妙的多出0D怎么解决?

1. 解决方法一,使用 stty 命令设置串口参数

在Linux系统中,要禁止串口输出换行符 (\n) 被自动转换为回车符 (\r),你可以通过设置串口的控制标志(control flags)来实现。这样可以确保串口输出的数据保持原始的格式,不会被操作系统自动转换。

在终端中可以使用 stty 命令来配置串口的属性,具体为禁止换行符转换:

stty -F /dev/ttyS0 -onlcr
  • -F /dev/ttyS0:指定要配置的串口设备,例如 /dev/ttyS0
  • -onlcr:禁止将输出的换行符 (\n) 转换为回车 (\r)。这个选项确保在输出时不会自动添加回车符。

2.方法二:通过编程设置串口属性

如果你在自己的程序中使用串口,可以通过编程的方式来控制串口的属性。下面是一个简单的C语言示例代码,用来设置串口属性并禁止换行符的转换:

#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

int main() {
    int fd;
    struct termios options;

    // 打开串口设备
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    // 获取当前串口属性
    tcgetattr(fd, &options);

    // 禁止输出换行符转换
    options.c_oflag &= ~ONLCR;

    // 设置串口属性
    tcsetattr(fd, TCSANOW, &options);

    // 示例:向串口发送数据
    char data[] = "Hello World\n";
    write(fd, data, sizeof(data) - 1); // -1 以避免发送末尾的 \0 字符

    // 关闭串口
    close(fd);

    return 0;
}

在上述代码中:
‘options.c_oflag &= ~0NLCR;`表示禁止输出换行符(`\n`) 被转换为回车(`\r`)。
‘write(fd,data,sizeof(data) - 1);`发送数据时,确保不发送字符串结尾的空字符`\θ`。

注意事项
·权限问题:确保程序有足够的权限打开和操作串口设备。可以使用
sudo运行程序或者适当设置设备权限。
·终端设置:如果使用终端程序(如minicom、screen等),也需要确保在终端的设置中关闭自动添
加回车换行符的选项,以免额外的字符转换。
通过以上方法,你可以在Linux系统中有效地控制串口输出的格式,确保数据按照原始的方式进行传输,而不受操作系统的自动转换影响。

 3.方法三,串口初始化修改


int uuart_init(const char* dev, unsigned int speed)
{
    int            fd = 0;
    struct termios tty;

    fd = open(dev, O_RDWR);
    if (fd < 0) {
        perror(__func__);
        return fd;
    }
    if (tcgetattr(fd, &tty) != 0) {
        perror("uuart_init: tcgetattr");
        close(fd);
        return -1;
    }

    tty.c_cflag &= ~PARENB; // 禁用奇偶校验
    tty.c_cflag &= ~CSTOPB; // 1个停止位
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;      // 8位数据位
    tty.c_cflag &= ~CRTSCTS; // 禁用硬件流控制
    tty.c_cc[VMIN]  = 1;     // 最少读取字符数
    tty.c_cc[VTIME] = 5;     // 读取超时时间(单位为0.1秒)
    tty.c_oflag &= ~OPOST;
    tty.c_iflag &= ~(ICRNL | INLCR); // 禁用输入换行符转换
    tty.c_oflag &= ~(ONLCR | OCRNL); // 禁用输出换行符转换
    
    cfsetospeed(&tty, speed);
    cfsetispeed(&tty, speed);

    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        perror("uuart_init: tcsetattr");
        close(fd);
        return -2;
    }

    return fd;
}

        以上这段代码是用来配置串口(或终端)的属性,以禁止特定的换行符转换。让我们逐行解释这段代码的含义:

禁止输出换行符转换

tty.c_oflag &= ~OPOST;
  • tty 是一个 struct termios 结构体,用来表示串口(或终端)的属性。
  • c_oflagtermios 结构体中的一个成员,表示输出模式标志。
  • OPOST 是一个常量,表示输出处理。
  • &= 是按位与赋值运算符,用来清除 c_oflag 中的特定位。

~OPOST 表示取 OPOST 的按位取反,即将 OPOST 对应的位设为0,其他位设为1。这样通过按位与操作 &=c_oflag 中的 OPOST 位清除,从而禁止输出处理。在串口(或终端)的情况下,禁用 OPOST 可以防止输出数据被处理成特定的格式,例如禁止将换行符 (\n) 转换为回车换行符 (\r\n)。

 禁用输入换行符转换

tty.c_iflag &= ~(ICRNL | INLCR);
  • c_iflagtermios 结构体中的输入模式标志。
  • ICRNLINLCR 是常量,分别表示输入时将回车 (CR) 和换行 (NL) 转换成换行 (NL),以及将换行 (NL) 转换成回车换行 (CRNL)。

~(ICRNL | INLCR) 表示取 ICRNLINLCR 的按位取反,即将它们对应的位设为0,其他位设为1。通过按位与操作 &=c_iflag 中的 ICRNLINLCR 位清除,从而禁用输入时的换行符转换。这样可以确保输入的数据保持原始的格式。

禁用输出换行符转换

tty.c_oflag &= ~(ONLCR | OCRNL);
    • 类似于输入换行符转换的设置,这里是针对输出时的换行符转换。

    ONLCROCRNL 分别表示输出时将换行 (NL) 转换成回车换行 (CRNL),以及将回车换行 (CRNL) 转换成换行 (NL)。通过 ~(ONLCR | OCRNL) 将其按位取反,然后按位与操作 &=c_oflag 中的 ONLCROCRNL 位清除,从而禁用输出时的换行符转换。

  1. 总结

        以上代码片段用于配置串口(或终端)的属性,以确保输入和输出的数据不会被自动转换或添加特定的换行符。这对于某些应用场景中需要原始数据格式的串口通信尤为重要。

二.函数参数是void* 该怎么定义参数呢

        在 C 语言中,`void*` 是一个通用指针类型,可以指向任何类型的数据。使用 `void*` 作为函数参数时,你需要在调用函数时将具体类型的指针转换为 `void*`,并在函数内部将 `void*` 转换回具体类型的指针。

#include <stdio.h>

// 函数声明,参数为 void*
void printValue(void* data, char type);

int main() {
    int intValue = 42;
    float floatValue = 3.14;
    char charValue = 'A';

    // 调用函数时,将具体类型的指针转换为 void*
    printValue(&intValue, 'i');
    printValue(&floatValue, 'f');
    printValue(&charValue, 'c');

    return 0;
}

// 函数定义,根据类型参数将 void* 转换回具体类型的指针
void printValue(void* data, char type) {
    switch (type) {
        case 'i':
            printf("Integer: %d\n", *(int*)data);
            break;
        case 'f':
            printf("Float: %.2f\n", *(float*)data);
            break;
        case 'c':
            printf("Char: %c\n", *(char*)data);
            break;
        default:
            printf("Unknown type\n");
    }
}


在这个示例中:
1. `printValue` 函数接受一个 `void*` 类型的参数 `data` 和一个 `char` 类型的参数 `type`,用于指示数据的类型。
2. 在 `main` 函数中,调用 `printValue` 时,将具体类型的指针(如 `int*`、`float*`、`char*`)转换为 `void*`。
3. 在 `printValue` 函数内部,根据 `type` 参数,将 `void*` 转换回具体类型的指针,并打印相应的值。

三.函数参数是const strcut *该怎么定义结构体呢

        当函数参数是 `const struct *` 时,你需要先定义结构体类型,然后在函数中使用该结构体类型的指针作为参数。以下是一个示例,展示如何定义结构体并使用 `const struct *` 作为函数参数:

#include <stdio.h>

// 定义结构体类型
struct Person {
    char name[50];
    int age;
};

// 函数声明,参数为 const struct Person*
void printPersonInfo(const struct Person* person);

int main() {
    // 创建结构体实例并初始化
    struct Person person1 = {"Alice", 30};

    // 调用函数,传递结构体指针
    printPersonInfo(&person1);

    return 0;
}

// 函数定义,参数为 const struct Person*
void printPersonInfo(const struct Person* person) {
    // 由于参数是 const struct Person*,不能修改 person 指向的内容
    printf("Name: %s\n", person->name);
    printf("Age: %d\n", person->age);
}


在这个示例中:
1. **定义结构体类型**:定义了一个名为 `Person` 的结构体,包含 `name` 和 `age` 两个成员。
2. **函数声明**:声明了一个名为 `printPersonInfo` 的函数,参数为 `const struct Person*`,表示该函数接受一个指向 `Person` 结构体的常量指针。
3. **创建结构体实例**:在 `main` 函数中,创建并初始化一个 `Person` 结构体实例 `person1`。
4. **调用函数**:调用 `printPersonInfo` 函数,并传递 `person1` 的指针。
5. **函数定义**:在 `printPersonInfo` 函数中,使用 `const struct Person*` 参数访问结构体成员,并打印其值。由于参数是 `const`,函数不能修改 `person` 指向的内容。
这种方法确保了函数不能修改传入的结构体数据,提供了一种安全的方式来传递只读数据。

  • 29
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值