摘要:高速串口數據通訊,要求在接收數據采集設備發送大量數據的同時,完成對已接收到數據的實時存儲。利用多線程技術,解決高速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\\");
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.