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

【经验分享】STM32L0系列之【工程开始】

[复制链接]
STMCU小助手 发布时间:2021-11-15 21:01
1.前言
# [% s: D6 Q2 [! Y4 j一直没有正经从完全无知开始去接触了解一款新的stm型号芯片。趁着这次11月份的新项目的开端需要用到stm32L0系列的单片机,搭载lora模块进行项目开发。这里开个系列博客记录下学习过程和调试过程。
% }7 d# n/ B# c$ K+ z% K) s
$ o: t% l5 G! y2.开发工具4 l  E+ q( V, M2 A& C) w3 b9 g
以前做stm32的开发都是基本用的stm32F系列,代码结构也是套用的公司以前的模板。# w1 z4 C7 V" p. ~- \+ r% ~
本次L0系列采用了st公司提供的一个新的(对笔者来说是新的,之前没用过,其实以前出来比较久了)开发代码生成工具-STMCubeMx。1 I8 Z2 q" M, n8 ]6 E; Z

/ z7 C* E% g9 O; M  {/ i. A
20191125101556652.png
, h; i4 Y0 Q8 a7 D  b& P
9 r0 W, o! `5 e1 F0 M# F( o; t
这个就是安装完后的工具图标。具体安装下载过程这里不做赘述,不了解的朋友可自行百度。
  U  l- p) f% R5 O" a
5 N$ r. s0 J8 K4 Y( U3.简述开发工具生成的代码结构
' R  A! y8 b. B3 E8 L
Stm32CubeMx自动用户所选的IC型号以及需要用到的mcu资源,外设等自动生成相应的代码,生成的代码使用HAL库。其代码结构基本不需要进行什么修改(用户所选所设置皆正确的情况下),仅仅需要对一些HAL中的回调进行重写(如果你需要)。) s5 C: W* O5 I/ \- `  {
20191125102002856.png

+ l& z0 G, W5 {, }5 E2 Q
( k3 B) s4 G# X" E1 f如图,代码编译工具还是使用keil软件,根据图中代码结构可以很清晰的看到整个代码分为  j: l$ o9 d# q' B& B
Application和Drivers(附加CMSIS)
" h; U3 |2 T- h3 U. }Application里分为MDK-ARM和User。
2 t0 U6 L/ @7 r5 Q) b; nMDK-ARM是代码工程的一个目录(基于编译,比如编译生成文件,中间文件.o之类的)
2 I: b' d) w5 u# ?User是用户程序的主入口,如main.c等。
; s! `$ T, q9 m需要注意的是User中还包含除main.c之外的两个文件,其中一个msp文件是工具自动生成的,后面分析。ic文件则是和中断回调相关的,这个相比都比较清楚。
0 H; l& \0 V+ ?  v4 s3 a4 R' [* v% B4 I& X+ y8 C5 T! a
20191125102405305.png

" h; Y: C. T( w5 i( ^, _' U& z4 U
在Drivers中包含HAL_Driver和CMSIS.+ C' z4 W8 G; U  }% j
CMSIS则是和内核相关的,如M0,M3等之类的内核。8 k3 ?' u  i' j% T# i
HAL_Driver则是st给用户提供一些接口,如flash,rtc等的操作接口。$ b) ]3 h& @! F: o: ]7 U, V: l% \) V
1 \. `: Q  `& _2 D7 z+ }
3.1 main.c简析
9 R" m: C# Z  W7 R最简单main.c里面的代码至少包括三部分:HAL_Init,SystemClock_Config,while(1);
4 n5 N8 w: E8 X& Y) j+ g* j6 X
4 H/ b, t$ b3 \
  1. int main(void)$ [9 z1 G; ^& N  K, V3 o3 T7 M
  2. {1 z9 n0 q5 C5 {  R2 {5 c$ t6 I
  3.         HAL_Init(); //HAL库的初始化$ v3 c- g" G4 D( W1 M: v7 [/ {
  4.         SystemClock_Config();//系统时钟配置初始化
    " n7 A# a7 ^# s
  5.         while(1)//主程序的运行" c2 _. S3 _3 P" I4 I$ J; Q, d
  6.         {3 S7 j2 U$ n, C) W! q& H
  7.         }
    5 P* u3 `# P& S3 }2 G* ^" s* y
  8. }
复制代码

$ M! c" }) L' G0 E3.2 代码运行流程以及HAL库的调用结构
- _  q! T' U, Y  u3.2.1 HAL_Init()  n9 k  |8 V2 Z) d. I* u; a( R
  1. /**2 V$ i3 {2 H! c
  2.   * @brief This function configures the Flash prefetch, Flash preread and Buffer cache,
    7 y  z, X; J$ r" ]  j3 e3 k$ Z% [
  3.   *        Configures time base source, NVIC and Low level hardware
    + s$ m$ P/ l' K( x  @
  4.   * @note This function is called at the beginning of program after reset and before2 U: s! \6 G* ^8 }
  5.   *       the clock configuration! k4 l1 j/ l2 n1 T% D
  6.   * @note The time base configuration is based on MSI clock when exiting from Reset.
    7 U* _& y. F. Z2 i6 z( b) b
  7.   *       Once done, time base tick start incrementing.* K# D; V5 P% W. y- G% j
  8.   *        In the default implementation,Systick is used as source of time base.
    ; ?' W% i/ a& [& n* C4 M
  9.   *        the tick variable is incremented each 1ms in its ISR.
    & G% T" {: F' c. W/ v) ], ~" g1 n( v
  10.   * @retval HAL status
    2 ]# w3 f) {2 c9 d" T$ H1 q
  11.   */, g: l) q6 V6 m7 b
  12. HAL_StatusTypeDef HAL_Init(void)- M8 P+ o" m$ C! d
  13. {
    ! e5 Q. G$ G& b" [* M
  14.   HAL_StatusTypeDef  status = HAL_OK;
    7 k- ~# O' i: K# O

  15. - C( l9 }- M# F5 ^# A
  16.   /* Configure Buffer cache, Flash prefetch,  Flash preread */
    , M' H7 x- P/ T
  17. #if (BUFFER_CACHE_DISABLE != 0)6 b7 [9 f3 E7 s6 `* b' @' q
  18.   __HAL_FLASH_BUFFER_CACHE_DISABLE();
    1 O" `  B6 y4 H# G
  19. #endif /* BUFFER_CACHE_DISABLE */: f3 [7 F# i3 M2 x
  20. / h# @( u! E8 ^' d" }( J
  21. #if (PREREAD_ENABLE != 0)+ i; y  \  |# B5 C. s# Q
  22.   __HAL_FLASH_PREREAD_BUFFER_ENABLE();2 ]/ U& S$ {. ]( Z) O) p* P
  23. #endif /* PREREAD_ENABLE */
    : A9 l  W' r8 d$ Z% {

  24. . a( H+ x9 Z) h/ a; U# l8 b/ W# m
  25. #if (PREFETCH_ENABLE != 0)
    ) J3 D* e6 |' L% B1 h
  26.   __HAL_FLASH_PREFETCH_BUFFER_ENABLE();( [- M7 ?1 ?- s& d
  27. #endif /* PREFETCH_ENABLE */0 Y: Y  n# t* }9 w- _
  28. 6 [/ @6 C7 J/ w' `. f9 [& S- w
  29.   /* Use SysTick as time base source and configure 1ms tick (default clock after Reset is MSI) */  i+ d7 @) R8 P- s0 e
  30.   if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
    0 f$ M  J: u8 [9 r) c5 C8 s3 `& I" F% J
  31.   {; z3 p: X2 l- Z7 H; f$ F9 E
  32.     status = HAL_ERROR;
    2 |1 O8 l& g& _4 J
  33.   }
    ' Z2 u! T+ T, H3 T+ f3 F8 c
  34.   else
    . _2 E, i( X; [- v3 J  ~( r
  35.   {
    3 d: W& J% n# p! K& V/ @
  36.     /* Init the low level hardware */
    4 I2 w* u7 S  k7 T1 ^' q
  37.     HAL_MspInit();
    9 f, H* D+ z- }/ {" I
  38.   }
    * B2 H  N8 [1 k0 X
  39. ) \) ]6 c8 k. g! u: S- W# z$ S: w
  40.   /* Return function status */
    ' }/ I2 Q. Z) ]& ~# ^& k
  41.   return status;  O6 _8 Q+ I. Y) `$ G
  42. }
复制代码

) u* |. l" u: Y- [这里抽出2个关键函数:. _% X- t$ Y/ k
HAL_InitTick,HAL_MspInit6 W: L7 a+ p: |$ m" Q6 X
可以看到mcu一启动则调用HAL_InitTick,它的功能是使用SysTick作为时基源并配置1ms刻度(复位后的默认时钟为MSI)" J( N1 Y' q+ V* V" L0 y
如果该函数出错,则调用HAL_MspInit。
  ?6 ]) x, U  a* y" i" G9 {这里提下该函数HAL_MspInit是被__weak修饰,叫做弱函数。被这种修饰的函数,通常需要用户自己去实现。实现的位置在哪里?还记得前面提到msp文件吗,就在那里面,当然你也可以写到你想写的地方,msp这个文件只是为了方面管理整个代码工程中的需要重写的函数。" P' Z+ c3 ~) V/ ?

+ S/ f7 v/ k/ i. v$ q6 ~3 w3.2.2 SystemClock_Config()
' h. i5 D  o: o$ V- X, W
  1. /**
    4 L, y1 W+ V, J0 V6 }; {
  2.   * @brief System Clock Configuration6 u& T% ?; Z& x
  3.   * @retval None
    " ~8 ]3 G  M' r! {  I; ^
  4.   */
    ! {$ j9 o% G7 d, {7 i
  5. void SystemClock_Config(void)
    % `4 Z/ I3 `+ P% `
  6. {# z4 U' F; l6 U0 i+ T
  7.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};& w6 G7 T$ L# d- I% X) d' i
  8.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    5 h. B1 v( p: D! Y" C" G; n2 l$ D
  9. - U1 c7 d$ I! x" p
  10.   /** Configure the main internal regulator output voltage ) n0 D1 N, d6 c3 W2 L" Q
  11.   *// m- y. F% ~; ^" P# \3 O3 z  a1 ^. c
  12.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);! [# |' u1 i6 D: D; D
  13.   /** Initializes the CPU, AHB and APB busses clocks 8 O' F5 Y1 v$ H# E& s+ M4 K6 L( l$ E- q$ F
  14.   */: l' Z/ r; |1 k: Q& y
  15.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;5 s" E! l7 g5 R3 T5 p
  16.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    6 q' \% o: N8 c2 }2 e; Z6 b
  17.   RCC_OscInitStruct.MSICalibrationValue = 0;5 \6 ?: u: k2 }
  18.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;3 x# P* a2 x6 N7 A5 E# ?. L
  19.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;# S' }' x* F& R8 K- \
  20.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)0 u4 }' c4 P1 b5 v
  21.   {
    , ^( N$ b+ ~; o* G8 C) g( O
  22.     Error_Handler();  j# ^) Q) e1 {! |& j2 `
  23.   }" c/ E2 D8 v4 Y
  24.   /** Initializes the CPU, AHB and APB busses clocks
    ' ~$ }4 K- s8 N3 {- ~6 C3 Z( s
  25.   *// B  T1 @3 b' D) M  }
  26.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    " }; k2 Y7 Q- h& d5 G" [; q) G
  27.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;( Q2 {4 y7 s& v% L9 c$ N$ B9 R
  28.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;2 f9 r* d# u' `. C0 d3 {
  29.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    ; i3 l9 M% p7 |3 q! t8 l0 ?
  30.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    - X$ ?' J+ @& p/ D' f
  31.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;0 p; C+ O. n3 x) }- i9 K
  32. + F; n4 o3 C6 Z
  33.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
    ; {  X: a4 L; V: n# n! v1 A* ]
  34.   {+ w$ a4 |0 x9 \* K: f* _
  35.     Error_Handler();
    : \- C, `7 ^+ w. H* l# {) Y/ T
  36.   }$ k9 J! I0 ^) V2 [0 B) X
  37. }
复制代码

0 p- q' ?  [1 i9 I6 F8 Q这里可以看到对于mcu的时钟选择配置,完全对上刚开始创建工程时的选择。先简单将这个函数分隔下:! }' D2 ?  |, }: y# M& U
第一步:配置内部主稳压器的输出电压
0 {4 T+ {, t3 ?4 b第二步:初始化RCC振荡器。HAL_RCC_OscConfig,这里选择了MSI时钟,频率是4.194Mhz4 m* i3 D( _4 t2 _" K/ N/ |+ n5 m
第三步:初始化CPU,AHB和APB总线时钟,HAL_RCC_ClockConfig8 V. p8 x$ j, T9 A
如图;4 M  B# Q; @, `( r$ b% ?; _6 [: d
5 M" M9 r( ^  u5 b7 t- s
20191125103747351.png
9 {! c7 D1 _$ n( _

6 S3 e. Q. X5 n; kps:关于STM32l0的时钟相关,可以参考datasheet。也可以往官网下载(英文版)% m& ]5 \$ Y1 M+ O9 R0 R7 k1 N! T
6 Z' |0 E8 X' T: P2 p3 T6 O
4. 话说在前面系列
5 \0 q& p7 D9 H" f5 H在使用St’m32CubeMx生成代码的时候,后期单独修改代码的时候,需要注意:. d( h: R( ^. |6 s
1.stm32l0xx_hal_conf.h 头文件指定了哪些文件是否参与编译,文件内是按模块声明的。# V8 |; o/ v5 s& F. |% y
2.第一次调试测试单独功能的时候,可以使用工具生成单独模块的代码进行单独测试。$ P9 L, i: A) c  i0 ~5 T
7 K1 G% ^9 `7 p% a! L. ?# Q

  W; k9 r' l3 Y( Q/ _3 N! R( [  ^4 u# w/ t+ v
赞 收藏 评论0 发布时间:2021-11-15 21:01

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版