uart串口发送---那些年我们一起玩mini2440(arm9)裸机

Uart工作原理:

数据通信方式为:并行通信串行通信两种:

§并行通信:利用多条数据线将数据的各位同时传送

它的特点是:传输速度快,是用于短距离通信;

§串行通信:利用一条数据线将数据一位位地顺序传送。

特点是通信线路简单,利用简单的线缆就实现通信,低成本,是用于远距离通信。

异步通信:

ª异步通信:以一个字符为传输单位,通过两个字符间的时间间隔是不固定的,然而同一字符中的两个相邻位之间的时间间隔是固定的

ª通信协议:是指通信双方约定的一些规则。在异步通讯时,对数据格式有如下约定:规定有空闲位、起始位、资料位、奇偶校验位、停止位。

起始位:先发一个逻辑“0”信号,表示传输字符的开始;

数据位:紧接在起始位之后。数据位的个数可以是45678等,从最低位开始传送,靠时钟定位。

奇偶校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或(奇校验),以此校验数据传送的正确性。

停止位:它是一个字符数据的结束标志。

空闲位:处于逻辑“1”状态,表示当前线路没有数据传送。

波特率:

是衡量数据传送率的指标:记录每秒中传送的二进制位数。例如:数据传送速率为120字符、每秒。而每一个字符为10位,则其传送的波特率为10*120=1200/=1200波特率

UART基本原理

通用异步收发器,简称UART,即“Universal Asynchronous Receiver Transmitter”,它用来传输串行数据;

发送数据时:

CPU将并行数据写入UARTUART按照一定的格式在一根电线上串行发出;

接收数据时:

UART检测另一根电线上的信号,将串行数据放在缓冲区中,CPU可读取UART获得的这些数据。

UART驱动程序设计

UART初始化:1.发送数据;2.接收数据;

UART初始化:1.设置波特率; 2.设置数据传输格式;3.选择通道工作模式;

一.设置波特率:UBRDIV

s3c2440中,通过UBRDIV(p352)寄存器可以设定UART的波特率。Uart0Uart1Uart2分别对应UBRDIV0UBRDIV1UBRDIV2

到底UBRDIV寄存器中的值与波特率有何关系?

UBRDIV=(int)UART clock/ (buad rate *16)-1

UART clockPCLK or FCLK/ n or UEXTCLK

如波特率为115200bpsUART时钟为40MHZ

UBRDIV =(int) (40MHZ /(115200*16))-1

二.设置数据传输格式ULCON

s3c2440中,通过ULCON(page341),可以设置传输格式(有多少个数据位是否使用校验位、是奇校验还是偶校验,有多少个停止位、是否使用流量控制

Uart0Uart1Uart2分别对应ULCON0ULCON1ULCON2.

三.设置通道工作模式UCON

s3c2440中,通过UCON(page342),可以设置UART通道的工作模式,(中断模式、查询模式、或DMA模式)

Uart0Uart1Uart2分别对应UCON0UCON1UCON2.

这三步都属于初始化:初始化完成之后à发送或/接收数据

发送数据:

将要发送的数据写UTXHn, UART会将保存到缓冲区中,并自动发出去

UTXH0UTXH1UTXH2

接收数据:

UART收到数据时UTRSTATn寄存器bit[0]被置1CPU读取URXHn寄存器,即可获得数据。

URXH0URXH1URXH2寄存器中读取数据

Main.c

#define   GLOBAL_CLK           1

#include <stdlib.h>

#include <string.h>

#include "def.h"

#include "option.h"

#include "2440addr.h"

#include "2440lib.h"

#include "2440slib.h"

#include "mmu.h"

#include "profile.h"

#include "memtest.h"

 

static void cal_cpu_bus_clk(void);

void Set_Clk(void);

/*************************************************

Function name: delay

Parameter    : times

Description    :延时函数

Return          : void

Argument     : void

Autor & date : Daniel

**************************************************/

void delay(int times)

{

    int i,j;

    for(i=0;i<times;i++)

       for(j=0;j<400;j++);

}

/*************************************************

Function name: Main

Parameter    : void

Description     : 主功能函数,实现了串口的收发功能

               首先想串口发送十次“hello world”,

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/

void Main(void)

{     

    int i;

    int Scom=0;

    Set_Clk();

    beep_init();

    

    /*设置波特率、数据位、停止位、校验位*/

    Uart_Init(0,115200);

    Uart_Select(Scom);

    for(i=0;i<10;i++)

    Uart_Printf("\nHello World!\n");

    

    while(1)

    {

      while(Uart_GetKey()=='r')

      {

          for(i=0;i<10;i++)

          beep_run();

          Uart_Printf("\nBeep Quit!\n");

      }

       }

 

}     

     

/*************************************************

Function name: Set_Clk()

Parameter    : void

Description     : 设置CPU的时钟频率

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/

void Set_Clk(void)

{

       int i;

       U8 key;

       U32 mpll_val = 0 ;

       i = 2 ;                  //don't use 100M!

                               //boot_params.cpu_clk.val = 3;

       switch ( i ) {

       case 0:     //200

              key = 12;

              mpll_val = (92<<12)|(4<<4)|(1);

              break;

       case 1:     //300

              key = 13;

              mpll_val = (67<<12)|(1<<4)|(1);

              break;

       case 2:     //400

              key = 14;

              mpll_val = (92<<12)|(1<<4)|(1);

              break;

       case 3:     //440!!!

              key = 14;

              mpll_val = (102<<12)|(1<<4)|(1);

              break;

       default:

              key = 14;

              mpll_val = (92<<12)|(1<<4)|(1);

              break;

       }

       

       //init FCLK=400M, so change MPLL first

       ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);   //set the register--rMPLLCON

       ChangeClockDivider(key, 12);    //the result of rCLKDIVN [0:1:0:1] 3-0 bit

       cal_cpu_bus_clk();    //HCLK=100M   PCLK=50M

}

/*************************************************

Function name: cal_cpu_bus_clk

Parameter    : void

Description     : 设置PCLK\HCLK\FCLK的频率

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/

static void cal_cpu_bus_clk(void)

{

       static U32 cpu_freq;

    static U32 UPLL;

       

       U32 val;

       U8 m, p, s;

       

       val = rMPLLCON;

       m = (val>>12)&0xff;

       p = (val>>4)&0x3f;

       s = val&3;

 

       //(m+8)*FIN*2不要超出32位数!

       FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;     //FCLK=400M  FIN=12000000

       

       val = rCLKDIVN;

       m = (val>>1)&3;

       p = val&1;     

       val = rCAMDIVN;

       s = val>>8;

       

       switch (m) {

       case 0:

              HCLK = FCLK;

              break;

       case 1:

              HCLK = FCLK>>1;

              break;

       case 2:

              if(s&2)

                     HCLK = FCLK>>3;

              else

                     HCLK = FCLK>>2;

              break;

       case 3:

              if(s&1)

                     HCLK = FCLK/6;

              else

                     HCLK = FCLK/3;

              break;

       }

       

       if(p)

              PCLK = HCLK>>1;

       else

              PCLK = HCLK;

       

       if(s&0x10)

              cpu_freq = HCLK;

       else

              cpu_freq = FCLK;

              

       val = rUPLLCON;

       m = (val>>12)&0xff;

       p = (val>>4)&0x3f;

       s = val&3;

       UPLL = ((m+8)*FIN)/((p+2)*(1<<s));

       UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;

}

 


2440lib.c

#include "def.h"

#include "option.h"

#include "2440addr.h"

#include "2440lib.h"

#include "2440slib.h"

 

#include <stdarg.h>

#include <string.h>

#include <stdlib.h>

#include <stdio.h>

#include <ctype.h>

static int whichUart=0;

 

void Port_Init0(void)  //IO端口初始化

{

       //*** PORT H GROUP

  //Ports  :  GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1  GPH0 //Signal : CLKOUT1 CLKOUT0 UCLK nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0

    //Binary :   10   ,  10     10 , 11    11  , 10   10 , 10   10 , 10    10

     rGPHCON = 0x00faaa;

     rGPHUP  = 0x7ff;    // The pull up function is disabled GPH[10:0]

}

 

void Uart_Init(int pclk,int baud)

{

    int i;

    if(pclk == 0)

    pclk    = PCLK;

    rUFCON0 = 0x0;   //UART channel 0 FIFO control register, FIFO disable

    rUMCON0 = 0x0;   //UART chaneel 0 MODEM control register, AFC disable(AFC:流量控制)

   //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

    for(i=0;i<100;i++);

}

 

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

void Uart_Select(int ch)

{

    whichUart = ch;

}

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

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;

    }       

}               

 

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

void Uart_SendString(char *pt)

{

    while(*pt)

        Uart_SendByte(*pt++);

}

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

//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);//va_start、 va_end成对出现,ap指向fmt之后的参数

    vsprintf(string,fmt,ap);//把ap之后的参数拷贝进string

    Uart_SendString(string);

    va_end(ap);

}


中断方式,串口发送:

#define    GLOBAL_CLK             1

#include <stdlib.h>

#include <string.h>

#include "def.h"

#include "option.h"

#include "2440addr.h"

#include "2440lib.h"

#include "2440slib.h"

#include "mmu.h"

#include "profile.h"

#include "memtest.h"

 

 

void Uart0INT_init(void);

static void __irq IRQ_ISR_UART0(void);

void Set_Clk(void);

static void cal_cpu_bus_clk(void);

/*************************************************

Function name: delay

Parameter    : times

Description     : 延时函数

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/

void delay(int times)

{

    int i,j;

    for(i=0;i<times;i++)

       for(j=0;j<400;j++);

}

/*************************************************

Function name: Main

Parameter    : void

Description     : 主功能函数

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/

int Main(void)

{     

    Set_Clk();

    MMU_Init();

    Uart0INT_init();

       return 0 ;

}     

/*************************************************

Function name: Uart0INT_init()

Parameter    : void

Description     : 中断初始化函数,用于配置中断所需要的

               几个寄存器

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/   

void Uart0INT_init(void)

{

  

  Uart_Init( 0,115200);

  Uart_Select(0);

  

  rPRIORITY = 0x00000000;     /*默认优先级*/

  rINTMOD = 0x00000000;       /*默认IRQ中断*/

  

  /*清中断*/

  ClearSubPending(BIT_SUB_RXD0);

  ClearPending(BIT_UART0);

  

  /*设置UART的ISR*/

  pISR_UART0 = (U32)IRQ_ISR_UART0;

  EnableIrq(BIT_UART0);

  EnableSubIrq(BIT_SUB_RXD0);

 

}

/*************************************************

Function name: IRQ_ISR_UART0()

Parameter    : void

Description     : 中断服务子程序,该子程序的作用就是把

               串口收到的数据发送到超级终端。

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/

static void __irq IRQ_ISR_UART0(void)

{

        if(rSUBSRCPND & 0x1)

           {

                     rUTXH0 = rURXH0;  /*这里没考虑回车*/

                     ClearSubPending(BIT_SUB_RXD0);

              }

           ClearPending(BIT_UART0);

}

 

/*************************************************

Function name: Set_Clk()

Parameter    : void

Description     : 设置CPU的时钟频率

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/

void Set_Clk(void)

{

       int i;

       U8 key;

       U32 mpll_val = 0 ;

       i = 2 ;                  //don't use 100M!

                               //boot_params.cpu_clk.val = 3;

       switch ( i ) {

       case 0:     //200

              key = 12;

              mpll_val = (92<<12)|(4<<4)|(1);

              break;

       case 1:     //300

              key = 13;

              mpll_val = (67<<12)|(1<<4)|(1);

              break;

       case 2:     //400

              key = 14;

              mpll_val = (92<<12)|(1<<4)|(1);

              break;

       case 3:     //440!!!

              key = 14;

              mpll_val = (102<<12)|(1<<4)|(1);

              break;

       default:

              key = 14;

              mpll_val = (92<<12)|(1<<4)|(1);

              break;

       }

       

       //init FCLK=400M, so change MPLL first

       ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);   //set the register--rMPLLCON

       ChangeClockDivider(key, 12);    //the result of rCLKDIVN [0:1:0:1] 3-0 bit

       cal_cpu_bus_clk();    //HCLK=100M   PCLK=50M

}

/*************************************************

Function name: cal_cpu_bus_clk

Parameter    : void

Description     : 设置PCLK\HCLK\FCLK的频率

Return            : void

Argument     : void

Autor & date : Daniel

**************************************************/

static void cal_cpu_bus_clk(void)

{

       static U32 cpu_freq;

    static U32 UPLL;

       

       U32 val;

       U8 m, p, s;

       

       val = rMPLLCON;

       m = (val>>12)&0xff;

       p = (val>>4)&0x3f;

       s = val&3;

 

       //(m+8)*FIN*2不要超出32位数!

       FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;     //FCLK=400M  FIN=12000000

       

       val = rCLKDIVN;

       m = (val>>1)&3;

       p = val&1;     

       val = rCAMDIVN;

       s = val>>8;

       

       switch (m) {

       case 0:

              HCLK = FCLK;

              break;

       case 1:

              HCLK = FCLK>>1;

              break;

       case 2:

              if(s&2)

                     HCLK = FCLK>>3;

              else

                     HCLK = FCLK>>2;

              break;

       case 3:

              if(s&1)

                     HCLK = FCLK/6;

              else

                     HCLK = FCLK/3;

              break;

       }

       

       if(p)

              PCLK = HCLK>>1;

       else

              PCLK = HCLK;

       

       if(s&0x10)

              cpu_freq = HCLK;

       else

              cpu_freq = FCLK;

              

       val = rUPLLCON;

       m = (val>>12)&0xff;

       p = (val>>4)&0x3f;

       s = val&3;

       UPLL = ((m+8)*FIN)/((p+2)*(1<<s));

       UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值