介绍
9 [: W8 r1 N D+ }* X# L8 R3 U9 _串口(UART通用异步收发器,TTL)通讯是一种设备间的串行全双工通讯方式。由于UART是异步传输,没有传输同步时钟,为了保证数据的正确性,UART采用16倍数据波特率的时钟进行采样。 , L8 }0 [3 T) z% }; {
数据格式 起始位:先发出一个逻辑”0”的信号,表示传输数据的开始。 数据位:可以选择的值有5,6,7,8这四个值,可以传输这么多个值为0或者1的bit位。这个参数最好为8,因为如果此值为其他的值时当你传输的是ASCII值时一般解析肯定会出问题。理由很简单,一个ASCII字符值为8位,如果一帧的数据位为7,那么还有一位就是不确定的值,这样就会出错。 校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。 停止位:它是一帧数据的结束标志。可以是1bit、1.5bit、2bit的空闲电平。 空闲位:没有数据传输时线路上的电平状态。为逻辑1。 ' s. s2 d' y% K$ I4 K5 e- v* H
: r, x' B) A% b: g& `UART传输数据顺序 刚开始传输一个起始位,接着传输数据位,接着传输校验位(可不需要此位),最后传输停止位。这样一帧的数据就传输完了。接下来接着像这样一直传送。
$ [) x8 k" f O' P6 j& Q发送数据过程 空闲状态,线路处于高电平;当收到发送指令后,拉低线路的一个数据位的时间T,接着数据按低位到高位依次发送,数据发送完毕后,接着发送奇偶校验位和停止位,一帧数据发送完成。 $ j- k# Z+ H1 f1 O: N* y
数据接收过程 空闲状态,线路处于高电平;当检测到线路的下降沿(高电平变为低电平)时说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕后,接着接收并比较奇偶校验位是否正确,如果正确则通知后续设备接收数据或存入缓冲。 2 g' p. E: ^" Y, J# b
硬件连接 UART的硬件连接比较简单,只需要两个设备的TXD和RXD相互反接,再将GND相连即可。 : K- P$ j/ y: P: Q0 K
2 g g: _2 j1 M, \" \- n- x! k8 _4 j# Q/ b; R8 u
软件实现+ {& K Y- g3 J M# x+ ]6 N6 y `6 Z4 ?
USART初始化结构体详解 标准库函数对每个外设都建立了一个初始化结构体,例如USART_InitTypeDef,结构体成员用于设置外设工作参数,并由外设初始化配置函数,比如USART_Init()调用,这些设定参数将会设置外设相应的寄存器。初始化结构体和初始化库函数配合使用是标准库精髓所在。初始化结构体定义在stm32f10x_usart.h文件中,初始化库函数定义在stm32f10x_usart.c。 " M7 f/ n1 f) d
USART初始化结构体 1 B% @! j1 G2 @" n
typedef struct{- `; A' A+ x* u; `& _
uint32_t USART_BaudRate; //波特率 ) _9 Z6 |, T5 q8 \8 N
uint16_t USART_WordLength; //字长: o) b5 w# X: @$ f* }! k* V
uint16_t USART_StopBits; //停止位
( l0 t5 q0 x- R$ d uint16_t USART_Parity; //校验位
6 N2 w3 e) t+ I# c uint16_t USART_Mode; //USART模式 0 I# B- ]+ Y+ b& [) q
uint16_t USART_HardwareFlowControl;//硬件流控制 } USART_InitTypeDef;2 Y1 G0 X+ }1 G6 m6 H
USART_BaudRate:设置波特率,一般设置为2400,9600,115200.标准库会根据设定值计算得到USARTDIV值,从而设置USART_BRR寄存器值。 USART_WordLength:数据帧字长,可选8位或9位。它设置USART_CR1寄存器的M位的值。如果没有使能奇偶校验控制,一般设置8数据位。 USART_StopBits; 停止位设置,可选0.5个,1个,1.5个,2个停止位,它设定USART_CR2寄存器的STOP【1:0】位的值,一般选择1个停止位。 USART_StopBits:奇偶校验控制选择,可选USART_StopBits_No(无校验)、USART_StopBits_Even(偶校验)以及USART_StopBits_Odd(奇校验),它设定USART_CR1寄存器的PCE位和PS位的值。 USART_Mode:USART模式选择,有USART_Mode_Rx和USART_Mode_Tx,允许使用逻辑或运算选择两个,它设定USART_CR1寄存器的RE位和TX位。 USART_HardwareFlowControl:硬件流控制选择,只有在硬件控制模式下才有效。 , G0 L h. m9 D* O8 b4 x
6 G& x) x& G" L6 O T3 N
串口通信实例 学习完串口的相关知识,肯定需要一个例子来实现。下面我们来制作一个简单的串口发送项目。 其中配置串口函数,一般分为中断和非中断两种配置方法,我会分别进行介绍。 $ m' H% W& c7 |6 [9 D
+ Q9 `& R" J% v3 {
非中断实现 非中断配置串口函数,只需要编写Usart1_Configuration函数即可。 - void Usart1_Configuration(u32 BAUD){. Z- e; J& B7 a& n3 p0 s) W
- GPIO_InitTypeDef GPIO_InitStructure;
0 T$ e0 i: m8 K# x% V - USART_InitTypeDef USART_InitStructure;
7 w9 N% j# e i: m' J - //第一步:初始化时钟) A( `* Y* h r! ]. B
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
a8 o1 Y+ q- H& w - //第二步:初始化GPIO
6 j# g) y* i1 C6 j - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9% k5 R8 V h9 Z% t/ D1 q' B
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;. @6 C0 Z! l( h% ~, K8 i0 I
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出, Q/ H7 ~ F) _4 f& I, Y# R
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9" B& Y* ~( d* ~" u& n7 h
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
0 E- V$ `' G" d8 {$ c8 \; x3 P+ o - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
- X: R3 |4 O. t' Y, f. |- \. a! K - GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
8 v& h+ c* t% N- _) D - //第三步:初始化串口参数6 K/ B% y- w5 l# e+ [3 d# h' W* x" `% ?
- USART_InitStructure.USART_BaudRate = BAUD;//串口波特率
3 A/ g+ Z: h* A$ R# ^5 v5 _$ c - USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
9 b) O) a& c! D7 r+ T* @ T - USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
: k6 r' N/ ^4 c0 \) C - USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位, w' K) K6 ^" D* Z; Q
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制$ _/ f$ _. h% I2 z- N1 c Y
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式+ i( E7 g2 V6 b* ^" Z
- USART_Init(USART1, &USART_InitStructure); //初始化串口1
2 d! W( P1 k: c; x7 o - //第四步:使能串口
3 u4 g# ]$ q. U6 L) O* S - USART_Cmd(USART1, ENABLE); //使能串口1
+ s2 s- g- r6 L/ A% X, T- q - USART_ClearFlag(USART1, USART_FLAG_TC); //清空发送完成标志}
复制代码 % a4 ^# r3 } i3 o
中断实现 中断配置串口函数,除了编写Usart1_Configuration函数还需要配置中断。 串口1中断配置 0 r# y' F# @- y2 U
- static void Usart1_NVIC_Configuration(void){+ V' O* ?- v% |$ d6 p! A2 h
- NVIC_InitTypeDef NVIC_InitStructure;
" c6 L6 @* Q) E- s - NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;- J7 x5 d1 r( x" L; }# |, y' S7 P9 k
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级
! m p# |' ~( H: G. R* A - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级
7 c* z* Y" V; G0 A1 e - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
. ?, n; Y- e9 @! l/ y6 I1 u - NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器}
复制代码 2.串口1配置函数
6 L4 x' x% S0 j/ @4 P1 e- void Usart1_Configuration(u32 BAUD){% X$ m; t# T; f) l6 B8 c
- GPIO_InitTypeDef GPIO_InitStructure;1 M4 C# J& h. U4 R3 v% S H
- USART_InitTypeDef USART_InitStructure;
9 M h% T; v' Q; j! ^- O3 o: E
' Q; z2 B8 M+ o9 K- //第一步:初始化时钟8 Q& A4 O& C5 T! K
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);1 k: Y0 S; E5 @" d/ _6 b
7 A O4 W4 {9 ^; B- //第二步:初始化GPIO
* p/ B! h; v! W9 p: E: p6 F - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9. \# \! F% |5 E+ Y( \
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
. A c" ^# E5 e9 a4 a - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
) s+ V3 u* E, Y1 |4 m" d - GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9/ b4 w) [; |3 d8 @. ~& e
- 2 o D/ C7 N8 E) m H. Q9 L. M
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10: \2 t3 I2 G& T! X
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入& S" O: T# N0 X) O: f( y' i# Y
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
; h- m0 U# c/ B+ h - # Y' a c$ N! C7 [- a$ B
- //第三步:初始化串口参数
' v2 `- h6 ^4 _# y z0 m - USART_InitStructure.USART_BaudRate = BAUD;//串口波特率/ J! e N) ?- U6 q
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
3 _3 z. N4 g( M& e# Y - USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位& ^" R5 ~6 v. P( P7 p; h; l
- USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位2 l& j% y4 ^+ n9 l
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
, [& A5 B7 Y: q% A - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
9 ^* l( f3 ^: L! a3 v t* `. f( { - USART_Init(USART1, &USART_InitStructure); //初始化串口1# v, C7 M. _/ o* w/ m; O9 O3 @5 K+ e
- 2 S8 f) D6 g X$ |1 y5 a9 V
- //第四步:开启相关中断9 b. }8 b [# }! z( n
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
% J- |' t/ E- C( @ S - USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断
$ S9 U' @) {& p( {4 T
0 ~2 f* e) A. y. S& Y4 O- //第五步:配置中断优先级" T0 l6 [8 O( {$ _( v; ^
- Usart1_NVIC_Configuration();" q% Q% F+ y5 S. ?$ Z8 v: C3 H
/ m' |. r8 ` B- //第六步:使能串口) ^6 K9 R) `* a2 B
- USART_Cmd(USART1, ENABLE); //使能串口1
y1 i$ I _ ~( o# v3 Z - USART_ClearFlag(USART1, USART_FLAG_TC); //清空发送完成标志}
复制代码
: d3 l3 O+ T0 s/ Y, ?发送数据 串口1发送一个字节 8 V; y' F0 i% G: ^( n
- void Usart1_SendByte(u8 val){; G! K* M3 V" A; D' p2 x
- USART_SendData(USART1, val);. ~" m- j. [+ H' N
- while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送完成}
复制代码 $ x$ ^ k, C' \1 y& \- X
7 M" N' g/ g0 `# A2.串口1发送一个数据包
0 A6 c: D0 {# [: _4 V- void Usart1_SendBuf(u8 *buf,u8 len){3 \* u' S2 s9 M; I! E: o
- while(len--) Usart1_SendByte(*buf++);}
复制代码
! n. X* |) v7 j9 V; P q0 @
+ x. T' p) Z E$ d: a- j; W5 |0 S3.串口1发送一个字符串
J; k- _7 Z0 l1 i' t- void Usart1_SendString(char *str){4 V0 j G6 c$ C, y
- while(*str) Usart1_SendByte(*str++);}
复制代码 0 r+ K3 ^3 t8 b K! Q5 [
使用 我们使用的时候,只需要先初始化串口1配置函数Usart1_Configuration(选择自己想要设定的波特率); 之后调用发送函数Usart1_SendString(“发送的内容”); 即可。 - <font size="3"><font face="Tahoma"><font color="#000000">int main(void){
# D7 R7 o! Q; Z0 h; O( s2 f - Usart1_Configuration(115200);! `# a9 Y/ j2 I9 ^
- while(1){
9 c+ e4 K( p& n: ^4 s - …… Usart1_SendString(" usart1 is ok!\r\n");
) L; } h7 l+ W - }}</font></font></font> I- v2 ^; N6 ^0 v) M' u% D! X0 L9 j
复制代码 * w5 j9 q& \% i5 i0 t& Q! M' y2 ]
转载自: 跋扈洋
; R' S4 ^- y+ K9 L" M4 O |