打印

学习嵌入式的最佳路线ARM7—ARM7(LPC2136)串口通信原理

[复制链接]
6253|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
即时生效|  楼主 | 2011-3-2 22:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这里所说的串口也叫RS232或这UART(Universal Asynchronous Receiver/Transmitter)。
  下面的两个图是串口通信的两种应用场合。
  三线制,用于一般的数据收发;
  九线制,用于Modem(调制解调器)功能,应用于拨号上网设备,手机等通信设备中。
  我们这里主要讨论三线制。
  6.2 设置串口
  也许很多人在XP下面用过串口,我们在"设备管理器"里面,有一个端口属性,
  里面就是串口设备
    这些基本的配置,在单片机和ARM里面也有。
  6.2.1 波特率
  这里第一个要设置的是串口波特率,波特率就是每秒传输的数据位数,用bps来表示。在LPC2136中,波特率通过公式
  计算得到。
  pclk指CPU的peripheral devices clock。
  U0DLM是指UART0除法锁存器(Divisor Latch Register)的高八位;
  U0DLL是指UART0除法锁存器(Divisor Latch Register)的低八位;
  (注意:U0DLL的复位值为0)
  LPC2136 datasheet提供了一个表,我们可以根据这个表设置这两个寄存器的值就行了,很方便。
  6.2.2 设置串口数据格式
  我们一般设置8位数据位,1个停止位,无奇偶校验位,禁止间隔发送。
  注意,我们在设置波特率之前必须,使能访问除数锁存。
  6.3 发送数据
  到这里你就可以写程序来发送数据了。
  设置波特率和数据格式安照"2 设置串口"方法,那么,接下来还有两个问题:
  1:要发送的数据送到那里
  2:怎么知道发送完成
  6.3.1 要发送的数据送到哪里
  LPC2136是通过往U0THR(UART0 Transmit Holding Register 发送器保持寄存器)写数据来发送出去的。
  U0THR是UART0 TX FIFO的最高字节。它包含了Tx FIFO中最新的字符,可通过总线接口写入。LSB (bit0)代表最先发送的位。
  注:如果要访问U0THR,U0LCR的除数锁存访问位(DLAB即bit[7])必须为0。U0THR为只写寄存器。
  写UART0发送保持寄存器使数据保存到UART0发送FIFO中,当字节到达FIFO的最底部并且发送器就绪时,该字节将被发送。
  6.3.2 怎么知道发送完毕
  LPC2136有个线状态寄存器(U0LSR),其中的第六位就是用来判断是否发送完毕的。如果该位为1,则表示已经发送完毕。该位通过写U0THR清零。
  注:也许有人会问为什么不是判断第五位,
  答案是:可以用第五无位判断,但最好是用第六位,因为第六位指示的U0THR和U0TSR两个寄存器为空,如果你没有看LPC2136的英文datasheet,你不知道U0TSR是什么东西。U0TSR是UART0 TX Shift Register(UART0 传输移位寄存器,它从U0THR里面读出数据并装配发送到TXD0输出引脚)。
  6.3.3 通过代码实现发送"Hello World!"
  /****************************************************************************
  * 文件名:main.c
  * 功   能:向串口发送数据,在PC上用超级终端或串口助手就可以收到"Hello World!"字符串
  * 说   明:使用外部11.0592MHz晶振,根据CONFIG.H文件配置,Fpclk=11.0592MHz;
  *           通讯波特率,位数据位,位停止位,无奇偶校验。
  ****************************************************************************/
  #include  "config.h"
  #define  UART_BPS 115200   // 定义通讯波特率
  uint8 const  SEND_STRING[] = "Hello World!\r\n";
  /****************************************************************************
  * 名   称:DelayNS()
  * 功   能:长软件延时
  * 入口参数:dly  延时参数,值越大,延时越久
  * 出口参数:无
  ****************************************************************************/
  void  DelayNS(uint32  dly)
  {  
  uint32  i;   
  for(; dly>0; dly--)
  {
  for(i=0; i<5000; i++);
  }
  }
  /****************************************************************************
  * 名   称:UART0_Ini()
  * 功   能:初始化串口。设置为位数据位,位停止位,无奇偶校验,波特率为
  * 入口参数:无
  * 出口参数:无
  ****************************************************************************/
  void  UART0_Init(void)
  {  
  uint16 Fdiv;
  U0LCR = 0x83;      // DLAB = 1,可设置波特率
  Fdiv = (Fpclk / 16) / UART_BPS;  // 设置波特率
  U0DLM = Fdiv / 256;      
  U0DLL = Fdiv % 256;      
  U0LCR = 0x03;
  }
  /****************************************************************************
  * 名   称:UART0_SendByte()
  * 功   能:向串口发送字节数据,并等待发送完毕。
  * 入口参数:data  要发送的数据
  * 出口参数:无
  
  }

相关帖子

沙发
即时生效|  楼主 | 2011-3-2 23:11 | 只看该作者
****************************************************************************/
  void  UART0_SendByte(uint8 data)
  {  
  U0THR = data;         // 发送数据   
  while( (U0LSR&0x40)==0 );      // 等待数据发送完毕
  }
  /****************************************************************************
  * 名   称:UART0_SendStr()
  * 功   能:向串口发送一字符串
  * 入口参数:srt  要发送的字符串的指针
  * 出口参数:无
  ****************************************************************************/
  void  UART0_SendStr(uint8 const *str)
  {  
  while(1)
  {  
  if( *str == '\0' ) break;
  UART0_SendByte(*str++);      // 发送数据
  }
  }
  /****************************************************************************
  * 名   称:main()
  * 功   能:向串口UART0发送字符串"Hello World!"
  ****************************************************************************/
  int  main(void)
  {  
  PINSEL0 = 0x00000005;      // 设置I/O连接到UART0
  UART0_Init();
  while(1)
  {  
  UART0_SendStr(SEND_STRING);
  DelayNS(10);
  }
  return(0);
  }
  6.4 接收数据
  6.4.1 接收到的数据保存在哪里?
  接收到的数据放在U0RBR寄存器,U0RBR是UART0 Rx FIFO的最高字节。它包含了最早接收到的字节,可通过总线接口读出。LSB (bit0)代表最早接收到的数据位。如果接收到的字符小于8位,未使用的MSB填充为0。
  如果要访问U0RBR,U0LCR的除数锁存访问位(DLAB)必须为0。U0RBR为只读寄存器。
  6.4.2 怎么知道接收到了数据
  LPC2136是通过U0LSR(线状态寄存器)的bit[0]来指示U0RBR接收到了数据的。
  所以,我们程序就可以根据读取该位来判断是否有新的数据。
  如果U0LSR[0]=1,U0RBR包含有效数据。
  U0RBR中的数据读出后,U0LSR[0]位被清零。
  6.4.3 接收数据源代码
  /****************************************************************************
  * 文件名:main.c
  * 功   能:从串口接收数据,如果PC那边用超级终端或串口助手发送数据,在板子这边将会收到数据。
  * 说   明:使用外部11.0592MHz晶振,根据CONFIG.H文件配置,Fpclk=11.0592MHz;
  *           通讯波特率,位数据位,位停止位,无奇偶校验。
  ****************************************************************************/
  #include  "config.h"
  #define  UART_BPS 115200   // 定义通讯波特率
  uint8   RECEIVE_BUFFER[20];
  /****************************************************************************
  * 名   称:UART0_Ini()
  * 功   能:初始化串口。设置为位数据位,位停止位,无奇偶校验,波特率为
  * 入口参数:无
  * 出口参数:无
  ****************************************************************************/
  void  UART0_Init(void)
  {  
  uint16 Fdiv;
  U0LCR = 0x83;      // DLAB = 1,可设置波特率
  Fdiv = (Fpclk / 16) / UART_BPS;  // 设置波特率
  U0DLM = Fdiv / 256;      
  U0DLL = Fdiv % 256;      
  U0LCR = 0x03;
  }
  /****************************************************************************
  * 名   称:main()
  * 功   能:从串口接收数据
  ****************************************************************************/
  int  main(void)
  {  
  uint i="0";
  PINSEL0 = 0x00000005;      // 设置I/O连接到UART0
  UART0_Init();
  while(1)
  {  
  while( (U0LSR&0x01)==0 );      // 判断接收寄存器是否有新的数据
  RECEIVE_BUFFER[i++] = U0RBR;         // 把接收到的数据放到接收缓冲区
  if(i==20){
  i = 0;
  }
  }
  return(0);
  }
  6.5 中断方式
  以上代码都是polling方式实现的,一般发送数据时用polling,但接收数据时一般用中断方式。
  6.5.1 怎么使能接收中断
  LPC2114是通过U0IER(中断使能寄存器)来使能相关中断的。
  U0IER[0]是RBR中断使能位:
  U0IER[0]=0 禁能RDA中断,=1使能RDA中断;(RDA表示接收数据可用)
  6.5.2 怎么知道接收中断发生
  LPC2136中是通过U0IIR(中断标识寄存器),来指示当前哪个中断发生的。
  如果U0IIR[3:1]=010,则表示U0RBR接收到了新的数据。
  6.5.3 中断方式接收数据代码实现
  ****************************************************************************
  * 文件名:main.c
  * 功  能:从串口接收数据,如果PC那边用超级终端或串口助手发送数据,在板子这边将会收到数据。
  * 说  明:使用外部.0592MHz晶振,根据CONFIG.H文件配置,Fpclk=11.0592MHz;
  *           通讯波特率,位数据位,位停止位,无奇偶校验。
  ****************************************************************************/
  #include  "config.h"
  #define  UART_BPS 115200   // 定义通讯波特率
  uint8   RECEIVE_BUFFER[20*8];
  volatile uint8  **_Rece;    // 接收新数据标志
  uint8 ReceiveLen;
  /****************************************************************************
  * 名   称:IRQ_UART0()
  * 功   能:串口UART0接收中断。
  * 入口参数:无
  * 出口参数:无
  ****************************************************************************/
  void   __irq IRQ_UART0(void)
  {   uint8  i;
  if( 0x04==(U0IIR&0x0F) ) **_Rece = 1; // 设置接收到新的数据标志
  for(i=0; i<8; i++)
  {
  RECEIVE_BUFFER[ReceiveLen++] = U0RBR;  // 读取FIFO的数据,并清除中断标志
  }
  if( ReceiveLen > 160 )
  ReceiveLen=0;
  VICVectAddr = 0x00;                // 中断处理结束
  }      
  /****************************************************************************
  * 名  称:UART0_Ini()
  * 功  能:初始化串口。设置为位数据位,位停止位,无奇偶校验,波特率为
  * 入口参数:无
  * 出口参数:无
  ****************************************************************************/
  void  UART0_Init(void)
  {  
  uint16 Fdiv;
  U0LCR = 0x83;      // DLAB = 1,可设置波特率
  Fdiv = (Fpclk / 16) / UART_BPS;  // 设置波特率
  U0DLM = Fdiv / 256;      
  U0DLL = Fdiv % 256;      
  U0LCR = 0x03;
  U0FCR = 0x81;                         // 使能FIFO,并设置触发点为字节
  U0IER = 0x01;                         // 允许RBR中断,即接收中断
  }
  /****************************************************************************
  * 名  称:main()
  * 功  能:从串口接收数据
  ****************************************************************************/
  int  main(void)
  {  
  uint i="0";
  **_Rece =0;
  ReceiveLen = 0;
  PINSEL0 = 0x00000005;      // 设置I/O连接到UART0
  UART0_Init();
  /* 设置中断允许*/
  VICIntSelect = 0x00000000;            // 设置所有通道为IRQ中断
  VICVectCntl0 = 0x26;           // UART0中断通道分配到IRQ slot 0,即优先级最高
  VICVectAddr0 = (int)IRQ_UART0;        // 设置UART0向量地址
  VICIntEnable = 0x00000040;            // 使能UART0中断
  while(1)
  {  
  接收数据处理函数略
  }
  return(0);

使用特权

评论回复
板凳
szdianzijie| | 2011-3-3 11:27 | 只看该作者
void  UART0_Init(void)
  {  
  uint16 Fdiv;
  U0LCR = 0x83;      // DLAB = 1,可设置波特率
  Fdiv = (Fpclk / 16) / UART_BPS;  // 设置波特率
  U0DLM = Fdiv / 256;      
  U0DLL = Fdiv % 256;      
  U0LCR = 0x03;
  U0FCR = 0x81;                         // 使能FIFO,并设置触发点为字节
  U0IER = 0x01;                         // 允许RBR中断,即接收中断
  }

使用特权

评论回复
地板
huzixian| | 2011-3-3 22:54 | 只看该作者
这个程序可以直接拿来用吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

685

帖子

3

粉丝