文章目录
使用编写串口上位机程序
在前面关于串口的章节中编写了IMX6ULL的串口程序,并且使用串口助手测试了imx6ull程序。开始以前我以为这是一件麻烦的事情,麻烦的事情干的人多了就会变得简单。我在网上找到了完整的程序,稍作修改就可以完成对imx6ull的串口测试,并且可以作为以后编写模版。 其实做这种事情概率不高,因为只要完成一次,以后只要简单的修改一下,这个模块功能经过迭代就会非常 健壮。然后使用者会对该模块产生信任,然后忘记这个模块的存在,出现这样情况当然是最好的。一切法当 舍弃,否则会破坏大脑的记忆力。
一、程序
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include <stdint.h>
/* set_opt(fd,115200,8,'N',1) */
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;
if ( tcgetattr( fd,&oldtio) != 0) {
perror("SetupSerial 1");
return -1;
}
bzero( &newtio, sizeof( newtio ) );
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
newtio.c_oflag &= ~OPOST; /*Output*/
switch( nBits )
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
switch( nEvent )
{
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E':
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N':
newtio.c_cflag &= ~PARENB;
break;
}
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 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
default:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
if( nStop == 1 )
newtio.c_cflag &= ~CSTOPB;
else if ( nStop == 2 )
newtio.c_cflag |= CSTOPB;
newtio.c_cc[VMIN] = 1; /* 读数据时的最小字节数: 没读到这些数据我就不返回! */
newtio.c_cc[VTIME] = 0; /* 等待第1个数据的时间:
* 比如VMIN设为10表示至少读到10个数据才返回,
* 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)
* 假设VTIME=1,表示:
* 10秒内一个数据都没有的话就返回
* 如果10秒内至少读到了1个字节,那就继续等待,完全读到VMIN个数据再返回
*/
tcflush(fd,TCIFLUSH);
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
{
perror("com set error");
return -1;
}
//printf("set done!\n");
return 0;
}
int open_port(char *com)
{
int fd;
//fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY);
fd = open(com, O_RDWR|O_NOCTTY);
if (-1 == fd){
return(-1);
}
if(fcntl(fd, F_SETFL, 0)<0) /* 设置串口为阻塞状态*/
{
printf("fcntl failed!\n");
return -1;
}
return fd;
}
/*
* ./serial_send_recv <dev>
*/
int main(int argc, char **argv)
{
int fd;
int iRet;
char c;
char str_buf[32];
uint16_t count=0;
/* 1. open */
/* 2. setup
* 115200,8N1
* RAW mode
* return data immediately
*/
/* 3. write and read */
/* if (argc != 2)
{
printf("Usage: \n");
printf("%s </dev/ttySAC1 or other>\n", argv[0]);
return -1;
} */
fd = open_port("/dev/ttyUSB0");
if (fd < 0)
{
printf("open %s err!\n", argv[1]);
return -1;
}
iRet = set_opt(fd, 115200, 8, 'N', 1);
if (iRet)
{
printf("set port err!\n");
return -1;
}
ssize_t write_result;
while(1){
sleep(2);
sprintf(str_buf,"%d hello world",count++);
write_result = write(fd,str_buf, strlen());
printf("write_result:%ld\n",write_result);
if(count>100) break;
}
close(fd);
/* printf("Enter a char: ");
while (1)
{
scanf("%c", &c);
iRet = write(fd, &c, 1);
iRet = read(fd, &c, 1);
if (iRet == 1)
printf("get: %02x %c\n", c, c);
else
printf("can not get data\n");
} */
return 0;
}
总结
== 在工程中借用前人的经验是非常重要,只要使用 set_opt(fd, 115200, 8, ‘N’, 1)语句调用set_opt( )函数就可以实现对串口的配置,fd是串口文件的id.以前的书籍中翻译为“句柄”。在下愚钝,好就也没想明白。 后来学习的了操作系统,结合操作系统也就清除了。操作系统为了管理打开的设备资源,设定一个缓冲区进行 管理,当我是用使用设备资源时必须告诉操作系统设备的ID,通过这个ID操作系统就可以对设备进行读、写、 更新、关闭等操作。所谓的"句柄"可以分开理解,“句”就是语句,从操作系统的角度看就是用户。“柄”就是设备 的id. 合起来就是用户操作设备的ID。理解了“句柄”就能理解open( )、write( )、 read( )、close( )等函数。==