此程序是从天嵌提供的测试程序中裁剪出来的,这样看起来会比较简洁
程序到这边下载:http://download.csdn.net/detail/lufeiop02/4127780
一,首先是主程序:
int Main () { U8 key; U32 mpll_val = 0; Port_Init(); //端口初始化 key = 14; //这5行是关于cpu频率的设置,可以看另一篇文章: mpll_val = (92<<12)|(1<<4)|(1); ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3); ChangeClockDivider(key, 12); cal_cpu_bus_clk(); //这一段代码,选择了串口波特率为 115200。 consoleNum = 0; // s3c2440有三个UART,这里选择UART0 Uart_Init( 0,115200 ); //初始化UART Uart_Select( consoleNum ); //选择UART0 Uart_Printf(" TQ2440 Test Program\n"); //打印字符串,一般就是用这个函数来打印一些信息 return 0; }下面这一大堆函数就是2440lib.c文件中关于UART 的所有函数,当然我们一般只用到其中小部分,我尽量都分析一下
//***************************[ UART ]****************************** static int whichUart=0; void Uart_Init(int pclk,int baud) { int i; if(pclk == 0) pclk = PCLK; //如果参数为0,就用系统的PCLK,这个PCLK就APH设备所有的时钟频率,APH设备是指那些比较低速的外围设备
rUFCON0 = 0x0; //UART channel 0 FIFO control register, FIFO disable rUFCON1 = 0x0; //UART channel 1 FIFO control register, FIFO disable rUFCON2 = 0x0; //UART channel 2 FIFO control register, FIFO disable rUMCON0 = 0x0; //UART chaneel 0 MODEM control register, AFC disable rUMCON1 = 0x0; //UART chaneel 1 MODEM control register, AFC disable
//UART0 这个三个串口的配置都是一样的 rULCON0 = 0x3; //Line control register : Normal,No parity,1 stop,8 bits //配置功能列表 // [10] [9] [8] [7] [6] [5] [4] [3:2] [1:0] // Clock Sel,Tx Int,Rx Int,Rx Time Out,Rx err,Loop-back,Send break,Transmit Mode,Receive Mode // 0 1 0 , 0 1 0 0 , 01 01 // PCLK Level Pulse Disable Generate Normal Normal Interrupt or Polling rUCON0 = 0x245; //Control register 这个寄存器有16位需要配置,12-15位为零,所以禁止FCLK/n时钟(这里可以不理会) 11-10位如下图所示
所以只要第10位为0就选择PCLK给UART波特率 rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 ); //Baud rate divisior register 0 这句话也对应着上图 下图是对上面 《配置功能列表》的详细说明吧
//UART1 rULCON1 = 0x3; rUCON1 = 0x245; rUBRDIV1=( (int)(pclk/16./baud+0.5) -1 ); //UART2 rULCON2 = 0x3; rUCON2 = 0x245; rUBRDIV2=( (int)(pclk/16./baud+0.5) -1 ); for(i=0;i<100;i++);} //关于rUBRDIV可以再看看下图
//=================================================================== void Uart_Select(int ch) //s3c2440有三个UART,这个函数用来指定用哪个UART { whichUart = ch; } //===================================================================== //If you don't use vsprintf(), the code size is reduced very much. void Uart_Printf(char *fmt,...) //这个函数用到了可变参数,详细分析请看这篇文章:Uart_Printf()函数学习报告
{ va_list ap; char string[256]; va_start(ap,fmt); vsprintf(string,fmt,ap); //简单来说,上面这四行代码把参数中的那些字符串都整合在了string数组里了 Uart_SendString(string); //string里其实就是我们要打印到串口的内容了 va_end(ap); } //==================================================================== void Uart_SendString(char *pt) //打印pt指向的字符串 { while(*pt) //化整为零,逐个字符打印 Uart_SendByte(*pt++); //以字节为单位打印,对应ULCON中设置的“每帧用于发送或接收的数据位的个数”(8位) } //===================================================================== void Uart_SendByte(int data) //重头戏来了,这个函数就是真正在发送数据了 {//这边的三个分支对应三个UARTif(whichUart==0) //我们执行的是这个分支{if(data=='\n')//因为在WIN下,'\n'表示回车,换行两个意思,而在别的系统下,它只表示回车,所以最后得给它来个换行,也就是: '\r '{ //遇到'\n'时,实际发送的是'\r\n' while(!(rUTRSTAT0 & 0x2)); // Delay(1); //because the slow response of hyper_terminal WrUTXH0('\r'); }//下图为UTRSTAT寄存器第1位的功能描述while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty. 等待发送缓冲器空 // Delay(1); WrUTXH0(data);//2440addr.h中:#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)} else if(whichUart==1) //同上 { if(data=='\n') { while(!(rUTRSTAT1 & 0x2)); //Delay(1); //because the slow response of hyper_terminal rUTXH1 = '\r'; } while(!(rUTRSTAT1 & 0x2)); //Wait until THR is empty. //Delay(1); rUTXH1 = data; } else if(whichUart==2) //同上 { if(data=='\n') { while(!(rUTRSTAT2 & 0x2)); //Delay(1); //because the slow response of hyper_terminal rUTXH2 = '\r'; } while(!(rUTRSTAT2 & 0x2)); //Wait until THR is empty. //Delay(1); rUTXH2 = data; } }//===================================================================void Uart_TxEmpty(int ch) //判断发送移位寄存器是否为空{if(ch==0) while(!(rUTRSTAT0 & 0x4)); //Wait until tx shifter is empty. else if(ch==1) while(!(rUTRSTAT1 & 0x4)); //Wait until tx shifter is empty. else if(ch==2) while(!(rUTRSTAT2 & 0x4)); //Wait until tx shifter is empty. }***********************************************************************上面是有关发送的函数,下面是有关接收的函数,待以后分析//===================================================================== char Uart_Getch(void) { if(whichUart==0) { while(!(rUTRSTAT0 & 0x1)); //Receive data ready return RdURXH0(); } else if(whichUart==1) { while(!(rUTRSTAT1 & 0x1)); //Receive data ready return RdURXH1(); } else if(whichUart==2) { while(!(rUTRSTAT2 & 0x1)); //Receive data ready return RdURXH2(); } return 0 ; } //==================================================================== char Uart_GetKey(void) { if(whichUart==0) { if(rUTRSTAT0 & 0x1) //Receive data ready return RdURXH0(); else return 0; } else if(whichUart==1) { if(rUTRSTAT1 & 0x1) //Receive data ready return RdURXH1(); else return 0; } else if(whichUart==2) { if(rUTRSTAT2 & 0x1) //Receive data ready return RdURXH2(); else return 0; } return 0 ; } //==================================================================== void Uart_GetString(char *string) { char *string2 = string; char c; while((c = Uart_Getch())!='\r') { if(c=='\b') { if( (int)string2 < (int)string ) { Uart_Printf("\b \b"); string--; } } else { *string++ = c; Uart_SendByte(c); } } *string='\0'; Uart_SendByte('\n'); } //===================================================================== int Uart_GetIntNum(void) { char str[30]; char *string = str; int base = 10; int minus = 0; int result = 0; int lastIndex; int i; Uart_GetString(string); if(string[0]=='-') { minus = 1; string++; } if(string[0]=='0' && (string[1]=='x' || string[1]=='X')) { base = 16; string += 2; } lastIndex = strlen(string) - 1; if(lastIndex<0) return -1; if(string[lastIndex]=='h' || string[lastIndex]=='H' ) { base = 16; string[lastIndex] = 0; lastIndex--; } if(base==10) { result = atoi(string); result = minus ? (-1*result):result; } else { for(i=0;i<=lastIndex;i++) { if(isalpha(string[i])) { if(isupper(string[i])) result = (result<<4) + string[i] - 'A' + 10; else result = (result<<4) + string[i] - 'a' + 10; } else result = (result<<4) + string[i] - '0'; } result = minus ? (-1*result):result; } return result; } //***************************************************************************** //get a number for the uart //***************************************************************************** int Uart_GetIntNum_GJ(void) { char string[16] ; char *p_string = string ; char c; int i = 0 ; int data = 0 ; while( ( c = Uart_Getch()) != '\r' ) { if(c=='\b') p_string--; else *p_string++=c; Uart_SendByte( c ) ; } *p_string = '\0'; i = 0 ; while( string[i] != '\0' ) { data = data * 10 ; if( string[i]<'0'||string[i]>'9' ) return -1 ; data = data + ( string[i]-'0' ) ; i++ ; } return data ; } //*****************************************************************************