小米6有电脑怎么局部截屏图功能吗 现在截屏都能智能操作了

第20章 &&&& USART&串口通讯
全套集视频教程和页教程请到秉火论坛下载:
野火视频教程优酷观看网址:
本章参考资料:《中文参考手册》章节。
学习本章时,配合《中文参考手册》章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。
特别说明,本书内容是以系列控制器资源讲解。
20.1 串口通讯协议简介
串口通讯是一种设备间非常常用的串行通讯方式,因为它简单便捷,大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息。
在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和片上外设;标准库则是在寄存器与用户代码之间的软件层。对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。简单来说物理层规定我们用嘴巴还是用肢体来交流,协议层则规定我们用中文还是英文来交流。
下面我们分别对串口通讯协议的物理层及协议层进行讲解。
20.1.1 物理层
串口通讯的物理层有很多标准及变种,我们主要讲解标准,标准主要规定了信号的用途、通讯接口以及信号的电平标准。
使用标准的串口设备间常见的通讯结构见图。
图 201 串口通讯结构图
在上面的通讯方式中,两个通讯设备的"接口"之间通过串口信号线建立起连接,串口信号线中使用"标准"传输数据信号。由于电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个"电平转换芯片"转换成控制器能识别的"校准"的电平信号,才能实现通讯。
1.&&&&电平标准&&&&
根据通讯使用的电平标准不同,串口通讯可分为标准及标准,见表。
表 201 TTL电平标准与RS232电平标准
电平标准发送端
我们知道常见的电子电路中常使用的电平标准,理想状态下,使用表示二进制逻辑,使用表示逻辑;而为了增加串口通讯的远距离传输及抗干扰能力,它使用表示逻辑,表示逻辑。使用与电平校准表示同一个信号时的对比见图。
图 202 RS-232与TTL电平标准下表示同一个信号
因为控制器一般使用TTL电平标准,所以常常会使用MA3232芯片对TTL及RS-232电平的信号进行互相转换。
2.&&&&RS-232信号线
在最初的应用中,RS-232串口标准常用于计算机、路由与调制调解器(MODEN,俗称"猫")之间的通讯 ,在这种通讯系统中,设备被分为数据终端设备DTE(计算机、路由)和数据通讯设备DCE(调制调解器)。我们以这种通讯模型讲解它们的信号线连接方式及各个信号线的作用。
在旧式的台式计算机中一般会有RS-232标准的COM口(也称DB9接口),见图 203。
图 203 电脑主板上的COM口及串口线
其中接线口以针式引出信号线的称为公头,以孔式引出信号线的称为母头。在计算机中一般引出公头接口,而在调制调解器设备中引出的一般为母头,使用上图中的串口线即可把它与计算机连接起来。通讯时,串口线中传输的信号就是使用前面讲解的RS-232标准调制的。
在这种应用场合下,DB9接口中的公头及母头的各个引脚的标准信号线接法见图 204及表 202。
图 204 DB9标准的公头及母头接法
表 202 DB9信号线说明(公头,为方便理解,可把DTE理解为计算机,DCE理解为调制调解器)
,数据载波检测,用于告知对方,本机是否收到对方的载波信号
,数据接收信号,即输入。
,数据发送信号,即输出。两个设备之间的与应交叉相连
数据终端就绪
,数据终端就绪,用于向对方告知本机是否已准备好
地线,两个通讯设备之间的地电位可能不一样,这会影响收发双方的电平信号,所以两个串口设备之间必须要使用地线连接,即共地。
数据设备就绪
,数据发送就绪,用于告知对方本机是否处于待命状态
,请求发送,请求本设备向端发送数据
,允许发送,回应对方的发送请求,告知对方是否可以发送数据
,响铃指示,表示端与线路已接通
上表中的是计算机端的公头标准接法,由于两个通讯设备之间的收发信号与应交叉相连,所以调制调解器端的母头的收发信号接法一般与公头的相反,两个设备之间连接时,只要使用"直通型"的串口线连接起来即可,见图。
图 205 计算机与调制调解器的信号线连接
串口线中的、、、及信号,使用逻辑表示信号有效,逻辑表示信号无效。例如,当计算机端控制信号线表示为逻辑时,它是为了告知远端的调制调解器,本机已准备好接收数据,则表示还没准备就绪。
在目前的其它工业控制使用的串口通讯中,一般只使用、以及三条信号线,直接传输数据信号。而、、、及信号都被裁剪掉了,如果您在前面被这些信号弄得晕头转向,那就直接忽略它们吧。
20.1.2 协议层
串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备的RXD接口。在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其组成见图 206。
图 206 串口数据包的基本组成
1.&&&&波特率
本章中主要讲解的是串口异步通讯,异步通讯中由于没有时钟信号(如前面讲解的DB9接口中是没有时钟信号的),所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码,图 206中用虚线分开的每一格就是代表一个码元。常见的波特率为、115200等。
2.&&&&通讯的起始和停止信号
串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑0的数据位表示,而数据包的停止信号可由0.5、1、1.5或2个逻辑1的数据位表示,只要双方约定一致即可。
3.&&&&有效数据
在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为5、6、7或8位长。
4.&&&&数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)以及无校验(noparity),它们介绍如下:
?&&&&奇校验要求有效数据和校验位中"1"的个数为奇数,比如一个8位长的有效数据为:,此时总共有4个"1",为达到奇校验效果,校验位为"1",最后传输的数据将是8位的有效数据加上1位的校验位总共9位。
?&&&&偶校验与奇校验要求刚好相反,要求帧数据和校验位中"1"的个数为偶数,比如数据帧:,此时数据帧"1"的个数为4个,所以偶校验位为"0"。
?&&&&0校验是不管有效数据中的内容是什么,校验位总为"0",1校验是校验位总为"1"。
?&&&&在无校验的情况下,数据包中不包含校验位。
20.2 STM32的USART简介
芯片具有多个外设用于串口通讯,它是的缩写,即通用同步异步收发器可以灵活地与外部设备进行全双工数据交换。有别于,它还有具有外设,它是在基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是。
满足外部设备对工业标准异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率,使得它的应用更加广泛。支持同步单向通信和半双工单线通信;还支持局域互连网络、智能卡协议与红外线数据协会规范。
支持使用,可实现高速数据通信,有关具体应用将在章节作具体讲解。
在应用最多莫过于"打印"程序信息,一般在硬件设计时都会预留一个通信接口连接电脑,用于在调试程序是可以把一些调试信息"打印"在电脑端的串口调试助手工具上,从而了解程序运行是否正确、指出运行出错位置等等。
的输出的是电平信号,若需要标准的信号可使用芯片进行转换。
20.3 USART功能框图
的功能框图包含了最核心内容,掌握了功能框图,对就有一个整体的把握,在编程时就思路就非常清晰,见图。
图 207 USART功能框图
1.&&&&①功能引脚
:发送数据输出引脚。
:接收数据输入引脚。
:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。
:请求以发送,表示低电平有效。如果使能流控制,当接收器准备好接收新数据时就会将变成低电平;当接收寄存器已满时,将被设置为高电平。该引脚只适用于硬件流控制。
:清除以发送,表示低电平有效。如果使能流控制,发送器在发送下一帧数据之前会检测引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
:发送器时钟输出引脚。这个引脚仅适用于同步模式。
引脚在芯片具体发布见表。
表 203 STM32F429IGT6芯片的USART引脚
APB2(最高90MHz)
APB1(最高45MHz)
PB10/PD8/PC10
PB11/PD9/PC11
PB12/PD10/PC12
系统控制器有四个和四个,其中和的时钟来源于总线时钟,其最大频率为,其他六个的时钟来源于总线时钟,其最大频率为。
只是异步传输功能,所以没有、和功能引脚。
观察表可发现很多的功能引脚有多个引脚可选,这非常方便硬件设计,只要在程序编程时软件绑定引脚即可。
2.&&&&②数据寄存器
数据寄存器只有低位有效,并且第位数据是否有效要取决于控制寄存器的位设置,当位为时表示位数据字长,当位为表示位数据字长,我们一般使用位数据字长。
包含了已发送的数据或者接收到的数据。实际是包含了两个寄存器,一个专门用于发送的可写,一个专门用于接收的可读。当进行发送操作时,往写入数据会自动存储在内;当进行读取操作时,向读取数据会自动提取数据。
和都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到。
支持传输,可以实现高速数据传输,具体使用将在章节讲解。
3.&&&&③控制器
有专门控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等等。使用之前需要向寄存器的位置使能。发送或者接收数据字长可选位或位,由的位控制。
当寄存器的发送使能位置时,启动数据发送,发送移位寄存器的数据会在引脚输出,如果是同步模式也输出时钟信号。
一个字符帧发送需要三个部分:起始位数据帧停止位。起始位是一个位周期的低电平,位周期就是每一位占用的时间;数据帧就是我们要发送的位或位数据,数据是从最低位开始传输的;停止位是一定时间周期的高电平。
停止位时间长短是可以通过控制寄存器的位控制,可选个、个、个和个停止位。默认使用个停止位。个停止位适用于正常模式、单线模式和调制解调器模式。个和个停止位用于智能卡模式。
当选择位字长,使用个停止位时,具体发送字符时序图见图。
图 208 字符发送时序图
当发送使能位置之后,发送器开始会先发送一个空闲帧一个数据帧长度的高电平,接下来就可以往寄存器写入要发送的数据。在写入最后一个数据后,需要等待状态寄存器的位为,表示数据传输完成,如果寄存器的位置,将产生中断。
在发送数据时,编程的时候有几个比较重要的标志位我们来总结下。
发送寄存器为空,发送单个字节的时候使用
发送完成,发送多个字节数据的时候使用
发送完成中断使能
如果将寄存器的位置,使能接收,使得接收器在线开始搜索起始位。在确定到起始位后就根据线电平状态把数据存放在接收移位寄存器内。接收完成后就把接收移位寄存器数据移到内,并把寄存器的位置,同时如果寄存器的置的话可以产生中断。
在接收数据时,编程的时候有几个比较重要的标志位我们来总结下。
读数据寄存器非空
发送完成中断使能
为得到一个信号真实情况,需要用一个比这个信号频率高的采样信号去检测,称为过采样,这个采样信号的频率大小决定最后得到源信号准确度,一般频率越高得到的准确度越高,但为了得到越高频率采样信号越也困难,运算和功耗等等也会增加,所以一般选择合适就好。
接收器可配置为不同过采样技术,以实现从噪声中提取有效的数据。寄存器的位用来选择不同的采样采样方法,如果位设置为采用倍过采样,即用个采样信号采样一位数据;如果位设置为采用倍过采样,即用个采样信号采样一位数据。
的起始位检测需要用到特定序列。如果在线识别到该特定序列就认为是检测到了起始位。起始位检测对使用倍或倍过采样的序列都是一样的。该特定序列为:,其中表示电平任意,或皆可。
倍过采样速度更快,最高速度可达,为时钟,采样过程见图。使用第、、次脉冲的值决定该位的电平状态。
图 209 8倍过采样过程
倍过采样速度虽然没有倍过采样那么快,但得到的数据更加精准,其最大速度为,采样过程见图。使用第、、次脉冲的值决定该位的电平状态。
图 2010 16倍过采样过程
4.&&&&④小数波特率生成
波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,单位为波特。比特率指单位时间内传输的比特数,单位。对于波特率与比特率相等,以后不区分这两个概念。波特率越大,传输速率越快。
的发送器和接收器使用相同的波特率。计算公式如下:
公式 201 波特率计算
其中,为时钟,参考表;为寄存器的位对应的值,是一个存放在波特率寄存器的一个无符号定点数。其中位定义的整数部分,位定义的小数部分,位只有在位为时有效,否则必须清零。
例如,如果,且,此时值为;那么的小数位;整数位,最终的值为。
如果并且知道值为,那么,最接近的正整数为,所以为;整数,即位。
如果情况类似,只是把计算用到的权值由改为。
波特率的常用值有、、、。下面以实例讲解如何设定寄存器值得到波特率的值。
由表可知和使用总线时钟,最高可达,其他的最高频率为。我们选取作为实例讲解,即。
当我们使用倍过采样时即,为得到的波特率,此时:
解得,可算得,,即应该设置的值为。
在计算时经常出现小数情况,经过我们取舍得到整数,这样会导致最终输出的波特率较目标值略有偏差。下面我们从的值为开始计算得出实际输出的波特率大小。
由的值为,可得,,所以,所以实际波特率为:;这个值跟我们的目标波特率误差为,这么小的误差在正常通信的允许范围内。
倍过采样时计算情况原理是一样的。
5.&&&&校验控制
STM32F4xx系列控制器USART支持奇偶校验。当使用校验位时,串口传输的长度将是8位的数据帧加上1位的校验位总共9位,此时USART_CR1寄存器的M位需要设置为1,即9数据位。将USART_CR1寄存器的PCE位置1就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启动了奇偶校验控制之后,在发送数据帧时会自动添加校验位,接收数据时自动验证校验位。接收数据时如果出现奇偶校验位验证失败,会见USART_SR寄存器的PE位置1,并可以产生奇偶校验中断。
使能了奇偶校验控制后,每个字符帧的格式将变成:起始位+数据帧+校验位+停止位。
6.&&&&中断控制
有多个中断请求事件,具体见表。
表 204 USART中断请求
使能控制位
发送数据寄存器为空
准备好读取接收到的数据
检测到上溢错误
检测到空闲线路
奇偶校验错误
多缓冲通信中的噪声标志、上溢错误和帧错误
USART初始化结构体详解
标准库函数对每个外设都建立了一个初始化结构体,比如,结构体成员用于设置外设工作参数,并由外设初始化配置函数,比如调用,这些设定参数将会设置外设相应的寄存器,达到配置外设工作环境的目的。
初始化结构体和初始化库函数配合使用是标准库精髓所在,理解了初始化结构体每个成员意义基本上就可以对该外设运用自如了。初始化结构体定义在文件中,初始化库函数定义在文件中,编程时我们可以结合这两个文件内注释使用。
USART初始化结构体
uint32_t USART_BaudR
uint16_t USART_WordL
uint16_t USART_StopB
uint16_t USART_P
uint16_t USART_M
// USART模式
uint16_t USART_HardwareFlowC // 硬件流控制
8 } USART_InitTypeD
1)&&&&USART_BaudRate:波特率设置。一般设置为、1。标准库函数会根据设定值计算得到USARTDIV值,见公式 201,并设置USART_BRR寄存器值。
2)&&&&USART_WordLength:数据帧字长,可选8位或9位。它设定USART_CR1寄存器的M位的值。如果没有使能奇偶校验控制,一般使用8数据位;如果使能了奇偶校验则一般设置为9数据位。
3)&&&&USART_StopBits:停止位设置,可选0.5个、1个、1.5个和2个停止位,它设定USART_CR2寄存器的STOP[1:0]位的值,一般我们选择1个停止位。
4)&&&&USART_Parity:奇偶校验控制选择,可选USART_Parity_No(无校验)、USART_Parity_Even(偶校验)以及USART_Parity_Odd(奇校验),它设定USART_CR1寄存器的PCE位和PS位的值。
5)&&&&USART_Mode:USART模式选择,有USART_Mode_Rx和USART_Mode_Tx,允许使用逻辑或运算选择两个,它设定USART_CR1寄存器的RE位和TE位。
6)&&&&USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效,可选有⑴使能RTS、⑵使能CTS、⑶同时使能RTS和CTS、⑷不使能硬件流。
当使用同步模式时需要配置引脚输出脉冲的属性,标准库使用一个时钟初始化结构体来设置,因此该结构体内容也只有在同步模式才需要设置。
USART时钟初始化结构体
uint16_t USART_C
// 时钟使能控制
uint16_t USART_CPOL;
// 时钟极性
uint16_t USART_CPHA;
// 时钟相位
uint16_t USART_LastB
// 最尾位时钟脉冲
6 } USART_ClockInitTypeD
1)&&&&USART_Clock:同步模式下SCLK引脚上时钟输出使能控制,可选禁止时钟输出(USART_Clock_Disable)或开启时钟输出(USART_Clock_Enable);如果使用同步模式发送,一般都需要开启时钟。它设定USART_CR2寄存器的CLKEN位的值。
2)&&&&USART_CPOL:同步模式下SCLK引脚上输出时钟极性设置,可设置在空闲时SCLK引脚为低电平(USART_CPOL_Low)或高电平(USART_CPOL_High)。它设定USART_CR2寄存器的CPOL位的值。
3)&&&&USART_CPHA:同步模式下SCLK引脚上输出时钟相位设置,可设置在时钟第一个变化沿捕获数据(USART_CPHA_1Edge)或在时钟第二个变化沿捕获数据。它设定USART_CR2寄存器的CPHA位的值。USART_CPHA与USART_CPOL配合使用可以获得多种模式时钟关系。
4)&&&&USART_LastBit:选择在发送最后一个数据位的时候时钟脉冲是否在SCLK引脚输出,可以是不输出脉冲(USART_LastBit_Disable)、输出脉冲(USART_LastBit_Enable)。它设定USART_CR2寄存器的LBCL位的值。
USART1接发通信实验
只需两根信号线即可完成双向通信,对硬件要求低,使得很多模块都预留接口来实现与其他模块或者控制器进行数据传输,比如模块,模块、蓝牙模块等等。在硬件设计时,注意还需要一根"共地线"。
我们经常使用来实现控制器与电脑之间的数据传输。这使得我们调试程序非常方便,比如我们可以把一些变量的值、函数的返回值、寄存器标志位等等通过发送到串口调试助手,这样我们可以非常清楚程序的运行状态,当我们正式发布程序时再把这些调试信息去除即可。
我们不仅仅可以将数据发送到串口调试助手,我们还可以在串口调试助手发送数据给控制器,控制器程序根据接收到的数据进行下一步工作。
首先,我们来编写一个程序实现开发板与电脑通信,在开发板上电时通过发送一串字符串给电脑,然后开发板进入中断接收等待状态,如果电脑有发送数据过来,开发板就会产生中断,我们在中断服务函数接收数据,并马上把数据返回发送给电脑。
为利用实现开发板与电脑通信,需要用到一个转的,我们选择芯片来实现这个功能,是一个总线的转接芯片,实现转、转红外或者转打印机接口,我们使用其转功能。具体电路设计见图。
我们将的引脚与的引脚连接,的引脚与的引脚连接。芯片集成在开发板上,其地线已与控制器的连通。
图 2011 USB转串口硬件设计
这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本章配套的工程。我们创建了两个文件:和文件用来存放驱动程序及相关宏定义。
1.&&&&编程要点
1)&&&&使能RX和TX引脚GPIO时钟和USART时钟;
2)&&&&初始化GPIO,并将GPIO复用到USART上;
3)&&&&配置USART参数;
4)&&&&配置中断控制器并使能USART接收中断;
5)&&&&使能USART;
6)&&&&在USART接收中断服务函数实现数据接收和发送。
2.&&&&代码分析
GPIO和USART宏定义
代码清单 201 GPIO和USART宏定义
1 #define DEBUG_USART
2 #define DEBUG_USART_CLK
RCC_APB2Periph_USART1
3 #define DEBUG_USART_BAUDRATE
//串口波特率
5 #define DEBUG_USART_RX_GPIO_PORT
6 #define DEBUG_USART_RX_GPIO_CLK
RCC_AHB1Periph_GPIOA
7 #define DEBUG_USART_RX_PIN
GPIO_Pin_10
8 #define DEBUG_USART_RX_AF
GPIO_AF_USART1
9 #define DEBUG_USART_RX_SOURCE
GPIO_PinSource10
11 #define DEBUG_USART_TX_GPIO_PORT
12 #define DEBUG_USART_TX_GPIO_CLK
RCC_AHB1Periph_GPIOA
13 #define DEBUG_USART_TX_PIN
GPIO_Pin_9
14 #define DEBUG_USART_TX_AF
GPIO_AF_USART1
15 #define DEBUG_USART_TX_SOURCE
GPIO_PinSource9
17 #define DEBUG_USART_IRQHandler
USART1_IRQHandler
18 #define DEBUG_USART_IRQ
USART1_IRQn
使用宏定义方便程序移植和升级,根据图电路,我们选择使用,设定波特率为,一般我们会默认使用""参数,即个数据位、不用校验、一位停止位。查阅表可知的线可对于和引脚,线可对于和引脚,这里我们选择以及引脚。最后定义中断相关参数。
嵌套向量中断控制器NVIC配置
代码清单 202 中断控制器NVIC配置
1 static void NVIC_Configuration(void)
NVIC_InitTypeDef NVIC_InitS
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级为1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级为1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
在中断章节已对嵌套向量中断控制器的工作机制做了详细的讲解,这里我们就直接使用它,配置作为中断源,因为本实验没有使用其他中断,对优先级什么具体要求。
USART初始化配置
代码清单 203 USART初始化配置
1 void Debug_USART_Config(void)
GPIO_InitTypeDef GPIO_InitS
USART_InitTypeDef USART_InitS
/* 使能 USART GPIO 时钟 */
RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK |
DEBUG_USART_TX_GPIO_CLK,
/* 使能 USART 时钟 */
RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
/* GPIO初始化 */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 配置Tx引脚为复用功能
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
/* 配置Rx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
/* 连接 PXx 到 USARTx_Tx*/
GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,
DEBUG_USART_RX_SOURCE,
DEBUG_USART_RX_AF);
连接 PXx 到 USARTx__Rx*/
GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,
DEBUG_USART_TX_SOURCE,
DEBUG_USART_TX_AF);
/* 配置串DEBUG_USART 模式 */
/* 波特率设置:DEBUG_USART_BAUDRATE */
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
/* 字长(数据位+校验位):8 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
/* 停止位:1个停止位 */
USART_InitStructure.USART_StopBits = USART_StopBits_1;
/* 校验位选择:不使用校验 */
USART_InitStructure.USART_Parity = USART_Parity_No;
/* 硬件流控制:不使用硬件流 */
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_N
/* USART模式控制:同时使能接收和发送 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* 完成USART初始化配置 */
USART_Init(DEBUG_USART, &USART_InitStructure);
/* 嵌套向量中断控制器NVIC配置 */
NVIC_Configuration();
/* 使能串口接收中断 */
USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
/* 使能串口 */
USART_Cmd(DEBUG_USART, ENABLE);
使用和结构体定义一个初始化变量以及一个初始化变量,这两个结构体内容我们之前已经有详细讲解。
调用函数开启端口时钟,使用之前必须开启对应端口的时钟。使用函数开启时钟。
使用之前都需要初始化配置它,并且还要添加特殊设置,因为我们使用它作为外设的引脚,一般都有特殊功能。我们在初始化时需要把它的模式设置为复用功能。
每个都可以作为多个外设的特殊功能引脚,比如这个引脚不仅仅可以作为普通的输入输出引脚,还可以作为的线引脚、定时器通道引脚、全速的引脚以及的数据引脚这四个外设的功能引脚,我们只能从中选择一个使用,这时就通过引脚复用功能配置函数实现复用功能引脚的连接。
这时我们可能会想如果程序把用于,此时就没办法使用了,那岂不是不能使用了,实际上情况没有这么糟糕的,查阅表我们可以看到不仅仅只有,还可以是。所以此时我们可以这个引脚来实现通信。那要是也是被其他外设占用了呢?那就没办法了,只能使用其他。
函数接收三个参数,第一个参数为端口,比如;第二个参数是指定要复用的引脚号,比如;第三个参数是选择复用外设,比如。该函数最终操作的是复用功能寄存器和,分高低两个。
接下来,我们配置通信参数并调用初始化函数完成配置。
程序用到接收中断,需要配置,这里调用函数完成配置。配置就可以调用函数使能接收中断。
最后调用函数使能。
代码清单 204 字符发送函数
1 /*****************
发送一个字符 **********************/
2 void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
11 /*****************
发送字符串 **********************/
12 void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
unsigned int k=0;
Usart_SendByte( pUSARTx, *(str + k) );
} while (*(str + k)!='\0');
/* 等待发送完成 */
while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {
函数用来在指定发送一个码值字符,它有两个形参,第一个为,第二个为待发送的字符。它是通过调用库函数来实现的,并且增加了等待发送完成功能。通过使用函数来获取事件标志来实现发送完成功能等待,它接收两个参数,一个是,一个是事件标志。这里我们循环检测发送数据寄存器为空这个标志,当跳出循环时说明发送数据寄存器为空这个事实。
函数用来发送一个字符串,它实际是调用函数发送每个字符,直到遇到空字符才停止发送。最后使用循环检测发送完成的事件标志来实现保证数据发送完成后才退出函数。
USART中断服务函数
代码清单 205 USART中断服务函数
1 void DEBUG_USART_IRQHandler(void)
uint8_t ucT
if (USART_GetITStatus(DEBUG_USART,USART_IT_RXNE)!=RESET) {
ucTemp = USART_ReceiveData( DEBUG_USART );
USART_SendData(DEBUG_USART,ucTemp);
这段代码是存放在文件中的,该文件用来集中存放外设中断服务函数。当我们使能了中断并且中断发生时就会执行中断服务函数。
我们在代码清单使能了接收中断,当有接收到数据就会执行函数。函数与函数类似用来获取标志位状态,但函数是专门用来获取中断事件标志的,并返回该标志位状态。使用语句来判断是否是真的产生数据接收这个中断事件,如果是真的就使用数据读取函数读取数据到指定存储区。然后再调用数据发送函数把数据又发送给源设备。
代码清单 206 主函数
1 int main(void)
/*初始化USART 配置模式为 -N-1,中断接收*/
Debug_USART_Config();
Usart_SendString( DEBUG_USART,"这是一个串口中断接收回显实验\n");
while (1) {
首先我们需要调用函数完成初始化配置,包括配置,配置,接收中断使用等等信息。
接下来就可以调用字符发送函数把数据发送给串口调试助手了。
最后主函数什么都不做,只是静静地等待接收中断的产生,并在中断服务函数把数据回传。
保证开发板相关硬件连接正确,用USB线连接开发板"USB TO UART"接口跟电脑,在电脑端打开串口调试助手,把编译好的程序下载到开发板,此时串口调试助手即可收到开发板发过来的数据。我们在串口调试助手发送区域输入任意字符,点击发送按钮,马上在串口调试助手接收区即可看到相同的字符。
图 2012 实验现象
USART1指令控制RGB彩灯实验
在学习语言时我们经常使用语言标准函数库输入输出函数,比如、、等等。为让开发板也支持这些函数需要把发送和接收函数添加到这些函数的内部函数内。
正如之前所讲,可以在串口调试助手输入指令,让开发板根据这些指令执行一些任务,现在我们编写让程序接收数据,根据数据内容控制彩灯的颜色。
硬件设计同第一个实验。
这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本章配套的工程。我们创建了两个文件:和文件用来存放驱动程序及相关宏定义。
1.&&&&编程要点
1)&&&&初始化配置RGB彩色灯GPIO;
2)&&&&使能RX和TX引脚GPIO时钟和USART时钟;
3)&&&&初始化GPIO,并将GPIO复用到USART上;
4)&&&&配置USART参数;
5)&&&&使能USART;
6)&&&&获取指令输入,根据指令控制RGB彩色灯。
2.&&&&代码分析
GPIO和USART宏定义
代码清单 207 GPIO和USART宏定义
1 //引脚定义
2 /*******************************************************/
3 #define USARTx USART1
5 /* 不同的串口挂载的总线不一样,时钟使能函数也不一样,移植时要注意
* 串口1和6是 RCC_APB2PeriphClockCmd
* 串口2/3/4/5/7是 RCC_APB1PeriphClockCmd
9 #define USARTx_CLK RCC_APB2Periph_USART1
10 #define USARTx_CLOCKCMD RCC_APB2PeriphClockCmd
11 #define USARTx_BAUDRATE 115200 //串口波特率
13 #define USARTx_RX_GPIO_PORT GPIOA
14 #define USARTx_RX_GPIO_CLK RCC_AHB1Periph_GPIOA
15 #define USARTx_RX_PIN GPIO_Pin_10
16 #define USARTx_RX_AF GPIO_AF_USART1
17 #define USARTx_RX_SOURCE GPIO_PinSource10
19 #define USARTx_TX_GPIO_PORT GPIOA
20 #define USARTx_TX_GPIO_CLK RCC_AHB1Periph_GPIOA
21 #define USARTx_TX_PIN GPIO_Pin_9
22 #define USARTx_TX_AF GPIO_AF_USART1
23 #define USARTx_TX_SOURCE GPIO_PinSource9
25 /************************************************************/
使用宏定义方便程序移植和升级,这里我们可以,设定波特率为。
USART初始化配置
代码清单 208 USART初始化配置
1 void USARTx_Config(void)
GPIO_InitTypeDef GPIO_InitS
USART_InitTypeDef USART_InitS
RCC_AHB1PeriphClockCmd(USARTx_RX_GPIO_CLK|USARTx_TX_GPIO_CLK,ENABLE);
/* 使能 USART 时钟 */
USARTx_CLOCKCMD(USARTx_CLK, ENABLE);
/* GPIO初始化 */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 配置Tx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN ;
GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStructure);
/* 配置Rx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = USARTx_RX_PIN;
GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStructure);
/* 连接 PXx 到 USARTx_Tx*/
GPIO_PinAFConfig(USARTx_RX_GPIO_PORT,USARTx_RX_SOURCE,USARTx_RX_AF);
/* 连接 PXx 到 USARTx__Rx*/
GPIO_PinAFConfig(USARTx_TX_GPIO_PORT,USARTx_TX_SOURCE,USARTx_TX_AF);
/* 配置串DEBUG_USART 模式 */
/* 波特率设置:DEBUG_USART_BAUDRATE */
USART_InitStructure.USART_BaudRate = USARTx_BAUDRATE;
/* 字长(数据位+校验位):8 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
/* 停止位:1个停止位 */
USART_InitStructure.USART_StopBits = USART_StopBits_1;
/* 校验位选择:偶校验 */
USART_InitStructure.USART_Parity = USART_Parity_No;
/* 硬件流控制:不使用硬件流 */
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_N
/* USART模式控制:同时使能接收和发送 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* 完成USART初始化配置 */
USART_Init(USARTx, &USART_InitStructure);
/* 使能串口 */
USART_Cmd(USARTx, ENABLE);
使用和结构体定义一个初始化变量以及一个初始化变量,这两个结构体内容我们之前已经有详细讲解。
调用函数开启端口时钟,使用之前必须开启对应端口的时钟。
初始化配置线和线引脚为复用功能,并将指定的连接至,然后配置串口的工作参数为。最后调用函数使能。
重定向prinft和scanf函数
代码清单 209 重定向输入输出函数
1 ///重定向c库函数printf到串口,重定向后可使用printf函数
2 int fputc(int ch, FILE *f)
/* 发送一个字节数据到串口 */
USART_SendData(USARTx, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
return (ch);
13 ///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
14 int fgetc(FILE *f)
/* 等待串口输入数据 */
while (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USARTx);
在语言标准库中,函数是函数内部的一个函数,功能是将字符写入到文件指针所指向文件的当前写指针位置,简单理解就是把字符写入到特定文件中。我们使用函数重新修改函数内容,达到类似"写入"的功能。
函数与函数非常相似,实现字符读取功能。在使用函数时需要注意字符输入格式。
还有一点需要注意的,使用和函数达到重定向语言标准库输入输出函数必须在的工程选项把""勾选上,是缺省库的备选库,它对标准库进行了高度优化使代码更少,占用更少资源。
为使用、函数需要在文件中包含头文件。
输出提示信息
代码清单 2010 输出提示信息
1 static void Show_Message(void)
printf("\r\n这是一个通过串口通信指令控制RGB彩灯实验 \n");
printf("使用 USART1 参数为:%d 8-N-1 \n",USARTx_BAUDRATE);
printf("开发板接到指令后控制RGB彩灯颜色,指令对应如下:\n");
printf(" 指令 ------ 彩灯颜色 \n");
printf(" 1 ------ 红 \n");
printf(" 2 ------ 绿 \n");
printf(" 3 ------ 蓝 \n");
printf(" 4 ------ 黄 \n");
printf(" 5 ------ 紫 \n");
printf(" 6 ------ 青 \n");
printf(" 7 ------ 白 \n");
printf(" 8 ------ 灭 \n");
函数全部是调用函数,"打印"实验操作信息到串口调试助手。
代码清单 2011 主函数
1 int main(void)
/* 初始化RGB彩灯 */
LED_GPIO_Config();
/* 初始化USART 配置模式为 -N-1 */
USARTx_Config();
/* 打印指令输入提示信息 */
Show_Message();
/* 获取字符指令 */
ch=getchar();
printf("接收到字符:%c\n",ch);
/* 根据字符指令控制RGB彩灯颜色 */
switch (ch)
LED_GREEN;
LED_YELLOW;
LED_PURPLE;
LED_WHITE;
LED_RGBOFF;
/* 如果不是指定指令字符,打印提示信息 */
Show_Message();
首先我们定义一个字符变量来存放接收到的字符。
接下来调用函数完成彩色初始化配置,该函数定义在文件内。
调用函完成初始化配置。
函数使用函数打印实验指令说明信息。
函数用于等待获取一个字符,并返回字符。我们使用变量保持返回的字符,接下来判断内容执行对应的程序了。
我们使用语句判断变量内容,并执行对应的功能程序。
20.6.3 下载验证
保证开发板相关硬件连接正确,用线连接开发板""接口跟电脑,在电脑端打开串口调试助手,把编译好的程序下载到开发板,此时串口调试助手即可收到开发板发过来的数据。我们在串口调试助手发送区域输入一个特定字符,点击发送按钮,彩色灯状态随之改变。
20.7 每课一问
1、串口1实验中发送的数据都是8位的,如果要发送的数据是16位的话,怎么办,程序应该怎么修改?
1 /***************** 发送一个16位数 **********************/
2 void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch&0XFF00)&&8;
/* 取出低八位 */
temp_l = ch&0XFF;
/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
2、改写USART1指令控制RGB彩灯实验程序,把串口1换成串口2。
阅读(...) 评论()

我要回帖

更多关于 电脑如何局部截屏 的文章

 

随机推荐