想了解更多关于开源的内容,请访问:51CTO 开源基础软件社区https://ost.51cto.com
在连接时如图,两个芯片的GND引脚共地。
通常使用数据协议表格可以简单表示如下表| 数据帧内容 | 长度 | 功能 |
| 起始位 | 1位 | 标志帧的起始 |
| 数据位 | 8位 (有时描述为9位) | 传输数据 |
| 校验位 | 无校验(1位奇校验/偶校验) | 校验本帧数据正确性和完整性 |
| 停止位 | 1 (0.5 、1、 1.5、 2) | 标志帧的结束 |
如果对比于STM32单片机实现的逻辑可能更易于理解。
中断处理函数的名称不同:Linux使用的是irq函数,而STM32使用的是HAL_UART_IRQHandler函数。STM32的中断处理函数包含了发送中断和接收中断,需要在处理函数内部进行区分,而Linux中的发送和接收分别有对应的中断处理函数。在Linux中,可以通过tty设备文件直接访问串口,而STM32需要使用串口API进行访问和操作。STM32需要手动开启和关闭中断,而Linux的中断处理函数会在内核中自动启动和停止。Linux中,数据的接收和发送是由tty设备驱动完成的,而STM32需要在中断处理函数内部实现数据的接收和发送。两者关键差异是LINUX使用内核管理中断函数的启停。以下给出一种示例程序可以根据需要进行修改编译合入内核实现串口驱动。#include <linux/module.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#define DRIVER_NAME "my_serial_driver"
static struct uart_driver my_uart_driver = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = "ttyMY", // 设备文件名,例如 /dev/ttyMY0
.major = 0, // 自动分配主设备号
.minor = 0, // 自动分配从设备号
.nr = 1, // 支持的最大串口数量
};
// 串口 probe 函数,用于初始化串口参数和注册串口设备
static int my_serial_probe(struct uart_port *port)
{
// 设置串口参数
port->ops = &my_uart_driver.ops;
port->type = PORT_16550A;
port->iotype = UPIO_MEM;
port->ioport = 0x3f8; // 串口的 I/O 端口地址
port->irq = 4; // 串口的中断号
port->flags = UPF_BOOT_AUTOCONF;
return uart_add_one_port(&my_uart_driver, port); // 注册串口设备
}
// 串口 remove 函数,用于注销串口设备
static void my_serial_remove(struct uart_port *port)
{
uart_remove_one_port(&my_uart_driver, port); // 注销串口设备
}
// 串口操作函数表,这里只需要实现 probe 和 remove 函数
static struct uart_ops my_uart_ops = {
.tx_empty = NULL,
.set_mctrl = NULL,
.get_mctrl = NULL,
.stop_tx = NULL,
.start_tx = NULL,
.send_xchar = NULL,
.stop_rx = NULL,
.enable_ms = NULL,
.break_ctl = NULL,
.startup = NULL,
.shutdown = NULL,
.flush_buffer = NULL,
.set_termios = NULL,
.type = NULL,
.release_port = NULL,
.request_port = NULL,
.config_port = NULL,
.verify_port = NULL,
.ioctl = NULL,
.send_xchar_locked = NULL,
};
// 模块初始化函数,在这里注册串口驱动
static int my_serial_init(void)
{
int ret = 0;
// 注册串口驱动
ret = uart_register_driver(&my_uart_driver);
if (ret) {
printk(KERN_ERR "Failed to register UART driver\n");
return ret;
}
// 设置串口操作函数表中的 probe 和 remove 函数
my_uart_ops.probe = my_serial_probe;
my_uart_ops.remove = my_serial_remove;
my_uart_driver.ops = my_uart_ops;
return ret;
}
// 模块卸载函数,在这里注销串口驱动
static void my_serial_exit(void)
{
uart_unregister_driver(&my_uart_driver);
}
module_init(my_serial_init);
module_exit(my_serial_exit);
MODULE_LICENSE("GPL");#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#define DEVICE "/dev/ttyMY0"
int main()
{
int fd = 0;
struct termios tio;
char buf[256];
// 打开设备文件
fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
perror("open");
return -1;
}
// 设置串口参数
tcgetattr(fd, &tio);
tio.c_iflag = IGNBRK | IGNPAR;
tio.c_oflag = 0;
tio.c_cflag = CS8 | CREAD | CLOCAL;
tio.c_lflag = 0;
tio.c_cc[VTIME] = 0;
tio.c_cc[VMIN] = 1;
cfsetispeed(&tio, B9600);
cfsetospeed(&tio, B9600);
tcsetattr(fd, TCSANOW, &tio);
// 读取串口数据
printf("Reading from serial port...\n");
while (1) {
int n = read(fd, buf, sizeof(buf));
if (n > 0) {
buf[n] = '\0';
printf("Received: %s", buf);
}
}
// 关闭设备文件
close(fd);
return 0;#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
//宏定义
#define OK 0
#define ERR (-1)
//静态变量
static int fd1; // 串口设备文件描述符
static int fd2;
static int send_data; // 传输的数据
// 从串口读的线程
// 转换波特率
speed_t conver_baudrate(int baudrate)
{
switch (baudrate) {
case 9600L:
return B9600;
case 19200L:
return B19200;
case 38400L:
return B38400;
case 115200L:
return B115200;
case 1152000L:
return B1152000;
default:
return 1152000L;
}
}
void set_baud(int fd, int baud)
{
int ret = ERR;
struct termios opt;
tcgetattr(fd, &opt); // tcgetattr用来获取终端参数,将从终端获得的信息fd,保存到opt结构体中
tcflush(fd, TCIOFLUSH); // 刷清缓冲区
cfsetispeed(&opt, baud);
cfsetospeed(&opt, baud);
ret = tcsetattr(fd, TCSANOW, &opt); // 设置终端参数到opt中,使之立即生效
if (ret == ERR) {
perror("tcsetattr fd");
exit(0);
}
tcflush(fd, TCIOFLUSH); // 刷清缓冲区
}
// 设置数据位
int setup_data_bits(int setup_databits, struct termios *options_databits)
{
if (options_databits == NULL) {
perror("setup_data_bits error");
return ERR;
}
switch (setup_databits) {
case 5L:
options_databits->c_cflag |= CS5;
break;
case 6L:
options_databits->c_cflag |= CS6;
break;
case 7L:
options_databits->c_cflag |= CS7;
break;
case 8L:
options_databits->c_cflag |= CS8;
break;
default:
return ERR;
}
return OK;
}
// 设置校验位
int set_params_parity(int setup_parity, struct termios *options_parity)
{
switch (setup_parity) {
case 'n':
case 'N': // 无奇偶校验位
options_parity->c_cflag &= ~PARENB; // Clear parity enable/
options_parity->c_iflag &= ~INPCK; // disable input parity checking/
break;
case 'o':
case 'O': // 设置为奇校验
options_parity->c_cflag |= (PARODD | PARENB); // odd parity checking
options_parity->c_iflag |= INPCK; // enable parity checking
break;
case 'e':
case 'E': // 设置为偶校验
options_parity->c_cflag |= PARENB; // Enable parity /
options_parity->c_cflag &= ~PARODD; // even parity/
options_parity->c_iflag |= INPCK; // enable parity checking /
break;
case 'M':
case 'm': // 标记奇偶校验
options_parity->c_cflag |= PARENB | CMSPAR | PARODD;
options_parity->c_iflag |= INPCK; // enable parity checking /
break;
case 'S':
case 's': // 设置为空格
options_parity->c_cflag |= PARENB | CMSPAR;
options_parity->c_cflag &= ~PARODD;
options_parity->c_iflag |= INPCK; // enable parity checking /
break;
default:
return ERR;
}
return OK;
}
// 设置校验位
int set_params(int fd, int databits, int stopbits, int parity)
{
struct termios options;
int ret = ERR;
if (tcgetattr(fd, &options) != 0) {
perror("tcgetattr fail\n");
return ERR;
}
options.c_iflag = 0;
options.c_oflag = 0;
// setup data bits
options.c_cflag &= ~CSIZE;
ret = setup_data_bits(databits, &options);
if (ret == ERR) {
return ERR;
}
// parity
ret = set_params_parity(parity, &options);
if (ret == ERR) {
return ERR;
}
// stop bits/
switch (stopbits) {
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2L:
options.c_cflag |= CSTOPB;
break;
default:
return ERR;
}
// 请求发送和清除发送
options.c_cflag &= ~CRTSCTS;
options.c_lflag = 0;
options.c_cc[VTIME] = 10L;
options.c_cc[VMIN] = 1;
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &options) != 0) {
return ERR;
}
return OK;
}
// 设置波特率
int uart_init(int fd, int uartBaud)
{
set_baud(fd, conver_baudrate(uartBaud));
// uart param /
if (set_params(fd, 8L, 1, 'n')) {
perror("set uart parameters fail\n");
return ERR;
}
return OK;
}
int data_proce(recv){
if(recv=="hello_world"){
send_data=1;
return 1;
}
else{
send_data =0;
return 0;
}
}
void *_serial_output_task(void){
pthread_detach(pthread_self());
int ret;
ret=write(fd2,(unsigned char *) send_data,1);
if(ret>0)
printf("send success");
else {
printf("send error");
}
usleep(10000);
}
void *_serial_input_task(void)
{
int i = 0;
int ret = ERR; // 函数返回值
int buf = 0; // 用于保存读取到的字节
int recv[FRAME_LEN] = {0}; // 用于保存接收到的数据
while (1) {
// 读取一帧数据
for (i = 0; i < FRAME_LEN; i++) {
ret = read(fd1, &buf, 1); // 读取一个字节
if (ret == ERR) {
perror("read error\n");
exit(0);
}
recv[i] = buf; // 保存读取到的字节
}
// 处理接收到的数据
ret = data_proce(recv);
if (ret == ERR) {
perror("data process error\n");
exit(0);
}
}
}
int main(int argc, char **argv)
{
char *uart_dev ="ttyUSB1"; // 串口设备文件路径
char *uart_dev_t = "ttyUSB2"; // 串口设备文件路径
int ret1 = ERR; // 函数返回值
// 打开串口设备文件
fd1 = open(uart_dev, O_RDWR);
fd2= open(uart_dev_t,O_RDWR);
if (fd2== ERR) {
perror("open file fail\n");
return ERR;
}
if (fd1 == ERR) {
perror("open file fail\n");
return ERR;
}
// 初始化串口
ret1 = uart_init(fd1, 9600L);
ret2 = uart_init(fd2,9600L);
if (ret1 == ERR) {
perror("uart init error\n");
return ERR;
}
if (ret2 == ERR) {
perror("uart_t init error\n");
return ERR;
}
// 创建线程,一直执行读串口的操作
pthread_t pid_t;
pthread_create(&pid_t, NULL, (void *)_serial_input_task, 0);
pthread_create(&pid_t, NULL, (void *)_serial_output_task, 0);
while (1) {
sleep(10L); // 主线程等待
}
close(fd1); // 关闭串口设备文件
return 0;
}按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho
Linux操作系统——网络配置与SSH远程安装完VMware与系统后,需要进行网络配置。第一个目标为进行SSH连接,可以从本机到VMware进行文件传送,首先需要进行网络配置。1.下载远程软件首先需要先下载安装一款远程软件:FinalShell或者xhell7FinalShellxhell7FinalShell下载:Windows下载http://www.hostbuf.com/downloads/finalshell_install.exemacOS下载http://www.hostbuf.com/downloads/finalshell_install.pkg2.配置CentOS网络安装好
文章目录一基础定义二创建逻辑卷2-1准备物理设备2-2创建物理卷2-3创建卷组2-4创建逻辑卷2-5创建文件系统并挂载文件三扩展卷组和缩减卷组3-1准备物理设备3-2创建物理卷3-3扩展卷组3-4查看卷组的详细信息以验证3-5缩减卷组四扩展逻辑卷4-1检查卷组是否有可用的空间4-2扩展逻辑卷4-3扩展文件系统五删除逻辑卷5-1备份数据5-2卸载文件系统5-3删除逻辑卷5-4删除卷组5-5删除物理卷六LVM逻辑卷缩容6-1缩容注意事项6-2标准缩容步骤一基础定义LVM,LogicalVolumeManger,逻辑卷管理,Linux磁盘分区管理的一种机制,建立在硬盘和分区上的一个逻辑层,提高磁盘分
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我一直在Rails上做两个项目,它们运行良好,但在这个过程中重新发明了轮子,自来水(和热水)和止痛药,正如我随后了解到的那样,这些已经存在于框架中。那么基本上,正确了解框架中所有智能部分的最佳方法是什么,这将节省时间而不是自己构建已经实现的功能?从第1页开始阅读文档?是否有公开所有内容的特定示例应用程序?一个特定的开源项目?所有的rails交通?还是完全
如何在Ruby中获取linux系统(这必须适用于Fedora、Ubuntu等)的软件/硬件信息? 最佳答案 Chef背后的优秀人才,拥有一颗名为Ohai的优秀gemhttps://github.com/opscode/ohai以散列形式返回系统信息,例如操作系统、内核、规范、fqdn、磁盘、空间、内存、用户、接口(interface)、sshkey等。它非常完整,非常好。它还会安装命令行二进制文件(也称为ohai)。 关于ruby-如何在Ruby中获取linux系统信息,我们在Stack
我在LinuxMint17.2上。我最近使用apt-getpurgeruby删除了ruby。然后我安装了rbenv然后rbenvinstall2.3.0所以现在,~/.rbenv/versions/2.3.0/bin/ruby存在。但是现在,我无法执行geminstallrubocop。我明白了:$geminstallrubocoprbenv:gem:commandnotfoundThe`gem'commandexistsintheseRubyversions:2.3.0但是我可以~/.rbenv/versions/2.3.0/bin/geminstallrubocop。但是,