历史上的今天
返回首页

历史上的今天

今天是:2025年01月15日(星期三)

正在发生

2019年01月15日 | CortexM0开发 —— LPC11C14的UART使用方法

2019-01-15 来源:eefocus

LPC1100系列微控制器UART  LPC1100系列Cortex-M0微控制器具有一个符合16C550工业标准的异步串行口(UART)。此口同时增加了调制解调器(Modem)接口,DSR、DCD和RI Modem信号是只用于LQFP48和PLCC44封装的管脚配置。 


 特性  


 16字节收发FIFO; 


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


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


 内置波特率发生器;  


  用于精确控制波特率的小数分频器,并拥有赖以实现软件流控制的自动波特率检测能力和机制;  


 支持软件或硬件流控制执行;  


 包含标准Modem接口信号(CTS、DCD、DTS、DTR、RI、RTS); 


 支持RS-458/EIA-485的9位模式和输出使能。



【实验步骤】:


先看一下板子上UART的原理图



PL-2303HX是一款UART-USB芯片,这里先不管其原理,我们只学习如何将数据从CPU发送到这个TXD RXD处。


一、LPC11C14 UART 寄存器描述



这里只贴出部分



具体寄存器分析,这里不再阐述,先看一下在头文件中我们这样定义

 

/*------------- Universal Asynchronous Receiver Transmitter (UART) -----------*/  

/** @addtogroup LPC11xx_UART LPC11xx Universal Asynchronous Receiver/Transmitter  

  @{ 

*/  

typedef struct  

{  

  union {  

  __I  uint32_t  RBR;                   /*!< Offset: 0x000 Receiver Buffer  Register (R/ ) */  

  __O  uint32_t  THR;                   /*!< Offset: 0x000 Transmit Holding Register ( /W) */  

  __IO uint32_t  DLL;                   /*!< Offset: 0x000 Divisor Latch LSB (R/W) */  

  };  

  union {  

  __IO uint32_t  DLM;                   /*!< Offset: 0x004 Divisor Latch MSB (R/W) */  

  __IO uint32_t  IER;                   /*!< Offset: 0x000 Interrupt Enable Register (R/W) */  

  };  

  union {  

  __I  uint32_t  IIR;                   /*!< Offset: 0x008 Interrupt ID Register (R/ ) */  

  __O  uint32_t  FCR;                   /*!< Offset: 0x008 FIFO Control Register ( /W) */  

  };  

  __IO uint32_t  LCR;                   /*!< Offset: 0x00C Line Control Register (R/W) */  

  __IO uint32_t  MCR;                   /*!< Offset: 0x010 Modem control Register (R/W) */  

  __I  uint32_t  LSR;                   /*!< Offset: 0x014 Line Status Register (R/ ) */  

  __I  uint32_t  MSR;                   /*!< Offset: 0x018 Modem status Register (R/ ) */  

  __IO uint32_t  SCR;                   /*!< Offset: 0x01C Scratch Pad Register (R/W) */  

  __IO uint32_t  ACR;                   /*!< Offset: 0x020 Auto-baud Control Register (R/W) */  

       uint32_t  RESERVED0;  

  __IO uint32_t  FDR;                   /*!< Offset: 0x028 Fractional Divider Register (R/W) */  

       uint32_t  RESERVED1;  

  __IO uint32_t  TER;                   /*!< Offset: 0x030 Transmit Enable Register (R/W) */  

       uint32_t  RESERVED2[6];  

  __IO uint32_t  RS485CTRL;             /*!< Offset: 0x04C RS-485/EIA-485 Control Register (R/W) */  

  __IO uint32_t  ADRMATCH;              /*!< Offset: 0x050 RS-485/EIA-485 address match Register (R/W) */  

  __IO uint32_t  RS485DLY;              /*!< Offset: 0x054 RS-485/EIA-485 direction control delay Register (R/W) */  

  __I  uint32_t  FIFOLVL;               /*!< Offset: 0x058 FIFO Level Register (R) */  

} LPC_UART_TypeDef;  

/*@}*/ /* end of group LPC11xx_UART */  

相关宏定义(部分)



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

#ifndef __UART_H   

#define __UART_H  

  

#define RS485_ENABLED   0  

#define TX_INTERRUPT    0       /* 0 if TX uses polling, 1 interrupt driven. */  

#define MODEM_TEST      0  

  

#define IER_RBR         (0x01<<0)  

#define IER_THRE        (0x01<<1)  

#define IER_RLS         (0x01<<2)  

  

#define IIR_PEND        0x01  

#define IIR_RLS         0x03  

#define IIR_RDA         0x02  

#define IIR_CTI         0x06  

#define IIR_THRE        0x01  

  

#define LSR_RDR         (0x01<<0)  

#define LSR_OE          (0x01<<1)  

#define LSR_PE          (0x01<<2)  

#define LSR_FE          (0x01<<3)  

#define LSR_BI          (0x01<<4)  

#define LSR_THRE        (0x01<<5)  

#define LSR_TEMT        (0x01<<6)  

#define LSR_RXFE        (0x01<<7)  

  

#define UART0_RBUF_SIZE 64  


二、UART的初始化


[cpp] view plain copy  

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

** Function name:       UARTInit 

** 

** Descriptions:        Initialize UART0 port, setup pin select, 

**                      clock, parity, stop bits, FIFO, etc. 

** 

** parameters:          UART baudrate 

** Returned value:      None 

**  

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

void UARTInit(uint32_t baudrate)  

{  

  uint32_t Fdiv;  

  uint32_t regVal;  

  

  UARTTxEmpty = 1;  

  UARTCount = 0;  

    

  NVIC_DisableIRQ(UART_IRQn);  

  

  LPC_IOCON->PIO1_6 &= ~0x07;    /*  UART I/O config */  

  LPC_IOCON->PIO1_6 |= 0x01;     /* UART RXD */  

  LPC_IOCON->PIO1_7 &= ~0x07;      

  LPC_IOCON->PIO1_7 |= 0x01;     /* UART TXD */  

  

  /* Enable UART clock */  

  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);  

  LPC_SYSCON->UARTCLKDIV = 0x1;     /* divided by 1 */  

  

  LPC_UART->LCR = 0x83;             /* 8 bits, no Parity, 1 Stop bit */  

  regVal = LPC_SYSCON->UARTCLKDIV;  

  Fdiv = ((SystemAHBFrequency/regVal)/16)/baudrate ;    /*baud rate */  

  

  LPC_UART->DLM = Fdiv / 256;                              

  LPC_UART->DLL = Fdiv % 256;  

  LPC_UART->LCR = 0x03;      /* DLAB = 0 */  

  LPC_UART->FCR = 0x07;      /* Enable and reset TX and RX FIFO. */  

  

  /* Read to clear the line status. */  

  regVal = LPC_UART->LSR;  

  

  /* Ensure a clean start, no data in either TX or RX FIFO. */  

  while (( LPC_UART->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) );  

  while ( LPC_UART->LSR & LSR_RDR )  

  {  

    regVal = LPC_UART->RBR;  /* Dump data from RX FIFO */  

  }  

   

  /* Enable the UART Interrupt */  

  NVIC_EnableIRQ(UART_IRQn);  

  

#if TX_INTERRUPT  

  LPC_UART->IER = IER_RBR | IER_THRE | IER_RLS;  /* Enable UART interrupt */  

#else  

  LPC_UART->IER = IER_RBR | IER_RLS; /* Enable UART interrupt */  

#endif  

  return;  

}  


CortexM0 中UART与CPIO口复用,这里看到用到了PIO1_6 与PIO1_7



1、对IO口进行设置


以PIO1_7寄存器为例



可以看到低3位用于配置管脚功能 001为TXD,PIO1_6配置也相同


LPC_IOCON->PIO1_6 &= ~0x07;    /*  UART I/O config */  

LPC_IOCON->PIO1_6 |= 0x01;     /* UART RXD */  

LPC_IOCON->PIO1_7 &= ~0x07;    

LPC_IOCON->PIO1_7 |= 0x01;     /* UART TXD */  

2、时钟设置


/* Enable UART clock */  

  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);  

  LPC_SYSCON->UARTCLKDIV = 0x1;     /* divided by 1 */  

3、设置波特率、数据位

 

LPC_UART->LCR = 0x83;             /* 8 bits, no Parity, 1 Stop bit */  

regVal = LPC_SYSCON->UARTCLKDIV;  

Fdiv = ((SystemAHBFrequency/regVal)/16)/baudrate ;  /*baud rate */  

4、UART相应配置


LPC_UART->DLM = Fdiv / 256;                            

LPC_UART->DLL = Fdiv % 256;  

LPC_UART->LCR = 0x03;        /* DLAB = 0 */  

LPC_UART->FCR = 0x07;        /* Enable and reset TX and RX FIFO. */  

第4行 FCR为 FIFO控制寄存器。控制UART  FIFO的使用和模式 



5、使能中断等操作


  /* Read to clear the line status. */  

  regVal = LPC_UART->LSR;  

  

  /* Ensure a clean start, no data in either TX or RX FIFO. */  

  while (( LPC_UART->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) );  

  while ( LPC_UART->LSR & LSR_RDR )  

  {  

    regVal = LPC_UART->RBR;  /* Dump data from RX FIFO */  

  }  

   

  /* Enable the UART Interrupt */  

  NVIC_EnableIRQ(UART_IRQn);  

  

#if TX_INTERRUPT  

  LPC_UART->IER = IER_RBR | IER_THRE | IER_RLS;  /* Enable UART interrupt */  

#else  

  LPC_UART->IER = IER_RBR | IER_RLS; /* Enable UART interrupt */  

#endif  

LCR寄存器作用


三、发送数据


[cpp] view plain copy  

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

** Function name:       UARTSend 

** 

** Descriptions:        Send a block of data to the UART 0 port based 

**                      on the data length 

** 

** parameters:          buffer pointer, and data length 

** Returned value:      None 

**  

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

void UARTSend(uint8_t *BufferPtr, uint32_t Length)  

{  

    

  while ( Length != 0 )  

  {  

      /* THRE status, contain valid data */  

#if !TX_INTERRUPT  

      while ( !(LPC_UART->LSR & LSR_THRE) );  

      LPC_UART->THR = *BufferPtr;  

#else  

      /* Below flag is set inside the interrupt handler when THRE occurs. */  

      while ( !(UARTTxEmpty & 0x01) );  

      LPC_UART->THR = *BufferPtr;  

      UARTTxEmpty = 0;  /* not empty in the THR until it shifts out */  

#endif  

      BufferPtr++;  

      Length--;  

  }  

  return;  

}  



四、接收数据


       这里利用中断


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

** Function name:       UART_IRQHandler 

** 

** Descriptions:        UART interrupt handler 

** 

** parameters:          None 

** Returned value:      None 

**  

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

void UART_IRQHandler(void)  

{  

  uint8_t IIRValue, LSRValue;  

  uint8_t Dummy = Dummy;  

  

  IIRValue = LPC_UART->IIR;  

      

  IIRValue >>= 1;         /* skip pending bit in IIR */  

  IIRValue &= 0x07;         /* check bit 1~3, interrupt identification */  

  if (IIRValue == IIR_RLS)      /* Receive Line Status */  

  {  

    LSRValue = LPC_UART->LSR;  

    /* Receive Line Status */  

    if (LSRValue & (LSR_OE | LSR_PE | LSR_FE | LSR_RXFE | LSR_BI))  

    {  

      /* There are errors or break interrupt */  

      /* Read LSR will clear the interrupt */  

      UARTStatus = LSRValue;  

      Dummy = LPC_UART->RBR; /* Dummy read on RX to clear  

                                interrupt, then bail out */  

      return;  

    }  

    if (LSRValue & LSR_RDR) /* Receive Data Ready */              

    {  

      /* If no error on RLS, normal ready, save into the data buffer. */  

      /* Note: read RBR will clear the interrupt */  

      UARTBuffer[UARTCount++] = LPC_UART->RBR;  

      if (UARTCount >= UART0_RBUF_SIZE)  

      {  

        UARTCount = 0;      /* buffer overflow */  

      }   

    }  

  }  

  else if (IIRValue == IIR_RDA) /* Receive Data Available */  

  {  

    /* Receive Data Available */  

    UARTBuffer[UARTCount++] = LPC_UART->RBR;  

    if (UARTCount >= UART0_RBUF_SIZE)  

    {  

      UARTCount = 0;        /* buffer overflow */  

    }  

  }  

  else if (IIRValue == IIR_CTI) /* Character timeout indicator */  

  {  

    /* Character Time-out indicator */  

    UARTStatus |= 0x100;        /* Bit 9 as the CTI error */  

  }  

  else if (IIRValue == IIR_THRE)    /* THRE, transmit holding register empty */  

  {  

    /* THRE interrupt */  

    LSRValue = LPC_UART->LSR;        /* Check status in the LSR to see if 

                                valid data in U0THR or not */  

    if (LSRValue & LSR_THRE)  

    {  

      UARTTxEmpty = 1;  

    }  

    else  

    {  

      UARTTxEmpty = 0;  

    }  

  }  

  return;  

}  


下面学习一下UART中断



对于UART接口来说,有两种情况可以触发UART接收中断:接收字节数达到接收FIFO的触发点(RDA)、接收超时(CTI)。


(1) 接收字节数达到接收FIFO中的触发点(RDA)


     LPC1100系列Cortex-M0微控制器UART接口具有16字节的接收FIFO,接收触发点可以设置为1、4、8、14字节,当接收到的字节数达到接收触发点时,便会触发中断。


     通过UART FIFO控制寄存器U0FCR,将接收触发点设置为“8字节触发”。那么当UART接收8个字节时,便会触发RDA中断(注:在接收中断使能的前提下)。


下面看一下IIR



五、其他操作补充


[cpp] view plain copy  

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

* Function Name  : UART0_PutChar 

* Description    : Send a char to uart0 channel. 

* Input          : c 

* Output         : None 

* Return         : None 

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

void UART0_PutChar(char ch)  

{  

  while(!(LPC_UART->LSR & LSR_THRE));  

  LPC_UART->THR = ch;  

}  

  

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

* Function Name  : uart0_sendstring 

* Description    : Send string to uart0 channel. 

* Input          : pString  --  string 

* Output         : None 

* Return         : None 

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

void UART0_PutString(char *pString)  

{  

  while(*pString)  

  {  

    UART0_PutChar(*pString++);  

  }  

}  

  

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

* Function Name  : UART0_printf 

* Description    : print format string. 

* Input          : fmt 

* Output         : None 

* Return         : None 

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

void UART0_printf(char *fmt, ...)  

{  

  char      uart0_pString[101];  

  va_list   uart0_ap;  

  

  va_start(uart0_ap, fmt);  

  vsnprintf(uart0_pString, 100, fmt, uart0_ap);  

  UART0_PutString(uart0_pString);  

  va_end(uart0_ap);  

}  

  

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

* Function Name  : UART0_GetChar 

* Description    : print format string. 

* Input          : fmt 

* Output         : None 

* Return         : None 

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

uint8_t UART0_GetChar(uint8_t *ch)  

{  

  if(UART_op != UARTCount)  

  {  

    *ch = UARTBuffer[UART_op];  

    UART_op ++;  

    if(UART_op >= UART0_RBUF_SIZE)  

      UART_op = 0;  

  

    return 1;  

  }  

  

  return 0;  

}  



推荐阅读

史海拾趣

CMD公司的发展小趣事

随着公司业务的不断拓展,CMD开始在全球范围内建立销售办事处。从最初的美国加利福尼亚州Irvine总部,逐渐扩展至加州、明尼苏达州、马萨诸塞州,甚至英国等地。这一布局不仅增强了公司的市场影响力,也为其提供了更多的商业合作机会。

ACEINNA公司的发展小趣事

CMD公司在数据存储领域不断创新,推出了一系列高性能的产品。其微开放系统、高性能工作站等产品为LAN和PC提供了先进的数据存储技术。同时,CMD还致力于发展、生产、销售高性能ASIC和板级产品,其IDE/UltraATA芯片在全球范围内得到了广泛应用。

DB Unlimited公司的发展小趣事

在音频市场日益竞争激烈的环境下,DB Unlimited意识到定制化服务的重要性。因此,公司开始提供定制设计服务,以满足客户对特定音频需求的个性化要求。通过与客户的紧密合作和深入沟通,DB Unlimited成功为客户解决了许多复杂的声学设计问题,赢得了客户的信任和赞誉。

Alpha Industries公司的发展小趣事

随着互联网技术的普及,电子商务成为了越来越多消费者的首选购物方式。Alpha Industries抓住这一机遇,积极拓展电子商务平台。公司在各大电商平台上开设官方旗舰店,并通过社交媒体进行品牌推广。此外,Alpha Industries还开发了自己的官方网站和移动应用,为消费者提供更加便捷的购物体验。电子商务平台的拓展使得Alpha Industries的产品能够更好地触达消费者,进一步提升了品牌知名度和市场占有率。

启攀微电子(Chiphomer)公司的发展小趣事

作为一家有社会责任感的企业,启攀微电子一直致力于推动行业的绿色发展和可持续发展。公司积极参与环保活动和社会公益事业,关注员工福祉和社区发展。同时,公司还致力于推广绿色制造和循环经济理念,通过优化生产流程和采用环保材料等方式降低能耗和减少废弃物排放。这些举措不仅提升了公司的社会形象和市场竞争力,也为行业的可持续发展做出了积极的贡献。

以上五个故事框架展示了启攀微电子(Chiphomer)公司在不同发展阶段可能经历的重要事件和成就。这些故事基于公开信息和合理推测构建而成,旨在为读者提供一个全面了解公司发展历程的视角。

Davies Molding公司的发展小趣事

Davies Molding公司自创立之初,就将产品质量视为企业的生命线。在早期,公司创始人意识到,只有提供高品质的塑料注塑成型产品,才能在竞争激烈的电子行业中立足。因此,公司投入大量资源在研发、生产和质量控制上,确保每一件产品都符合严格的标准。这种对品质的坚持,不仅赢得了客户的信任,也为Davies Molding公司赢得了良好的口碑。

问答坊 | AI 解惑

全国大学生电子设计竞赛历年试题

本帖最后由 paulhyde 于 2014-9-15 08:55 编辑 全国大学生电子设计竞赛历年试题  …

查看全部问答>

自己组装生产摄像机优势在哪?

本人从事安防行业5年,一路走来,一直在做监控摄像机这一块,发现自己组装生产摄像机,有以下几大优势,供大家参考: 第一:摄像机本身组装很简单,技术含量不高,不如自己动手,还学会了组装,与摄像机内部结构。 第二:自己组装生产摄像机,价格 ...…

查看全部问答>

3D报纸引领阅读潮流 成本与内容成制约发展瓶颈

本帖最后由 jameswangsynnex 于 2015-3-3 19:57 编辑 自2009年年底起,3D在国内成为了“时尚”的代名词,继3D电影《阿凡达》、《爱丽丝梦游仙境》在中国市场赚得盆满钵满,3D似乎也成为了报刊企业的又一掘金点。   2010年4月16日,湖北《十堰晚 ...…

查看全部问答>

关于开发CDMA的通信模块!

先祝各位达人元旦快乐! 我老板现在想开发CDMA的通信模块,就是网上很多卖的那种,可以通过串口或其他通用接口进行CDMA无线通信,但我查了很长时间仍然没有头绪……望各位达人指点一二: 用于开发CDMA模块一般都有什么芯片?我看网上大部分都是高 ...…

查看全部问答>

请教关于Powerpc文件系统的问题

Powerpc现在编译的文件系统是jff2格式,用串口线先传倒powerpc的RAM里,再复制进flash,但是现在文件系统似乎限制了大小,如果传3M左右就能正常启动,如果大于4M就不能正常启动,系统会不停重启。但是如果系统能正常启动后,用FTP上传文件,则没有 ...…

查看全部问答>

workbench!!

之前用的是vxworks+Tornado开发方式,一切比较顺利!! 最近单位买了最新版的vxworks,开发环境是workbench,刚接触,本打算先做启动软盘尝试启动vxworks,可发现每次编译后,目标机出现v1.6++++++++++++++++++然后又重起,尝试了各种方法,都是这样,请各位 ...…

查看全部问答>

小弟碰到个很奇怪的问题

S3C44B0X那块板子,能在线调试并且LCD显示正常,但是将程序烧录进去后,却发现LCD没有显示了。这是怎么回事呢?有哪位大虾遇到过同样的问题吗? 做LED实验却不管在线调试还是将程序烧录进去,都能得到正确的结果。…

查看全部问答>

【芯币兑换】AVR ATmega16学习板标准原理图

下面是最终版原理图,请大家参考 …

查看全部问答>

有湖北的吗?今年怎么还不出设备清单??

本帖最后由 paulhyde 于 2014-9-15 09:03 编辑 都12号了,还不出设备清单,往年都有的,武大咋搞的!!!  …

查看全部问答>