|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在基础实验成功的基础上,对串口的调试方法进行实践。硬件代码顺利完成之后,对日后调试需要用到的printf重定义进行调试,固定在自己的库函数中。
3 q5 E+ }5 f# `; [ b) 初始化函数定义:
' i% {& f4 W6 J4 W void USART_Configuration(void); //定义串口初始化函数% X* C( b, N+ v/ w
c) 初始化函数调用:
4 Q2 r7 V8 N2 _! n- r; e void UART_Configuration(void); //串口初始化函数调用/ {) V$ L- Z0 E9 |) P2 y; W
初始化代码:
2 _' y4 l6 }+ a8 l8 I
$ t3 Y T* Q9 f- q; i; I- void USART_Configuration(void) //串口初始化函数
' ^/ K8 I A, \4 x! a3 P
8 o; v9 j( [' X/ Z* E9 a% D. ~5 h- {
* i8 Q, ^3 W9 F$ s9 u - * n0 j5 ^/ ]+ h( K& @1 b& r
- //串口参数初始化' e( ]; q2 P$ } H+ t
" q6 S8 k) y e- USART_InitTypeDef USART_InitStructure; //串口设置恢复默认参数3 i% v6 s) ], Y) j) ?+ e
( i p8 O8 `# O. j4 t- //初始化参数设置
6 b- J- W, n3 m) i! J
2 q% Q; D& q) e B3 h& @" H- USART_InitStructure.USART_BaudRate = 9600; //波特率9600
0 W* r( c! v8 M% I - 5 m7 p4 F! B( n8 \3 \8 M
- USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长8位 ~9 b% z8 F' k# x$ i) u
- . A' |, g; j5 X- J6 m6 `
- USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止字节# Q% V; b2 N& @* T6 ^
- ; S" P- w: S. N/ h# v! A
- USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验
3 w% A. H: l* f: i# r9 O1 o
9 d& H j. C. ? Y" `/ r5 X+ W- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无流控制0 o% x' @+ N% [- K
n0 M; w/ V. r- o& d1 I* Q9 E9 w3 ^- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打开Rx接收和Tx发送功能/ x5 ^0 m9 u$ M2 o' b4 T" I0 w# b q
- : `' S0 Q- Z, ~2 X9 Z: U& k
- USART_Init(USART1, &USART_InitStructure); //初始化8 [( S7 s! n# A: T/ D- M7 G
' \4 [7 p e! k$ _ m( E- USART_Cmd(USART1, ENABLE); //启动串口
x+ m4 b t7 x" Q
* h9 p/ u k+ N- }
复制代码
1 r) N! [7 \$ O/ A+ [ RCC中打开相应串口4 H1 s% v( U) z+ ]9 F% V
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);& O9 D+ w: m! Y: m* B& t6 y/ O1 V. B1 B
GPIO里面设定相应串口管脚模式) d$ c( b6 ~+ L0 y. o# P6 H) p2 R
/ k/ {- z+ U h6 A% {/ [ H- //串口1的管脚初始化0 D+ B! J& r# z9 _9 |8 E, L
" G" }7 Z0 l5 o- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //管脚9
4 N$ Q: T+ ]3 V% z6 G - 1 E, n6 V; \7 P/ [3 p+ H) Q
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出; R" j r0 j; c, j; P
- 9 V4 r" F0 q+ W# }8 X
- GPIO_Init(GPIOA, &GPIO_InitStructure); //TX初始化
) W( ]9 C- A* l
: `+ d- @! K$ ~; Q- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //管脚10% x, I1 j' ?% `) k( k1 _& M
- 6 {; G9 G" g, C, r
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入. G! M7 e. l! }% o
- . W( k! a$ w" ?7 J1 h* {
- GPIO_Init(GPIOA, &GPIO_InitStructure); //RX初始化
复制代码 9 r- ~; t( d9 U& n g( P
d) 简单应用:
8 t v6 a& t0 P2 A; E& D& [: M2 ] 发送一位字符" t( W1 a+ S! V; t. a
USART_SendData(USART1, 数据); //发送一位数据
3 r+ O1 ]! k' m, t! f/ F9 F6 d6 U2 z+ o
- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待发送完毕
复制代码
# v9 x# t% Z; ? 接收一位字符
/ g0 x8 u# u* J/ E. J2 H& R& h9 T. ^6 \& L, v4 F- v
- while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){} //等待接收完毕
复制代码 5 G& [; O) w+ a5 w
变量= (USART_ReceiveData(USART1)); //接受一个字节' q$ i# E6 u% y9 Z" c4 m, ~
发送一个字符串. [$ Q t. Q" m& R0 ]0 J
先定义字符串:char rx_data[250];
: U7 b7 m! a" ]3 @ 然后在需要发送的地方添加如下代码! Q8 t' K9 C2 T6 B/ i
* I3 m% j8 F7 N$ R- int i; //定义循环变量* T5 ^" @; w! k- m7 j% C
- ) N3 e* g1 N( x6 i5 u
- while(rx_data!='\0') //循环逐字输出,到结束字'\0'
3 r, [: r# ], e4 D! \
- D" h* S& U; v5 @, J7 u. R- {USART_SendData(USART1, rx_data); //发送字符
7 j, J/ d$ U9 c$ J. Z - % s$ R8 r9 t3 W9 y, q
- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符发送完毕
9 k- l; h- h/ p" L! m3 W8 P# z
8 F0 A2 J# S% _' n- i++;}
复制代码 . o; u# Q7 T) Y. U" n! T
e) USART注意事项:
0 u0 i$ C/ q3 ?0 J! H9 Y, h- E, ] 发动和接受都需要配合标志等待。
& f/ Y) G8 ^% l 只能对一个字节操作,对字符串等大量数据操作需要写函数
( W7 d0 y" N) J" { 使用串口所需设置:RCC初始化里面打开RCC_APB2PeriphClockCmd
) u$ |! d7 [/ Q2 e (RCC_APB2Periph_USARTx);GPIO里面管脚设定:串口RX(50Hz,IN_FLOATING);串口TX(50Hz,AF_PP);
z8 ^# Y3 E8 z f) printf函数重定义(不必理解,调试通过以备后用)
1 {% L6 w1 x4 J w (1) 需要c标准函数:) |/ Y4 g, m9 Z$ `* i
- q* ?/ g$ T5 O
: l% A/ v5 ^4 c" c# v9 S# ^# g
(2) 粘贴函数定义代码! O ]0 }, i& F$ o7 ~8 p
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch) //定义为putchar应用. R. t6 I- _- P: I$ D
(3) RCC中打开相应串口
8 n- ^9 T) K. Z) n T (4) GPIO里面设定相应串口管脚模式
X+ O: z" e6 U3 E6 \/ w (6) 增加为putchar函数。
% ^0 S9 t h, z int putchar(int c) //putchar函数
1 d) b- B1 l9 e+ j9 F
$ ^) l4 y# l6 s- <p> {</p>
' h/ p2 \" g) V+ q: _5 ?! E) y - <p> if (c == '\n'){putchar('\r');} //将printf的\n变成\r</p>' U8 ?) l X( N6 Z: I. G
- <p> USART_SendData(USART1, c); //发送字符</p># z8 @9 w: t) G! a# \0 X
- <p> while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待发送结束</p>! x& U/ @% i/ K- s3 L. j
- <p> return c; //返回值</p>
8 T$ M: B! j' U& a2 W - <p> }</p>
复制代码 ( P' a0 X* ~, W3 z6 D/ y
(8) 通过,试验成功。printf使用变量输出:%c字符,%d整数,%f浮点数,%s字符串,/n或/r为换行。注意:只能用于main.c中。
, e L2 f6 ?5 U5 O. e 3、 NVIC串口中断的应用' W* J+ o3 ?: j' T5 a
a) 目的:利用前面调通的硬件基础,和几个函数的代码,进行串口的中断输入练习。因为在实际应用中,不使用中断进行的输入是效率非常低的,这种用法很少见,大部分串口的输入都离不开中断。
8 h( _& x& G! o b) 初始化函数定义及函数调用:不用添加和调用初始化函数,在指定调试地址的时候已经调用过,在那个NVIC_Configuration里面添加相应开中断代码就行了。8 y6 ?8 l% d* P$ M. `
c) 过程:
# r9 \0 k# s, g i. 在串口初始化中USART_Cmd之前加入中断设置:
$ i+ f: D2 B% @* q& q1 U( W O
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个。2 R) S: E4 n1 L/ j+ @" l
, C& w& _+ k B" M- ii. RCC、GPIO里面打开串口相应的基本时钟、管脚设置3 X& a4 y* L; B( o1 f& L8 Q4 g
+ H8 z7 a g4 C" I5 I- iii. NVIC里面加入串口中断打开代码:
5 s' d$ l( n' V' z) B2 e2 Q
: \8 ~% M; {! r0 F# ]( X# p- NVIC_InitTypeDef NVIC_InitStructure;//中断默认参数1 S2 k& x+ E% X" N' j
- ) ?) X0 s" R& k8 | p8 L
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道设置为串口1中断$ m5 }9 e% n) P
& @3 `( z9 X8 L/ x- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中断占先等级0, Z/ X- h- a& f8 K) k5 x4 ^6 V
% g% ]% {$ u1 I; O/ b- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中断响应优先级08 o7 U4 v- B: y. ^% z
/ v) Z- [' ~; p# @4 r9 w- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打开中断
/ j4 ^$ @; M7 p" }9 g3 d" T8 J4 p
, ^2 `* b4 p% R/ {- |& D8 R" j- NVIC_Init(&NVIC_InitStructure); //初始化
复制代码 / N# z, M" z; I) b8 l
iv. 在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添入执行代码。一般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串赋值,或做其他事情。& t5 h& r3 o, h3 B
# k; b$ M1 w1 J/ d# ^$ l
- void USART1_IRQHandler(void) //串口1中断
7 t+ a2 r0 D/ X8 i' x; i/ u4 Z& V - ! e% q& P0 I6 q9 k& _
- {
4 p m; o' A( D p
$ Q* O" K9 M# c2 p) T- ?- char RX_dat; //定义字符变量$ n3 h0 I4 M7 k1 U
0 b0 m0 D1 ? c: f8 Q% T/ K1 {; E- if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断发生接收中断& h% w: s& i) Q7 q6 U
- ) d" I$ A# g: h, R. m- Z( ^
- {USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中断标志0 {. d* A5 g y+ p( ]
6 S( I" i* o! y; n- W. L- GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01); //开始传输6 F. e) [* W0 R: F( ]- x
- ) R4 n/ `5 V9 Q! Z' \% G
- RX_dat=USART_ReceiveData(USART1) & 0x7F; //接收数据,整理除去前两位
. J8 Q6 w$ f/ Q* ?7 v5 C7 g
. ^& F" p5 u, F8 J' I, m: {- USART_SendData(USART1, RX_dat); //发送数据: y5 S7 P1 n% k! R, m% k+ |
+ y q/ C4 C4 t% H- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待发送结束9 }& J' R8 n0 c8 Q D$ C: Z
& F- t O- ], b0 Z# I- }4 _7 \6 L) Z m' i9 U9 m! w7 w: n
- 5 s$ V8 _! o$ R% n7 s- I: l
- }
复制代码 ; G) o' S) h) d0 c0 j
d) 中断注意事项:4 a5 ]: M8 h7 F) \9 j, N8 W
可以随时在程序中使用USART_ITConfig(USART1, USART_IT_TXE, DISABLE);来关闭中断响应。! a, G/ R4 U F' t1 A5 z
NVIC_InitTypeDef NVIC_InitStructure定义一定要加在NVIC初始化模块的第一句。
6 i$ x0 X: v+ g 全局变量与函数的定义:在任意.c文件中定义的变量或函数,在其它.c文件中使用extern+定义代码再次定义就可以直接调用了。
% y0 g: R% ]5 X/ a( J0 R0 g% x STM32笔记之九:打断它来为我办事,EXIT (外部I/O中断)应用
_% J" h) }/ c3 U; H6 b( p G( k a) 目的:跟串口输入类似,不使用中断进行的IO输入效率也很低,而且可以通过EXTI插入按钮事件,本节联系EXTI中断。
+ m- {+ F1 o3 l" A2 Q ~8 c b) 初始化函数定义:- g& W: }5 }4 V% i6 N3 `' K
/ }: R; \2 S! Q
- void EXTI_Configuration(void); //定义IO中断初始化函数
复制代码 / U4 j3 \' A9 F
c) 初始化函数调用:& q# i0 K3 `+ K- e/ Y6 s
' V2 [2 S' U% i9 J# r$ [, h
- EXTI_Configuration();//IO中断初始化函数调用简单应用:
复制代码 ' |2 v. ^! {; |
d) 初始化函数:
M e6 X! B" X2 z$ m! o+ n. R) q3 N! }0 c5 Q/ K
- void EXTI_Configuration(void)
0 V0 S6 w1 J( Z% L: ? - 9 x: d0 u+ ?7 ` R! D. c3 j+ I
- { EXTI_InitTypeDef EXTI_InitStructure; //EXTI初始化结构定义+ w7 D7 J7 A+ t( \. @4 H8 `
- ( M, T& q' u3 _2 T( y
- EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中断标志
4 h& s. Y9 q5 t6 ]# g1 l1 i - - C( W0 K( L* {" y8 u
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管脚选择
( k. o. n1 K% U$ q2 ~
$ H7 G7 k* `* X: l ~ L- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);
: R1 g q' \9 `+ Q5 C3 H
2 x9 S) _ \! @ i- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5);) w- m; j3 C4 G
5 }0 O }- j0 @, O7 j- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);
2 S% H% G+ g# A6 v! {0 t - f" M) |9 Y/ X
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件选择 D# V3 f5 E/ @- [
) E: n" V( ^& P: ?; v5 m6 i& ^9 t- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//触发模式* Y, [3 S- n+ g: d9 Z0 `
- % X$ N. \) |3 ?+ R# J% f
- EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //线路选择
0 E) i9 C. z4 e2 B& `" F* I - ) b: c6 d" N* U( |/ {7 @3 _2 r0 q4 d
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;//启动中断
+ b _. J, z$ Q6 A1 e8 `; ]2 E, \ - / r5 O) o* w! o; c
- EXTI_Init(&EXTI_InitStructure);//初始化
' m! l4 C: O# j; i/ P- P; g
8 L. T1 V5 q2 {- }
复制代码
; H. T1 d8 l3 d e) RCC初始化函数中开启I/O时钟1 n' N# f/ O1 h2 J7 l4 l3 l
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);* N) _$ C0 \" o" w5 Q2 D
GPIO初始化函数中定义输入I/O管脚。9 T2 g; @9 Z" X# o
$ s& ~) ?; r( h) m6 Q1 [% M5 t% _- {- //IO输入,GPIOA的4脚输入5 o. M9 G( V2 v: Z, R9 a& r
4 R" Y0 i: v" Z' Y- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
: h' L. g( [6 g6 Q0 E" U
N7 e3 Y s* g6 r: W3 c$ x- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
( s$ t+ b8 a0 ^- }" q. K# y
' q; `- [8 C. n& ]' o) l- GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化
- j0 w0 q! T5 ?+ u7 ?+ p/ x" Z3 [
) }( U1 X* r; P" c% _ m- f) 在NVIC的初始化函数里面增加以下代码打开相关中断:
" H7 ]7 X* i* m2 ?) f% p7 t
8 c: I( v/ j& I- j) g0 S* P9 U! L- NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //通道# i; N ^, r0 f
" d, e4 r$ T n# x8 D- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先级* x( \. g# N4 ~
- + k2 ]) B" g5 ^
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应级! p0 }5 [- x' w% c7 g
- * k0 m4 Q- h; D5 f0 C5 m
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //启动
" D! Y+ T/ \ ^+ ^) T; F4 W% m
4 N" m+ I6 d4 y! D3 T7 U; C( j( A- NVIC_Init(&NVIC_InitStructure); //初始化
复制代码 , W) E7 ]/ ?4 n. o" v: s
g) 在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添入执行代码。一般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串赋值,或做其他事情。+ u8 e8 s( ~ r
9 E; j) I/ u6 o9 Q1 @3 k2 m! i$ `
- if(EXTI_GetITStatus(EXTI_Line3) != RESET) //判断中断发生来源
! F& ?7 V; _( v
: n$ U: Z2 Z' ?0 F% E1 r- { EXTI_ClearITPendingBit(EXTI_Line3); //清除中断标志
" Y! m) P3 X9 q% ~- ?% Y - / K# w$ \9 E3 G6 O w0 l
- USART_SendData(USART1, 0x41); //发送字符“a”2 R8 k. x1 S/ r# e- J
- ! G! [4 m: e$ ~4 S! r# Q
- GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED发生明暗交替0 `/ a E2 h* W1 ]9 B
- ! u/ t! Q% r$ M* [: A4 j
- }
复制代码 2 O9 d5 O u; W9 m
h) 中断注意事项:+ n6 F& o8 l1 X
中断发生后必须清除中断位,否则会出现死循环不断发生这个中断。然后需要对中断类型进行判断再执行代码。
: J3 Q. r/ {- X/ B$ Y, @ 使用EXTI的I/O中断,在完成RCC与GPIO硬件设置之后需要做三件事:初始化EXTI、NVIC开中断、编写中断执行代码。
- p! w+ }3 W. S, O6 q0 m6 ^3 x' b6 U2 S -----------------------------------------------------------------------------------) a& w: i0 Q. k" z. \
补充! E' Y$ j. _4 p6 T6 a1 b: u
上边的不足之处就是无法发送char类型数据,是u16类型的,会报错0 j) X$ G9 x- u5 K) L
后续可以更换为3.5的固件库,' Z" E6 ?5 e1 o% D# }( {0 m4 \
d) 简单应用中
* y2 P8 s! u# m8 u- W0 i 超级简单应用只可以发送u16类型数据
& B. B. q' |, u! d# r, o 下面发送char数组时,& G) p+ n3 K$ M; i- _
“{USART_SendData(USART1, rx_data);、、” 中rx_data需要改为4 P+ t3 c, R: g1 M% e
rx_data才可以,不然就会报错数据类型不匹配,& X0 y) d- `; D5 p
5 \9 _% V# S" c0 `9 ]4 s) @
/ y; E; _( j9 Y# E, ~6 K
' v" ~' F# O3 a# D5 [
- v: R4 g9 L4 u5 l* o* `' P) T5 |% x6 k) P- T, k
|
|