论文部分内容阅读
摘要:高速串口数据通讯,要求在接收数据采集设备发送大量数据的同时,完成对已接收到数据的实时存储。利用多线程技术,解决高速ARM在运行任务时应用程序的执行速度和串口传输数据速度不匹配,提高ARM对用户应用程序的响应速度,从而提高整个任务的执行速度和保证数据的完整性,提高系统整体性能。
关键词:ARM9;多线程;串行通信;嵌入式系统
中图分类号:TP311文献标识码:A文章编号:1009-3044(2008)23-854-03
Application of Multi-thread Technology in Serial Communication of ARM9
LIU Zhen
(Academic Affairs Office, Zaozhuang University, Zaozhuang 277160, China)
Abstract: High-speed serial data communications need receive large amounts of data by data acquisition equipment and realized real-time data storage. Used multi-thread technology, solved the applications's run speed mismatched the serial communications speed when arm run a task, raised the arm's respond to application,then raised the run speed of the whole task and ensured data integrity,improved the overall performance of the system.
Key words: ARM9; multi-thread; serial communication; embedded system
1 引言
基于s3c2410处理器的ARM9主频高达200MHZ,可以进行视频采集,无线通讯以及对音频视频的处理,如果用串口进行数据采集势必有高速处理能理和串口接收处理数据不匹配的问题,高速串口数据采集软件的设计不同于普通串口通信,要求在接收数据采集设备发送大量数据的同时完成对已接受到数据的实时存储,如果处理不好二者之间的关系,会造成数据的丢失甚至程序的崩溃[1]。
一个进程中可以同时运行多个线程。一个线程是指程序的一条执行路径,系统不停的在多个线程之间切换,由于时间很短,看上去多个线程在同时运行。对于通讯这种需要花费大量时间来测试I/O操作,同时又要保持响应用户其它操作的应用程序来说,创建多线程是最佳选择。
利用串口的信息反馈或者对实时要求很高的视频采集中可以有效地避免数据的丢失,也可以利用多线程实现终端的设计,本文正是基于利用多线程技术实现嵌入式系统下的串口通讯,在开发基于ARM9的智能机器人时对高速的光电码盘进行信息的反馈并发送指令来运行。
2 多线程串口通讯实现
在多个线程同时开始,CPU会为每一个线程一个时间片或更大时间片,使得每一个线程都可以在很短的时间内都得到执行。使用pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)获得使用的调度策略,它们是:SCHED_FIFO, SCHED_RR 和 SCHED_OTHER。SCHED_OTHER是不支持优先级使用的,而SCHED_FIFO和SCHED_RR支持优先级的使用,优先级别为1到99,数值越大优先级越高。可以利用pthread_attr_setschedparam(pthread_attr_t *attr,const struct sched_param *param);
pthread_attr_getschedparam(const pthread_attr_t *attr,struct sched_param *param);来设置线程的优先级。
2.1 串口通讯的三个线程的实现
void* keyboard(void * data)
//键盘线程它等待用户中止数据传输,捕获到用户输入ESC既ENDMINITERM的值为27 时则退出传输
for (;;){
c=getchar();
if( c== ENDMINITERM){STOP=TRUE;
break ;}}
void* receive(void * data)
//串口接收线程,这个线程实现串口的数据接收
{while (STOP==FALSE)
{read(fd,&c,1); //串口读入
write(1,&c,1); //标准输出 }}
void* send(void * data)
//串口发送线程,这个线程实现串口的数据发送
{printf("send data\n");
while (STOP==FALSE)
{c++;
c %= 255;
write(fd,&c,1);
//标准输出
usleep(100000);}
return NULL; }
2.2 串口通讯主程序
图2给出子线程的实现流程图,图3给出整个主程序的流程图,在主程序中给出了打开串口设备和创建线程,并实现数据的传输。
int main(int argc,char** argv)
{struct termios oldtio,newtio,oldstdtio,newstdtio;
struct sigaction sa;
int ok;
pthread_t th_a, th_b, th_c; //为三个线程设置变量
void * retval;
if( argc > 1)
fd = open(COM2, O_RDWR );
else
fd = open(COM1, O_RDWR ); //| O_NOCTTY |O_NONBLOCK);
if (fd <0) {
error(COM1);
exit(-1);}
tcgetattr(0,&oldstdtio);
tcgetattr(fd,&oldtio);//保存当前的模式设置
tcgetattr(fd,&newstdtio);
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; //控制标志
newtio.c_iflag = IGNPAR;//输入标志符
newtio.c_oflag = 0;//输出标志符
newtio.c_lflag = 0;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
/* now clean the modem line and activate the settings for modem */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio); /*set attrib*
sa.sa_handler = child_handler;
sa.sa_flags = 0;
sigaction(SIGCHLD,&sa,NULL); /* handle dying child */
pthread_create(&th_a, NULL, keyboard, 0);//创建键盘子线程
pthread_create(&th_b, NULL, receive, 0);//创建接收线程
pthread_create(&th_c, NULL, send, 0); //创建发送线程
pthread_join(th_a, &retval); //等待键盘线程结束
pthread_join(th_b, &retval); //等待接收线程结束
pthread_join(th_c, &retval); //等待发送线程结束
tcsetattr(fd,TCSANOW,&oldtio);//存储旧的调制解调器的设置
tcsetattr(0,TCSANOW,&oldstdtio);//存储旧的终端设置
close(fd);
exit(0);}
3 串口设置
3.1 打开串口
在Linux 下串口文件位于/dev 下,一般在老版本的内核中串口一为/dev/ttyS0 ,串口二为 /dev/ttyS1, 在开发板中串口设备位于/dev/tts/下,因为开发板中没有ttyS0这个设备,所以要建立一个连接,方法如下:
cd /dev
ln –sf /dev/tts/0 ttyS0
打开串口是通过标准的文件打开函数来实现的
int fd;
fd = open( "/dev/ttyS0", O_RDWR); //以读写方式打开串口
if (-1 == fd){ /* 不能打开串口一*/
perror(" 提示错误!");}
3.2 串口设置
最基本的设置串口包括波特率设置,效验位和停止位设置。串口的设置主要是设置 struct termios 结构体的各成员值,关于该结构体的定义可以查看/arm2410s/kernel-2410s/include/asm/termios.h 文件[3]。
struct termio
{unsigned short c_iflag; // 输入模式标志
unsigned short c_oflag;// 输出模式标志
unsigned short c_cflag;//控制模式标志
unsigned short c_lflag;//本地模式标志
unsigned char c_line;
unsigned char c_cc[NCC];//控制字符
1)波特率设置:下面是修改波特率的代码:
struct termios Opt;
tcgetattr(fd, &Opt);
cfsetispeed(&Opt,B19200); //设置为19200Bps*/
cfsetospeed(&Opt,B19200);
tcsetattr(fd,TCANOW,&Opt);//校验位和停止位的设置:
2)无效验8位
Option.c_cflag &= ~PARENB;Option.c_cflag &= ~CSTOPB;Option.c_cflag &= ~CSIZE;Option.c_cflag |= ~CS8;奇效验(Odd) 7 位
Option.c_cflag |= ~PARENB;Option.c_cflag &=
~PARODD;Option.c_cflag &= ~CSTOPB;Option.c_cflag &= ~CSIZE;Option.c_cflag |= ~CS7;
3)偶效验(Even)7位
Option.c_cflag &= ~PARENB;Option.c_cflag |= ~PARODD;Option.c_cflag &= ~CSTOPB;Option.c_cflag &= ~CSIZE;Option.c_cflag |= ~CS7;
Space 效验 7 位Option.c_cflag &= ~PARENB;Option.c_cflag &= ~CSTOPB;Option.c_cflag &= &~CSIZE;
Option.c_cflag |= CS8;
4)设置停止位:
1位:options.c_cflag &= ~CSTOPB;
2位:options.c_cflag |= CSTOPB;
5)读写串口:
设置好串口之后,读写串口就很容易了,把串口当作文件读写就可以了。
发送数据:
char buffer[1024];int Length=1024;int nByte;nByte = write(fd, buffer ,Length)
读取串口数据:
使用文件操作read 函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read 函数返回的字符数是实际串口收到的字符数。可以使用操作文件的函数来实现异步读取,如fcntl,或者select 等来操作。
char buff[1024];
int Len=1024;
int readByte = read(fd, buff, Len);
6)关闭串口:关闭串口就是关闭文件。
close(fd);
4 结论
实验证明了在ARM9中利用多线程技术实现串口通讯是一种简单有效的方法,并在实际项目开发中提高了数据的传输效率和精度,并且可以增加线程满足新的需求。
参考文献:
[1] 林涛.多线程技术在嵌入式数据采集系统中的应用[J].自动化博览,2006,23(1):49-50.
[2] 赵云鹏.MATLAB串口通信在数据采集中的应用[J].微计算机信息,2006,(01S):111-112.
[3] 唐雅娟,杨子杰.串口通信多线程实现的分析[J].计算机应用研究,2001,18(11):32-34.
[4] 朱英,周伟.串口通信在试验机测试系统中的应用[J].新技术新工艺,2002,(8):10-11.
[5] 贾广雷,刘培玉,耿长欣.多线程技术及其在串口通信中的应用[J].计算机工程,2003,29(1):247-249.
关键词:ARM9;多线程;串行通信;嵌入式系统
中图分类号:TP311文献标识码:A文章编号:1009-3044(2008)23-854-03
Application of Multi-thread Technology in Serial Communication of ARM9
LIU Zhen
(Academic Affairs Office, Zaozhuang University, Zaozhuang 277160, China)
Abstract: High-speed serial data communications need receive large amounts of data by data acquisition equipment and realized real-time data storage. Used multi-thread technology, solved the applications's run speed mismatched the serial communications speed when arm run a task, raised the arm's respond to application,then raised the run speed of the whole task and ensured data integrity,improved the overall performance of the system.
Key words: ARM9; multi-thread; serial communication; embedded system
1 引言
基于s3c2410处理器的ARM9主频高达200MHZ,可以进行视频采集,无线通讯以及对音频视频的处理,如果用串口进行数据采集势必有高速处理能理和串口接收处理数据不匹配的问题,高速串口数据采集软件的设计不同于普通串口通信,要求在接收数据采集设备发送大量数据的同时完成对已接受到数据的实时存储,如果处理不好二者之间的关系,会造成数据的丢失甚至程序的崩溃[1]。
一个进程中可以同时运行多个线程。一个线程是指程序的一条执行路径,系统不停的在多个线程之间切换,由于时间很短,看上去多个线程在同时运行。对于通讯这种需要花费大量时间来测试I/O操作,同时又要保持响应用户其它操作的应用程序来说,创建多线程是最佳选择。
利用串口的信息反馈或者对实时要求很高的视频采集中可以有效地避免数据的丢失,也可以利用多线程实现终端的设计,本文正是基于利用多线程技术实现嵌入式系统下的串口通讯,在开发基于ARM9的智能机器人时对高速的光电码盘进行信息的反馈并发送指令来运行。
2 多线程串口通讯实现
在多个线程同时开始,CPU会为每一个线程一个时间片或更大时间片,使得每一个线程都可以在很短的时间内都得到执行。使用pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)获得使用的调度策略,它们是:SCHED_FIFO, SCHED_RR 和 SCHED_OTHER。SCHED_OTHER是不支持优先级使用的,而SCHED_FIFO和SCHED_RR支持优先级的使用,优先级别为1到99,数值越大优先级越高。可以利用pthread_attr_setschedparam(pthread_attr_t *attr,const struct sched_param *param);
pthread_attr_getschedparam(const pthread_attr_t *attr,struct sched_param *param);来设置线程的优先级。
2.1 串口通讯的三个线程的实现
void* keyboard(void * data)
//键盘线程它等待用户中止数据传输,捕获到用户输入ESC既ENDMINITERM的值为27 时则退出传输
for (;;){
c=getchar();
if( c== ENDMINITERM){STOP=TRUE;
break ;}}
void* receive(void * data)
//串口接收线程,这个线程实现串口的数据接收
{while (STOP==FALSE)
{read(fd,&c,1); //串口读入
write(1,&c,1); //标准输出 }}
void* send(void * data)
//串口发送线程,这个线程实现串口的数据发送
{printf("send data\n");
while (STOP==FALSE)
{c++;
c %= 255;
write(fd,&c,1);
//标准输出
usleep(100000);}
return NULL; }
2.2 串口通讯主程序
图2给出子线程的实现流程图,图3给出整个主程序的流程图,在主程序中给出了打开串口设备和创建线程,并实现数据的传输。
int main(int argc,char** argv)
{struct termios oldtio,newtio,oldstdtio,newstdtio;
struct sigaction sa;
int ok;
pthread_t th_a, th_b, th_c; //为三个线程设置变量
void * retval;
if( argc > 1)
fd = open(COM2, O_RDWR );
else
fd = open(COM1, O_RDWR ); //| O_NOCTTY |O_NONBLOCK);
if (fd <0) {
error(COM1);
exit(-1);}
tcgetattr(0,&oldstdtio);
tcgetattr(fd,&oldtio);//保存当前的模式设置
tcgetattr(fd,&newstdtio);
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; //控制标志
newtio.c_iflag = IGNPAR;//输入标志符
newtio.c_oflag = 0;//输出标志符
newtio.c_lflag = 0;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
/* now clean the modem line and activate the settings for modem */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio); /*set attrib*
sa.sa_handler = child_handler;
sa.sa_flags = 0;
sigaction(SIGCHLD,&sa,NULL); /* handle dying child */
pthread_create(&th_a, NULL, keyboard, 0);//创建键盘子线程
pthread_create(&th_b, NULL, receive, 0);//创建接收线程
pthread_create(&th_c, NULL, send, 0); //创建发送线程
pthread_join(th_a, &retval); //等待键盘线程结束
pthread_join(th_b, &retval); //等待接收线程结束
pthread_join(th_c, &retval); //等待发送线程结束
tcsetattr(fd,TCSANOW,&oldtio);//存储旧的调制解调器的设置
tcsetattr(0,TCSANOW,&oldstdtio);//存储旧的终端设置
close(fd);
exit(0);}
3 串口设置
3.1 打开串口
在Linux 下串口文件位于/dev 下,一般在老版本的内核中串口一为/dev/ttyS0 ,串口二为 /dev/ttyS1, 在开发板中串口设备位于/dev/tts/下,因为开发板中没有ttyS0这个设备,所以要建立一个连接,方法如下:
cd /dev
ln –sf /dev/tts/0 ttyS0
打开串口是通过标准的文件打开函数来实现的
int fd;
fd = open( "/dev/ttyS0", O_RDWR); //以读写方式打开串口
if (-1 == fd){ /* 不能打开串口一*/
perror(" 提示错误!");}
3.2 串口设置
最基本的设置串口包括波特率设置,效验位和停止位设置。串口的设置主要是设置 struct termios 结构体的各成员值,关于该结构体的定义可以查看/arm2410s/kernel-2410s/include/asm/termios.h 文件[3]。
struct termio
{unsigned short c_iflag; // 输入模式标志
unsigned short c_oflag;// 输出模式标志
unsigned short c_cflag;//控制模式标志
unsigned short c_lflag;//本地模式标志
unsigned char c_line;
unsigned char c_cc[NCC];//控制字符
1)波特率设置:下面是修改波特率的代码:
struct termios Opt;
tcgetattr(fd, &Opt);
cfsetispeed(&Opt,B19200); //设置为19200Bps*/
cfsetospeed(&Opt,B19200);
tcsetattr(fd,TCANOW,&Opt);//校验位和停止位的设置:
2)无效验8位
Option.c_cflag &= ~PARENB;Option.c_cflag &= ~CSTOPB;Option.c_cflag &= ~CSIZE;Option.c_cflag |= ~CS8;奇效验(Odd) 7 位
Option.c_cflag |= ~PARENB;Option.c_cflag &=
~PARODD;Option.c_cflag &= ~CSTOPB;Option.c_cflag &= ~CSIZE;Option.c_cflag |= ~CS7;
3)偶效验(Even)7位
Option.c_cflag &= ~PARENB;Option.c_cflag |= ~PARODD;Option.c_cflag &= ~CSTOPB;Option.c_cflag &= ~CSIZE;Option.c_cflag |= ~CS7;
Space 效验 7 位Option.c_cflag &= ~PARENB;Option.c_cflag &= ~CSTOPB;Option.c_cflag &= &~CSIZE;
Option.c_cflag |= CS8;
4)设置停止位:
1位:options.c_cflag &= ~CSTOPB;
2位:options.c_cflag |= CSTOPB;
5)读写串口:
设置好串口之后,读写串口就很容易了,把串口当作文件读写就可以了。
发送数据:
char buffer[1024];int Length=1024;int nByte;nByte = write(fd, buffer ,Length)
读取串口数据:
使用文件操作read 函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read 函数返回的字符数是实际串口收到的字符数。可以使用操作文件的函数来实现异步读取,如fcntl,或者select 等来操作。
char buff[1024];
int Len=1024;
int readByte = read(fd, buff, Len);
6)关闭串口:关闭串口就是关闭文件。
close(fd);
4 结论
实验证明了在ARM9中利用多线程技术实现串口通讯是一种简单有效的方法,并在实际项目开发中提高了数据的传输效率和精度,并且可以增加线程满足新的需求。
参考文献:
[1] 林涛.多线程技术在嵌入式数据采集系统中的应用[J].自动化博览,2006,23(1):49-50.
[2] 赵云鹏.MATLAB串口通信在数据采集中的应用[J].微计算机信息,2006,(01S):111-112.
[3] 唐雅娟,杨子杰.串口通信多线程实现的分析[J].计算机应用研究,2001,18(11):32-34.
[4] 朱英,周伟.串口通信在试验机测试系统中的应用[J].新技术新工艺,2002,(8):10-11.
[5] 贾广雷,刘培玉,耿长欣.多线程技术及其在串口通信中的应用[J].计算机工程,2003,29(1):247-249.