
1.晶振在单片机中的作用 数字电路都是按节拍来进行处理的,而晶振就是提供这个节拍的,如果没有了晶振,也就没有了节拍,那也就不能处理任何数据了,晶振就像交通灯的时间计数一样,如果时间停止了,交通灯信号也不切换了,就僵死在那里。3 X. G/ N0 T) a. M : h% Y/ B/ X/ H9 r; r% [9 [. E 通常由石英晶体振荡器和与非门组成的正反馈振荡电路组成,其输出送至环形脉冲发生器,为微控制器提供时钟源6 U) F+ g) r/ G1 F6 r/ Q! l! p( ? 单片机内部是不会放晶振的,只有RC振荡器(在振荡电路中的频率选择部分可以只用电阻和电容构成。 这种只用电阻和电容构成的振荡器称为RC振荡器 ),如果对频率要求不高,一般是优先选用内部振荡,省去了晶振的钱。RC振荡器能够快速启动,成本也比较低, 如果你要省电,用了SLEEP,那你就不能用内部振荡了,内部振荡会停止,内部RC振荡器只是为了降低电路的复杂程度和成本。如果要单片机实现严格的时序操作或者串口通信,就必须使用外部晶振,因为晶振受到的干扰小。3 }, d+ o: d" Q2 h1 h& R # N/ `+ x1 [2 y: U 2.UART简介1 u' s, Q5 N5 `8 k UART即异步收发传输器,是一种串行数据总线,全双工通信,常称为串口,主要用于通信。# A5 I9 _( {$ X: t% G7 s ; {2 g2 l/ I. K! F1 k+ [% A 3.通信协议(原理)引用:9 M/ T- \) a! I- Y 异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。 数据传送速率用波特率来表示,即每秒钟传送的二进制位数。例如数据传送速率为120字符/秒,而每一个字符为10位(1个起始位,7个数据位,1个校验位,1个结束位),则其传送的波特率为10×120=1200字符/秒=1200波特。# @, J5 K1 F4 r! x 数据通信格式如下图:% G/ C& s- q4 u8 l 0 Y; A# R: U; g5 Z ![]() 0 p+ @& C) s( q' m; O; S) \ 其中各位的意义如下:$ u' e& V! F' | 起始位:先发出一个逻辑”0”信号,表示传输字符的开始。 ~: m3 k8 ] h& x) {- p 数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输' P" B$ K" ^3 X$ c 校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验) 停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。 注:异步通信是按字符传输的,接收设备在收到起始信号之后只要在一个字符的传输时间内能和发送设备保持同步就能正确接收。下一个字符起始位的到来又使同步重新校准(依靠检测起始位来实现发送与接收方的时钟自同步的)! q2 i5 U H; p: i: V6 O (以下摘自百度百科) 数据发送的思想是,当启动字节发送时,通过TxD先发起始位,然后发数据位和奇偶数校验位,最后再发停止位,发送过程由发送状态机控制,每次中断只发送1个位,经过若干个定时中断完成1个字节帧的发送。# [, A( ^4 F7 y2 j, e% J 数据接收的思想是,当不在字节帧接收过程时,每次定时中断以3倍的波特率监视RxD的状态,当其连续3次采样电平依次为1、0、0时,就认为检测到了起始位,则开始启动一次字节帧接收,字节帧接收过程由接收状态机控制,每次中断只接收1个位,经过若干个定时中断完成1个字节帧的接收。4 [, x4 b/ x! T& D, m3 L" w 发送时,数据被写入发送FIFO。如果UART 被使能,则会按照预先设置好的参数(波特率、数据位 、停止位、校验位等)开始发送数据,一直到发送FIFO 中没有数据。一旦向发送FIFO 写数据(如果FIFO 未空),UART 的忙标志位BUSY 就有效,并且在发送数据期间一直保持有效。BUSY 位仅在发送FIFO 为空,且已从移位寄存器 发送最后一个字符,包括停止位时才变无效。即 UART 不再使能,它也可以指示忙状态。BUSY 位的相关库函数是UARTBusy( ) 收发FIFO 主要是为了解决UART 收发中断过于频繁而导致CPU 效率不高的问题而引入的。在进行 UART 通信时,中断方式比轮询方式要简便且效率高。但是,如果没有收发 FIFO,则每收发一个数据都要中断处理一次,效率仍然不够高。如果有了收发FIFO,则可以在连续收发若干个数据(可多至14 个)后才产生一次中断然后一并处理,这就大大提高了收发效率。2 C+ o) k5 s7 c% q+ t! s 2 c7 X+ t, P; d. D 4.优缺点(适用范围)2 M! l8 f1 I0 W. O- H0 U # q: i, q1 G9 O4 X" J% O" J& B UART就是两线,一根发送一根接收,可以全双工通信,线数也比较少。数据是异步传输的,对双方的时序要求比较严格,按照标准波特率完成双向通讯,速度慢。串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。对于串口而言,长度可达1200米。 . g7 r+ Y! E6 C* ]4 Y" |( k, _0 W 5.通信实现过程; S( S: C8 i) |0 v* ~. c) H 时钟系统是 CPU 的脉搏,就像人的心跳一样。所以时钟系统的重要性就不言而喻了。 STM32 的时钟系统比较复杂,不像简单的 51 单片机一个系统时钟就可以解决一切。于是有人要问,采用一个系统时钟不是很简单吗?为什么 STM32 要有多个时钟源呢? 因为首先STM32 本身非常复杂,外设非常的多,但是并不是所有外设都需要系统时钟这么高的频率,比如看门狗以及 RTC 只需要几十 k 的时钟即可。同一个电路,时钟越快功耗越大,同时抗电磁干扰能力也会越弱,所以对于较为复杂的 MCU 一般都是采取多时钟源的方法来解决这些问题。 APB2 上面连接的是高速外设包括 UART1、 SPI1、 Timer1、 ADC1、 ADC2、所有普通 IO 口(PA~PE)、第二功能 IO 口等。 $ x* _' e* t! ^& W( W STM32系统架构图如下,) J: I# q; H9 F0 I, L ![]() 1)由图可看出UART1挂载在 APB2 下面的外设,所以第一步要打开APB2的时钟。打开APB2时钟的同时也要打开GPIO时钟,因为UART也是挂在GPIO上的外设。6 h$ L) a K' r4 ?) U, _7 [ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);% r. B$ d. C4 S% n) M & R9 ]" M- X3 K% A7 I+ _3 P 2)根据芯片原理图查看RX与TX引脚,如图所示连线9 H; R7 `( u' e5 N) O, t ![]() 所以要对PA9、PA10的IO口作配置,包括管脚号、输入输出模式、工作频率等。 3)串口复位。 当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。 USART_DeInit(USART1);& n6 w* l" a5 J6 U1 C 4)初始化串口的相关参数$ b5 s) j6 n% E USART_Init(USART1, &UASRT_InitStruct);2 }/ H! N4 m8 m4 l6 T UASRT_InitStruct结构体是串口的波特率、停止位、校验位等相关参数设置。 5)数据的发送接收处理,如果需要中断发送接收处理,则需要配置中断等信息,关于中断后续章节会整理。这里仅贴出部分代码1 }% D9 f& C2 B8 \ ![]() 串口的中断类型有很多种。比如在接收到数据的时候( RXNE 读数据寄存器非空),要产生中断,则如上图所示初始化中断配置。! t: \) p) i V 其他类似还有发送结束中断:USART_ITConfig(USART1, USART_IT_TC, ENABLE);0 [; i. c+ g/ U" R4 h2 _ 8 w5 x: E5 A) p5 Z) ]# h2 l 6)数据发送与接收中断处理。 STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收到收据的时候,也是存在该寄存器内。) c$ f, Y- X* _ 接口函数:USART_ReceiveData(USART1),USART_SendData();" b' R# r1 q5 @" O# ] + d7 c; b" K4 \9 R* U$ I( w RXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将该位清零,也可以向该位写 0,直接清除。: e& C! c5 G4 {$ w TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式: 1)读 USART_SR,写USART_DR。 2)直接向该位写 0。$ j( i& N$ [; v5 O: Z4 x3 { 8 G8 ?3 k5 C" d' ]) e$ l3 Y0 ~, K5 _ 比如RXNE(读数据寄存器非空)以及 TC(发送完成)。例如我们要判断读寄存器是否非空(RXNE),操 作库函数的方法是: USART_GetFlagStatus(USART1, USART_FLAG_RXNE); 我们要判断发送是否完成(TC),操作库函数的方法是: USART_GetFlagStatus(USART1, USART_FLAG_TC);" K z9 x6 u) u" r" g( L) b3 _% y 所以可以在中断处理函数中,判断串口处于那种状态,比如我们使能了串口发送完成中断,那么当中断发生了, 我们便可以在中断处理函数中调用这个函数来判断到底是否是串口发送完成中断,方法是:USART_GetITStatus(USART1, USART_IT_TC)返回值是 SET,说明是串口发送完成中断发生。 然后就可以接收到的数据进行处理,做相应的业务逻辑了。! P& i( |4 H4 y 4 j8 s. \ J6 d, o: P2 r ; o/ q* K% D& G; o( X! C* t2 t/ I . B( a& o8 u [8 ?% W$ B" W- [4 c3 a0 `6 ~ , f& Z/ u5 H5 v% q2 T! | |
【经验分享】STM32F1 GPIO工作原理
【经验分享】STM32F0xx_DMA收发USART数据配置详细过程
【经验分享】STM32F1和STM32F4 区别
【经验分享】STM32F1系列之常用外设说明
【经验分享】STM32介绍
【经验分享】STM32F1x系列——Flash 模拟 EEPROM
【经验分享】STM32F1在MDK下新建标准库函数工程
【经验分享】stm32f1的存储器与复位
【经验分享】STM32F10X-架构
【经验分享】stm32F1 us延时函数