瑞芯微Rockchip开发者社区
直播中

ouxiaolong

11年用户 470经验值
擅长:嵌入式技术 光电显示
私信 关注
[经验]

【LuckFox Pico Plus开发板免费试用】LuckFox Pico Plus 串口应用开发

1 LuckFox Pico Plus串口简介

LuckFox Pico Plus 有四个串口,UART2、UART3、UART4 和 UART5,其中 UART2 为调试串口。

1.jpg

2 串口概述

随着嵌入式系统应用的发展,Linux操作系统的应用也越来越广泛。Linux作为一款免费的并且开放源代码的操作系统,与Windows操作系统相比有许多独特的优势。Linux可以进行定制内核;Linux的GUI图形界面能够任意选择;Linux可以更方便、更安全地进行远程操作。随着Linux操作系统的不断发展和完善,基于Linux操作系统的软件开发也得到了长足的发展和应用。如果在工控领域引入Linux,不可避免的会遇到在嵌入式Linux下如何实现串行通信的问题。

在Linux操作系统下,对设备和文件的操作都等同于文件的操作,这样大大简化了系统对不同设备的操作,提高了效率。在程序中,设备和文件都是通过文件描述符来操作的。文件描述符是一个非负数的索引值,指向内核中每个进程打开的文件记录表。当打开一个现存的文件或者创建一个新文件时,内核就向进程返回一个文件描述符。当需要对设备进行读写操作时,也需要把文件描述符作为参数传递给相应的函数。

Linux的设备文件都存放在“/dev”目录下,串口资源对应的设备名是“/dev/ttys+编号”,因此串口对应的设备文件的路径是“/dev/ttys*”。而且USB转串口的设备名通常为“/dev/ttyUSB0”,在Linux下对设备的操作方法与对文件的操作方法一样。

3 串口使用详解

在配置完串口的相关属性后,就可以对串口进行打开和读写操作了。它所使用的函数和普通文件的读写函数一样,都是open()、write()和 read()。它们之间的区别的只是串口是一个终端设备,因此在选择函数的具体参数时会有一些区别。另外,这里会用到一些附加的函数,用于测试终端设备的 连接情况等。下面将对其进行具体讲解。

3.1 打开串口

打开串口和打开普通文件一样,都是使用open()函数,如下所示:

fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);

可以看到,这里除了普通的读写参数外,还有两个参数O_NOCTTY和O_NDELAY。

O_NOCTTY标志用于通知Linux系统,该参数不会使打开的文件成为这个进程的控制终端。如果没有指定这个标志,那么任何一个输入(诸如键盘中止信号等)都将会影响用户的进程。

O_NDELAY标志通知Linux系统,这个程序不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。如果用户指定了这个标志,则进程将会一直处在睡眠状态,直到DCD信号线被激活。

接下来可恢复串口的状态为阻塞状态,用于等待串口数据的读入,可用fcntl()函数实现,如下所示:

fcntl(fd, F_SETFL, 0);

再接着可以测试打开文件描述符是否连接到一个终端设备,以进一步确认串口是否正确打开,如下所示:

isatty(STDIN_FILENO);

该函数调用成功则返回0,若失败则返回-1。

这时,一个串口就已经成功打开了。接下来就可以对这个串口进行读和写操作。

3.2 读写串口

读写串口操作和读写普通文件一样,使用read()和write()函数即可,如下所示:

write(fd, buff, strlen(buff));
read(fd, buff, BUFFER_SIZE);

下面两个实例给出了串口读和写的两个程序,其中用到前面所讲述的open_port()和set_com_config ()函数。写串口的程序将在宿主机上运行,读串口的程序将在目标板上运行。

写串口的程序如下所示。

/*com_writer.c*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include "uart_api.h"

int main(void)
{
    int fd;
    char buff[BUFFER_SIZE];
    if((fd=open_port(TARGET_COM_PORT))<0)  /*打开串口*/
    {
        perror("open_port");
        return 1;
    }
    if(set_com_config(fd,115200,8,'N',1)<0) /*配置串口*/
    {
        perror("set_com_config error");
        return 1;
    }
    do
    {
        printf("Input some words(enter 'quit' to exit):");
        memset(buff,0,BUFFER_SIZE);
        if(fgets(buff,BUFFER_SIZE,stdin)==NULL)
        {
            perror("fgets");
            break;
        }
        write(fd,buff,strlen(buff));
    }while(strncmp(buff,"quit",4));
    close(fd);
    return 0;
}

读串口的程序如下所示:

/*com_reader.c*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include "uart_api.h"


int main(void)
{
int fd;
char buff[BUFFER_SIZE];
if((fd=open_port(TARGET_COM_PORT))<0)
{
perror("open_port");
return 1;
}
if(set_com_config(fd,115200,8,'N',1)<0) /*配置串口*/
{
perror("set_com_config ");
return 1;
}
do
{
memset(buff,0,BUFFER_SIZE);
if(read(fd,buff,BUFFER_SIZE)>0)
{
printf("the receive words are:%s",buff);
}
}while(strncmp(buff,"quit",4));
close(fd);
return 0;
}
/*uart_api.c*/
#include "uart_api.h"

/*

* @函数名:set_com_config
* @函数功能:串口设置函数
  */
  int set_com_config(int fd,int baud_rate,int data_bits, char parity, int stop_bits)
  {
  struct termios new_cfg;
  int speed;
  
  /* 保存并测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息 */
  
  if (tcgetattr(fd, &new_cfg) != 0)
  {
  perror("tcgetattr save");
  return -1;
  }
  //修改控制模式,保证程序不会占用串口
  new_cfg.c_cflag |= CLOCAL;
  //修改控制模式,使得能够从串口中读取输入数据
  new_cfg.c_cflag |= CREAD;
  new_cfg.c_oflag &= ~(ONLCR | OCRNL);
  new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
  new_cfg.c_iflag &= ~(ICRNL | INLCR);
  new_cfg.c_iflag &= ~(IXON | IXOFF | IXANY);
  
  /* 设置波特率 */
  switch (baud_rate)
  {
  case 2400:
  {
  speed = B2400;
  }
  break;
  case 4800:
  {
  speed = B4800;
  }
  break;
  case 9600:
  {
  speed = B9600;
  }
  break;
  case 19200:
  {
  speed = B19200;
  }
  break;
  case 38400:
  {
  speed = B38400;
  }
  break;
  default:
  case 115200:
  {
  speed = B115200;
  }
  break;
  }
  
  cfsetispeed(&new_cfg, speed);//输入波特率
  cfsetospeed(&new_cfg, speed);//输出波特率
  switch (data_bits) /* 设置数据位 */
  {
  case 7:
  {
  new_cfg.c_cflag |= CS7;
  }
  break;
  default:
  case 8:
  {
  new_cfg.c_cflag |= CS8;
  }
  break;
  }
  
  switch (parity) /* 设置奇偶校验位 */
{
default:
case 'n':
case 'N':
{
new_cfg.c_cflag &= ~PARENB;
new_cfg.c_iflag &= ~INPCK;
}
break;
case 'o':
case 'O':
{
new_cfg.c_cflag |= (PARODD | PARENB);
new_cfg.c_iflag |= INPCK;
}
break;
case 'e':
case 'E':
{
new_cfg.c_cflag |= PARENB;
new_cfg.c_cflag &= ~PARODD;
new_cfg.c_iflag |= INPCK;
}
break;
case 's': /* as no parity */
case 'S':
{
new_cfg.c_cflag &= ~PARENB;
new_cfg.c_cflag &= ~CSTOPB;
}
break;
}
switch (stop_bits) /* 设置停止位 */
  {
  default:
  case 1:
  {
  new_cfg.c_cflag &= ~CSTOPB;
  }
  break;
  case 2:
  {
  new_cfg.c_cflag |= CSTOPB;
  }
  }
  //修改输出模式,原始数据输出
  new_cfg.c_oflag &= ~OPOST;
  new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  new_cfg.c_lflag &= ~(ISIG | ICANON);
  
  //设置等待时间和最小接收字符
  new_cfg.c_cc[VTIME] = 0; /* 读取一个字符等待0*(0/10)s */
new_cfg.c_cc[VMIN] = 1; /* 读取字符的最少个数为0 */
  
  //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读
  tcflush(fd, TCIFLUSH); /* 处理未接收字符 */
if ((tcsetattr(fd, TCSANOW, &new_cfg)) != 0) /* 激活新配置 */
  {
  perror("tcsetattr action");
  return -1;
  }
  printf("serial set success\n");
  return 0;
  }

/*

* @函数名:open_port
* @返回值:fd
* @函数功能:打开串口函数
  */
  int open_port(char *com_port)
  {
  int fd;
  
  /*分别为com1,com2, com3对应 ttyUSB0 ttyUSB1 ttyUSB2 */
  fd = open( com_port, O_RDWR|O_NOCTTY|O_NDELAY);
  if (fd < 0)
  {
  perror("Can't Open Serial Port");
  return -1;
  }
  /*恢复串口为阻塞状态*/
  if (fcntl(fd,F_SETFL,0)<0)
  {
  perror("fcntl F_SETFL\n");
  }
  /*测试是否为终端设备*/
  if(isatty(STDIN_FILENO) == 0)
  {
  perror("standard input is not a terminal device");
  }
  return fd;
  }

/*

* @函数名:init_port
* @输出参数:com_port
* @返回值:fd
* @函数功能:串口初始化函数
  */
  int init_port(char *com_port)
  {
  int fd;
  
  if ((fd = open_port(com_port)) < 0 )
  {
  perror("open_port");
  return -1;
  }
  printf("open port success\n");
  if(set_com_config(fd,115200,8,'N',1) < 0)
  {
  perror("set_com_config");
  return -1;
  }
  return fd;
  }
/*uart_api.h*/
#ifndef UART_API_H
#define UART_API_H

#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <termios.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <ctype.h>

#define BUFFER_SIZE  36

#define TARGET_COM_PORT "/dev/ttyS3"

int set_com_config(int fd,int baud_rate, int data_bits,char parity,int stop_bits);
int open_port(char *com_port);
int init_port(char *com_port);

#endif

在开发板上运行写串口的程序,而在目标板上运行读串口的程序。

串口写数据:

2.png
串口收数据:

3.png

更多回帖

发帖
×
20
完善资料,
赚取积分