提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
RM比赛中很可能会用到Linux上位机与stm32单片机进行串口通信,为实现串口通信学习termios。
提示:以下是本篇文章正文内容,下面案例可供参考
一、termios是什么?
termios是Linux系统提供的标准串口编程接口,通过操作终端 I/O 来进行串口通信。
二、使用示例
一个最简单的示例如下:
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
int main(void)
{
int fd; /*File Descriptor*/
printf("\n +----------------------------------+");
printf("\n | Serial Port Write |");
printf("\n +----------------------------------+");
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);// 打开串口,返回文件描述符
if (fd == -1) /* Error Checking */
printf("\n Error! in Opening ttyUSB0 ");
else
printf("\n ttyUSB0 Opened Successfully ");
struct termios SerialPortSettings;
tcgetattr(fd, &SerialPortSettings);
//设置波特率
cfsetispeed(&SerialPortSettings, B115200);
cfsetospeed(&SerialPortSettings, B115200);
//设置没有校验
SerialPortSettings.c_cflag &= ~PARENB;
//停止位 = 1
SerialPortSettings.c_cflag &= ~CSTOPB;
SerialPortSettings.c_cflag &= ~CSIZE;
//设置数据位 = 8
SerialPortSettings.c_cflag |= CS8;
SerialPortSettings.c_cflag &= ~CRTSCTS;
SerialPortSettings.c_cflag |= CREAD | CLOCAL;
//关闭软件流动控制
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);
//设置操作模式
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
SerialPortSettings.c_oflag &= ~OPOST;
if ((tcsetattr(fd, TCSANOW, &SerialPortSettings)) != 0)
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 115200 \n StopBits = 1 \n Parity = none");
//定义传输内容
char write_buffer[] = "Hello World";
//传输字节数
int bytes_written = 0;
//串口写数据
bytes_written = write(fd, write_buffer, sizeof(write_buffer));
printf("\n %s written to ttyUSB0", write_buffer);
printf("\n %d Bytes written to ttyUSB0", bytes_written);
printf("\n +----------------------------------+\n\n");
close(fd);
return 0;
}
效果展示
废话少说,与其理论分析,不如先直接用stm32把串口发送的信息接受下来再发回来看看到底对不对。
可以看到,我们stm32收到了我们发送的字符串并通过串口发送回来,验证了我们的代码是正确的。
附调stm32用hal库的核心代码: 注:如果您不懂stm32,可以把这部分交给电控。
代码详解
其实串口的配置在弄懂之前完全可以照抄,并不会引发大问题,关键要明白例子中涉及的关键API的使用和背后的原因(后者了解即可)。
1.linux一切皆文件的特性
由fd = open()可知,打开串口的本质上是打开一个文件,后续参数的含义读者可自寻查找
2.write()函数的使用
write()使用了三个参数,分别为串口,发送信息的首地址(又叫缓存区),以及要发送的字节数,或者说尾地址,而返回值为成功发送的字节数。
思考:如果要使用长度来表示尾地址的指针,那么数据应该是连续存储的,因此我们也常用数组或者vetcor容器存储要发送的数据,那到底能不能将数据分开存储呢?
三、大小端存储
具体可参考这篇文章:https://zhuanlan.zhihu.com/p/316347205
大段存储
四、循环冗余校验
具体算法可参考这篇文章:
六、double的字节序
未完待续
博主比较懒,先把框架放在这里,边学边写,不定期更。