你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32(ARM)开发初级知识(一)

[复制链接]
STMCU小助手 发布时间:2022-10-31 22:39
STM32,从字面上来理解, ST 是意法半导体, M 是 Microelectronics 的缩写, 32 表示 32 位,合起来理解, STM32 就是指 ST 公司开发的 32 位微控制器。在如今的 32 位控制器当中, STM32 可以说是最璀璨的新星,它受宠若娇,大受工程师和市场的青睐,无芯能出其右。) q" @! F4 K) l  j

/ y4 M; a2 H7 s4 \51 是嵌入式学的一款入门级的精典 MCU,因其结构简单,易于教学。 51诞生于 70 年代,属于传统的 8 位单片机,如今,久经岁月的洗礼,既有其辉煌又有其不足。现在的市场产品竞争越来越激烈,对成本极其敏感,相应地对 MCU 的性能要求也更苛刻:更多功能,更低功耗,易用界面和多任务。面对这些要求, 51 现有的资源就显得得抓襟见肘。所以无论是高校教学还是市场需求,都急需一款新的 MCU 来为这个领域注入新的活力。
5 j) K, M' N% C  P0 x
3 q) g" D# t9 n  b基于这样的市场需求, ARM 公司推出了其全新的基于 ARMv7 架构的 32 位 Cortex-M3 微控制器内核。紧随其后, ST(意法半导体)公司就推出了基于 Cortex-M3 内核的 MCU——STM32。STM32凭借其产品线的多样化、极高的性价比、简单易用的库开发方式,迅速在众多 Cortex-M3 MCU 中脱颖而出,成为最闪亮的一颗新星。 / Z" `+ \# ?2 h. o0 w
6 _  I& _* B! h& b2 P4 F+ s
STM32 一上市就迅速占领了中低端 MCU 市场,受到了市场和工程师的无比青睐,颇有星火燎原之势。作为一名合格的嵌入式工程师,面对新出现的技术,我们不是充耳不闻,而是要尽快吻合市场的需要,跟上技术的潮流。如今 STM32 的出现就是一种趋势,一种潮流,我们要做的就是搭上这趟快车,让自己的技术更有竞争力。7 y  x; D, D0 N3 {! k5 g  d5 L' l" A

+ i4 |- _, j. [STM32 USART串口的应用. _( i1 i# ~. k* s4 \* b

, h+ P/ }; g2 ?% CUSART:Universal Synchronous  Asynchronous Receiver and Transmitter的缩写,即通用同步异步收发器可以灵活地与外部设备进行全双工数据交换。
- E9 a7 l4 U0 q2 n: k: |% P
8 T6 e( h# X* \/ d' HUART:(Universal Asynchronous Receiver andTransmitter),它是在 USART基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是UART。' L6 }' g9 O3 j2 b! }2 K8 k
  B% e( L+ V+ }
USART 在 STM32应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一个 USART通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、指出运行出错位置等等。* v  X9 ]# n3 u% w8 `2 w9 z. E5 H
( O0 L' o9 `9 ]* {
用户平时基本上用的都是UART,很多外设与STM32进行数据传送时都是用的UART。
. d! ~" f/ n% j6 h) h
/ d% V( i$ ^; [2 Z  Y9 U 微信图片_20221031223941.png # S1 Y  q! a* n& C; j4 M* w

8 g7 o# w# ?% C3 D开发板与电脑对于电平的定义是不一样的,即对逻辑1和0的电平定义不同,因此需要一个转换器,和其他开发板连接时,由于电平一样,可直接连接。
. K  L9 \) O/ s% R  a6 x; O. F8 P9 G% x  V. ?# L7 A3 ~, a& o! b! v! `
微信图片_20221031223935.png
% @" J, m: ?3 ?% y# t5 v! P+ t9 K7 E1 `* M! h9 C
串口通信协议介绍:正常情况下,没有数据传输时,两端的信号线保持高电平,要发送数据时,发送方向接收方发送一个低电平,接收方就知道对面要发送数据了。接下来发送方发送数据,两端约定好数据大小是8位还是9位,一般情况下是8位,紧跟数据位后的校验位和停止位。
( N: g# z& d& \, I# u( ^% S
/ t! J* C8 n& a4 t# L& c6 a  { 微信图片_20221031223931.png
8 [4 u, V% q- g' O- |3 f5 s. c( b* i3 C
在串行通信中,用“波特率”来描述数据的传输速率。所谓波特率,既每秒传送的二进制位数,其单位为bps(bits per second)。它是衡量串行数据速度快慢的重要指标。国际上规定一个标准的波特率系列: 110、300、600、1200、1800、2400、4800、9600、115200、14.4Kbps、19.2Kbps、……
' j- }; N5 d' x/ _  I; Y" I* ]. o' ~- o
例如:115200bps、指每秒传送115200位。通信双方必须设置同样的同学速率才能正常通信
1 H, d5 s  q) x: D% g8 p
, S! h0 O* f; b. R% o注意:实际的数据没这么多,还包括起始位,结束位,校验位。& R. E1 I( e$ A( z, P7 p
7 Y& B& w" i! m5 Y
使用寄存器方法发送数据% ^- T2 t  }  Y+ H) N" v
; q( \- {. R% g$ N
位7TXE:发送数据寄存器为空(Transmit data register empty)9 G: |' y/ a8 r. l
2 L# [" P( y/ L) Z
当TDR寄存器的内容已传输到移位寄存器时,该位由硬件置1。如果 USART_CR1寄存器中 TXEIE位=1,则会生成中断。通过对 USART_DR寄存器执行写入操作将该位清零。8 B& A4 c% b  S! M/ ]& Y4 C
( I+ w6 d0 x6 h  S& f6 d- S, X: d
0:数据未传输到移位寄存器。( j/ T) m+ K3 x
" S8 i3 u% f& D, _/ _0 s" S6 F
1:数据传输到移位寄存器,也就是数据寄存器为空。2 m, p9 k3 z9 e- d
: }. a; k. k( M7 e" \( \
注意:单缓冲区发送期间使用该位。。! B5 |. O" V3 u1 J

8 X" i5 e, X/ i% r" h发送数据前一定要检查发送数据寄存器是否为空,为空才可以发送数据。( `( A% _2 H- e; _! y
& e: f5 I/ U% x* ?
void USART1_PutChar(uint8_t ch){
. x6 p3 g( A' O; ]5 a: @
. W/ r( H; b# K) p) ]6 i   while(!(USART1->SR & 1<<7));//等待TDR为空 - R9 F5 ]8 R+ o% ]& S
4 j$ g( e7 @% O0 w( X
   USART1->DR = ch;//直接将数据扔给数据寄存器; [2 h  P! Q# W9 P: A6 y2 [1 Y
+ W# n1 W& d/ X5 G) G" A* R3 {
}   - o; q* Y$ N# F3 @8 T" h$ {

+ z- E2 @# |5 b1 l//第7位为0,与出来的结果为0,非运算之后为1,继续while循环   
( N8 E, X4 ^1 t& Z+ x
4 A: z, |% t# |4 A6 H//第7位为1,与出来的结果为非0值,非运算之后为0,退出while循环   
. s% T% `* {" A3 N8 V! H3 g4 }; _" D9 }! ]
( Q& g# E- \# h  ^* k
使用寄存器方法接收数据- N( V8 w: O' x
& E% Y8 j" G* M# ^8 a) K8 u
位5 RXNE:读取数据寄存器不为空(Read data register not empty)8 e3 b5 x, |  I3 O7 |

. g" H0 q' I( Q" a当 RDR移位寄存器的内容已传输到USART_DR寄存器时,该位由硬件置1。如果USART_CR1寄存器中 RXNEIE= 1,则会生成中断。通过对 USART_DR寄存器执行读入操作将该位清零。RXNE标志也可以通过向该位写入零来清零。建议仅在多缓冲区通信时使用此清零序列。
% A9 D* X, }5 O( G! o( v: j0 ^# H
6 q  m& c: Z. o1 O0 o7 h5 D0:未接收到数据  ]8 q( e& _  f& L
1 \0 G3 g$ e: g" C9 E
1:已准备好读取接收到的数据,即读取数据寄存器不为空
" Q7 Y/ g+ A5 K; B, d% r, H: d% Y& V! j$ j1 T4 H
uint8_t USART1_GetChar(void){& G: {9 J" E4 w

) m0 I* [1 P& A/ Y    while(!(USART1->SR & 1<<5));//等待RDR不为空
0 W. w- S1 }0 [1 r3 E/ {
' ?) l, _' A( ]5 t% w2 ^    return USART1->DR;' m4 F5 P: Y" o; T3 o) `% n
1 s2 f/ M' V4 X; q
}% {( K! P/ W$ o8 U8 H8 c$ p' e
! m+ X0 g+ \' v% _) P) E
//第5位为0,没有得到数据,与出来的结果为0,非运算之后为1,继续while循环     
# C" ?% _8 f  W4 }# K. ?; W# ]1 s8 B0 \4 h( A% H
//第5位为1,数据寄存器不为空,与出来的结果为非0值,非运算之后为0,退出while循环     % M. [0 h4 H6 w  w

. }6 V- O5 K1 F8 Q/ iprintf的实现:
; x$ [5 W3 F: ~  e: M" B
1 J6 o, ]# W! J0 l0 ~
  1. int fputc(int ch,FILE *p){2 h' d; n" C: N) @, J0 E
  2.    while(!(USART1->SR & 1<<7));
    / L! O) M' y, p8 Z4 N$ x% \1 D
  3.    USART1->DR = ch;   2 [) a9 E& f( p$ j) K6 N
  4.    return ch;
    # ~) `' Z; x8 B, x" Y
  5. }//实现原理参考上文
复制代码

9 _3 {! N% S7 z( hSTM32 中断系统专题讲解
5 G; S6 \4 P- E0 u4 \- }2 n
8 p- I" S+ q5 M; V# G! }- Q2 x
中断能提高CPU的效率,同时能对突发事件做出实时处理。实现程序的并行化,实现嵌入式系统进程之间的切换。7 V: }. }$ y# }# Z5 h4 \& t

7 f2 v0 U( e  C, R% e7 L4 w4 Q 微信图片_20221031223926.png
  t) ^( g; f9 Z3 L* ]0 T+ b" I
5 Z6 w1 e5 O3 }8 z; [ 微信图片_20221031223924.png
; P4 ~: C3 ~4 J2 x( C7 e( m1 q! D- B  s* e) v: }$ q
NVIC(内嵌向量中断控制器:Nested Vectored Interrupt Controlle)的主要功能:
3 m2 t$ w7 P9 r/ }' p) S3 c4 b( B. M% u. _# C8 }
NVIC其实就是一个中断管理的部件,这个部件和其他外设没有区别,内部仍然是由一系列寄存器构成的,它的功能都可已通过寄存器的设置来实现。控制一个中断本质上就是操作寄存器。' F& E- t% l/ o. n) K

# o' }9 V+ B8 Z. r: Y. w# _( A9 ~1.中断管理8 j+ F9 e8 p7 t" F9 k2 H

2 V9 ?+ c1 c0 P. J9 x" ECortex-M4 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有256 级的可编程中断优先级设置。但 STM32F4 并没有使用 Cortex-M4 内核的全部东西,而是只用了它的一部分。Cortex-M4处理器中,每一个外部中断都可以被使能或者禁止,并且可以被设置为挂起状态或者清除状态。
% x0 O' H3 p1 A) @
: y$ L. T& _+ f% {9 F 微信图片_20221031223921.png * w8 p. F5 e& r' W+ N
! a5 m8 R' I' {0 z
注:9 d  C# J" D+ ~' W) [+ t

9 d9 e7 i9 m3 `) }- ?2 @- ?' MISER:使能中断,8位刚好控制256个中断的使能,有些中断是不可以被屏蔽的。+ A% l+ o  v( K: {3 Q! E

" i$ _1 B  V9 B6 aICER:清除中断使能,8位刚好控制256个中断的清除使能
/ f# N( I1 R. H% c  z7 S
% m4 T3 C7 P! l  H0 N& YISPR:   挂起中断,若中断产生但没有立即执行,它就会被挂起(产生的中断没有当前正在处理的中断的优先级高就会被挂起,但是当前中断处理完成后仍然会处理新的中断,总之,有中断就会被处理)
3 W# m  j( I6 ]3 U
  D: a  X  d  ], ~. hICPR:清除挂起,中断处理完成后应该清除挂起,表示已被处理完成,如果不清除挂起标志位,下一次CPU检查的时候发现该中断还在等待处理,就会重复触发,这不是我们想要的。也就是我们常说的清中断。
- }8 u% [( a/ Z% s8 t$ s, R; D* s9 c$ `
IABR:每个外部中断都有一个活跃状态位,当处理器正在处理时,该位会被置1$ U0 C/ K2 j9 K

5 U" p. h) ~& j, a# P% N) O8 t# _IP:用于设置中断的优先级,8位宽原则上可以设置256级优先级,但实际上STM32并没有使用到这么多,而是使用了高4位,低4位保留,共16个可编程优先级。
/ j' }# x- F- ?4 p2 f! R5 C2 [* f1 T: d+ \# c2 K8 W
3 y3 \, w+ @" S* N' y1 K2 z1 @! b
2.中断和异常向量表
5 c. W2 w$ N1 F& r# F+ l  @! b
1 x. F. ^" v% {1 F  w* RCortex-M4 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断。STM32F407实际上只使用了10个内部异常和82个外部中断。当异常或中断发生时,处理器会把PC设置为一个特定地址,这一地址就称为异常向量。每一类异常源都对应一个特定的入口地址,这些地址按照优先级排列以后就组成一张异常向量表。统一的处理方式需要软件去完成。采用向量表处理异常,M0处理器会从存储器的向量表中,自动定位异常的程序入口。从发生异常到异常的处理中间的时间被缩减。
4 H9 Y4 T4 T; y- s# Y
, E9 {' [6 U5 x0 f 微信图片_20221031223918.png ) {3 m# J! D/ j( }0 q3 A

( H) O$ i7 T4 g" H, _! y" g注:中断和异常的区别:
0 G' B8 i8 u  t  c. h* Q7 `2 b+ L2 H1 O$ n2 Z5 M. g
中断是微处理器外部发送的,通过中断通道送入处理器内部,一般是硬件引起的,比如串口接收中断,而异常通常是微处理器内部发生的,大多是软件引起的,比如除法出错异常,特权调用异常等待。不管是中断还是异常,微处理器通常都有相应的中断/异常服务程序。. U; H) U3 }- b+ \2 l5 i

" M% P7 \* d' W) j! b8 [. p! s3.支持嵌套中断:在执行一个中断服务程序的时候9 _6 v/ ]. W+ O2 j4 u
9 u6 j: `8 U& q, m, Q
当前处理器正在执行某一中断处理程序时,在执行期间有一优先级更高,更紧急的中断需要处理,会打断当前的中断处理程序,去执行高优先级中断的处理程序,执行完成后再继续当前的中断处理程序。
' l  z* c( P( Z6 o
2 F7 L% j9 c6 {" MSTM32有3个固定的优先级,都是负值,不能改变,值越小优先级越高,有16个可编程优先级,用4个bit位表示。
; x- {4 b! ?( O" D0 N
9 {, c5 Z2 e  s- W; R: t 微信图片_20221031223915.png : t$ n0 B) v! c3 z
. q5 s: j. d3 E9 B  U' A9 G- L0 S
在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx(在 F407 中,x=0...81,即82个外部中断)用来配置外部中断的优先级,IPR宽度为 8bit,原则上每个外部中断可配置的优先级为0~255,数值越小,优先级越高。但是绝大多数 CM4芯片都会精简设计,以致实际上支持的优先级数减少,在 F407 中,只使用了高 4bit。
3 \  q7 u( L  S" }4 W6 n7 Y
) {* N% f9 b- x! x+ N. I. h3 bSTM32还会把优先级分为两级,一级叫做主优先级,第二级叫做子优先级,主优先级又叫做抢占优先级,子优先级又叫做响应优先级。比较时首先比较主优先级,主优先级高则优先级一定高,主优先级相同时比较子优先级,响应优先级数值越小,则优先级越高。
7 i: k5 k9 D! A/ {% m1 f1 |  S3 |/ O; k
IPR中的高4 位,又分为抢占优先级和响应优先级。抢占优先级在前,响应优先级在后。而这两个优先级各占几个位又要根据SCB->AIRCR中的中断分组设置来决定。这里简单介绍一下STM32F4的中断分组:STM32F4 将中断分为 5 个组,组 0~4。该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。注意:工程开发中应当首先确定中断优先级分组,之后就不要再做修改了。. P3 v! U1 L" u% F% N' p! ~( T0 s

$ O0 z* t) H8 y9 ]7 | 微信图片_20221031223912.png ! _7 h% C1 d0 u8 o  j

8 ~6 E  D; c3 r: ^9 f3 i; G1 c+ Q7 z0 ^. ?# j
4.中断优先级总结
) \3 i% r6 g2 ~$ _1 R5 y
* i4 c" U$ Y/ y+ B- e
抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。 同一时刻发生的中断,优先处理优先级较高的中断。高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
+ x6 Z/ h. }9 Q/ Y# n
/ @, K. L; \( p9 {' }抢占优先级相同就看响应优先级,同样数值越小优先级越高。如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行。如果同时发生则优先处理编号较小(对10个内部异常和82个外部中断所对应的中断入口进行编号,如EXIT5-EXIT9合用一个中断入口,其编号为23,内部异常的中断入口编号均为负数)的那个,也就是异常向量表中排前面的先执行。2 _, H% J1 _7 p
# l4 O( d+ g. N! ~+ R6 ^
微信图片_20221031223908.png
3 b- C/ c2 r5 \- Z
7 F# q, c5 v: T, B: ^2 WEXTI,外部中断控制器6 x0 q! z  k0 y8 ~4 t# Z
& P/ Y% o- a+ G5 X
简单来说,EXTI就是管理GPIO产生的中断,是GPIO与NVIC连接的中介,由于GPIO管脚太多,需要一个统一管理,就是EXIT,而其他的片内外设如串口、定时器、I2C等产生的中断直接被NVIC管理。
$ U, c8 n& N* l3 m1 Q  B  e5 }- L; _- w% c, P+ b
微信图片_20221031223905.png , B3 U, x( w6 t* x& _2 ~5 I

. m0 s/ @) }+ C" m* V' s0 Y9 f! B/ D! L! H" t
EXTI共有16个通道选择器,每一个编号相同的GPIO管脚连接到编号相同的通道选择器中,每个通道选择器最终输出一根中断输入线,工作时,每一个选择器下同时只能有一个管脚被配置使用,具体配置哪一个管脚由该器件的外部中断配置控制器SYSCFG配置。( x' J" t' g7 T: |

5 \; F* P, e5 `EXTI0-EXTI4每一个都有单独的中断入口,而EXTI5-EXTI9合用一个中断入口,EXTI10-EXTI15也合用一个中断入口。! [2 ?* M+ c  C5 w! j, @
# M2 Z9 C, @! E8 D& P# K. J
一个SYSCFG只能配置4个通道选择器,因此需要4个SYSCFG。$ Z9 l# H- T4 d5 ~! p

& Y) _1 y+ s4 ?5 n/ i7 _$ { 微信图片_20221031223901.png 6 Q# |/ R8 [2 ]8 o7 o& u* S
* L5 A- g' }7 o
外部中断处理流程:
7 M7 v, S# P: V# n! q8 `- Y, r7 `" Y0 I: |/ {  j# z9 W4 a: k
微信图片_20221031223858.png 9 W6 y5 ^- j& F
" v- i$ x1 f# i$ k: M3 _; s
1:中断输入线,外部管脚产生的中断由此输入。可以是高电平,也可以是低电平,根据设定要求产生
7 A5 f4 ]4 o1 q/ q- H3 Q) V$ M* {- ?8 f
2:边沿检测电路会根据设定中断产生的方式检测电平,判断是否发生中断,如上升沿触发中断、下降沿触发中断或者上升沿和下降沿均可触发中断
, B5 T  A" i; g+ e3 n; y5 p8 Z
2 ]) P, }2 Q% L0 h4 r0 _/ g7 P3:如果2满足条件,会经过一个“或”门,“或”表示由外部输入的中断信号可以触发中断,内部的事件也可以产生中断,如定时器的更新事件等,不论外部内部,只有有一个就继续下去
, F0 A% f7 M% N. Q1 P$ C8 O
7 U$ V: t9 u2 f如果是电平,就向上走,如果是事件就向下走
; \+ I4 A" P8 h0 Z5 b" y# z! q6 m( {1 U+ J
4:通过一个“与” 门,与表示新来的中断已被挂起(中断产生还未处理)记录,且次此中断没有被屏蔽,二者同时满足后可交由NVIC处理,传送至内核进行响应。
5 ^% c! |0 q7 S6 z% Z2 E7 ?& m% i: ?, A6 U3 G( o

8 u9 Z6 L- t9 n按键中断实例
6 @' T: Z6 b# m6 e2 Q
% N! t/ B9 J; z6 V. H配置GPIO为外部中断模式,触发方式为下降沿触发,使能外部中断入口,设置优先级,包括主优先级和子优先级。
" ?1 Y& a9 X5 e8 o: V
$ O* s9 `& \  s& t, t% H' o在Cube MX中只要使能了中断入口肯定会生成对应的中断处理函数,这些处理函数被归纳到stm32f4xx_it.c当中,这里面的文件都是中断处理函数的入口(IRQHander,Interrupt ReQuest Hander,中断处理请求函数)
- v+ I" ~# D7 Y4 }9 q
& z/ `% _- E; S- O5 F9 p6 S在此文件的相应的函数入口处一步步追下去,就可以得到相应的中断处理代码。
% n& t  A$ e) I7 X3 X" s% C' a7 c' u7 M8 P
微信图片_20221031223854.png
: \# a( V6 J3 R: z
6 Z  W- }& M4 m 微信图片_20221031224527.png 5 R, f  j7 j. ]6 B+ _
/ `* _' a" S* f! @2 r6 _# h# [
这里的Callback函数一般是若函数,意味着用户可以对该函数进行重新编写完成自己的逻辑功能。将该函数复制到gpio.c中进行重新编写,复制时不需要复制函数前的__weak(弱函数典型的标记为函数前有__weak),因此在整个工程里就会有两个同名的函数,系统在编译的时候遇到两个同名函数时,就会自动忽略有__weak标记的函数,转而去编译用户自己编写的同名函数。2 l# C2 H9 R$ \5 h

* d' j. n, i, s2 j8 m3 L" x3 p
  1. //gpio.c
    - n- D, g% S5 j  ^
  2. 2 O' z( a+ z8 |% ]  h% Z8 |+ ?
  3. void HALGPIO EXTI_Callback (uint16_t GPIO_ Pin){' q$ t; g. p" W
  4.   if(GPIO_ Pin == GPIO_PIN_9){
    ) X! j, t0 Q. g0 e: o
  5.         HAL_Delay(20);//延时,用于消除抖动
    7 k$ s' A+ r. |; o5 ^6 Z5 z
  6.               if(HAL_GPIO_ReadPin(GPIOI,GPIO_PIN_9) == GPIO_PIN_RESET){
    ) M$ B: p1 j7 m$ X; l! P9 `
  7.               //读管脚为低电平表示确实被按下了
    9 q, e9 s8 H* f! G- J
  8.                         printf("KEY3 INT success\n");
    ; G4 r0 D. |3 N7 o+ n! J! R  u
  9.                }
    - i. o/ {8 ^& \
  10.    }
    : }. u, c* c% ^
  11. }
复制代码
  1. //main.c+ @( ?$ X4 K( [1 i

  2. $ h; }; ?4 ~/ {# T
  3. include "gpio.c"' p4 H) p& @5 T' P6 f5 J) P1 _
  4. include "usart.c" # b9 Q. ]2 I. N# E3 ?8 b$ {
  5. : }6 G/ j! g$ j- }* m9 s( U; Y
  6. main(){4 D1 m% F' h  e8 }
  7. MX_GPIO_Init();//对GPIO口时钟配置,中断优先级配置,触发方式等的初始化4 ?) A1 ^7 L0 M+ C% b
  8. MX_USART1_UART_Init();对USART1初始化配置 3 x  _: w- Q, l! ]
  9. while(){} * S0 n- i5 W: h$ u
  10. }
复制代码
' h/ X$ E+ Z8 k% Q) Z- k
HAL_Delay()函数是由Systick定时器实现的,也涉及到一个中断的处理过程,执行的是系统内部的定时器产生的异常处理函数,因此设置按键中断的优先级必须要比HAL_Delay()要小,否则HAL_Delay()函数无法抢占导致程序死掉。
) Z' H* q' K! G+ f/ N: w& j6 l- z, ?$ v; `
! D+ ]2 Q% Z6 l- W5 [/ Z* d
串口中断实例
' W% [- Z5 d: _+ a4 ~2 h配置串口管脚参数,使能串口中断入口,设置优先级分组,设置串口中断优先级。
1 B1 z8 a9 p+ Q6 v2 l+ O- t$ ~( D
微信图片_20221031223850.jpg , Y" I$ y0 j# q) O
3 b5 z8 E" D6 z( Y
微信图片_20221031223847.png % L# a$ P% {8 l; o' Q: ?& O
+ }8 b2 F4 ^8 T3 @% [; b0 Z
1.HAL_UART_IRQHandler ( &huart1);追进去有相当多类型的中断处理函数,选择串口在传输模式下发送完成的中断处理函数。& [9 C* \* V; X9 \/ }) ^0 c! l

7 f" s: Z" @/ x5 M* f2 i 微信图片_20221031223841.png 6 _/ ~0 i* h* g. n6 {- p: t  i

+ K/ ]2 S& q/ ]+ g/ H8 b% A 微信图片_20221031223838.png
4 V( F! r! N& c" x* o' w/ \$ m) O& M) u6 R- L% ?* \
微信图片_20221031223836.png
) _( x/ f7 B7 j$ m6 M4 A, B, k7 G, M* F: [9 q$ r" J
用户只需实现void HAL_UART_ TxCpltCallback (UART_HandleTypeDef *huart)的逻辑代码
! ~/ w: t/ }9 Y/ d5 f# n
; L9 M: h% G4 y7 {/ t1 o- x
4 C% ^* c8 [. N8 g2.HAL_UART_IRQHandler ( &huart1);追进去有相当多类型的中断处理函数,选择串口在接收模式下的中断处理函数。
6 B$ G: u9 M6 p" j) A/ [/ t$ p  O2 h+ F$ H4 A% S4 C1 u
微信图片_20221031223834.png
: x& U) z/ ^3 Y5 G$ z: g' r- X# g4 c7 O& a8 a  F
该中断处理函数仍然会调用一个回调函数。- M3 p2 u4 H; d: `; A3 h) Y0 R
% Y' j0 R! |* {4 Z
微信图片_20221031223831.png
& K3 I9 w( k+ g8 Y% h: \' s1 }! L2 b# J) u
微信图片_20221031223829.png & e* `$ P; B$ ]7 l! s, p8 d

8 a/ {9 N( i  C$ }9 g3 f' B2 D4 z, q/ p& K5 R
用户只需实现void HAL UART RxCpltCallback(UART HandleTypeDef *huart)的逻辑代码
2 C& c) A" v+ d/ p% p: K
) W# \5 g; k. Z串口中断有专门的串口接收中断函数和发送中断函数用来触发中断。! U3 ~+ X8 R$ y# u4 \
- p3 p3 U. K5 ]" S
HAL_UART_Transmit_IT();! `' R9 P, A; J  f7 m

, f$ K6 C' K+ z; X: [& b. z1 S$ {HAL_UART_Receive_IT ();
' d+ P- |% l! `7 H; T
, D! J, K, n5 S2 g; k  x
  1. //main.c 0 t) D" C% g  L

  2. 9 h# J/ E, p7 n
  3. include "gpio.c" * U: D# B. {* R, q2 c, W7 r
  4. include "usart.c"
    9 P2 f1 j" Y) _6 S9 ~: p- G! A
  5. uint8_t revbuff[2]={0};//接收缓冲区,定义全局为变量用于外部引用
    & \, |. r- j9 m$ L
  6. main(){ # ~2 Z3 l4 s0 a2 ~8 u
  7.   MX_GPIO_Init(); 8 r* t3 K) `) h3 t
  8.   MX_USART1_UART_Init();//对USART1初始化配置,中断优先级配置
    1 P* P' g" X3 P" ], v
  9.   HAL_UART_Transmit_IT(&usart1,(uint8_t *)"USART SEND\n",11);
    + B6 u( R/ U5 [* C/ \
  10.   //只有发送11个字符完成之后会触发发送完成中断,只触发一次
    , Q4 q: I  C  ]- ?6 S
  11.   HAL_UART_Receive_IT(&usart1,revbuff,2); * p. X3 ~  L: M( I8 d
  12.   //只有接收到2个数据后触发接收中断,只触发一次,若想多次触发,必须再次调用 5 Y2 Y3 h/ o# y( o1 z* j
  13.   while(){}
    - l/ a4 H1 C# j; K7 J4 b
  14. }
      X* `; a; E: v% P3 P0 L9 |. [
复制代码
  1. //usart.c
    ( i) G& w+ [' @' B

  2. 0 H* D: X4 W; a# `; s4 @9 n
  3. void HALUART_ TxCpltCallback (UART_HandleTypeDef *huart){   
    / N1 i6 K6 f% j
  4.   if(huart->Instance == USART1){        
    2 g; f! }4 W  ?, l: A" H
  5.   printf("UART SEND end\n");        * i. @! O! q' _/ c9 l( J% M0 I+ B
  6.   } + O2 z4 g9 k; u, r6 h/ U# _
  7. }
    ' b+ c; D& j# V) }/ V8 I
  8. extern uint8_t revbuff[2]={0};
    # `( S! J: e; K5 o$ I( R
  9. void HAL UART RxCpltCallback(UART HandleTypeDef *huart){   
    3 L  L, m9 O& X9 @
  10.   if(huart->Instance == USART1){       % H  B) M5 s: U  C6 y
  11.   printf("revbuff[0]=%x,revbuff[0]\n");          " C; p7 k  e: d; \' L- C
  12.   printf("revbuff[1]=%x,revbuff[1]\n");         
    , U8 J4 I$ c0 R! M$ |$ S" m
  13.   HAL_UART_Receive_IT(&usart1,revbuff,2);//用于多次触发接收中断   
    * c7 P, g+ G: E+ x: L
  14.   }     + A" U$ J; L2 Z# G( M, V& v
  15. }
复制代码
. _' F8 f4 L" j- @8 J
转载自:骆驼听海
2 H/ d' g& q% o" K% P# x
) y) k& D2 M, d
收藏 评论0 发布时间:2022-10-31 22:39

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版