Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7723652
  • 博文数量: 961
  • 博客积分: 15795
  • 博客等级: 上将
  • 技术积分: 16612
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-07 14:23
文章分类

全部博文(961)

文章存档

2016年(1)

2015年(61)

2014年(41)

2013年(51)

2012年(235)

2011年(391)

2010年(181)

分类: 嵌入式

2011-07-14 16:12:44

SPIIICUART是最常用的三种串行总线,这三种总线在s3c2440中都被集成了。在这里我们主要介绍UART,另两个总线在后面的文章中给出。

 

UARTUniversal Asynchronous Receiver/Transmitter,通用异步接收/发送装置)用于异步通信,可以实现全双工发送和接收。它不仅可以实现不同嵌入式系统之间的通信,还可以实现与PC之间的通信。

s3c2440提供了三个UART端口,它们都可以通过查询、中断和DMA方式传输数据,而且每个UART都分别有一个64个字节的接收FIFO和一个64个字节的发送FIFO。在这里,我们只给出非FIFO模式,即传输数据不利用FIFO缓存,一个字节一个字节地传输。

 

下面我们就给出如何用s3c2440来实现非FIFOUART通信。要实现某种通信,就必须遵循该通信协议。UART的协议包括传输数据的位数,停止位的位数,以及是否进行奇偶校验,这些设置是利用ULCONn寄存器完成的。另一个很重要的地方就是设置波特率。s3c2440波特率的时钟源有三个:PCLKFCLK/nUEXTCLK。时钟源的选择是由UCONn的第10位和第11位来完成的。波特率的具体计算公式为:

时钟源频率÷(波特率×16)-1

 

这个计算结果很可能是小数,把该小数取最接近的整数,放入寄存器UBRDIVn中就完成了波特率的设置。如我们选择波特率的时钟源为PCLK,它为50MHz,我们设置的波特率为115.2kHz,通过上式计算的结果为26.13,取整后得到26,那么我们把26放入UBRDIVn中即可。由于我们没有使用FIFOMODEM,所以可以不用设置FIFO控制寄存器UFCONnMODEM控制寄存器UMCONn。通过以上寄存器的设置,UART就可以正常传输数据。

 

接收到的数据是放到接收缓存器URXHn中,要发送数据时,是把数据放入发送缓存器UTXHn中。由于UART是通过字节方式传输数据的,因此要区分是大端模式还是小端模式,也就是说这两个寄存器在这两种模式下,所在的地址是不同。为了了解当前数据传输的各种状态,还需要一些状态寄存器。传输状态寄存器UTRSTATn非常有用,它的第0位可以用来判断接受缓存器内是否有可接收的数据,第1位和第2位可以用来判断发送缓存器中是否为空,为空时可以发送数据。由于在这里我们不进行传输数据时错误的判断,因此错误状态寄存器UERSTATn不需要,FIFO状态寄存器UFSTATnMODEM状态寄存器UMSTATn在这里也不需要。

我们给出UART通信的两种方法:查询和中断。为了验证程序,使用任一款的串行通信软件来实现PCs3c2440之间的通信即可。

首先给出的是查询程序。它是在主程序的循环体内不断查询UART端口,当有数据来时,就接收数据,并再通过UART发送该数据。然后根据所接收数据的不同,分别执行不同的内容,如点亮、熄灭LED,蜂鸣器响、或不响。在这里,我们每次只完成一个字节的传输。

 

 

//======================================================================

//  工程名称:  UART.mcp

//  功能描述:  通过超级终端完成PCS3C2440的数据传输,

//              利用超级终端输入需要发送的字符

//              读取接到的数字控制LED灯的亮灭

//  IDE环境:   ADS v1.2 TX2440A

//  组成文件: 

//  硬件连接: 

//  维护记录:  Lzy     2011-7-14  V1.0       

//======================================================================

 

#include "2440addr.h"   

#include "string.h"

#include "def.h"

#include "2440lib.h"

#include "uart.h"

 

#define LED1ON    0xFE

#define LED2ON    0xFD

#define LED3ON    0xFB

#define LED4ON    0xF7

#define LEDOFF    0xFF

 

int Main(void)

{  

    char num;

   

    memcpy((unsigned char *)0x0,(unsigned char *)0x30000000,0x1000);

 

    /*初始化系统时钟*/

    SetSysFclk(FCLK_400M);      //设置系统时钟 400M    

    ChangeClockDivider(2, 1);      //设置分频 148

    CalcBusClk();                     //计算总线频

 

    rGPFCON = (rGPFCON | 0xFFFF) & 0x55;  //GPF0--GPF3设置为output    

   rGPFUP  = rGPFUP & 0xFFF0;                  //使能GPF上拉电阻

   rGPFDAT = 0xFF;                            //GPF4位初始化为1  

   

   

    Uart_Select(0);                       //选择串口

    Uart_Init(0,115200);             //选择时钟源(0->PCLL)和设置波特率

    Uart_Printf("\nUART TEST\n");

   

    while(1)

    {

   

        Uart_Printf("\n\n灯号(1-4)> ");         //发送命令提示行

        num = Uart_Getch();                  //接收数据

       

        switch(num)

        {

        case '1':

            Uart_Printf("LED1 ON!\n");     

           rGPFDAT = LED1ON;                   //点亮LED1

               break;

        case '2': 

               Uart_Printf("LED2 ON!\n");      

               rGPFDAT = LED2ON;                   //点亮LED2

               break;

        case '3':

               Uart_Printf("LED3 ON!\n");      

               rGPFDAT = LED3ON;                   //点亮LED3

               break;

        case '4':

               Uart_Printf("LED4 ON!\n");      

            rGPFDAT = LED4ON;                   //点亮LED4

               break;

        default:

           Uart_Printf("LED OFF!\n"); 

           rGPFDAT = LEDOFF;

           break;

        }

    }  

}

 

 

 

//=============================================================

// 文件名称:  uart.c

// 功能描述:  UART相关函数

// 维护记录:  2009-8-14  V1.0 

//=============================================================

#include

#include

#include

#include

#include

 

#include "option.h"

#include "2440addr.h" 

#include "2440lib.h"

 

extern unsigned int PCLK;

static int UartNum=0;

char *string;

 

void Uart_Select(int ch)

{

    UartNum = ch;

}

 

//====================================================

// 语法格式:void Uart_Init(int whichuart, int baud)

// 功能描述: Uart进行初始化,以所需要的波特率为输入参数

// 入口参数: UART端口号  波特率

// 出口参数:

//======================================================================

void Uart_Init(int pclk, int baud)

{

   if(pclk == 0)

       pclk = PCLK;

   if(UartNum==0)        //判断是否使用UART0    

   {

       rGPHCON = rGPHCON & (~(0xffff));   //UART0: RXD0<==>GPH3  TXD0<==>GPH2

        rGPHCON = rGPHCON | (0xaaa0) ;     //设置GPH端口为UART

       rGPHUP  = 0x0;                     //使能上拉功能

   

        rUFCON0=0x0;   // 不使用FIFO 

        rUMCON0=0x0;   //不使用自动流控制

        rULCON0=0x3;   //不采用红外线传输模式,无奇偶校验位,1个停止位,8个数据位

        rUCON0=0x245;   //发送中断为电平方式,接收中断为边沿方式,禁止超时中断,允许产生错误状态中断,禁止回送模式,禁止中止信号,传输模式为中断请求模式,接收模式也为中断请求模式。       

                       

       rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 ); //根据波特率计算UBRDIV0的值

        Delay(10);

    }

    else if(UartNum==1)

    {       

        rGPHCON = rGPHCON & (~(0xffff)) ; //UART1: RXD1<==>GPH5  TXD1<==>GPH4

        rGPHCON = rGPHCON | (0xaaa0) ;    //设置GPH端口为UART

       rGPHUP  = 0x0;                    // 使能上拉功能

   

        rUFCON1=0x0;    

        rUMCON1=0x0;  

        rULCON1=0x3;

        rUCON1=0x245;

        rUBRDIV1=((int)(pclk/(baud*16))-1);

        Delay(10);

    }

    else if(UartNum==2)

    {       

        rGPHCON = rGPHCON & (~(0xffff)) ; //UART1: RXD2<==>GPH7  TXD2<==>GPH6

        rGPHCON = rGPHCON | (0xaaa0) ;    //设置GPH端口为UART

       rGPHUP  = 0x0;                    // 使能上拉功能

   

        rUFCON2=0x0;   

        rUMCON2=0x0;  

        rULCON2=0x3;

        rUCON2=0x245;

        rUBRDIV2=((int)(pclk/(baud*16))-1);

        Delay(10);

    }

}

 

//====================================================

// 语法格式:void Uart_TxEmpty(int ch)

// 功能描述:

// 入口参数: 串口号

// 出口参数:

//====================================================================

void Uart_TxEmpty(int ch)

{

    if(ch==0)

        while(!(rUTRSTAT0 & 0x4)); //等待发送缓冲区为空

         

    else if(ch==1)

        while(!(rUTRSTAT1 & 0x4));

       

    else if(ch==2)

        while(!(rUTRSTAT2 & 0x4));

}

 

 

//====================================================

// 语法格式:void Uart_SendByte(char ch)

// 功能描述: 发送字节数据

// 入口参数: 发送的字节数据      

// 出口参数:

//====================================================================

void Uart_SendByte(char ch)

{

    if (UartNum == 0)

    {

        if(ch=='\n')

        {

            while(!(rUTRSTAT0 & 0x2));  //等待,直到发送缓冲区为空

//          Delay(10);                //超级中断的响应速度较慢

            WrUTXH0('\r');              //发送回车符

        }

        while(!(rUTRSTAT0 & 0x2));      //等待,直到发送缓冲区为空

//      Delay(10);

        WrUTXH0(ch);                    //发送字符

   }

    else if (UartNum == 1)

    {

        if(ch=='\n')

        {

            while(!(rUTRSTAT1 & 0x2));   //等待,直到发送缓冲区为空

//          Delay(10);                     //等待

            rUTXH1='\r';

        }

        while(!(rUTRSTAT1 & 0x2));  //Wait until THR is empty.

//      Delay(10);

        WrUTXH1(ch);

    }

    else if (UartNum == 2)

    {

        if(ch=='\n')

        {

            while(!(rUTRSTAT2 & 0x2));   //等待,直到发送缓冲区为空

//          Delay(10);                     //等待

            rUTXH2='\r';

        }

        while(!(rUTRSTAT2 & 0x2));  //Wait until THR is empty.

//      Delay(10);

        WrUTXH2(ch);

    }     

}

 

 

//====================================================

// 语法格式:char Uart_ReceiveByte(void)

// 功能描述: 接收字节数据

// 入口参数:

// 出口参数: 接收的字节数据

//====================================================================

char Uart_ReceiveByte(void)

{

    if(UartNum==0)

    {      

        while(!(rUTRSTAT0 & 0x1)); //等待接收数据

        return RdURXH0();

    }

    else if(UartNum==1)

    {      

        while(!(rUTRSTAT1 & 0x1)); //等待接收数据

        return RdURXH1();

    }

    else if(UartNum==2)

    {

        while(!(rUTRSTAT2 & 0x1));

        return RdURXH2();

    }

    return 0;

}

 

 

//====================================================

// 语法格式:char Uart_Getch(void)

// 功能描述: 接收一个字符,和Uart_ReceiveByte一样

// 入口参数:

// 出口参数: 接收的字节数据

//====================================================================

char Uart_Getch(void)

{

    if(UartNum==0)

    {      

        while(!(rUTRSTAT0 & 0x1));

        return RdURXH0();

    }

    else if(UartNum==1)

    {      

        while(!(rUTRSTAT1 & 0x1));

        return RdURXH1();

    }

    else if(UartNum==2)

    {

        while(!(rUTRSTAT2 & 0x1));

        return RdURXH2();

    }

   

    return 0 ;

}

 

 

//====================================================

// 语法格式:char Uart_GetKey(void)

// 功能描述: 得到键值,和Uart_ReceiveByte一样

// 入口参数:

// 出口参数: 接收的字节数据

//====================================================================

char Uart_GetKey(void)

{

    if(UartNum==0)

    {      

        if(rUTRSTAT0 & 0x1)    //Receive data ready

            return RdURXH0();

        else

            return 0;

    }

    else if(UartNum==1)

    {

        if(rUTRSTAT1 & 0x1)    //Receive data ready

            return RdURXH1();

        else

            return 0;

    }

    else if(UartNum==2)

    {      

        if(rUTRSTAT2 & 0x1)    //Receive data ready

            return RdURXH2();

        else

            return 0;

    }   

 

    return 0 ;

}

 

 

//====================================================

// 语法格式:void Uart_Send (char *str)

// 功能描述: 发送字符串

// 入口参数: 字符串指针

// 出口参数:

//====================================================================

void Uart_Send (char *str)

{

    while (*str)

        Uart_SendByte(*str++);

}  

 

 

//====================================================

// 语法格式:void Uart_receive(char *string)

// 功能描述: 接收字符串

// 入口参数: 字符串指针

// 出口参数:

//===================================================================

void Uart_receive(char *string)

{

     char *string2 ;

     char c;

     string2 = string;

     while((c = Uart_ReceiveByte())!='\r')

     {

        if(c=='\b')

        {

            if( (int)string2 < (int)string )

            {

                printf("\b \b");

                string--;

            }

        }

        else

        {

            *string++ = c;           

            Uart_SendByte(c);

        }

     }

     *string='\0';

     Uart_SendByte('\n');   

    

}

 

 

//====================================================

// 语法格式:int Uart_GetIntNum(void)

// 功能描述: 得到整型数

// 入口参数:

// 出口参数: 整型数

//====================================================================

int Uart_GetIntNum(void)

{

    char str[30];

    char *string = str;

    int base     = 10;

    int minus    = 0;

    int result   = 0;

    int lastIndex;   

    int i;

   

   Uart_receive(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 ;

}

 

 

//====================================================

// 语法格式:void Uart_Printf(char *fmt,...)

// 功能描述: 按格式输出字符串

// 入口参数: printf格式的字符串

// 出口参数:

//===================================================================

 

void Uart_Printf(char *fmt,...)

{

    va_list ap;               //指向参数的指针

    char string[256];   

 

    va_start(ap,fmt);        //初始化变量刚定义的VA_LIST变量;

    vsprintf(string,fmt,ap);//送格式化输出到串中

    Uart_Send(string);

    va_end(ap);               //结束可变参数的获取

}

 

 

//=============================================================

// 文件名称:  uart.h

// 功能描述:  UART相关函数

// 维护记录:  2009-8-14  V1.0 

//=============================================================

 

#ifndef __UART_H_

#define __UART_H_

 

void Uart_Select(int ch);

void Uart_Init(int whichuart, int baud);

void Uart_TxEmpty(int ch);

void Uart_SendByte(char ch);

char Uart_ReceiveByte(void);

char Uart_Getch(void);

char Uart_GetKey(void);

int  Uart_GetIntNum(void);

int  Uart_GetIntNum_GJ(void);

void Uart_Send(char *str);

void Uart_receive(char *string);

void Uart_Printf(char *fmt,...);

 

#endif //__UART_H_

 

 

 

va_list 详解 VA_LIST 是在C语言中解决变参问题的一组宏

他有这么几个成员:

1 va_list型变量:

#ifdef  _M_ALPHA

typedef struct {

        char *a0;       /* pointer to first homed integer argument */

        int offset;     /* byte offset of next parameter */

} va_list;

#else

typedef char *  va_list;

#endif

2_INTSIZEOF 宏,获取类型占用的空间长度,最小占用长度为int的整数倍:

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

3VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):

#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )

4VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):

#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

5VA_END宏,清空va_list可变参数列表:

#define va_end(ap)      ( ap = (va_list)0 )

VA_LIST的用法:     

       1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;

       2)然后用VA_START宏初始化变量刚定义的VA_LIST变量;

       3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);

       4)最后用VA_END宏结束可变参数的获取。

使用VA_LIST应该注意的问题:

   1)可变参数的类型和个数完全由程序代码控制,它并不能智能地识别不同参数的个数和类型;

   2)如果我们不需要一一详解每个参数,只需要将可变列表拷贝至某个缓冲,可用vsprintf函数;

   3)因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码;

小结:可变参数的函数原理其实很简单,而VA系列是以宏定义来定义的,实现跟堆栈相关。我们写一个可变参数的C函数时,有利也有弊,所 以在不必要的场合,我们无需用到可变参数,如果在C++里,我们应该利用C++多态性来实现可变参数的功能,尽量避免用C语言的方式来实现。

va_list 详解:http://hi.baidu.com/kang_liang/blog/item/168c9059a9a1ca2d2934f05f.html

 

 

 串口程序代码 uart.rar   

 

 

阅读(2001) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~