UART总线


整理收集自网络



UART (Universal Asynchronous Receiver/Transmitter) 通用异步收发器。

UART是用于控制计算机与串行设备的芯片。有一点要注意的是,它提供了RS-232C数据终端设备接口,这样计算机就可以和调制解调器或其它使用RS-232C接口的串行设备通信了。


 RS232

    COM口是PC(个人计算机)上,异步串行通信口的简写。由于历史原因,IBM的PC外部接口配置为RS232,成为实际上的PC界默认标准。所以,现在PC机的COM口均为RS232。
   




  上图最右边的是串口接口,统称为RS232接口(封装DB9)
  通信过程中实际只有两个管脚参与通信
    2脚:电脑的输入RXD 
    3脚:电脑的输出TXD 
    
    5脚:接地
  通过2,3脚就实现全双工(可同时收发)的串行异步通信


作为接口的一部分,UART还提供以下功能:将由计算机内部传送过来的并行数据转换为输出的串行数据流。将计算机外部来的串行数据转换为字节,供计算机内部使用并行数据的器件使用。在输出的串行数据流中加入奇偶校验位,并对从外部接收的数据流进行奇偶校验。在输出数据流中加入启停标记,并从接收数据流中删除启停标记。处理由键盘或鼠标发出的中断信号(键盘和鼠票也是串行设备)。可以处理计算机与外部串行设备的同步管理问题。有一些比较高档的UART还提供输入输出数据的缓冲区,现在比较新的UART是16550,它可以在计算机需要处理数据前在其缓冲区内存储16字节数据,而通常的UART是8250。现在如果您购买一个内置的调制解调器,此调制解调器内部通常就会有16550 UART。

 

 

 

UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用来与PC进行通信,包括与监控调试器和其它器件,如EEPROM通信。

UART通信

        UART首先将接收到的并行数据转换成串行数据来传输。消息帧从一个低位起始位开始,后面是7个或8个数据位,一个可用的奇偶位和一个或几个高位停止位。接收器发现开始位时它就知道数据准备发送,并尝试与发送器时钟频率同步。如果选择了奇偶,UART就在数据位后面加上奇偶位。奇偶位可用来帮助错误校验。

        在接收过程中,UART从消息帧中去掉起始位和结束位,对进来的字节进行奇偶校验,并将数据字节从串行转换成并行。UART也产生额外的信号来指示发送和接收的状态。例如,如果产生一个奇偶错误,UART就置位奇偶标志。

数据方向和通信速度

        数据传输可以首先从最低有效位(LSB)开始。然而,有些UART允许灵活选择先发送最低有效位或最高有效位(MSB)。

       微控制器中的UART传送数据的速度范围为每秒几百位到1.5Mb。例如,嵌入在ElanSC520微控制器中的高速UART通信的速度可以高达1.1152Mbps。UART波特率还受发送和接收线对距离(线长度)的影响。

       目前,市场上有只支持异步通信和同时支持异步与同步通信的两种硬件可用于UART。前者就是UART名字本身的含义,在摩托罗拉微控制器中被称为串行通信接口(SCI);Microchip微控制器中的通用同步异步收发器(USART)和在富士通微控制器中的UART是后者的两个典型例子。

 

 

 

数据通信的基本方式可分为并行通信与串行通信两种:

Ø         并行通信:是指利用多条数据传输线将一个资料的各位同时传送。它的特点是传输速度快,适用于短距离通信,但要求通讯速率较高的应用场合。

Ø         串行通信:是指利用一条传输线将资料一位位地顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。

 

一、异步通信及其协议

异步通信以一个字符为传输单位,通信中两个字符间的时间间隔是不固定的,然而在同一个字符中的两个相邻位代码间的时间间隔是固定的。

通信协议(通信规程):是指通信双方约定的一些规则。在使用异步串口传送一个字符的信息时,对资料格式有如下约定:规定有空闲位、起始位、资料位、奇偶校验位、停止位。

异步通讯的时序,如图5-1。

zt:UART总线

 

其中各位的意义如下:

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

资料位:紧接着起始位之后。资料位的个数可以是4、5、6、7、8等,构成一个字符。通常采用ASCII码。从最低位开始传送,靠时钟定位。

奇偶校验位:资料位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验资料传送的正确性。
停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。

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

波特率:是衡量资料传送速率的指针。表示每秒钟传送的二进制位数。例如资料传送速率为120字符/秒,而每一个字符为10位,则其传送的波特率为10×120=1200字符/秒=1200波特。

注:异步通信是按字符传输的,接收设备在收到起始信号之后只要在一个字符的传输时间内能和发送设备保持同步就能正确接收。下一个字符起始位的到来又使同步重新校准(依靠检测起始位来实现发送与接收方的时钟自同步的)。



笼统的说明一下UART鲜明的特点:


异步:通信双方不需要时钟同步


两线制:只有Tx和Rx两根数据线(不需要Clock线)


波特率:通信双方需要事前约定好相同的波特率,他们有各自的时钟


RS232是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。现在PC机的COM口均为RS232。所以实现UART通信就必须通过RS232的一个转化。(更多的直接理解成是一种电平转化,就是TTL电平与3.3V之间的转化),可以把RS232理解成一个UART通信协议的一部分,属于协议的物理层。


 


以上是uart发送的数据格式和基本特点。下面通过LCP2131中的UATR0和UART1来具体的介绍UART!


 首先来介绍一下LPC2131中的UART的特性


UART16字节收发FIFO


UART寄存器位置符合16C550工业标准


UART接收器的FIFO触发点可为1、4、8和14字节


UART内置波特率发生器


UART包含使能实现软件流控制的机制


 


结构:


  UART接受模块:接受缓冲。


               数据UxRSR移位寄存器UxRBR缓存寄存器(即FIFO)然后等待CPU读取接收


  UART发送模块:发送保持。


               数据UxTHR保持寄存器(FIFO)UxTSR移位寄存器,然后通过串口发送出去


  波特率产生及控制模块:由波特率产生模块UxBRG和UxDLL、UxDLM寄存器组成


  中断接口:包含中断使能寄存器UxIER和中断标识寄存器UxIIR组成


  VPB接口:提供CPU或主机与UART之间的通信连接


 


 


关于UART接受数据的两种方式:查询和中断


查询:通过不断查询状态标志寄存器UxLSR的接受标志位来判断是否有数据,如果有数据则从UxRBR(FIFO)中取出数据


中断:FIFO的深度可以设置为1、4、8和14字节,当到达深度时,触发中断,在中断服务程序中去一次性读取数据。


 


心得:这些基层的东西必须要了解,前段时间在做关于FPGA的一个项目时读到一个问题,在NiosII环境下,关于底层的库函数的封装程度已经比较高了,它的UART的读取函数已经封装为fgetch()形式,但是问题是这个函数实现的有残缺,当没有数据来临时,这个函数就会“死等”,这和我们程序实现的思想是向冲突的,故而必须从底层入手,抛弃原来的函数,自己封装一个符合自己需要的取数据函数,基本思想是查询和中断相结合,程序直接读取底层寄存器的标志位,然后从寄存器FIFO中去读取数据,由于处理器实现的不通,可能其中需要屏蔽中断、改变工作模式等操作,这个实现的具体细节,需参考处理器的技术手册。

 



二、资料传送方式

根据资料传送方向的不同有以下三种方式。如图5-2所示。

单工方式                   半双工方式                    全双工方式

zt:UART总线

图5-2 资料传送方式

1. 单工方式:资料始终是从A设备发向B设备。

2. 半双工方式:资料能从A设备传送到B设备,也能从B设备传送到A设备。在任何时候资料都不能同时在两个方向上传送,即每次只能有一个设备发送,另一个设备接收。但是通讯双方依照一定的通讯协议来轮流地进行发送和接收。

3. 全双工方式:允许通信双方同时进行发送和接收。这时,A设备在发送的同时也可以接收,B设备亦同。全双工方式相当于把两个方向相反的单工方式组合在一起,因此它需要两条数据传输线。在计算机串行通讯中主要使用半双工和全双工方式。

 

三、串行接口标准

串行接口标准:指的是计算机或终端(资料终端设备DTE)的串行接口电路与调制解调器MODEM等(数据通信设备DCE)之间的连接标准。
RS-232C标准

RS-232C是一种标准接口,D型插座,采用25芯引脚或9芯引脚的连接器,如图所示。

 

 zt:UART总线

微型计算机之间的串行通信就是按照RS-232C标准设计的接口电路实现的。如果使用一根电话线进行通信,那幺计算机和MODEM之间的联机就是根据RS-232C标准连接的。其连接及通信原理如图所示

 

 

RS232信号定义

RS-232C标准规定接口有25根联机。只有以下9个信号经常使用.

引脚和功能分别如下:

Ø         (第2脚):TXD发送资料线,输出。发送资料到MODEM。

Ø         (第3脚):RXD接收资料线,输入。接收资料到计算机或终端。

Ø         (第4脚):请求发送,输出。计算机通过此引脚通知MODEM,要求发送资料。

Ø         (第5脚):允许发送,输入。发出 作为对 的回答,计算机才可以进行发送资料。

Ø         (第6脚):资料装置就绪(即MODEM准备好),输入。表示调制解调器可以使用,该信号有时直接接到电源上,这样当设备连通时即有效。

Ø         (第8脚):CD载波检测(接收线信号测定器),输入。表示MODEM已与电话线路连接好。

如果通信线路是交换电话的一部分,则至少还需如下两个信号:

Ø         (第22脚):RI振铃指示,输入。MODEM若接到交换台送来的振铃呼叫信号,就发出该信号来通知计算机或终端。

Ø         (第20脚):资料终端就绪,输出。计算机收到RI信号以后,就发出 信号到MODEM作为回答,以控制它的转换设备,建立通信链路。

Ø         (第7脚):GND信号地

 

逻辑电平

RS-232C标准采用EIA电平,规定:

“1”的逻辑电平在-3V~-15v之间;“0”的逻辑电平在+3V~+15V之间。

由于EIA电平与TTL电平完全不同,必须进行相应的电平转换,MCl488完成TTL电平到EIA电平的转换,MCl489完成EIA电平到ITL电平的转换。还有MAX232可以同时完成TTL->EIA和EIA->TTL的电平转换。




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寄存器中读取数据



 

  1. Main.c  
  2.   
  3. <span style="color: rgb(0, 0, 0);">#define   GLOBAL_CLK           1  
  4.   
  5. #include <stdlib.h>  
  6.   
  7. #include <string.h>  
  8.   
  9. #include "def.h"  
  10.   
  11. #include "option.h"  
  12.   
  13. #include "2440addr.h"  
  14.   
  15. #include "2440lib.h"  
  16.   
  17. #include "2440slib.h"  
  18.   
  19. #include "mmu.h"  
  20.   
  21. #include "profile.h"  
  22.   
  23. #include "memtest.h"  
  24.   
  25.    
  26.   
  27. static void cal_cpu_bus_clk(void);  
  28.   
  29. void Set_Clk(void);  
  30.   
  31. /*************************************************  
  32.   
  33. Function name: delay  
  34.   
  35. Parameter    : times  
  36.   
  37. Description    :延时函数  
  38.   
  39. Return          : void  
  40.   
  41. Argument     : void  
  42.   
  43. Autor & date : Daniel  
  44.   
  45. **************************************************/  
  46.   
  47. void delay(int times)  
  48.   
  49. {  
  50.   
  51.     int i,j;  
  52.   
  53.     for(i=0;i<times;i++)  
  54.   
  55.        for(j=0;j<400;j++);  
  56.   
  57. }  
  58.   
  59. /*************************************************  
  60.   
  61. Function name: Main  
  62.   
  63. Parameter    : void  
  64.   
  65. Description     : 主功能函数,实现了串口的收发功能  
  66.   
  67.                首先想串口发送十次“hello world”,  
  68.   
  69. Return            : void  
  70.   
  71. Argument     : void  
  72.   
  73. Autor & date : Daniel  
  74.   
  75. **************************************************/  
  76.   
  77. void Main(void)  
  78.   
  79. {       
  80.   
  81.     int i;  
  82.   
  83.     int Scom=0;  
  84.   
  85.     Set_Clk();  
  86.   
  87.     beep_init();  
  88.   
  89.       
  90.   
  91.     /*设置波特率、数据位、停止位、校验位*/  
  92.   
  93.     Uart_Init(0,115200);  
  94.   
  95.     Uart_Select(Scom);  
  96.   
  97.     for(i=0;i<10;i++)  
  98.   
  99.     Uart_Printf("\nHello World!\n");  
  100.   
  101.       
  102.   
  103.     while(1)  
  104.   
  105.     {  
  106.   
  107.       while(Uart_GetKey()=='r')  
  108.   
  109.       {  
  110.   
  111.           for(i=0;i<10;i++)  
  112.   
  113.           beep_run();  
  114.   
  115.           Uart_Printf("\nBeep Quit!\n");  
  116.   
  117.       }  
  118.   
  119.        }  
  120.   
  121.    
  122.   
  123. }       
  124.   
  125.        
  126.   
  127. /*************************************************  
  128.   
  129. Function name: Set_Clk()  
  130.   
  131. Parameter    : void  
  132.   
  133. Description     : 设置CPU的时钟频率  
  134.   
  135. Return            : void  
  136.   
  137. Argument     : void  
  138.   
  139. Autor & date : Daniel  
  140.   
  141. **************************************************/  
  142.   
  143. void Set_Clk(void)  
  144.   
  145. {  
  146.   
  147.        int i;  
  148.   
  149.        U8 key;  
  150.   
  151.        U32 mpll_val = 0 ;  
  152.   
  153.        i = 2 ;                  //don't use 100M!  
  154.   
  155.                                //boot_params.cpu_clk.val = 3;  
  156.   
  157.        switch ( i ) {  
  158.   
  159.        case 0:     //200  
  160.   
  161.               key = 12;  
  162.   
  163.               mpll_val = (92<<12)|(4<<4)|(1);  
  164.   
  165.               break;  
  166.   
  167.        case 1:     //300  
  168.   
  169.               key = 13;  
  170.   
  171.               mpll_val = (67<<12)|(1<<4)|(1);  
  172.   
  173.               break;  
  174.   
  175.        case 2:     //400  
  176.   
  177.               key = 14;  
  178.   
  179.               mpll_val = (92<<12)|(1<<4)|(1);  
  180.   
  181.               break;  
  182.   
  183.        case 3:     //440!!!  
  184.   
  185.               key = 14;  
  186.   
  187.               mpll_val = (102<<12)|(1<<4)|(1);  
  188.   
  189.               break;  
  190.   
  191.        default:  
  192.   
  193.               key = 14;  
  194.   
  195.               mpll_val = (92<<12)|(1<<4)|(1);  
  196.   
  197.               break;  
  198.   
  199.        }  
  200.   
  201.          
  202.   
  203.        //init FCLK=400M, so change MPLL first  
  204.   
  205.        ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);   //set the register--rMPLLCON  
  206.   
  207.        ChangeClockDivider(key, 12);    //the result of rCLKDIVN [0:1:0:1] 3-0 bit  
  208.   
  209.        cal_cpu_bus_clk();    //HCLK=100M   PCLK=50M  
  210.   
  211. }  
  212.   
  213. /*************************************************  
  214.   
  215. Function name: cal_cpu_bus_clk  
  216.   
  217. Parameter    : void  
  218.   
  219. Description     : 设置PCLK\HCLK\FCLK的频率  
  220.   
  221. Return            : void  
  222.   
  223. Argument     : void  
  224.   
  225. Autor & date : Daniel  
  226.   
  227. **************************************************/  
  228.   
  229. static void cal_cpu_bus_clk(void)  
  230.   
  231. {  
  232.   
  233.        static U32 cpu_freq;  
  234.   
  235.     static U32 UPLL;  
  236.   
  237.          
  238.   
  239.        U32 val;  
  240.   
  241.        U8 m, p, s;  
  242.   
  243.          
  244.   
  245.        val = rMPLLCON;  
  246.   
  247.        m = (val>>12)&0xff;  
  248.   
  249.        p = (val>>4)&0x3f;  
  250.   
  251.        s = val&3;  
  252.   
  253.    
  254.   
  255.        //(m+8)*FIN*2不要超出32位数!  
  256.   
  257.        FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;     //FCLK=400M  FIN=12000000  
  258.   
  259.          
  260.   
  261.        val = rCLKDIVN;  
  262.   
  263.        m = (val>>1)&3;  
  264.   
  265.        p = val&1;       
  266.   
  267.        val = rCAMDIVN;  
  268.   
  269.        s = val>>8;  
  270.   
  271.          
  272.   
  273.        switch (m) {  
  274.   
  275.        case 0:  
  276.   
  277.               HCLK = FCLK;  
  278.   
  279.               break;  
  280.   
  281.        case 1:  
  282.   
  283.               HCLK = FCLK>>1;  
  284.   
  285.               break;  
  286.   
  287.        case 2:  
  288.   
  289.               if(s&2)  
  290.   
  291.                      HCLK = FCLK>>3;  
  292.   
  293.               else  
  294.   
  295.                      HCLK = FCLK>>2;  
  296.   
  297.               break;  
  298.   
  299.        case 3:  
  300.   
  301.               if(s&1)  
  302.   
  303.                      HCLK = FCLK/6;  
  304.   
  305.               else  
  306.   
  307.                      HCLK = FCLK/3;  
  308.   
  309.               break;  
  310.   
  311.        }  
  312.   
  313.          
  314.   
  315.        if(p)  
  316.   
  317.               PCLK = HCLK>>1;  
  318.   
  319.        else  
  320.   
  321.               PCLK = HCLK;  
  322.   
  323.          
  324.   
  325.        if(s&0x10)  
  326.   
  327.               cpu_freq = HCLK;  
  328.   
  329.        else  
  330.   
  331.               cpu_freq = FCLK;  
  332.   
  333.                 
  334.   
  335.        val = rUPLLCON;  
  336.   
  337.        m = (val>>12)&0xff;  
  338.   
  339.        p = (val>>4)&0x3f;  
  340.   
  341.        s = val&3;  
  342.   
  343.        UPLL = ((m+8)*FIN)/((p+2)*(1<<s));  
  344.   
  345.        UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;  
  346.   
  347. }  
  348.   
  349. </span>   
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

  1. #include "def.h"  
  2.   
  3. #include "option.h"  
  4.   
  5. #include "2440addr.h"  
  6.   
  7. #include "2440lib.h"  
  8.   
  9. #include "2440slib.h"  
  10.   
  11.    
  12.   
  13. #include <stdarg.h>  
  14.   
  15. #include <string.h>  
  16.   
  17. #include <stdlib.h>  
  18.   
  19. #include <stdio.h>  
  20.   
  21. #include <ctype.h>  
  22.   
  23. static int whichUart=0;  
  24.   
  25.    
  26.   
  27. void Port_Init0(void)  //IO端口初始化  
  28.   
  29. {  
  30.   
  31.        //*** PORT H GROUP  
  32.   
  33.   //Ports  :  GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1  GPH0 //Signal : CLKOUT1 CLKOUT0 UCLK nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0  
  34.   
  35.     //Binary :   10   ,  10     10 , 11    11  , 10   10 , 10   10 , 10    10  
  36.   
  37.      rGPHCON = 0x00faaa;  
  38.   
  39.      rGPHUP  = 0x7ff;    // The pull up function is disabled GPH[10:0]  
  40.   
  41. }  
  42.   
  43.    
  44.   
  45. void Uart_Init(int pclk,int baud)  
  46.   
  47. {  
  48.   
  49.     int i;  
  50.   
  51.     if(pclk == 0)  
  52.   
  53.     pclk    = PCLK;  
  54.   
  55.     rUFCON0 = 0x0;   //UART channel 0 FIFO control register, FIFO disable  
  56.   
  57.     rUMCON0 = 0x0;   //UART chaneel 0 MODEM control register, AFC disable(AFC:流量控制)  
  58.   
  59.    //UART0  
  60.   
  61.     rULCON0 = 0x3;   //Line control register : Normal,No parity,1 stop,8 bits  
  62.   
  63.      //    [10]       [9]     [8]        [7]        [6]      [5]         [4]           [3:2]        [1:0]  
  64.   
  65.      // Clock Sel,  Tx Int,  Rx Int, Rx Time Out, Rx err, Loop-back, Send break,  Transmit Mode, Receive Mode  
  66.   
  67.      //     0          1       0    ,     0          1        0           0     ,       01          01  
  68.   
  69.      //   PCLK       Level    Pulse    Disable    Generate  Normal      Normal        Interrupt or Polling  
  70.   
  71.     rUCON0  = 0x245;   // Control register  
  72.   
  73.     rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 );   //Baud rate divisior register 0  
  74.   
  75.     for(i=0;i<100;i++);  
  76.   
  77. }  
  78.   
  79.    
  80.   
  81. //===================================================================  
  82.   
  83. void Uart_Select(int ch)  
  84.   
  85. {  
  86.   
  87.     whichUart = ch;  
  88.   
  89. }  
  90.   
  91. //=====================================================================  
  92.   
  93. void Uart_SendByte(int data)  
  94.   
  95. {  
  96.   
  97.     if(whichUart==0)  
  98.   
  99.     {  
  100.   
  101.         if(data=='\n')  
  102.   
  103.         {  
  104.   
  105.             while(!(rUTRSTAT0 & 0x2));  
  106.   
  107.            // Delay(1);                 //because the slow response of hyper_terminal  
  108.   
  109.             WrUTXH0('\r');  
  110.   
  111.         }  
  112.   
  113.         while(!(rUTRSTAT0 & 0x2));   //不为换行符时,Wait until THR is empty.  
  114.   
  115.       //  Delay(1);  
  116.   
  117.         WrUTXH0(data);//往寄存器写数据  
  118.   
  119.     }  
  120.   
  121.     else if(whichUart==1)  
  122.   
  123.     {  
  124.   
  125.         if(data=='\n')  
  126.   
  127.         {  
  128.   
  129.             while(!(rUTRSTAT1 & 0x2));  
  130.   
  131.             //Delay(1);                 //because the slow response of hyper_terminal  
  132.   
  133.             rUTXH1 = '\r';  
  134.   
  135.         }  
  136.   
  137.         while(!(rUTRSTAT1 & 0x2));   //Wait until THR is empty.  
  138.   
  139.         //Delay(1);  
  140.   
  141.         rUTXH1 = data;  
  142.   
  143.     }     
  144.   
  145.     else if(whichUart==2)  
  146.   
  147.     {  
  148.   
  149.         if(data=='\n')  
  150.   
  151.         {  
  152.   
  153.             while(!(rUTRSTAT2 & 0x2));  
  154.   
  155.             //Delay(1);                 //because the slow response of hyper_terminal  
  156.   
  157.             rUTXH2 = '\r';  
  158.   
  159.         }  
  160.   
  161.         while(!(rUTRSTAT2 & 0x2));   //Wait until THR is empty.  
  162.   
  163.         //Delay(1);  
  164.   
  165.         rUTXH2 = data;  
  166.   
  167.     }         
  168.   
  169. }                 
  170.   
  171.    
  172.   
  173. //====================================================================  
  174.   
  175. void Uart_SendString(char *pt)  
  176.   
  177. {  
  178.   
  179.     while(*pt)  
  180.   
  181.         Uart_SendByte(*pt++);  
  182.   
  183. }  
  184.   
  185. //=====================================================================  
  186.   
  187. //If you don't use vsprintf(), the code size is reduced very much.  
  188.   
  189. void Uart_Printf(char *fmt,...)  
  190.   
  191. {  
  192.   
  193.     va_list ap;  
  194.   
  195.     char string[256];  
  196.   
  197.    
  198.   
  199.     va_start(ap,fmt);//va_start、 va_end成对出现,ap指向fmt之后的参数  
  200.   
  201.     vsprintf(string,fmt,ap);//把ap之后的参数拷贝进string  
  202.   
  203.     Uart_SendString(string);  
  204.   
  205.     va_end(ap);  
  206.   
  207. }  
#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);

}


中断方式,串口发送:

  1. #define    GLOBAL_CLK             1  
  2.   
  3. #include <stdlib.h>  
  4.   
  5. #include <string.h>  
  6.   
  7. #include "def.h"  
  8.   
  9. #include "option.h"  
  10.   
  11. #include "2440addr.h"  
  12.   
  13. #include "2440lib.h"  
  14.   
  15. #include "2440slib.h"  
  16.   
  17. #include "mmu.h"  
  18.   
  19. #include "profile.h"  
  20.   
  21. #include "memtest.h"  
  22.   
  23.    
  24.   
  25.    
  26.   
  27. void Uart0INT_init(void);  
  28.   
  29. static void __irq IRQ_ISR_UART0(void);  
  30.   
  31. void Set_Clk(void);  
  32.   
  33. static void cal_cpu_bus_clk(void);  
  34.   
  35. /*************************************************  
  36.   
  37. Function name: delay  
  38.   
  39. Parameter    : times  
  40.   
  41. Description     : 延时函数  
  42.   
  43. Return            : void  
  44.   
  45. Argument     : void  
  46.   
  47. Autor & date : Daniel  
  48.   
  49. **************************************************/  
  50.   
  51. void delay(int times)  
  52.   
  53. {  
  54.   
  55.     int i,j;  
  56.   
  57.     for(i=0;i<times;i++)  
  58.   
  59.        for(j=0;j<400;j++);  
  60.   
  61. }  
  62.   
  63. /*************************************************  
  64.   
  65. Function name: Main  
  66.   
  67. Parameter    : void  
  68.   
  69. Description     : 主功能函数  
  70.   
  71. Return            : void  
  72.   
  73. Argument     : void  
  74.   
  75. Autor & date : Daniel  
  76.   
  77. **************************************************/  
  78.   
  79. int Main(void)  
  80.   
  81. {       
  82.   
  83.     Set_Clk();  
  84.   
  85.     MMU_Init();  
  86.   
  87.     Uart0INT_init();  
  88.   
  89.        return 0 ;  
  90.   
  91. }       
  92.   
  93. /*************************************************  
  94.   
  95. Function name: Uart0INT_init()  
  96.   
  97. Parameter    : void  
  98.   
  99. Description     : 中断初始化函数,用于配置中断所需要的  
  100.   
  101.                几个寄存器  
  102.   
  103. Return            : void  
  104.   
  105. Argument     : void  
  106.   
  107. Autor & date : Daniel  
  108.   
  109. **************************************************/     
  110.   
  111. void Uart0INT_init(void)  
  112.   
  113. {  
  114.   
  115.     
  116.   
  117.   Uart_Init( 0,115200);  
  118.   
  119.   Uart_Select(0);  
  120.   
  121.     
  122.   
  123.   rPRIORITY = 0x00000000;     /*默认优先级*/  
  124.   
  125.   rINTMOD = 0x00000000;       /*默认IRQ中断*/  
  126.   
  127.     
  128.   
  129.   /*清中断*/  
  130.   
  131.   ClearSubPending(BIT_SUB_RXD0);  
  132.   
  133.   ClearPending(BIT_UART0);  
  134.   
  135.     
  136.   
  137.   /*设置UART的ISR*/  
  138.   
  139.   pISR_UART0 = (U32)IRQ_ISR_UART0;  
  140.   
  141.   EnableIrq(BIT_UART0);  
  142.   
  143.   EnableSubIrq(BIT_SUB_RXD0);  
  144.   
  145.    
  146.   
  147. }  
  148.   
  149. /*************************************************  
  150.   
  151. Function name: IRQ_ISR_UART0()  
  152.   
  153. Parameter    : void  
  154.   
  155. Description     : 中断服务子程序,该子程序的作用就是把  
  156.   
  157.                串口收到的数据发送到超级终端。  
  158.   
  159. Return            : void  
  160.   
  161. Argument     : void  
  162.   
  163. Autor & date : Daniel  
  164.   
  165. **************************************************/  
  166.   
  167. static void __irq IRQ_ISR_UART0(void)  
  168.   
  169. {  
  170.   
  171.         if(rSUBSRCPND & 0x1)  
  172.   
  173.            {  
  174.   
  175.                      rUTXH0 = rURXH0;  /*这里没考虑回车*/  
  176.   
  177.                      ClearSubPending(BIT_SUB_RXD0);  
  178.   
  179.               }  
  180.   
  181.            ClearPending(BIT_UART0);  
  182.   
  183. }  
  184.   
  185.    
  186.   
  187. /*************************************************  
  188.   
  189. Function name: Set_Clk()  
  190.   
  191. Parameter    : void  
  192.   
  193. Description     : 设置CPU的时钟频率  
  194.   
  195. Return            : void  
  196.   
  197. Argument     : void  
  198.   
  199. Autor & date : Daniel  
  200.   
  201. **************************************************/  
  202.   
  203. void Set_Clk(void)  
  204.   
  205. {  
  206.   
  207.        int i;  
  208.   
  209.        U8 key;  
  210.   
  211.        U32 mpll_val = 0 ;  
  212.   
  213.        i = 2 ;                  //don't use 100M!  
  214.   
  215.                                //boot_params.cpu_clk.val = 3;  
  216.   
  217.        switch ( i ) {  
  218.   
  219.        case 0:     //200  
  220.   
  221.               key = 12;  
  222.   
  223.               mpll_val = (92<<12)|(4<<4)|(1);  
  224.   
  225.               break;  
  226.   
  227.        case 1:     //300  
  228.   
  229.               key = 13;  
  230.   
  231.               mpll_val = (67<<12)|(1<<4)|(1);  
  232.   
  233.               break;  
  234.   
  235.        case 2:     //400  
  236.   
  237.               key = 14;  
  238.   
  239.               mpll_val = (92<<12)|(1<<4)|(1);  
  240.   
  241.               break;  
  242.   
  243.        case 3:     //440!!!  
  244.   
  245.               key = 14;  
  246.   
  247.               mpll_val = (102<<12)|(1<<4)|(1);  
  248.   
  249.               break;  
  250.   
  251.        default:  
  252.   
  253.               key = 14;  
  254.   
  255.               mpll_val = (92<<12)|(1<<4)|(1);  
  256.   
  257.               break;  
  258.   
  259.        }  
  260.   
  261.          
  262.   
  263.        //init FCLK=400M, so change MPLL first  
  264.   
  265.        ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);   //set the register--rMPLLCON  
  266.   
  267.        ChangeClockDivider(key, 12);    //the result of rCLKDIVN [0:1:0:1] 3-0 bit  
  268.   
  269.        cal_cpu_bus_clk();    //HCLK=100M   PCLK=50M  
  270.   
  271. }  
  272.   
  273. /*************************************************  
  274.   
  275. Function name: cal_cpu_bus_clk  
  276.   
  277. Parameter    : void  
  278.   
  279. Description     : 设置PCLK\HCLK\FCLK的频率  
  280.   
  281. Return            : void  
  282.   
  283. Argument     : void  
  284.   
  285. Autor & date : Daniel  
  286.   
  287. **************************************************/  
  288.   
  289. static void cal_cpu_bus_clk(void)  
  290.   
  291. {  
  292.   
  293.        static U32 cpu_freq;  
  294.   
  295.     static U32 UPLL;  
  296.   
  297.          
  298.   
  299.        U32 val;  
  300.   
  301.        U8 m, p, s;  
  302.   
  303.          
  304.   
  305.        val = rMPLLCON;  
  306.   
  307.        m = (val>>12)&0xff;  
  308.   
  309.        p = (val>>4)&0x3f;  
  310.   
  311.        s = val&3;  
  312.   
  313.    
  314.   
  315.        //(m+8)*FIN*2不要超出32位数!  
  316.   
  317.        FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;     //FCLK=400M  FIN=12000000  
  318.   
  319.          
  320.   
  321.        val = rCLKDIVN;  
  322.   
  323.        m = (val>>1)&3;  
  324.   
  325.        p = val&1;       
  326.   
  327.        val = rCAMDIVN;  
  328.   
  329.        s = val>>8;  
  330.   
  331.          
  332.   
  333.        switch (m) {  
  334.   
  335.        case 0:  
  336.   
  337.               HCLK = FCLK;  
  338.   
  339.               break;  
  340.   
  341.        case 1:  
  342.   
  343.               HCLK = FCLK>>1;  
  344.   
  345.               break;  
  346.   
  347.        case 2:  
  348.   
  349.               if(s&2)  
  350.   
  351.                      HCLK = FCLK>>3;  
  352.   
  353.               else  
  354.   
  355.                      HCLK = FCLK>>2;  
  356.   
  357.               break;  
  358.   
  359.        case 3:  
  360.   
  361.               if(s&1)  
  362.   
  363.                      HCLK = FCLK/6;  
  364.   
  365.               else  
  366.   
  367.                      HCLK = FCLK/3;  
  368.   
  369.               break;  
  370.   
  371.        }  
  372.   
  373.          
  374.   
  375.        if(p)  
  376.   
  377.               PCLK = HCLK>>1;  
  378.   
  379.        else  
  380.   
  381.               PCLK = HCLK;  
  382.   
  383.          
  384.   
  385.        if(s&0x10)  
  386.   
  387.               cpu_freq = HCLK;  
  388.   
  389.        else  
  390.   
  391.               cpu_freq = FCLK;  
  392.   
  393.                 
  394.   
  395.        val = rUPLLCON;  
  396.   
  397.        m = (val>>12)&0xff;  
  398.   
  399.        p = (val>>4)&0x3f;  
  400.   
  401.        s = val&3;  
  402.   
  403.        UPLL = ((m+8)*FIN)/((p+2)*(1<<s));  
  404.   
  405.        UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL;  
  406.   
  407. }  


  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用HAL库进行UART总线空闲中断时,需要进行以下步骤: 1. 在原有的串口1中断服务函数中添加代码,判断是否是空闲中断,并进行相应的处理。例如,可以使用`__HAL_UART_GET_FLAG`函数判断是否是空闲中断,使用`__HAL_UART_CLEAR_IDLEFLAG`函数清除空闲中断标志,使用`HAL_UART_DMAStop`函数停止DMA传输,使用`HAL_UART_Receive_DMA`函数重新打开DMA接收。\[1\] 2. 重定义串口发送完成回调函数,在这里清空标志位。可以使用`HAL_UART_TxCpltCallback`函数,在函数中判断是否是USART1实例,然后释放总线。\[2\] 3. 使用空闲中断进行串口接收。一般情况下,我们使用RXNE中断,在接收到一个字节数据时进入中断并将其放入缓存。但是当数据量很大时,频繁进入中断会影响单片机的时效性。此时可以使用IDLE空闲中断,在接收到一段数据后,在一定的时间内检测到没有数据到来,就认为串口总线空闲,并产生一个空闲中断。\[3\] 以上是使用HAL库进行UART总线空闲中断的步骤。 #### 引用[.reference_title] - *1* *2* [STM32-UART 空闲中断+DMA发送接收](https://blog.csdn.net/my_id_kt/article/details/122412078)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [STM32 hal库串口空闲中断最新用法](https://blog.csdn.net/qq_47159466/article/details/124542339)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值