Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ttytest
LOCAL_SRC_FILES := $(call all-subdir-c-files)
include $(BUILD_EXECUTABLE)
tty_test.c
/**@file main.c
* @brief 串口应用编程测试
* @details
* @author wanghuan any question please send mail to 371463817@qq.com
* @date 2019-06-17
* @version V1.0
* @copyright Copyright (c) 2019-2022
**********************************************************************************
* @attention
* 硬件平台:iMX6ULL \n
* 内核版本:L4.1.15
* @par 修改日志:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2019/06/17 <td>1.0 <td> <td>创建初始版本
* </table>
**********************************************************************************
*/
/* 包含的头文件 */
#include <stdio.h> //标准输入输出,如printf、scanf以及文件操作
#include <stdlib.h> //标准库头文件,定义了五种类型、一些宏和通用工具函数
#include <unistd.h> //定义 read write close lseek 等Unix标准函数
#include <sys/types.h> //定义数据类型,如 ssiz e_t off_t 等
#include <sys/stat.h> //文件状态
#include <fcntl.h> //文件控制定义
#include <termios.h> //终端I/O
#include <errno.h> //与全局变量 errno 相关的定义
#include <getopt.h> //处理命令行参数
#include <string.h> //字符串操作
#include <time.h> //时间
#include <sys/select.h> //select函数
//#define DEV_NAME "/dev/ttymxc3" ///< 串口设备
#define DEV_NAME "/dev/ttyS2"
/**@brief 设置串口参数:波特率,数据位,停止位和效验位
* @param[in] fd 类型 int 打开的串口文件句柄
* @param[in] nSpeed 类型 int 波特率
* @param[in] nBits 类型 int 数据位 取值 为 7 或者8
* @param[in] nParity 类型 int 停止位 取值为 1 或者2
* @param[in] nStop 类型 int 效验类型 取值为N,E,O,,S
* @return 返回设置结果
* - 0 设置成功
* - -1 设置失败
*/
int setOpt(int fd, int nSpeed, int nBits, int nParity, int nStop)
{
struct termios newtio, oldtio;
// 保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息
if (tcgetattr(fd, &oldtio) != 0)
{
perror("SetupSerial 1");
return -1;
}
//bzero(&newtio, sizeof(newtio)); //新termios参数清零
memset(&newtio, 0, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD; //CLOCAL--忽略 modem 控制线,本地连线, 不具数据机控制功能, CREAD--使能接收标志
// 设置数据位数
newtio.c_cflag &= ~CSIZE; //清数据位标志
switch (nBits)
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
default:
fprintf(stderr, "Unsupported data size\n");
return -1;
}
// 设置校验位
switch (nParity)
{
case 'o':
case 'O': //奇校验
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'e':
case 'E': //偶校验
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'n':
case 'N': //无校验
newtio.c_cflag &= ~PARENB;
break;
default:
fprintf(stderr, "Unsupported parity\n");
return -1;
}
// 设置停止位
switch (nStop)
{
case 1:
newtio.c_cflag &= ~CSTOPB;
break;
case 2:
newtio.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return -1;
}
// 设置波特率 2400/4800/9600/19200/38400/57600/115200/230400
switch (nSpeed)
{
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 19200:
cfsetispeed(&newtio, B19200);
cfsetospeed(&newtio, B19200);
break;
case 38400:
cfsetispeed(&newtio, B38400);
cfsetospeed(&newtio, B38400);
break;
case 57600:
cfsetispeed(&newtio, B57600);
cfsetospeed(&newtio, B57600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
case 230400:
cfsetispeed(&newtio, B230400);
cfsetospeed(&newtio, B230400);
break;
default:
printf("\tSorry, Unsupported baud rate, set default 9600!\n\n");
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
// 设置read读取最小字节数和超时时间
newtio.c_cc[VTIME] = 1; // 读取一个字符等待1*(1/10)s
newtio.c_cc[VMIN] = 1; // 读取字符的最少个数为1
tcflush(fd,TCIFLUSH); //清空缓冲区
if (tcsetattr(fd, TCSANOW, &newtio) != 0) //激活新设置
{
perror("SetupSerial 3");
return -1;
}
printf("Serial set done!\n");
return 0;
}
/**@brief 串口读取函数
* @param[in] fd 打开的串口文件句柄
* @param[in] *rcv_buf 接收缓存指针
* @param[in] data_len 要读取数据长度
* @param[in] timeout 接收等待超时时间,单位ms
* @return 返回设置结果
* - >0 设置成功
* - 其他 读取超时或错误
*/
int UART_Recv(int fd, char *rcv_buf, int data_len, int timeout)
{
int len, fs_sel;
fd_set fs_read;
struct timeval time;
time.tv_sec = timeout / 1000; //set the rcv wait time
time.tv_usec = timeout % 1000 * 1000; //100000us = 0.1s
FD_ZERO(&fs_read); //每次循环都要清空集合,否则不能检测描述符变化
FD_SET(fd, &fs_read); //添加描述符
// 超时等待读变化,>0:就绪描述字的正数目, -1:出错, 0 :超时
fs_sel = select(fd + 1, &fs_read, NULL, NULL, &time);
// printf("fs_sel = %d\n", fs_sel);
if(fs_sel)
{
len = read(fd, rcv_buf, data_len);
return len;
}
else
{
// printf("Sorry,I am wrong!");
return -1;
}
}
/**@brief 串口发送函数
* @param[in] fd 打开的串口文件句柄
* @param[in] *send_buf 发送数据指针
* @param[in] data_len 发送数据长度
* @return 返回结果
* - data_len 成功
* - -1 失败
*/
int UART_Send(int fd, char *send_buf, int data_len)
{
ssize_t ret = 0;
ret = write(fd, send_buf, data_len);
if (ret == data_len)
{
printf("send data is %s\n", send_buf);
return ret;
}
else
{
printf("write device error\n");
tcflush(fd,TCOFLUSH);
return -1;
}
}
/**@fn main
* @brief main入口函数
*/
int main(int argc, char **argv)
{
int fdSerial;
int rw_flag = 1;
printf("argc:%d argv:%s\n",argc,*argv);
// 打开串口设备
fdSerial = open(DEV_NAME, O_RDWR | O_NOCTTY | O_NDELAY);
if(fdSerial < 0)
{
perror(DEV_NAME);
return -1;
}
// 设置串口阻塞, 0:阻塞, FNDELAY:非阻塞
if (fcntl(fdSerial, F_SETFL, 0) < 0) //阻塞,即使前面在open串口设备时设置的是非阻塞的
{
printf("fcntl failed!\n");
}
else
{
printf("fcntl=%d\n", fcntl(fdSerial, F_SETFL, 0));
}
if (isatty(fdSerial) == 0)
{
printf("standard input is not a terminal device\n");
close(fdSerial);
return -1;
}
else
{
printf("is a tty success!\n");
}
printf("fd-open=%d\n", fdSerial);
// 设置串口参数
if (setOpt(fdSerial, 115200, 8, 'N', 1)== -1) //设置8位数据位、1位停止位、无校验
{
fprintf(stderr, "Set opt Error\n");
close(fdSerial);
exit(1);
}
tcflush(fdSerial, TCIOFLUSH); //清掉串口缓存
fcntl(fdSerial, F_SETFL, 0); //串口阻塞
char rcv_buf[100];
int len;
while(1) //循环读取数据
{
#if 0
len = UART_Recv(fdSerial, rcv_buf, 99, 10000);
if(len > 0)
{
rcv_buf[len] = '\0';
printf("receive data is %s\n", rcv_buf);
printf("len = %d\n", len);
UART_Send(fdSerial, rcv_buf, len);
}
else
{
printf("cannot receive data\n");
}
usleep(100000); //休眠100ms
#else
if(rw_flag)
{
UART_Send(fdSerial, "forward 1000 4000\n\r", strlen("forward 1000 4000\n\r"));
rw_flag = 0;
}
else
{
len = UART_Recv(fdSerial, rcv_buf, 99, 10000);
if(len > 0)
{
rcv_buf[len] = '\0';
printf("receive data is %s\n", rcv_buf);
printf("len = %d\n", len);
len = 0;
//UART_Send(fdSerial, rcv_buf, len);
}
rw_flag = 1;
}
#endif
}
}