介绍
8 d# A* k$ N) \# l; J0 {串口(UART通用异步收发器,TTL)通讯是一种设备间的串行全双工通讯方式。由于UART是异步传输,没有传输同步时钟,为了保证数据的正确性,UART采用16倍数据波特率的时钟进行采样。
/ }& }) O+ M: _数据格式 起始位:先发出一个逻辑”0”的信号,表示传输数据的开始。 数据位:可以选择的值有5,6,7,8这四个值,可以传输这么多个值为0或者1的bit位。这个参数最好为8,因为如果此值为其他的值时当你传输的是ASCII值时一般解析肯定会出问题。理由很简单,一个ASCII字符值为8位,如果一帧的数据位为7,那么还有一位就是不确定的值,这样就会出错。 校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。 停止位:它是一帧数据的结束标志。可以是1bit、1.5bit、2bit的空闲电平。 空闲位:没有数据传输时线路上的电平状态。为逻辑1。 UART传输数据顺序 刚开始传输一个起始位,接着传输数据位,接着传输校验位(可不需要此位),最后传输停止位。这样一帧的数据就传输完了。接下来接着像这样一直传送。 7 m7 i w$ F' a3 e; x" P
发送数据过程 空闲状态,线路处于高电平;当收到发送指令后,拉低线路的一个数据位的时间T,接着数据按低位到高位依次发送,数据发送完毕后,接着发送奇偶校验位和停止位,一帧数据发送完成。
% J& l" u' [6 ~8 {5 K; y/ o% w数据接收过程 空闲状态,线路处于高电平;当检测到线路的下降沿(高电平变为低电平)时说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕后,接着接收并比较奇偶校验位是否正确,如果正确则通知后续设备接收数据或存入缓冲。
# ~0 [2 `) r5 W硬件连接 UART的硬件连接比较简单,只需要两个设备的TXD和RXD相互反接,再将GND相连即可。
5 Y% ?9 {1 W* f8 G# O2 L3 d) F) ^& R, d) p/ k e# F0 d
. n4 w/ a7 b9 A( I4 G" c+ O. K1 }+ P6 T6 y6 ?# I/ q( p
软件实现
) K) J4 @" \, w9 }' LUSART初始化结构体详解 标准库函数对每个外设都建立了一个初始化结构体,例如USART_InitTypeDef,结构体成员用于设置外设工作参数,并由外设初始化配置函数,比如USART_Init()调用,这些设定参数将会设置外设相应的寄存器。初始化结构体和初始化库函数配合使用是标准库精髓所在。初始化结构体定义在stm32f10x_usart.h文件中,初始化库函数定义在stm32f10x_usart.c。 ; r, |8 c$ y# d4 P$ A1 G, c
USART初始化结构体 - <font face="Tahoma"><font size="3"><font color="#000000">typedef struct{1 Z" v+ v) x4 r* K- \! R
- uint32_t USART_BaudRate; //波特率
/ h p1 i; H7 E2 [& a' v - uint16_t USART_WordLength; //字长0 P2 ]+ W5 @; b* o' C: a
- uint16_t USART_StopBits; //停止位
; B3 b, ~) \( r% p8 O - uint16_t USART_Parity; //校验位 . `; Z) o2 h& ?2 v
- uint16_t USART_Mode; //USART模式 </font></font></font><div><font face="Tahoma"><font size="3"><font color="#000000"> uint16_t USART_HardwareFlowControl;//硬件流控制 } USART_InitTypeDef;</font></font></font></div>
复制代码 ( W6 Q( I ]( w+ C8 m
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:硬件流控制选择,只有在硬件控制模式下才有效。
5 ]" `$ E7 W: |$ F/ J, \
串口通信实例 学习完串口的相关知识,肯定需要一个例子来实现。下面我们来制作一个简单的串口发送项目。 其中配置串口函数,一般分为中断和非中断两种配置方法,我会分别进行介绍。
7 j/ M$ x2 p9 u c7 n0 q非中断实现 非中断配置串口函数,只需要编写Usart1_Configuration函数即可。 - void Usart1_Configuration(u32 BAUD){. x. \, h4 d3 q o
- GPIO_InitTypeDef GPIO_InitStructure;
^) ^, @( u* t5 a" f) l - USART_InitTypeDef USART_InitStructure;# `/ I9 i7 L4 J* A
- //第一步:初始化时钟
1 H1 c E7 ^0 \$ u - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
( n) K) ?1 w; U! l; x& y5 N - //第二步:初始化GPIO
; q& N1 Z6 \8 k# Z/ y6 d - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
! r' K6 n; y0 x" E, R r; h" ^2 k - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;7 Q2 e1 Z2 _% ]+ `9 ?+ a7 p9 m
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出. q6 g5 X/ c. F; x9 N) s
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.98 g2 a+ S0 x7 n' K9 b2 D2 ^7 g
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
, H. z8 Y( Y1 A- W. v6 y: Y, R - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
8 t5 u/ ^' B) [' g9 v5 U4 G - GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
# X8 e# k8 D+ e0 v S6 } - //第三步:初始化串口参数* K! d1 P/ J' \5 i5 t7 R
- USART_InitStructure.USART_BaudRate = BAUD;//串口波特率* z# K' e0 R; h9 j0 o: J
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式7 w- i3 }/ ^) D. J4 a# i+ B& b
- USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
* k1 g: J6 K% }6 a - USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位% s6 r$ Z2 m% y! D) H8 `
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制- \; s- x$ A' H. j, S# X1 \
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式1 X; [& @. I4 D! v2 I1 U$ h
- USART_Init(USART1, &USART_InitStructure); //初始化串口1
. ?/ ~2 e5 u2 c* q4 ?0 T( K - //第四步:使能串口$ w* X6 R7 m: z% P. K$ [& j, w
- USART_Cmd(USART1, ENABLE); //使能串口12 l) r/ z. Z6 L8 ]
- USART_ClearFlag(USART1, USART_FLAG_TC); //清空发送完成标志}
复制代码中断实现 中断配置串口函数,除了编写Usart1_Configuration函数还需要配置中断。
' I# l4 F) y! P1 I' }3 @串口1中断配置
5 ~, S( ~; Q1 c8 E2 ?- q
- static void Usart1_NVIC_Configuration(void){
5 }; r0 ]8 n5 _4 I/ [ e - NVIC_InitTypeDef NVIC_InitStructure;
. {5 J+ L+ p) w7 T3 g7 `6 j; t - NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
7 g$ A; K: Q% Y1 X7 Q7 _3 ` - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级- Y2 a: l6 P0 t4 e3 @9 a0 H
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级, R5 a" A) A4 M% A! [0 t7 V' D; X- Q& E
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
" k7 |. X1 T1 j; x - NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器}
复制代码 / u: ]! u8 I. U+ e: \" y/ v
串口1配置函数 ! D& y2 `' {& y; }4 R A7 ~
- <font face="Tahoma"><font size="3"><font color="#000000">void Usart1_Configuration(u32 BAUD){
$ S+ Z2 N3 {) O( d, d b! \ - GPIO_InitTypeDef GPIO_InitStructure;7 h! q* V! l1 l' N$ X& J
- USART_InitTypeDef USART_InitStructure;
1 B( q: W3 c/ L) o" A! J- J* } - : o9 y% p9 M( g# J- X
- //第一步:初始化时钟# `3 A- }2 a8 H" }+ Z, e7 X
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);. C; G! l2 O% I" K5 l2 x" q3 u
- M, m& G: D' x ]. l' v+ u% M% P- //第二步:初始化GPIO
: j0 o$ J% Z ?. k, S1 G - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9% \/ T5 p' k3 I% I9 q# Z) A( F2 u: @
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
, P7 `# i2 ` O& ?/ ~) \ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出- Z0 e/ d2 @' K1 p
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
# B; L$ t% ?# T2 Y. t3 @4 K
2 M5 x2 d, [* M* ?& Y! X) U, B- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
+ G. O- ?" x2 i" D- x2 C% J - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入. F' l4 Z. V+ c
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10) e% {* A& |' m
! W8 ^: Y3 t" X R! Q& f- //第三步:初始化串口参数
* I: H) @ t9 [* M+ n' g6 A$ u - USART_InitStructure.USART_BaudRate = BAUD;//串口波特率
) H: m( h% L2 k2 J5 f - USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
; S$ A$ r; i# F; h' A3 e - USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
4 D7 b+ |2 e$ R1 c( F0 U$ M - USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
. S$ _, ^7 t8 S3 N - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
2 F/ \6 O! V4 w& ]- H7 q0 X - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式. r2 T9 k f% r& U- d9 h
- USART_Init(USART1, &USART_InitStructure); //初始化串口1
8 U% j/ \0 q( K$ y# O3 O I% T" d( O
$ b9 P% K: d7 y, |$ d% N. ~% q& k- //第四步:开启相关中断
# u/ P6 [6 L0 }9 U7 w; T - USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
0 p" y# _% u% J9 h' V% V4 ~; ^ - USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断3 R: u8 O' ^ g' M2 e [1 m
+ C: z. o3 r% M* e1 V; C: F- //第五步:配置中断优先级4 g) y, Y" z7 @& F5 D
- Usart1_NVIC_Configuration();6 v2 K3 O7 u$ S! y: Y6 m
- + c# F$ M( K0 z! \3 j
- //第六步:使能串口
, \$ g+ H, i _) [5 r. ~; J - USART_Cmd(USART1, ENABLE); //使能串口10 S. f3 @4 |5 S
- </font></font></font><div align="left"><font face="Tahoma"><font size="3"><font color="#000000"> USART_ClearFlag(USART1, USART_FLAG_TC); //清空发送完成标志}</font></font></font></div>
复制代码
4 l. P9 i, p5 H1 D& f发送数据 串口1发送一个字节
4 p* K+ \( B( a; C
- void Usart1_SendByte(u8 val){
# F4 _; K; J4 v! q' q - USART_SendData(USART1, val);
/ ~; e9 X: z/ Q/ |! U. J9 V2 U$ i - while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送完成}
复制代码
0 J2 e8 k7 i2 B5 y7 a$ c8 P串口1发送一个数据包 - void Usart1_SendBuf(u8 *buf,u8 len){
+ \/ O0 t3 k8 G. i+ I( k- m - % N1 [8 S2 z# J C: N2 x
- while(len--) Usart1_SendByte(*buf++);}
复制代码 4 S7 P; @/ M) h) r9 V6 A' P
) m; X0 [$ ^' \* w! }# R$ F
串口1发送一个字符串
& b% S j8 x' i5 m) l
- void Usart1_SendString(char *str){: |9 U8 {. l9 K/ W, {+ L/ r
- while(*str) Usart1_SendByte(*str++);}
复制代码
5 Z% P3 N9 b6 e( E使用 我们使用的时候,只需要先初始化串口1配置函数Usart1_Configuration(选择自己想要设定的波特率); 之后调用发送函数Usart1_SendString(“发送的内容”); 即可。 - int main(void){ / s' e1 q" h1 b4 S% `# u
- Usart1_Configuration(115200);
7 k( ?: Z& G# S/ a, r - while(1){1 K4 b0 |4 i/ N3 Y$ N8 O/ l
- …… Usart1_SendString(" usart1 is ok!\r\n");
8 L6 E( i$ X) |% }" ~# A& X - }}
复制代码
5 L2 I7 {. n/ s5 K- J: O9 @0 k. {6 Y6 G- ]! `: H0 z7 {; p2 r% W
转载自: 跋扈洋& ]/ q" V+ k# N
2 P1 g0 Y% w/ X" ^
) X& v' q/ ?% t' S5 \# |4 h! A |