Linux串口编写
来源:互联网 发布:java游戏开发 编辑:程序博客网 时间:2024/06/10 15:06
最基本的串口编程无非涉及下面的几点:
- 打开串口;
- 设置串口,如波特率、数位,等;
- 读/写串口(接收数据、发送数据);
- 关闭串口。
一、打开串口
串口的打开需要使用系统调用open,
int open_port(int port)
{
int fd = -1; /* File descriptor for the port, we return it. */
int ret;
char device[13] = {0}; /* ??? sizeof("/dev/ttyUSB0")=12 */
if (port < 1 || port > 4)
error_ret("Sorry, the port number must be 1~4.");
if (USB_SERIAL)
sprintf(device, "/dev/ttyUSB%d", port-1);
else
sprintf(device, "/dev/ttyS%d", port-1);
//printf("%s %d\n", device, sizeof(device));
fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
unix_error_ret("Unable to open the port");
/* block */
ret = fcntl(fd, F_SETFL, 0);
if (ret < 0)
unix_error_ret("fcntl");
ret = isatty(STDIN_FILENO);
if (ret == 0)
error_ret("Standard input is not a terminal device.");
debug_msg("Open the port success!\n");
return fd;
}
我们只能打开前面4个串口(如果存在的话),一般来说足够了。在处理设备文件名称时使用sprintf函数,而不是一一指定文件名称。其中的出错处理函数是自己定义的,可以在在线手册中看到它们的源代码(其实它们是宏定义,不是函数)。
二、关闭串口
串口的关闭十分简单,直接使用系统调用close就可以了。代码如下:
int close_port(int fd)
{
if(close(fd) < 0)
unix_error_ret("Unable to close the port.");
debug_msg("Close the port success!\n");
return 0;
}
三、设置串口参数
串口的设置是最复杂的,先附上完整的代码,之后再简单说一下。
int setup_port(int fd, int speed, int data_bits, int parity, int stop_bits)
{
int speed_arr[] = {B115200, B9600, B38400, B19200, B4800};
int name_arr[] = {115200, 9600, 38400, 19200, 4800};
struct termios opt;
int ret=-1;
int i=0;
int len=0;
ret = tcgetattr(fd, &opt); /* get the port attr */
if (ret < 0)
unix_error_ret("Unable to get the attribute");
opt.c_cflag |= (CLOCAL | CREAD); /* enable the receiver, set local mode */
opt.c_cflag &= ~CSIZE; /* mask the character size bits*/
/* baud rate */
len = sizeof(speed_arr) / sizeof(int);
for (i = 0; i < len; i++)
{
if (speed == name_arr[i])
{
cfsetispeed(&opt, speed_arr[i]);
cfsetospeed(&opt, speed_arr[i]);
}
if (i == len)
error_ret("Unsupported baud rate.");
}
/* data bits */
switch (data_bits)
{
case 8:
opt.c_cflag |= CS8;
break;
case 7:
opt.c_cflag |= CS7;
break;
default:
error_ret("Unsupported data bits.");
}
/* parity bits */
switch (parity)
{
case 'N':
case 'n':
opt.c_cflag &= ~PARENB;
opt.c_cflag &= ~INPCK; /* ?? */
break;
case 'O':
case 'o':
opt.c_cflag|=(INPCK|ISTRIP); /*enable parity check, strip parity bits*/
opt.c_cflag |= (PARODD | PARENB);
break;
case 'E':
case 'e':
opt.c_cflag|=(INPCK|ISTRIP); /*enable parity check, strip parity bits*/
opt.c_cflag |= PARENB;
opt.c_cflag &= ~PARODD;
break;
default:
error_ret("Unsupported parity bits.");
}
/* stop bits */
switch (stop_bits)
{
case 1:
opt.c_cflag &= ~CSTOPB;
break;
case 2:
opt.c_cflag |= CSTOPB;
break;
default:
error_ret("Unsupported stop bits.");
}
/* raw input */
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/* raw ouput */
opt.c_oflag &= ~OPOST;
tcflush(fd, TCIFLUSH);
opt.c_cc[VTIME] = 0; /* no time out */
opt.c_cc[VMIN] = 0; /* minimum number of characters to read */
ret = tcsetattr(fd, TCSANOW, &opt); /* update it now */
if (ret < 0)
unix_error_ret("Unable to setup the port.");
debug_msg("Setup the port OK!\n");
return 0; /* everything is OK! */
}
首先使用tcgetattr获取串口属性。termios中的成员只能通过“与”("&")、“或”("|")来操作,而不能直接赋值。之后,设置控制标志CLOCAL和CREAD,这两个选项可以保证程序不会变成端口的所有者,而端口所有者必须去处理发散性作业控制和挂断信号,同时还保证了串行接口驱动会读取过来的数据字节。在设置波特率时使用了点小技巧,就将最常用的放到数组的最前面,校验位也是如此。最后设置原始输入/输出,再使用这些属性重新设置串口。
四、读/写串口
这两个操作同样简单,就是使用系统调用read/write就行了。
本来打算使用两个线程进行读写操作的,但不成功,后面用minicom读取数据,而我们的串口程序只负责发送。我是短接串口的2、3脚进行测试的。让我不明白的是,为何这个程序不是独占串口?是不是上面的代码设置了?这些将会随着学习的深入而解决的。
下面是发送数据的线程:
void *write_port_thread(void *argc)
{
int ret;
int fd;
int i = 3;
fd = (int)argc;
//while (i--)
while (1)
{
debug_msg("writing... ");
ret = write(fd, buf, strlen(buf));
if (ret < 0)
pthread_exit(NULL);
write(fd, "\r\n", 2);
debug_msg("write: %d\n", ret);
sleep(1);
}
pthread_exit(NULL);
}
我们的main函数:
int main(void)
{
int fd;
int ret;
//signal(SIGINT, sig_handle);
fd = open_port(1); /* open the port(com1) */
if (fd < 0)
exit(0);
ret = setup_port(fd, 115200, 8, 'N', 1);
if (ret<0)
exit(0);
ret = pthread_create(&write_tid, NULL, write_port_thread, (void*)fd);
if (ret < 0)
unix_error_exit("Create write thread error.");
#if 0
ret = pthread_create(&read_tid, NULL, read_port_thread, (void*)fd);
if (ret < 0)
unix_error_exit("Create read thread error.");
#endif
pthread_join(write_tid, NULL);
//pthread_join(read_tid, NULL);
close_port(fd);
return 0;
}
- Linux串口编写
- linux 下串口程序编写
- 2440 linux 串口驱动编写(大内密探)
- linux下使用 qextserialport 编写串口程序
- LINUX串口驱动(8250)的编写与调试
- linux系统管理客户端2--串口实现测试代码编写
- linux系统管理客户端1--串口配置代码编写
- linux下使用 qextserialport 编写串口小程序
- Linux串口驱动(8250)的编写与调试
- arm linux下使用 qextserialport 编写串口小程序
- Linux串口驱动(8250)的编写与调试
- 串口的编写步骤
- QT5串口编写
- C# 编写串口程序
- 嵌入式Linux应用学习(二)------依赖Linux kernel驱动的uart串口应用程序编写
- linux 串口
- linux 串口
- linux串口
- 直接拿来用!10段超有用的Git命令行代码
- android开发--翻转闹铃(从制作到打包)
- 值得IT运维人员警示的“一件事儿”
- 函数x264_stack_align
- 在Python中,OS模块操作
- Linux串口编写
- DES、AES加密解密的方法
- 调试方法和摘要
- OD修改程序的属性(如标题啊啥的)
- 串口uart调试小小结
- XMPPFrameWork IOS 开发(七)消息回执
- 产品经理的自我修养:方法论
- Linux Shell脚本开发
- java获取真实的客户端IP地址