本节我们来使用LPC1343的UART接口做一个简单的收发实验。
大家之前应该都有使用51或AVR一类单片机做过异步串行收发实验,当然串口在电子开发中的应用地位就无需多言。我们直接进入主题。
本次试验这样设计,用PC作为上位机向UART发送一个(串)字节,然后LPC1343收到这个(串)字节后再发回UART,在PC上的串口观察软件显示出来。
我们来看NXP带给我们的UART例程来看看UART的设置以及工作过程。首先是主函数:
int main (void)
{
UARTInit(115200);//初始化UART接口并设置为波特率115200,NVIC也在内一并设置
while (1)
{
if ( UARTCount != 0 )
{
LPC_UART->IER = IER_THRE | IER_RLS;
UARTSend( (uint8_t *)UARTBuffer, UARTCount );//发送数据
UARTCount = 0;
LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR;
}
}
}
从主函数就可以看到本次例程的目的了:初始化UART——一旦接收到数据之后立即停止接收——发送——开启下一次接收。最重要的当然是初始化函数UARTInit():
void UARTInit(uint32_t baudrate)
{
uint32_t Fdiv;
uint32_t regVal;
UARTTxEmpty = 1;
UARTCount = 0;
NVIC_DisableIRQ(UART_IRQn); //关闭UART中断,避免此后的初始化有中断打断
LPC_IOCON->PIO1_6 &= ~0x07;
LPC_IOCON->PIO1_6 |= 0x01;
LPC_IOCON->PIO1_7 &= ~0x07;
LPC_IOCON->PIO1_7 |= 0x01;
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);
LPC_SYSCON->UARTCLKDIV = 0x1;
LPC_UART->LCR = 0x83;
regVal = LPC_SYSCON->UARTCLKDIV;
Fdiv=(((SystemCoreClock*LPC_SYSCON->SYSAHBCLKDIV)/regVal)/16)
//baudrate ;
LPC_UART->DLM = Fdiv / 256; //写入波特率计算值高位
LPC_UART->DLL = Fdiv % 256; //写入波特率计算值低位
LPC_UART->LCR = 0x03;
LPC_UART->FCR = 0x07;
regVal = LPC_UART->LSR;
while (( LPC_UART->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) );
while ( LPC_UART->LSR & LSR_RDR )
{
regVal = LPC_UART->RBR;
}
NVIC_EnableIRQ(UART_IRQn);
#if TX_INTERRUPT //是否使用发送中断,本次例程使用
LPC_UART->IER = IER_RBR | IER_THRE | IER_RLS;
#else //所以执行此else
LPC_UART->IER = IER_RBR | IER_RLS;
#endif
return;
}
打星号的地方是笔者认为比较值得关注的地方:
1、UART的IO口设置,根据上述函数中的语句查找相关寄存器,可以发现它将P16、P17设置为:UART_RXD和UART_TXD功能;
2、选择UART时钟分频数,此处1分频,和波特率设置有直接关系;
3、选择数据格式,此处选择数据长度8位,无校验,1位停止位,并开启除数锁存;
4、除数锁存器:分为LSB(8位)和MSB(8位),用来填入对应某波特率的计数值,更改之前解除锁定,更改完毕恢复锁定,这样就可以锁定波特率了(可以这样简单的理解);
5、计算波特率,此处是重点了。首先我们肯定知道系统核心频率为72MHz,即SystemCoreClock=72 000 000(参考本系列前几章内容)。而UART作为AHB总线上的设备,自然要经过AHB分频器,在此处,AHB分频系数并未做过特别设置,所以为默认值1。时钟经过AHB分频之后要经过UART分频器进行再分频,分频系数仍为1(第2点)。因此我们来计算这个公式:
Fdiv = (((SystemCoreClock*LPC_SYSCON->SYSAHBCLKDIV)/regVal)/16)/baudrate
其中SystemCoreClock=72000000,LPC_SYSCON->SYSAHBCLKDI=1,regVal=1,baudrate=115200,所以可以计算出:
Fdiv=39.0625≈0x27
这个便是产生115200波特率所要填入除数锁存器的值。逆过来就可以计算出计数值对应的波特率。
6、线状态寄存器(下文稍加讲述)是以读操作来清空的;
其实这个函数,对于用户来说,只需要填入想要产生的波特率作为函数参数就可以完成LPC1343的UART初始化以及波特率设定工作。
设定完成之后,UART就开始工作了,因为初始化函数里面开启了“启用缓存数据可用中断、线状态中断”所以当有数据从上位机向UART发送数据时,进入中断服务函数:
void UART_IRQHandler(void)
{
uint8_t IIRValue, LSRValue;
uint8_t Dummy = Dummy;
IIRValue = LPC_UART->IIR;
IIRValue >>= 1;
IIRValue &= 0x07;
if (IIRValue == IIR_RLS)
{
LSRValue = LPC_UART->LSR;
if (LSRValue & (LSR_OE | LSR_PE | LSR_FE | LSR_RXFE | LSR_BI))
{
UARTStatus = LSRValue;
Dummy = LPC_UART->RBR;
return;
}
if (LSRValue & LSR_RDR)
{
UARTBuffer[UARTCount++] = LPC_UART->RBR;
if (UARTCount == BUFSIZE)
{
UARTCount = 0;
}
}
}
else if (IIRValue == IIR_RDA)
{
UARTBuffer[UARTCount++] = LPC_UART->RBR;
if (UARTCount == BUFSIZE)
{
UARTCount = 0;
}
}
else if (IIRValue == IIR_CTI)
{
UARTStatus |= 0x100;
}
else if (IIRValue == IIR_THRE)
{
LSRValue = LPC_UART->LSR;
if (LSRValue & LSR_THRE)
{
UARTTxEmpty = 1;
}
else
{
UARTTxEmpty = 0;
}
}
return;
}
这个中断服务函数是一个if…else if….else if结构。在进入此中断服务函数后,读取
中断标识寄存器判断中断源,选择进入相应的if环节执行相应语句。我们看看UART都有哪些中断。第一个是RLS,Receive Line Status即接收线中断:
可以在用户手册查看到接受线中断分别有以下多种:
RDR :Receiver Data Ready,接受数据就绪中断;
OE:Overrun Error,即溢出错误中断;
PE:Parity Error,校验错误中断;
FE:Framing Error,帧错误中断;
BI:Break Interrupt,间隔状态中断;
THRE:Transmitter Holding Register Empty,发送保持寄存器空中断;
TEMP:Transmitter Empty,发送保持寄存器与临时寄存器空中断;
RXFE:Error in RX FIFO,RX错误中断;
对照上述中断服务函数第一个if部分,当判断确定为线中断之后,即判断是否是OE——RXFE中的任何一个错误,如果有错误,则读出数据有效保存,如果有错误,则读出数据但丢弃。
所以,线中断在进行数据校验的场合才会使用。而本次实验中并未用到数据校验位。所以此中断不会进入。
当不使用校验功能之时,收到数据之后会进入第一个else if结构:
else if (IIRValue == IIR_RDA)
{}
在进入此部分之后将数据读出。
当接受一个字符(5~8位不等)超时时,会进入“接受字符超时中断”部分。
发送完成中断在本次试验中并未使能,略过。
如此我们应该可以预知本次试验中当PC上位机发送一个(串)字符之后,会进入中断服务函数并且进入else if (IIRValue == IIR_RDA{}环节,将收到的数据保存在UARTBuffer中,并使UARTCount++。然后退出中断函数之后,回到主函数,执行发送部分:
if ( UARTCount != 0 )
{
LPC_UART->IER = IER_THRE | IER_RLS;
UARTSend( (uint8_t *)UARTBuffer, UARTCount );//发送数据
UARTCount = 0;
LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR;
}
}
找到UARTSend():
void UARTSend(uint8_t *BufferPtr, uint32_t Length)
{
while ( Length != 0 )
{
#if !TX_INTERRUPT//未使用中断发送方式,所以编译此部分
while ( !(LPC_UART->LSR & LSR_THRE) );//等待发送保持寄存器空
LPC_UART->THR = *BufferPtr;//将待发数据写入发送保持寄存器
#else
while ( !(UARTTxEmpty & 0x01) );
LPC_UART->THR = *BufferPtr;
UARTTxEmpty = 0;
#endif
BufferPtr++;
Length--;
}
return;
}
此UART数据发送函数,第一个参数要求填入存放待发送数据(注意为8位,即字符型数据)的数组名,第二个参数为待发数据长度。通过注释可以看到发送的过程很简单,等待发送保持寄存器为空后将数据写入发送保持寄存器就完成了发送。
这样我们就将本次的UART收发试验的过程“初始化——等待接收——UART中断——保存数据——发送数据”分析完毕。
NXP赠送的这个LPC1343并没有挂载UART接口,而只留了P16、P17两个IO给用户拓展,所以笔者使用了其他开发板的串口连接,需要注意的是,我们手上的这块开发板是3.3V供电,而市面上比较多采用的MAX232是5V供电。所以或者使用LPC1343评估板的5V给MAX232供电,或者使用3.3V供电的电平转换芯片。笔者这里使用了3.3V供电的ST232芯片。
导入lpc1343.examples->uart,编译链接。连好硬件,从串口调试终端发送一个(串)数据,可以看到串口调试终端的接收框里准确的显示了我们所发送的数据,本次实验完结。
关键字:LPC1343 串口学习
引用地址:
LPC1343串口学习
推荐阅读最新更新时间:2024-03-16 14:44
STM8学习笔记---通过示波器分析串口数据
在用单片机做串口通信时,经常会遇到通信错误,但是检查程序时却没发现有什么问题。这时候就可以借助示波器来观察串口数据是不是正确。但是串口数据的波形要怎么看呢。先来看看串口数据帧的定义: 常用的数据格式为 1位起始位、8位数据位、1位结束位、无奇偶校验位。一个数据位上总共有10个电平跳变。下来看看示波器上的串口的波形到底是怎么样的。 用串口助手发送16进制数 0x00,波特率9600,停止位1位、数据位8位、无校验位。这时看看示波器上数据波形是什么样的。 示波器上只看到来一段低电平,那么如何分析电平呢。我们知道串口通信数据帧的格式为 起始位、数据位、结束位、起始位为低电平,结束位为高电平,数据位为8位,那么根据这个特点对波
[单片机]
STM32单片机学习笔记——USART串口通信
首先,USART是什么呢? USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备。(来自百度) 这是官方解释,而我对它的通俗解释是:这是一个用于和其他设备(如电脑、单片机等)通信(交换数据、信息等)的端口,就像手机数据线那样。 当然,这只是我的一种通俗看法,大家经过了深入的学习之后,一定会产生更为准确、成熟的看法。 我所学习的,就是通过这个模块来实现单片机和电脑之间的通信,并以此为基础,实现利用电脑来简单地控制单片机的目的。 那么,我们来简单地看一看我们这段代码由哪几部分组成: 1. 用于存储相关配置的结构体。 2. 变量Temp,用于存储从电脑接收到的信息。 3.
[单片机]
51单片机学习笔记———12.1UART串口通信
UART一般用于板间通讯,即单片机和外围设备之间的通讯。 当单片机的电压与外设之间的电压不同时,需要一个中介芯片来转换: 常用的是CH340T,原理图如下: 先发一位 0 表示起始位,然后发送 8 位数据位,数据位是先低后高的顺序,数据位发完后再发一位 1 表示停止位。这样本来要发送一个字节的 8 位数据,而实际上我们一共发送了 10 位,多出来的两其中一位起始位,一位停止位。 有关寄存器: SCON:串行口控制寄存器 `SM0`,`SM1`:工作方式选择位(方式) `TI`:发送中断标志,发送一帧结束,`TI = 1`,必须软件清0 `RI`:接受中断标志,接受一帧结束,`RI = 1`,必须软件清0 P
[单片机]
用Proteus学习51单片机之串口
串口的理论知识我就不记了,网上多的是。51单片机的串口,有4种方式,分别为方式0,方式1,方式2,方式3.由于我的目的,使用串口主要是为了和电脑进行通信,所以主要使用方式1(事实上我也只学了方式1,其他方式等用到的时候再学吧)。 串口的方式1,其波特率与定时器T1相关,公式如下: 方式1波特率 = (2SMOD×32)/(T1溢出率) SMOD是一个寄存器,一般我们就取0了 T1的溢出率,即每秒T1计数满几次(相关知识可以看看前面笔记的记录) 正是因为如上的公式,所以设置TH1和TL1的初值,就能控制方式1的波特率了。不过一般波特率是固定的那么几种,像2400,4800和9600等,要用的时候查一下初值就成了。 由于用的是Prot
[单片机]
STM8学习笔记---串口通信中如何自己定义通信协议
在单片机刚开始学习的时候,串口通信是经常要用到的,但是实际产品中串口通信是需要通信协议的。好多人不明白为什么要用通信协议,如何定义通信协议,带通信协议的程序要怎么写。今天就来说一下如何串口通信协议是如何定义出来的。 先看一段最简单的串口程序。 void Uart1_Init( unsigned int baudrate ) { unsigned int baud; baud = 16000000 / baudrate; Uart1_IO_Init(); //IO口初始化 UART1_CR1 = 0; UART1_CR2 = 0; UART1_CR3 = 0; UART1_BRR2 = ( uns
[单片机]