串口USART(续二)
通过前面的分析知道,在LPC824中,USART所拥有的配置寄存器有很多,但在一般情况下,如果只是简单地使用收发功能,则只需要使用到配置寄存器CFG、波特率发生器寄存器BRG、中断使能读取和置位寄存器INTENSET、中断状态寄存器INTSTAT、接收器数据寄存器RXDAT、发送器数据寄存器TXDAT等6个主要寄存器,其余的寄存器取默认值即可。下面就来看一个实例。
例子:要求LPC824把USART接收到的数据原样发送回去,波特率115200,8位数据位,1位停止位。
完整代码如下。
#include <LPC82x.h>
//************************串口初始化***********************************
void uart_init(void)
{
LPC_SYSCON->SYSAHBCLKCTRL|=1<<7; //开启SWM时钟
LPC_SWM->PINASSIGN0 &= ~0xFFFF;
LPC_SWM->PINASSIGN0 |= 0x04;
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<7); //关闭SWM时钟(使用完之后记得关闭,节省功耗)
LPC_SYSCON->SYSAHBCLKCTRL |= 1<<14; //开启USART0时钟
LPC_SYSCON->PRESETCTRL &= ~(1<<3); //开启复位USART0
LPC_SYSCON->PRESETCTRL |= (1<<3); //关闭复位USART0
LPC_USART0->CFG &= ~(1<<0); //串口USART0禁止
LPC_USART0->CFG|=1<<2; //配置USART0为8位数据方式
LPC_SYSCON->UARTCLKDIV = 1;
LPC_SYSCON->UARTFRGDIV = 0xFF;
LPC_SYSCON->UARTFRGMULT = 0; //配置串口的外设时钟U_PCLK
LPC_USART0->BRG = 12; //配置USART0的波特率为115200
LPC_USART0->CFG |= 1<<0; //串口USART0使能
}
//***************************主函数************************************
int main(void)
{
uart_init();
LPC_USART0->INTENSET |= 1<<0; //使能串口接收中断
NVIC_ClearPendingIRQ(UART0_IRQn); //清除挂起的中断
NVIC_EnableIRQ(UART0_IRQn); //使能NVIC串口中断
while(1)
;
}
//************************串口中断***********************************
void UART0_IRQHandler(void)
{
// if(LPC_USART0->STAT & 0x1)
if(LPC_USART0->INTSTAT & 0x1) //如果是接收到数据的中断
LPC_USART0->TXDAT = LPC_USART0->RXDATSTAT; //把接收到的数据发送出去
}
从上述代码中可以看出,在默认状态下,LPC824是没有把USART(包括USART0~USART2)的引脚映射到芯片的物理引脚上的,所以初始化串的第一步,就要把串口所需要的引脚映射出来。 在上述程序中,通过操作开关矩阵寄存器SWM,把USART0的RXD和TXD引脚分别映射到了PIO0_0和PIO0_4物理引脚上。引脚映射完成后,要关闭SWM时钟,以节约能耗。接下来需要开启USART0的时钟,并对其进行一次复位操作。开启USART0的时钟,配置的是SYSAHBCLKCTRL寄存器,详见前面时钟配置部分。复位USART0配置的是PRESETCTRL寄存器,详见前面多速率定时器部分。
接下来配置CFG寄存器,使能USART0,设置为8位数据方式。本例的波特率为115200,为了弄清波特率的配置,需要先讨论一下在LPC824中,串口的波特率是如何进行计算的。
先来看一下LPC824的USART时钟结构,如下图所示。
从图中可以看到USART的时钟分为两个部分,第一部分是由系统时钟(system clock)提供的USART模块时钟,它为整个USART模块提供正常工作所需的时钟,受SYSAHBCLKCTRL寄存器第15到17位的控制(详见前面时钟配置部分)。第二部分是由主时钟(main clock)分频后提供一个统一的外设时钟(U_PCLK),外设时钟再经由各自(USART0~USART2)的波特率时钟发生器,为各自的异步通信提供独立的波特率。
外设时钟的值为:U_PCLK = FRGCLKDIV/(1+MULT/DIV)。三个USART模块共用一个外设时钟,并且在需要时共用一个带小数的波特率发生器。
上面公式中的FRGCLKDIV项由USART时钟分频器寄存器UARTCLKDIV来实现,下面给出的是它全部位结构,其字节地址为0x40048094。
(1)第0到7位(DIV)为USART小数波特率生成器时钟分频器值,值从0到255,分别对应相应的分频值,其中值为0时时钟被禁止。
(2)第8到31位为保留位。
公式中的MULT项由USART小数生成器乘法器值寄存器UARTFRGMULT来实现,下面给出的是它全部位结构,其字节地址为0x400480F4。
(1)第0到7位(MULT)为小数分频器分子,MULT等于设定值。
(2)第8到31位为保留位。
公式中的DIV项由USART小数生成器分频器值寄存器UARTFRGDIV来实现,下面给出的是它全部位结构,其字节地址为0x400480F0。
(1)第0到7位(DIV)为小数分频器分母,DIV等于设定值+1。要使用小数波特率生成器,应当始终设为0xFF。
(2)第8到31位为保留位。
UARTFRGDIV寄存器位于分母上,其默认值为0,表明默认时分频不启用小数部分,如果分频需要启用小数部分,则它的值只能是255(即0xFF)。如果在启用后位于分子的UARTFRGMULT寄存器的值为0(默认值),则小数分频仍为1分频,即不分频,除非UARTFRGMULT的值大于0。综上所述,默认状态下不启用分频的小数部分,若要启用则UARTFRGDIV及UARTFRGMULT两个寄存器的值都不为0。
配置上述三个寄存器,可以得到一个统一的外设时钟U_PCLK。注意,U_PCLK时钟并不区分是哪个USART模块的,它是三个USART模块共用的时钟,如果USART0~USART2三个模块的波特率不一致,则还需要配置各自模块内的USART波特率发生器寄存器BRG,该寄存器的具体位结构参见前面“串口USART(续一)”部分。每个USART模块的波特率为:Baud rate=U_PCLK/(16×(BRGVAL+1))。
下面总结一下计算波特率的步骤:
1、主时钟(main clock)先除以UARTCLKDIV中的分频值,得到分频以后的时钟,如果分频值为1,则分频后的值与主时钟一致。
2、如果启用了分频的小数部分,则把第1步中得到的分频值再乘以小数部分,得到的值即为U_PCLK时钟,小数部分的值按公式 1/(1+UARTFRGMULT/256)进行计算。若未启用小数部分,则第1步中得到的分频值即为U_PCLK时钟。
3、对上面得到的U_PCLK时钟进行16的倍数的再分频,倍数值即为BRG寄存器的值加1(BRGVAL+1),再分频后的时钟值即为最终的波特率。
4、有时无论如何取三个寄存器的值,得到的波特率都不会完全等于预期值,仍会有一定的误差,一般来说只要该误差控制在2%以内,USART的异步通信就可以正常工作了。
另外,在LPC824中,波特率时钟一般是实际波特率的16倍(默认为16倍,可在过采样选择寄存器OSR中进行配置),这种超采样允许将数据采样时间集合到一个通信位的单元中,并可通过从接收数据中取三次采样来降低噪声和实行检测。比如说,在接收到的某一个位上是高电平1,按传统的方式只对该位采样一次,而在LPC824中会采样三次,若三次都为高电平则表明该位是1,若三次采样中有一次是低电平,则表明通信上存在噪声干扰,此时虽然该位仍然是1,但LPC824会在RXDATSTAT、STAT及INTSTAT寄存器中标记一个位(第15位),以供程序进行通信噪声检测。
在前面的示例程序中,要配置波特率为115200,则各寄存器的取值如下:UARTCLKDIV=1, UARTFRGMULT=0,UARTFRGDIV=255(DIV等于设定值+1),BRGVAL=12。计算如下。
主时钟(main clock)为24MHz。
U_PCLK的分频值为:1/(1+0/256)=1,即1分频,则外设时钟U_PCLK的值也为24MHz。
波特率为:Baud rate=24000000/(16×(12+1))=115384,该值最为接近115200,误差仅为0.2%以内。
同理,如果要把波特率改为9600,则各寄存器的取值改为如下:UARTCLKDIV=1, UARTFRGMULT=64,UARTFRGDIV=255,BRGVAL=124。通过这样的配置,可准确的产生出9600的波特率,没有误差。当然,也可以有其他配置,比如:UARTCLKDIV=2, UARTFRGMULT=0,UARTFRGDIV=255,BRGVAL=77。但这个配置存在误差,经过计算,该误差仍控制在0.2%以内。下表给出在24MHz的主时钟下,能产生出一部分精确波特率的配置情况。
在前面的示例程序中,采用了接收中断的方式来实现,在中断服务程序中,由于响应的是USART的NVIC中断,所以需要判断一下具体是什么类型的USART中断,有两种方式,一种是通过读取INTSTAT寄存器来判断,另一种是通过读取STAT寄存器来判断,效果是一样的。此外,在配置CFG寄存器时,一般建议先把该USART禁能,等配置完成后再使能,以避免出错。
该示例程序只是以最简单的方式来验证USART的异步收发功能,在实际的项目应用中,应该结合LPC824中丰富的各个串口配置寄存器,把USART的通信程序做的即高效又健壮,这里就不再进行深入讨论了。
串口USART(续二)的更多相关文章
- STM32串口usart发送数据
主函数请直接关注41行到47行代码!! #include "stm32f10x.h" // 相当于51单片机中的 #include <reg51.h> #include ...
- 基于STM32之UART串口通信协议(二)发送
一.前言 1.简介 在上一篇UART详解中,已经有了关于UART的详细介绍了,也有关于如何使用STM32CubeMX来配置UART的操作了,而在该篇博客,主要会讲解一下如何实现UART串口的发送功能. ...
- 基于STM32F10x的串口(USART)输入输出编程
1 前言 STM32有强大的固件库,绝大部分函数都可以有库里面的函数组合编写.固件库可以到ST官网(www.st.com)上下载,也可以搜索“STM32 固件库 v3.5”下载到固件库.本文章就是基于 ...
- STM32串口中断实例二
int main(void) { uint8_t a=;//LED高低电压控制 /* System Clocks Configuration */ RCC_Configuration(); //系统时 ...
- STM32F072从零配置工程-串口USART配置
也是使用HAL库进行配置,通过STMCube生成代码,可以通过这个简单的配置过程看到STMCube生成代码的一种规范: 从main函数入手观察其外设配置结构: 首先是HAL_Init()进行所有外设的 ...
- 串口(USART)框图的讲解
STM32 的 USART 简介 通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备,可以灵 ...
- STM32串口USART通信总结
一.GPIO设置USART的初始化 /**************************实现函数******************************************** *函数原型: ...
- STM32 串口USART DMA方式发送接收数据
硬件:stm32f103cbt6 软件:STM32F10x_StdPeriph_Lib_V3.5.0 文章目录 头文件 USART3_DR的地址 DMA的通道 DMA的中断 USART接收回调函数 头 ...
- QT串口助手(二):参数配置
作者:zzssdd2 E-mail:zzssdd2@foxmail.com 一.前言 主要实现功能 串口参数的配置:波特率.数据位.停止位.校验位 本机串口设备的查询与添加显示 串口设备的手动更新与打 ...
- STM32串口USART的使用方法和程序
通用同步异步收发器(USART)提供了一种灵活的方法来与使用工业标准NR 异步串行数据格式的外部设备之间进行全双工数据交换. USART利用分数波特率发生器提供宽范围的波特率选择,支持同步单向通信和半 ...
随机推荐
- PHP中的超级变量
超级变量,又名超级全局变量,是PHP内置的变量,这些变量在代码的任意位置都能正常使用 PHP中的超级变量 9种超级变量 $GLOBALS $_SERVER 9种超级变量 目前,PHP提供了9种超级变量 ...
- 如何在mac上配置Apache服务器
如何在mac上配置Apache服务器 1. 打开终端,开启Apache: //开启apache: sudo apachectl start //重启apache: sudo apachectl ...
- lowcodeEngine 组件面板的拖拽功能
设计器和渲染器处在不同的 Frame 渲染器以单独的 iframe 嵌入,xxx-simulator-renderer 通过和 host进行通信来和设计器打交道,比如点击渲染画布任意一个位置,需要能计 ...
- python 爬虫 selenium 与 chromedriver
selenium 安装 pip install selenium chromedriver 下载 https://npm.taobao.org/mirrors/chromedriver?spm ...
- 通过 HDU 2048 来初步理解动态规划
HDU 2048 数塔 问题描述: 题目链接-点我查看题目 给出一个数塔,要求从顶层走到底层,每一步只能从高层走到相邻的低层节点,求经过的结点的数字之和最大是多少? 动态规划的定义 dynam ...
- 12组-Beta冲刺-5/5
一.基本情况 队名:字节不跳动 组长博客:https://www.cnblogs.com/147258369k/p/15609352.html Github链接:https://github.com/ ...
- vuecli创建项目-vue项目目录介绍-es6导入导出语法-小练习登录功能-scoped
目录 vuecli创建项目-vue项目目录介绍-es6导入导出语法-小练习登录功能-scoped 今日内容概要 今日内容详细 1 vue-ci创建项目 2 vue项目目录介绍 3 es6导入导出语法 ...
- 如何使用使用Mysql中的慢查。
在MySQL中可以使用慢查找出运行速度慢的SQL语句. 1.在MySQL命令行中查看慢查: show variables like '%query%' 如图 "ON" 表示慢查 ...
- Git客户端部署使用-生成ssh密钥2
1. 设置用户名 其中双引号中的 XXX 是用户名,记得替换成自己的用户名,需要注意的是这里的用户名是git服务器所使用的名称,一般公司用的都是员工名称的全拼. # 在git窗口中输入命令行: git ...
- vue2的响应式原理
响应式的话,主要指的是这个状态改变以后,视图要去主动更新 这个过程,vue是通过两个步骤来实现的 1 数据的劫持 数据劫持也叫做数据拦截,通过Object.defineProperty来把对象中的每一 ...