通过串口与上位机通信是经常用到的调试方法。! u! u) r! T: g% H
6 y3 \8 ]# g$ ? ?; L* j
STM32上外设USART引脚配置
) a. ^! B5 _0 G* t. A3 GTX(默认PA9):复用推挽输出* B5 R8 j) e! [7 d; `( T
RX(默认PA10):浮空输入或上拉输入
) {3 ~+ l" N1 d# [9 X9 ~
8 X1 Z/ j3 a! B; h在写代码前需要检查硬件是否满足要求,使用串口通信时一般需要安装CH340驱动或者CP210x等,这取决于你的电平转换芯片是什么。* Q) J( g! L! v. ^/ G& ~
5 M) m8 a! Q4 T" x8 L串口设置的步骤一般为:
6 d- a( ^( a2 _; [1.使能串口时钟,使能GPIO时钟;- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA);
复制代码 4 Y5 D$ [" @) D5 H
需要同时打开GPIO和外设时钟。, @8 b( `7 o. v/ J( m) M& N# m
2. 设置GPIO端口模式;! K8 ~9 f" ]" ]2 L3 ^, e1 K
' f/ a$ U; E! t' @ ^- GPIO_InitTypeDef GPIO_InitStructure;
* A0 W; w4 o, i2 ^# ^5 v - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;4 m% I' l) r- W9 w3 t2 _
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
* }8 P' Q8 t9 j x2 G, V, } {: a6 ~ - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
6 A/ z5 z, \" I4 y. e/ L - GPIO_Init(GPIOA, &GPIO_InitStructure);0 l# s0 m t8 y9 E% ?7 V
- # E5 B5 S3 x) X
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
6 z! M- D3 i X - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
A1 \# D6 A) I, V$ \; r - GPIO_Init(GPIOA, &GPIO_InitStructure);
复制代码 8 \: O# r( I) y7 O& T, D
PA9:复用推挽模式 PA10:浮空输入# d# N, `. N3 k+ {5 E& \1 ^# X
! n/ u. K2 w3 W4 E9 \3. 初始化串口参数;: }" _ t% F, P* T0 a
( n, Y) C4 I+ K: v. o9 K$ i: C. D d- USART_InitTypeDef USART_InitStructure;
- _. a( y: g- p" a - USART_InitStructure.USART_BaudRate = 115200; //设置波特率; `5 `6 p# K' R) S! W" A
- USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
8 g- a4 z0 W! d; Z) p& c2 i# o+ x - USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位) p/ t& V/ a; k
- USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
( I/ g% a1 J1 ~; \ F - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
! W. _: J5 v$ {% Q" i - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式- P( U: f- [& H. R. B
- USART_Init(USART1, &USART_InitStructure); //初始化串口
复制代码 & O4 Z: D" V5 w5 M. P" F4 N3 I) X
4. 开启中断并初始化NVIC(如果需要开启中断才需要这个步骤);; `: B$ ~$ O$ F/ _+ b9 ]% s
0 g# E8 K x+ g _6 P* g, W4 J1 r* P
- NVIC_Init(&NVIC_InitStructure);8 O' n! K, @1 P6 S
- USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);2 H9 b8 A$ K0 ] `3 C* ~2 J
- USART_ITConfig(USART1, USART_IT_TXE,ENABLE);
复制代码 5 @5 x1 ?8 V7 _ _
RXNE是“准备好读取到的数据”事件标志,TXE是“发送数据寄存器为空”事件标志。& t; k) u* G5 y$ T. R. Q3 _0 T
5. 使能串口;+ v" F: n" n9 {$ t( Y6 v3 g- t& \
7 H. m0 e7 ]" f- USART_Cmd(USART1, ENABLE);
复制代码
" ?/ O5 L7 U" C" V6. 编写中断处理函数;
" H6 F( p# F) |( r% b2 \& P2 U- y" s3 Z' w+ r2 V; E9 Q9 P$ E0 G
- void USART1_IRQHandler(void)! X8 E1 i. D( ~9 F, d( F
- {
+ `+ J% r! h( C) ~6 F8 C0 _9 Y - if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
2 \) K7 `; h5 D1 \2 U% h - {
3 \1 W+ l! o# n+ l: ]( P: e( E - //编写处理程序
* E8 S* {; O" V5 K3 ` - }
; B- x' P Z0 t0 J - }
复制代码 # w7 p/ r* u7 Y% E; P
可以根据特定的中断事件,比如判断是否发生串口发送完成中断(如代码所示)。# }) a. Q- ?0 L& `: c
/ r! N. I ~& K! b) _& x+ \- t7. 发送接收数据。
+ z# ~1 @$ }& ]# p. p: _# e( l6 Y! U3 r8 A) O% @
利用发送数据函数USART_SendData(USARTx,ch); 可以发送一个字节到串口,并利用USART_GetFlagStatus() 读取发送数据寄存器的状态来 等待发送寄存器将数据成功发送。/ x) h6 }/ [+ V
+ b; ?2 V& d% b5 ~- void USART1_IRQHandler(void)
$ f; Y, w; b6 d8 p- l+ p) g - {
: e; V% X- O6 M0 `7 s0 v' C+ r - if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)* G4 m, S; C |4 I
- {4 x; a& G# Q! P9 U" y2 X, h* T
- /* 发送一个字节数据到USART */ * H& M* w1 N& H+ [/ i
- USART_SendData(USART1,ch); ! e& H2 s: R" q$ V$ m
- /* 等待发送数据寄存器为空 */+ D3 c: \% v' }
- while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);: j+ Y( n* j$ t/ O3 V
- }" d; z( `) W8 l) v" H
- }
复制代码
; E- h5 a! c9 f接收数据利用函数USART_ReceiveData(); 从DR寄存器读取接收到的数据;在中断处理函数中通过if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)判断是否是接收中断,如果是,则读取串口接收到的数据:Result=USART_ReceiveData(USART1);
& B7 M+ Y# T& G) M' Q5 ~: b( z; F/ {( t! T* l
- void USART1_IRQHandler(void)
$ K, m! S4 {! @2 Q - {4 I5 ?: d7 {4 P4 C6 m3 r
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
9 L# \5 y* C) T3 j# c; D - {- A: k: r. c$ h; o& z! z# U
- Result = USART_ReceiveData(USART1,ch);
; { q8 j6 V) b |, g G - while (USART_GetFlagStatus(USART1, USART_IT_RXNE) == RESET);. |* w' E4 @ q$ T3 C. ^$ _/ H! Z
- }
+ n$ \ I# N, h D% H1 d: q" Y7 ` - }
复制代码
! }+ |0 J. s/ [! S' ]根据USART_SendData(USARTx,ch);和USART_ReceiveData();两个函数,每次发送或接收一个字节数据,以此为基础,可编写一次发送或接收一个字符串的函数,但这样还是不够方便,为了能像C语言那样使用printf语句输出,需要重定向printf函数发送字符串。* J. h- Y# J3 O
printf()函数实际上是一个宏,最终调用的是 fputc()这个函数来执行输出的,所以如果重新定义了这个函数,就能使函数向串口输出。6 f- E' K; t1 `& S, q/ Z" K( I
2 I! A8 ?! N6 d% d# ~) T7 o0 }- /* 重定向printf函数 */+ _/ e% M9 F" w5 S6 | }
- int fputc(int ch, FILE *f) 0 M3 H) o( I9 Y' G5 ?
- {
* b2 F3 |9 t( |& N - USART_SendData(USART1, (uint8_t) ch);
) p/ \5 p- L8 G7 P - /* 等待发送完毕 */ 2 d1 B3 f! v% s$ B8 ]
- while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);2 R: C+ Z' ~$ A+ r: F4 w' r( e
- return ch;
/ G f; s- n. p i. X# i - }
复制代码
+ U5 T6 ]" i/ y2 k2 \$ q5 @! V同时也可以重定向scanf()函数接收字符串:
* Z4 ]& A4 b. E- y+ M/ j( l) r
9 T+ | u: O: u- R5 U- int fgetc(FILE *f)
! l) |4 r7 j0 @. A A% o. Z - {
) T. Q6 f0 p4 j# R4 p6 A7 k - /* 等待串口输入数据 */
9 v& p& S; ?+ a - while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);0 J F' Q# @3 d" q$ J" m
- return (int)USART_ReceiveData(USART1);
. \. `5 y$ ?; ^; B) E8 x$ O6 w - }
复制代码 & N7 p1 i& |. ^8 U5 r1 u
————————————————. W) g# u- A" h" z4 I; f1 p( F- C
版权声明:云缙
/ d5 u- p3 c/ X1 R( e9 p2 g, t
, n+ o/ P5 i' v% ?" Z& {5 m1 K" ?
7 [# m" f6 q$ p5 y% N |