Mini2440有三个串口,USRT0,UART1,UART3。
对串口的操作有三种:串口初始化,串口接收,串口发送
1 串口初始化
1)串口初始化函数
void Uart_Init(int pclk,int baud)
{
int i;
if(pclk == 0)
pclk = PCLK;
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
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++);
}
l 串口时钟的设置
pclk = PCLK;使用PCLK作为串口的时钟。
l 寄存器进行了设置
主要是对三种寄存器进行了设置
rUFCONn (n=0,1,2) —— 串口FIFO控制寄存器
rUMCONn (n=0,1)——串口调制控制寄存器
rULCONn (n=0,1,2)——串口线性控制寄存器
rUCONn(n=0,1,2)——串口控制寄存器
rUBRDIVn(n=0,1,2)——串口Tx,Rx收发速率的设定
2)串口的选择
void Uart_Select(int ch)
{
whichUart = ch;
}
2 串口发送
串口发送数据通过判断rUTRSTATn (n=0,1,2)的第2位是不是为1来判断发送缓存是否为空。
1) 串口发送字节
void Uart_SendByte(int data)
{
if(whichUart==0)
{
if(data=='/n')
{
while(!(rUTRSTAT0 & 0x2));
// Delay(1); //because the slow response of hyper_terminal
WrUTXH0('/r');
}
while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty.
// Delay(1);
WrUTXH0(data);
}
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;
}
}
首先是串口通道的选择;然后判断THR是否为空,直到等到发送缓存为空,退出while循环;再要发送的字节data放到发送缓存中。如果发送的数据是回车的话,直接发送转义字符/r,当然也要等到THR为空才可以发送。
2) 串口发送字符串
void Uart_SendString(char *pt)
{
while(*pt)
Uart_SendByte(*pt++);
}
把字符串看作是字符数组,字符指针*pt来指代字符数组的首地址,读取指针指向的字符,这样就可以把发送的的字符串逐个进行字节发送了。
2 串口接收
串口接收通过判断rUTRSTATn (n=0,1,2)的第1位是不是为1来判断发送缓存是否为空。
1)串口等待接收状态
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.
}
寄存器rUTRSTATn & 0x4 (n=0,1,2)来判断tx shifter是不是为空
3) 接收字符
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 ;
}
寄存器rUTRSTATn & 0x1 (n=0,1,2)来判断Receive data ready?并把接收到的数据写到接收缓存里面。
4) 接收字符串
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');
}
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 ;
}
寄存器rUTRSTATn & 0x1 (n=0,1,2)
来判断Receive data ready?并把接收到的数据写到接收缓存里面。否则返回空。与getchar类似,并且也是返回字符类型。
5) 接收整形数字
函数返回类型:整形
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))
{
if(isupper(string))
result = (result<<4) + string - 'A' + 10;
else
result = (result<<4) + string - 'a' + 10;
}
else
result = (result<<4) + string - '0';
}
result = minus ? (-1*result):result;
}
return result;
}
首先以字符串的形式接收数据Uart_GetString(string);
然后通过判断是不是以‘-’开头来确定是不是负数,是负数则minus=1;再通过以0x,oX开头或者以H,h结尾来判断是不是16进制,否则为10进制;如果是10进制,则通过atoi把字符串转化为数字,并加上正负,如果是16进制,判断是不是字母,再判断大小写字母分别进行转换。16进制也支持正负号。
6) 接收10进制的数
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 != '/0' )
{
data = data * 10 ;
if( string<'0'||string>'9' )
return -1 ;
data = data + ( string-'0' ) ;
i++ ;
}
return data ;
}
只转化10进制的数字。首先用getchar接收单个字符存储在string中,然后把string转换为整型的data。并返回整形的data。
3串口打印
//If you don't use vsprintf(), the code size is reduced very much.
void Uart_Printf(char *fmt,...)
{
va_list ap;
char string[256];
va_start(ap,fmt);
vsprintf(string,fmt,ap);
Uart_SendString(string);
va_end(ap);
}
va_list完成可变参数的操作
具体实现如下
n 由于无法列出传递函数的所有实参的类型和数目时,用省略号指定参数表
void Uart_Printf(char *fmt,...)
n 函数参数的传递原理
函数参数是以数据结构:栈的形式存取,从右至左入栈.
n 获取省略号指定的参数
在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。
va_list ap;
char string[256];
va_start(ap,fmt);
vsprintf(string,fmt,ap);
Uart_SendString(string);
va_end(ap);
va_start使ap指向第一个可选参数。va_end把ap指针清为NULL。函数体内可以多次遍历这些参数,但是都必须以va_start开始,并以va_end结尾。
vsprintf(string,fmt,ap);实现向字符数组中写指定格式的内容
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/garby2004/archive/2009/09/28/4604887.aspx