UART实验程序设计及分析
void Uart_Printf(char *fmt,...)
{
va_list ap; //声明一个va_list,
char string[256];
va_start(ap,fmt); //然后用va_start函数来获取参数列表中的参数
/* 函数名: vsprintf 功能: 送格式化输出到串中
返回值: 正常情况下返回生成字串的长度
(除去\0),错误情况返回负值
用 法: int vsprintf(char *string, char *format, va_list param);
// 将param 按格式format写入字符串string中
注: 该函数会出现内存溢出情况,
建议使用vsnprintf */
vsprintf(string,fmt,ap);
Uart_SendString(string);
va_end(ap); //把ap指向NULL
}
http://blog.sina.com.cn/s/blog_642c9bdd0100llov.html
//发送字符串由发送字符组成
void Uart_SendString(char *pt)
{
while(*pt)
Uart_SendByte(*pt++);
}
void Uart_SendByte(int data)
{
if(whichUart==0) //选择第几个串口
{
if(data=='\n') //当发送的是换行回车符时做的动作
{
while(!(rUTRSTAT0 & 0x2));
WrUTXH0('\r');
}
//等待原来的数据已经发送结束再把数据写进发送缓冲寄存器
while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty.
WrUTXH0(data);
}
}
其中:#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000023)=(unsigned char)(ch)
寄存器定义。
WrUTXH0('\r');就是把'\r'写到寄存器[0x50000023]里
<tbody><tr><td width="670px"><div>RdURXH0(),WrUTXH0(),找不到函数的原型,后来在寄存器定义里面看到了。如下:
<p>#define rUTXH0 (*(volatile unsigned char *)0x1d00020)<br>#define rUTXH1 (*(volatile unsigned char *)0x1d04020)<br>#define rURXH0 (*(volatile unsigned char *)0x1d00024)<br>#define rURXH1 (*(volatile unsigned char *)0x1d04024)<br>#define WrUTXH0(ch) (*(volatile unsigned char *)0x1d00020)=(unsigned char)(ch)<br>#define WrUTXH1(ch) (*(volatile unsigned char *)0x1d04020)=(unsigned char)(ch)<br>#define RdURXH0() (*(volatile unsigned char *)0x1d00024)<br>#define RdURXH1() (*(volatile unsigned char *)0x1d04024)<br>#define UTXH0 (0x1d00020) //byte_access address by BDMA<br>#define UTXH1 (0x1d04020)<br>#define URXH0 (0x1d00024)<br>#define URXH1 (0x1d04024)</p>
<p> WrUTXH0('\r'),即把'\r'写到寄存器[0x1d00020]里面,而寄存器[0x50000027]是UART0的发送寄存器,也就是换行。而rUTXH0,也是UART的发送保持寄存器,若要做WrUTXH0('\r')相同的效果,则需把相应的命令值赋给rUTXH0:即:rUTXH0=“\r”。</p>
</div></td></tr></tbody></table>
http://www.360doc.com/content/11/0112/17/4591140_86020062.shtml
#define A (* (volatile unsigned *) 0x48000000 )</span></div>
<div><br>对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。</div>
<div>如果是内存映射,那就方便的多了。</div>
<div>举个例子,比如向寄存器A(地址假定为0x48000000)写入数据0x01,那么就可以这样设置了:</div>
<div>#define A (*(volatile unsigned *) 0x48000000 )<br>...<br> A = 0x01;<br>...</div>
<div>这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一个重要特点。</div>
<div>volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去改变,而是由硬件去改变。</div>
<div>volatile 限定编译器不对这个指针的指向的存储单元进行优化, 即不用通用寄存器暂时代替这个指针的指向的存储单元,而是每次取值都直接到指针的指向的存储单元取值.volatile 主要用于变量会异步改变的情下,主要有三个方面:</div>
<div>1.cpu外设寄存器</div>
<div>2.中断和主循环都会用到的全局变量</div>
<div>3.操作系统中的线程间都会用到的公共变量.</div>
<div> </div>
<div>上述表达式拆开来分析:</div>
<div>首先(volatile unsigned *) 0x48000000的意思是把0x48000000强制转换成volatile unsigned类型的指针,即对指针的操作的范围是从0x48000000开始的4个字节(int型),暂记为p。那么就有:</div>
<div>#define A *p,即A为P指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作!</div>
//串口初始化设置
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
rUCON0 = 0x245; // Control register interrupt request mode, trigger level use PCLK
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++);
}
同理,接收数据的程序如下:
//判断接收是否空
void Uart_TxEmpty(int ch)
{
if(ch==0)
while(!(rUTRSTAT0 & 0x4)); //Wait until tx shifter is empty.
}
char Uart_Getch(void)
{
if(whichUart==0)
{
while(!(rUTRSTAT0 & 0x1)); //Receive data ready
return RdURXH0();
}
}
//此函数供RTC 调用,和Uart_Getch的区别在于没while的死循环
char Uart_GetKey(void)
{
if(whichUart==0)
{
if(rUTRSTAT0 & 0x1) //Receive data ready
return RdURXH0();
else
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;
}
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 ;
}