|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在基础实验成功的基础上,对串口的调试方法进行实践。硬件代码顺利完成之后,对日后调试需要用到的printf重定义进行调试,固定在自己的库函数中。
6 {' z; ]) n- h- S b) 初始化函数定义:( D/ j4 O/ J3 h. h# q3 g
void USART_Configuration(void); //定义串口初始化函数
% o* W5 w0 l3 u9 k) [0 t" ~ c) 初始化函数调用:9 N6 Q8 [2 R; K5 g4 I$ n# v2 ^
void UART_Configuration(void); //串口初始化函数调用5 W* ?0 S( A% O. Y9 C5 f# F0 z( e
初始化代码:
% Q: N4 z# Q/ D7 Y* r) o: N7 z$ ~3 g6 s; u# w
- void USART_Configuration(void) //串口初始化函数
- m& Y6 Z- r- S; @5 p
* ]) G# l4 N% j5 {. G- {4 X4 T y% E; @6 j
- # Y4 @4 I, ~2 Z- O( P" a5 h
- //串口参数初始化
9 Z" S0 I( H- V f& ? O - . I8 V2 K; b% v I; M0 {
- USART_InitTypeDef USART_InitStructure; //串口设置恢复默认参数9 I j+ h0 a& N g- Q' `* u
' |4 W# P1 M; o) u7 @5 h, h- //初始化参数设置/ `* _0 }" Y9 p8 r! U* B$ J) a
x8 ~6 y+ } Y3 \1 [ W- USART_InitStructure.USART_BaudRate = 9600; //波特率9600
B* b. `& ]: N% z. \" C0 Y- s - 8 m; ^2 Q$ `: I# r: S
- USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长8位( ~2 M; U2 b& v, R B& y
- ) [: u$ n( g# j. I8 Q! z6 M/ K
- USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止字节! ]% d% v/ ]1 R, h: E. X, v
- 5 P/ L( Y- L* W0 q. e, @" ~
- USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验
% U" @ X8 ]; e5 i
@; w/ W# r7 V& X2 w; `- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无流控制: ?# K" P) _/ B2 K3 A |9 W* J
- " R: y, K0 U: n, }" G3 t3 T1 T
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打开Rx接收和Tx发送功能
& B8 @1 } v! w# r9 e' [
# J* V, q* F1 y Y3 x4 d- USART_Init(USART1, &USART_InitStructure); //初始化. O6 `, u& L9 D6 H9 f/ g
; ]4 V4 d; B, U+ _7 L- v! ]: z- USART_Cmd(USART1, ENABLE); //启动串口
4 w: ?# @: q; k& t4 @4 _
; s% P9 M$ N; E# V% P- }
复制代码
4 x" [) }1 \4 t# F% u8 V) L RCC中打开相应串口$ g2 @; I: X# m# g9 m
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);# X$ W6 F# @. {4 ?0 @
GPIO里面设定相应串口管脚模式
" N3 h% s4 y$ V. D4 H4 n+ E: G. y2 a5 \: n0 e' S
- //串口1的管脚初始化# m& j0 G" x: _. L' r) S/ F4 ]
- 7 v t6 \8 z' {0 p
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //管脚9) P0 c6 k" g! p2 ?! T/ r1 J' |- c
) r+ z* a& m) a5 W- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出8 U$ M) r% H4 U8 P' @: N& C
& J2 T1 z, u# V- GPIO_Init(GPIOA, &GPIO_InitStructure); //TX初始化
$ ~# h! N1 C3 U - ( P8 y& n% o! K! v1 G
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //管脚10
% W$ N* D$ t$ b0 z+ m7 P( c! N" c - 8 S: W9 q1 X8 C3 D
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
9 q. R0 v. }7 V5 @ - ; }/ z: s a* Z% N: R& P, G0 _
- GPIO_Init(GPIOA, &GPIO_InitStructure); //RX初始化
复制代码 5 t0 N/ r) r8 x3 j$ n
d) 简单应用:% ]+ h% S$ b8 ? O' o) i
发送一位字符
! C9 i1 A* j7 j8 _) M) \1 y0 x! a% P USART_SendData(USART1, 数据); //发送一位数据5 k; }8 [7 ?" i) v7 G. v; @! T
" ^3 y+ ~- U2 \2 L" P* f3 {, w9 b
- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待发送完毕
复制代码
6 n$ e! B! n7 j s8 ~ 接收一位字符+ K' z X4 t0 {4 N
" f2 k/ H( }% B, p# s- while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){} //等待接收完毕
复制代码
4 T$ v1 ^' x( E2 [ 变量= (USART_ReceiveData(USART1)); //接受一个字节# J0 ?: X4 B- B
发送一个字符串
$ \9 _6 V! N! b, _: i4 M 先定义字符串:char rx_data[250];/ g% l# w! ]" F3 O" O
然后在需要发送的地方添加如下代码
9 {- Q2 ~" n* k9 t& e$ V! y( `
* U, I, H+ _1 s; F3 _- int i; //定义循环变量7 C- Z, L/ m. U$ |0 [! w0 X; p
7 U7 ^+ v5 ~% r, {4 }- while(rx_data!='\0') //循环逐字输出,到结束字'\0'3 B; X. u9 M: B
) G( q0 L8 G1 Q- {USART_SendData(USART1, rx_data); //发送字符- r" o" ~# Z3 _( C8 R& D
- # U% ~1 \: B3 E/ Z& `
- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符发送完毕
! `0 l, E# f/ Y0 h3 `
+ T3 m! Y* _9 A9 M- i++;}
复制代码
# X" ]+ [' V4 u$ r+ G/ { e) USART注意事项:
1 R% j. ]3 T/ a4 v( A 发动和接受都需要配合标志等待。
0 B" |8 ?3 O/ k ] 只能对一个字节操作,对字符串等大量数据操作需要写函数
/ h6 J- l4 x3 z8 ~6 ^# r. e" ^ 使用串口所需设置:RCC初始化里面打开RCC_APB2PeriphClockCmd
% G: X- q6 I h7 s (RCC_APB2Periph_USARTx);GPIO里面管脚设定:串口RX(50Hz,IN_FLOATING);串口TX(50Hz,AF_PP);8 U+ |2 g5 z9 @% g: L2 V0 g! a
f) printf函数重定义(不必理解,调试通过以备后用)5 W0 v! S' ^0 S/ n7 r
(1) 需要c标准函数:) F% t0 {; ]" y |5 s
! w" i: G& e4 k+ D( T5 w: [, X$ W" c" f) u- H! L
(2) 粘贴函数定义代码
4 h* f5 R ~- @6 h( e- ?$ ? #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) //定义为putchar应用' n9 B) u- @# g7 V1 v i; ^" g% ^# h
(3) RCC中打开相应串口2 O/ J! m! f- X7 B. }
(4) GPIO里面设定相应串口管脚模式
) {" Z9 }2 _, o$ M3 @/ ?# K (6) 增加为putchar函数。
* z; i: Y: _, P! d int putchar(int c) //putchar函数, {! `' k8 n) J
- s' y& T- F. C
- <p> {</p>+ z, J) F. L$ _2 j5 {
- <p> if (c == '\n'){putchar('\r');} //将printf的\n变成\r</p>
* \: H6 j/ f) l. Z9 r. s! J' c7 [ - <p> USART_SendData(USART1, c); //发送字符</p>
% d, U; b* w) O6 C4 Q - <p> while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待发送结束</p>- o2 C) H& `3 Q1 v
- <p> return c; //返回值</p>
& [' L) m7 }' z% n, S( r! V - <p> }</p>
复制代码
: H9 ~: [, m: Y1 e* j2 I (8) 通过,试验成功。printf使用变量输出:%c字符,%d整数,%f浮点数,%s字符串,/n或/r为换行。注意:只能用于main.c中。
& C4 \9 Y7 x+ V5 H" U4 T) b 3、 NVIC串口中断的应用
" L0 ^: y; X* `( [* n a) 目的:利用前面调通的硬件基础,和几个函数的代码,进行串口的中断输入练习。因为在实际应用中,不使用中断进行的输入是效率非常低的,这种用法很少见,大部分串口的输入都离不开中断。
8 Y' Z- q: _" [7 H b) 初始化函数定义及函数调用:不用添加和调用初始化函数,在指定调试地址的时候已经调用过,在那个NVIC_Configuration里面添加相应开中断代码就行了。, K& c7 e/ j6 Z/ n- d* w; }
c) 过程:
* J1 c6 p2 V0 E- U# I5 a- D @+ _ i. 在串口初始化中USART_Cmd之前加入中断设置:, G) J' c" Q3 ~5 v( L$ ?: f% o% _
( `& e9 i$ U" v2 x4 s& Y6 J" w9 P
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个。
' z2 y5 U0 m$ Q% X. ] - \- d" o7 b# i+ W
- ii. RCC、GPIO里面打开串口相应的基本时钟、管脚设置: M1 `- n5 S8 @7 b( |
' h, p& M( x# X8 W) @7 `. M+ X" `- iii. NVIC里面加入串口中断打开代码:
3 x' t' T4 b# x( n) Z - % N+ ^ a2 X, X4 [
- NVIC_InitTypeDef NVIC_InitStructure;//中断默认参数) P& F% ^( a D9 r! u: E$ U
- , {8 }( P U% V3 m$ u
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道设置为串口1中断
' e, V* {3 \: c# [9 ~# ~% Q8 ?. a
+ a, K9 e/ ?) X, Y- C4 T+ X- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中断占先等级0' {' ~' L. Y2 {+ W" J6 q
- 1 c c, E4 L7 m7 v& K" C
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中断响应优先级0
6 g- H- a- A' P7 X8 o
8 B# \% l1 f$ P- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打开中断/ N2 O5 Q7 {3 G$ b9 a! W" B. q
# M# y( Q3 G( f9 m1 C" ^- NVIC_Init(&NVIC_InitStructure); //初始化
复制代码
, @4 x2 z4 A# C2 x% o. b iv. 在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添入执行代码。一般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串赋值,或做其他事情。
6 G9 E/ l' i \, a9 |/ ?' a' P# g5 [: ^# A. }
- void USART1_IRQHandler(void) //串口1中断2 L2 I! N) n0 ^5 v8 I/ {" G8 `
- 2 y* t- d) f: d2 T- V
- {# ?) N2 \9 F q; k) I) o4 r
- " z) m$ [) D2 S: N: L
- char RX_dat; //定义字符变量: R6 J5 V8 H. d
5 q' O Z- d) N3 Y0 k% t# ]" C2 W- if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断发生接收中断: E$ }# l) h Z3 P
3 G) f0 h/ K7 }) A* b! U- {USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中断标志5 S! A h$ a& u. E; l" o* y, T0 _
- * L8 ?* p# O" ]
- GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01); //开始传输
& a/ J5 B! w5 ]
/ ^! \2 N/ w9 T9 }# T$ J- RX_dat=USART_ReceiveData(USART1) & 0x7F; //接收数据,整理除去前两位" z7 y( u$ O! \- ~: H: }
- . P+ U8 L4 C, `" V" K4 l [* O
- USART_SendData(USART1, RX_dat); //发送数据) P3 `, {& C( L8 V; Q* b6 f
9 k5 c7 C+ F9 X- X- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待发送结束4 ^8 s3 n# @. n& Z2 O4 |. X
9 a5 e" S" p3 L7 M- }
* _5 F! p$ P$ J1 {& `4 j - # K$ j- ~4 z, J" H3 d) l
- }
复制代码
4 \9 A8 f3 O# O J( M% w* J5 ]7 \ d) 中断注意事项:
* l: f* l8 B: x& T 可以随时在程序中使用USART_ITConfig(USART1, USART_IT_TXE, DISABLE);来关闭中断响应。% H( p0 N+ U4 h) G, g$ a
NVIC_InitTypeDef NVIC_InitStructure定义一定要加在NVIC初始化模块的第一句。
# s% }6 Y+ C( g# f$ N# D1 Y3 [ 全局变量与函数的定义:在任意.c文件中定义的变量或函数,在其它.c文件中使用extern+定义代码再次定义就可以直接调用了。
; L9 L) X+ _: N8 I& I" d. H G STM32笔记之九:打断它来为我办事,EXIT (外部I/O中断)应用' R" f* h, u1 r$ }, f+ @
a) 目的:跟串口输入类似,不使用中断进行的IO输入效率也很低,而且可以通过EXTI插入按钮事件,本节联系EXTI中断。+ ]* D' s0 J6 M9 W0 N5 ?
b) 初始化函数定义:
' Y$ a/ A/ O6 a8 Z8 m- r% ]9 a& g% |) v
- void EXTI_Configuration(void); //定义IO中断初始化函数
复制代码
+ @* E! ?1 W( J' ? c) 初始化函数调用:+ l! J. s5 S& j3 `
7 W( B' I4 } V" U- EXTI_Configuration();//IO中断初始化函数调用简单应用:
复制代码 - N; S+ |) D! ~) H7 X% @7 Q
d) 初始化函数:
( }1 Y4 B2 g+ R( K0 \' K5 b
# Z6 L* W; S; x0 W4 X4 m: H- void EXTI_Configuration(void)
: Z. [" v, J: y K, d( |3 ` - 7 T9 D$ v( m2 h% z
- { EXTI_InitTypeDef EXTI_InitStructure; //EXTI初始化结构定义! N- o( N4 E! u# O0 o# H0 Q! b
- 8 ~% j" ]' s) F: Q( d9 c
- EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中断标志
. ~7 g4 \3 e0 u+ n+ i1 | - * h$ ^# J6 l. T( g- a! e" K* ~
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管脚选择 D0 u, ?0 C: E5 O/ n+ ~' [, L
1 p' y5 ^6 R J& Y6 l! F- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);
# f+ O8 l2 N) T1 J/ G. d5 s k& B
6 c/ n5 d( Y( _1 k, L( z8 D" n a5 E- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5);
) `- B; ^ K5 l ] - * H( X/ t3 d; c/ J7 ^6 d4 U+ E
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);, c1 [* u" H7 E. @2 ]6 V
- 0 {' p3 B5 n$ {; K4 ]: j. u
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件选择$ }" e8 D+ V9 G8 Z3 Y6 o9 V
- $ J v# _/ z! Z0 n
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//触发模式1 Q6 s9 |2 K/ n/ u
- - o! g7 f `# R1 I
- EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //线路选择2 `; r8 t2 ?1 V7 L
% E$ ]3 Q" }0 i/ {8 v, Q- EXTI_InitStructure.EXTI_LineCmd = ENABLE;//启动中断
0 u, E; F+ J8 ]0 p; s5 i8 O2 F
1 q# z- t0 Y2 Q0 H- \- EXTI_Init(&EXTI_InitStructure);//初始化
; \( f6 Z/ i) d1 f- T j" u - ) |8 a3 c v# X3 ^
- }
复制代码
7 K* K5 @& M5 @, v! c e) RCC初始化函数中开启I/O时钟
" L6 ~0 b: Q# _# _* R' ^ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);3 V; Y/ p7 i! ` H( J) Z6 c' {
GPIO初始化函数中定义输入I/O管脚。9 g T3 @0 Q/ Z9 O ?- c) L
6 W+ \: t8 l9 T- //IO输入,GPIOA的4脚输入
7 }# ?1 C/ D2 G2 F5 P& G6 ~! ^
9 U5 R+ l: U1 _* A3 ?- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
+ e) ]$ m. v; h- S! K0 \3 A
% W5 B& O. f3 Q) ~# s- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
+ t! ?! S; M( K q
$ f- v7 d7 R+ L5 m- GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化
# M& f. T7 e8 g. K8 |' C - 6 ^1 X6 S4 F3 y6 `8 X
- f) 在NVIC的初始化函数里面增加以下代码打开相关中断:
. X4 c5 {2 U2 ?- }; ?. \
, Q0 r: E0 M" ~ j( `8 j- NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //通道5 b( `$ O; A. l" d$ D P
7 j f0 L: v( B! v1 c4 P5 S1 U- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先级; Y; q5 Q0 _3 W7 E- S( y9 Q
- ; O, i- }9 v$ h
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应级6 R4 X- f7 o0 c
/ T& M9 y; Q' J* w. J- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //启动0 q/ y. H4 P7 U# V
- " g( K5 T& O4 e' d* u
- NVIC_Init(&NVIC_InitStructure); //初始化
复制代码
/ @% Y. N, O* y% V! j# `) d3 k9 y- B g) 在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添入执行代码。一般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串赋值,或做其他事情。& _* v( `* S) q1 y
5 O1 j$ V) a- {' P) _
- if(EXTI_GetITStatus(EXTI_Line3) != RESET) //判断中断发生来源
! ?5 y, X+ l# @' v6 u, B
5 H( f" t$ U* w) g4 H- { EXTI_ClearITPendingBit(EXTI_Line3); //清除中断标志
" o# Q# e. n8 d: u - 0 v7 n) _( U7 S! N W" ~
- USART_SendData(USART1, 0x41); //发送字符“a”
0 B5 ?- H5 i, W) d* H6 o* J4 g' C
& L7 Z/ B1 A" l" I+ H- GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED发生明暗交替
7 |$ ?# O; O8 O9 K( M
; Y( ^# v5 x$ m4 g( P+ ~" T: M- }
复制代码
2 _* L8 V; F& N% Q6 z h) 中断注意事项:
) l8 K9 D2 t% O$ Y7 k 中断发生后必须清除中断位,否则会出现死循环不断发生这个中断。然后需要对中断类型进行判断再执行代码。
8 L& x6 n/ [# N$ c, i& A 使用EXTI的I/O中断,在完成RCC与GPIO硬件设置之后需要做三件事:初始化EXTI、NVIC开中断、编写中断执行代码。, K2 |+ @5 u( N/ A
-----------------------------------------------------------------------------------' _/ B1 u* K' o' s
补充
$ h9 o5 n7 i b' r, K# ` 上边的不足之处就是无法发送char类型数据,是u16类型的,会报错
" s% i M- ~% x" [ 后续可以更换为3.5的固件库,7 U* F* }2 w" r7 K- C( P3 Z. v- [: F7 `
d) 简单应用中
* M7 k0 b5 z G6 n) w 超级简单应用只可以发送u16类型数据
) p. D- \* Z7 O% x7 X! }6 p( B 下面发送char数组时,! l+ }6 r$ K. `& I! }' g0 |- v
“{USART_SendData(USART1, rx_data);、、” 中rx_data需要改为- Z+ v+ H9 S2 t8 q
rx_data才可以,不然就会报错数据类型不匹配,
* z6 ^6 l6 ], n; e$ D- x7 K9 e% j& p0 u$ c
( S: ]: t- D. F$ \) H
0 E3 j$ U, s9 F- v1 H' J+ L: _4 @$ A/ @
! p, W4 _/ H! d8 O# j8 e1 | |
|