Tiny6410串口应用程序
开发环境
开发环境如下图所示:
开发PC:开发PC上运行超级终端,编写、编译串口程序
Tiny6410:运行串口程序,其中/dev/ttySAC0通过串口线与开发PC相连接,/dev/ttySAC3通过串口线与测试PC相连接
测试PC:测试PC上运行串口调试工具,进行串口数据的收发
程序功能描述:Tiny6410通过/dev/ttySAC3串口与测试PC进行串口数据的收发。这个程序是在友善之臂提供的串口应用程序的基础上精简来的。原来的程序看起来有些复杂,初学者读起来有一定难度。经过精简之后,只保留了串口收发数据的关键部分。
源代码
/*==========================================================================
*Name: uart_S3C6410.c
*Desc: 友善之臂开发板串口收发程序,根据友善之臂提供的串口程序精简而来
* 在超级终端输入要发送的字符,通过串口发送;串口接收的数据由超级
* 终端显示出来。交叉编译后,下载到开发板,执行./uart_S3C6410
*Parameter:
*Return:
*Author: yoyoba(stuyou@126.com)
*Date: 2016-11-03
*Modify: 2016-12-07
*=========================================================================*/
# include <stdio.h>
# include <stdlib.h>
# include <termio.h>
# include <unistd.h>
# include <fcntl.h>
# include <getopt.h>
# include <time.h>
# include <errno.h>
# include <string.h>
//错误消息提示函数
static void Error(const char *Msg)
{
fprintf (stderr, "%s\n", Msg);
fprintf (stderr, "strerror() is %s\n", strerror(errno));
exit(1);
}
//警告消息提示函数
static void Warning(const char *Msg)
{
fprintf (stderr, "Warning: %s\n", Msg);
}
//使用select监视FD是否可写
static inline void WaitFdWriteable(int Fd)
{
fd_set WriteSetFD;
FD_ZERO(&WriteSetFD);
FD_SET(Fd, &WriteSetFD);
if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {
Error(strerror(errno));
}
}
int main()
{
int UART_fd, tty_fd;
struct termios TtyAttr;
struct termios BackupTtyAttr;
UART_fd = open("/dev/ttySAC3", O_RDWR, 0);//打开ttySAC3串口
if (UART_fd < 0)
Error("Unable to open device");
if (fcntl(UART_fd, F_SETFL, O_NONBLOCK) < 0)//设置串口为非阻塞
Error("Unable set to NONBLOCK mode");
memset(&TtyAttr, 0, sizeof(struct termios));//清空ttyattr
//配置串口:
TtyAttr.c_iflag = IGNPAR; //忽略校验
TtyAttr.c_cflag = B115200 | HUPCL | CS8 | CREAD | CLOCAL;//115200波特率,数据位8,启用接收
TtyAttr.c_cc[VMIN] = 1; //最小可读取字符数
if (tcsetattr(UART_fd, TCSANOW, &TtyAttr) < 0)//配置串口
Warning("Unable to set comm port");
tty_fd = open("/dev/tty", O_RDWR | O_NDELAY, 0); //打开终端/dev/tty,当前shell终端
if (tty_fd < 0)
Error("Unable to open tty");
TtyAttr.c_cflag = B115200 | HUPCL | CS8 | CREAD | CLOCAL;//和开发板超级终端属性的配置一致,否则会有问题
if (tcgetattr(tty_fd, &BackupTtyAttr) < 0)//把终端属性保存在BackupTtyAttr,程序退出时恢复终端使用
Error("Unable to get tty");
if (tcsetattr(tty_fd, TCSANOW, &TtyAttr) < 0)//设置终端属性
Error("Unable to set tty");
//启动循环,串口接收和发送数据
while(1){
unsigned char buf = 0;
fd_set ReadSetFD;
//select监控串口和终端是否可读
FD_ZERO(&ReadSetFD);
FD_SET(UART_fd, &ReadSetFD);
FD_SET( tty_fd, &ReadSetFD);
#define max(x,y) ( ((x) >= (y)) ? (x) : (y) )
if (select(max(UART_fd, tty_fd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {
Error(strerror(errno));
}
#undef max
//如果串口可读
if (FD_ISSET(UART_fd, &ReadSetFD)){
while (read(UART_fd, &buf, 1) == 1) {
WaitFdWriteable(tty_fd);//等待终端可写
if (write(tty_fd, &buf, 1) < 0) {//把从串口读取的字符输出到终端显示
Error(strerror(errno));
}
}
}
//如果终端可读,在终端中输入发送的数据
if (FD_ISSET(tty_fd, &ReadSetFD)) {
while (read(tty_fd, &buf, 1) == 1) {//读取终端中输入的字符
static int EscKeyCount = 0;//统计按下ESC键的次数,如果连续按下三次ESC键,则退出程序
WaitFdWriteable(UART_fd);//如果串口可写,就通过串口发送
if (write(UART_fd, &buf, 1) < 0) {
Error(strerror(errno));
}
if(buf != '\x1b')//如果输入的不是ESC键,则在超级终端显示输入的字符
fwrite((char*)&buf, 1, 1, stderr);//如果不执行这句,超级终端看不到输入的字符
if (buf == '\x1b') {
EscKeyCount ++;
if (EscKeyCount >= 3)
goto ExitLabel;
// 跳出到退出label
} else
EscKeyCount = 0;
}
}
}
ExitLabel:
if (tcsetattr(tty_fd, TCSANOW, &BackupTtyAttr) < 0)//退出程序之前,恢复超级终端的配置
Error("Unable to set tty");
return 0;
}
编译
在开发PC上对串口程序进行交叉编译:arm-linux-gcc -o uart_S3C6410 uart_S3C6410.c
运行测试
把开发PC上编译好的uart_S3C6410下载到开发板,并添加执行权限:chmod +x uart_S3C6410
,
执行:./uart_S3C6410
1.接收测试:在测试PC的串口调试工具中,发送数据,在开发PC的超级终端中可以看到接收的数据;
2.发送测试:在开发PC的超级终端中输入要发送的数据,在测试PC的串口调试工具中看到接收的数据
3.退出程序:在开发PC超级终端中连续输入三个“ESC”键,则退出程序。