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

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

[复制链接]
STMCU小助手 发布时间:2021-11-15 21:01
1.前言& C: ~3 q/ `+ \: X7 [
一直没有正经从完全无知开始去接触了解一款新的stm型号芯片。趁着这次11月份的新项目的开端需要用到stm32L0系列的单片机,搭载lora模块进行项目开发。这里开个系列博客记录下学习过程和调试过程。) N$ s+ B1 w/ l* P( i$ t4 g7 \

! R* E7 X$ U/ _! [* {$ l$ t6 s2.开发工具
# F  v7 P9 k5 J; B2 g2 n/ I以前做stm32的开发都是基本用的stm32F系列,代码结构也是套用的公司以前的模板。
' O# I4 U# L8 N8 w本次L0系列采用了st公司提供的一个新的(对笔者来说是新的,之前没用过,其实以前出来比较久了)开发代码生成工具-STMCubeMx。
, U4 C; y; u: }. ~+ Y9 a8 _9 l: B* V2 Q2 ^' L+ o' N
20191125101556652.png

2 d! ?1 d- T. J
. t3 {& X. u' T这个就是安装完后的工具图标。具体安装下载过程这里不做赘述,不了解的朋友可自行百度。
4 ^! S7 ]$ \% m; y1 e- P, y8 c  e5 l  t% F4 _- j9 I1 S$ X. l# c
3.简述开发工具生成的代码结构

* O- G5 m# K8 _$ H" s: MStm32CubeMx自动用户所选的IC型号以及需要用到的mcu资源,外设等自动生成相应的代码,生成的代码使用HAL库。其代码结构基本不需要进行什么修改(用户所选所设置皆正确的情况下),仅仅需要对一些HAL中的回调进行重写(如果你需要)。
3 p; k6 E% r/ ^/ Z7 n
20191125102002856.png
# b0 ~; o. g" F0 _
$ K  |. ?$ h: m& @( |
如图,代码编译工具还是使用keil软件,根据图中代码结构可以很清晰的看到整个代码分为8 a1 |) s: B; @/ Z% t$ u
Application和Drivers(附加CMSIS)8 \3 m! q+ r& S
Application里分为MDK-ARM和User。
1 ~  Y  p, i$ L$ _2 rMDK-ARM是代码工程的一个目录(基于编译,比如编译生成文件,中间文件.o之类的)
! e7 z+ t2 }+ t. @User是用户程序的主入口,如main.c等。
. U6 A1 f& F. A6 O需要注意的是User中还包含除main.c之外的两个文件,其中一个msp文件是工具自动生成的,后面分析。ic文件则是和中断回调相关的,这个相比都比较清楚。2 G9 A4 d5 @- T# O; X6 A

# g2 ~8 x1 e! n; p) M& V
20191125102405305.png

2 ~! b+ \  V( u% ~
: z# a3 O+ X: r* e0 L- |; v8 Z在Drivers中包含HAL_Driver和CMSIS.. I  e6 A7 W+ d1 d/ ^) o, {. f
CMSIS则是和内核相关的,如M0,M3等之类的内核。, B6 ?  O* R1 X( c4 p! u
HAL_Driver则是st给用户提供一些接口,如flash,rtc等的操作接口。
1 @; U$ U" u- A7 w0 |/ Q
# y' A3 d. q# f9 m, c* u3.1 main.c简析
' r* y1 V# C$ Z7 n  _最简单main.c里面的代码至少包括三部分:HAL_Init,SystemClock_Config,while(1);+ b: L& ~( g/ R8 L1 V7 R% e9 K

1 y/ q4 q& ^$ @
  1. int main(void)% _6 s; Q( O6 N. Y1 S  d9 o+ j
  2. {
    & A' A! k' ~( m3 a9 g2 d6 z7 L' O
  3.         HAL_Init(); //HAL库的初始化. t: v  @" K% [# r" }% u% B2 h
  4.         SystemClock_Config();//系统时钟配置初始化
    ' w# X! u; _: R  j7 O' R' \! P
  5.         while(1)//主程序的运行
    , D  l+ w  S" ^
  6.         {" t4 T7 a4 v: e1 r# b
  7.         }
    9 c5 D) V- C1 R! B, l% |1 T4 W
  8. }
复制代码
- n. w  c+ \- H9 G+ t$ Z
3.2 代码运行流程以及HAL库的调用结构
& a" U# M% X6 m3.2.1 HAL_Init()# y" Q1 k4 u6 ?
  1. /**
    # W8 }+ a# V# h" b5 u4 l
  2.   * @brief This function configures the Flash prefetch, Flash preread and Buffer cache,* M+ q' I$ b) ^8 f
  3.   *        Configures time base source, NVIC and Low level hardware+ V6 s7 {5 I" [& B2 D7 ~% x  b
  4.   * @note This function is called at the beginning of program after reset and before+ G6 q( ?) @; J" j3 K2 D8 O# P
  5.   *       the clock configuration
    / g% b1 i1 A* Z/ l
  6.   * @note The time base configuration is based on MSI clock when exiting from Reset.
    7 u8 U" K# m, O$ t
  7.   *       Once done, time base tick start incrementing., I$ P' W& O6 a1 n6 e' I
  8.   *        In the default implementation,Systick is used as source of time base.( e2 y2 k" Y7 @8 q
  9.   *        the tick variable is incremented each 1ms in its ISR.8 t& r* ?6 s! I' }2 s8 S
  10.   * @retval HAL status
    3 L* B& i! b2 ^% S: u! h
  11.   */( q! `, t$ S2 U# I- \$ R5 x
  12. HAL_StatusTypeDef HAL_Init(void)( o1 {5 W; c) t6 `/ E
  13. {
    : x( S' q2 u! H8 s+ N8 L) X
  14.   HAL_StatusTypeDef  status = HAL_OK;
    8 x% z! m. K0 d4 I( ^) a3 \
  15. 7 I9 V% E! K  L. j
  16.   /* Configure Buffer cache, Flash prefetch,  Flash preread */
      ], D+ u: A3 B- I, C
  17. #if (BUFFER_CACHE_DISABLE != 0)
    2 s4 a& Q( c. D( m: M
  18.   __HAL_FLASH_BUFFER_CACHE_DISABLE();
    + H) f' S7 E4 w
  19. #endif /* BUFFER_CACHE_DISABLE */! v, ~& L; k" j/ E+ J  i% ?, m
  20. / E# ~* B$ ]/ ?2 y
  21. #if (PREREAD_ENABLE != 0)
    * w" E0 f9 e, w* ~
  22.   __HAL_FLASH_PREREAD_BUFFER_ENABLE();, F, o( @" G) W9 R* ~) |) }- y
  23. #endif /* PREREAD_ENABLE */
    5 v& i" }. l! _3 x! h& W

  24. ) h6 D  n; M/ C* G$ v
  25. #if (PREFETCH_ENABLE != 0)
    & o6 q0 s7 B! n
  26.   __HAL_FLASH_PREFETCH_BUFFER_ENABLE();2 A7 a: q/ a( m3 d- i* Y% h
  27. #endif /* PREFETCH_ENABLE */
    5 U2 z: G& E8 r& v% {9 G4 N+ w
  28. 6 z+ W, j" X0 g; F& x3 O. y; G
  29.   /* Use SysTick as time base source and configure 1ms tick (default clock after Reset is MSI) */# s6 H: O8 u9 Y. P; H
  30.   if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)8 z$ U% l4 q! U: C+ }
  31.   {
    $ e7 n; x; c" x  ]2 d1 X8 j
  32.     status = HAL_ERROR;9 w: k4 t5 Y) R) a. t5 A
  33.   }, W3 S" q2 Q" s/ Z5 c- L! n0 [
  34.   else
    ! b  y) [1 [) V! r# o. g+ Y' m6 c
  35.   {& h0 v4 f" S1 F: E+ A0 u$ i! m
  36.     /* Init the low level hardware */
    ' P. T! k' U3 b
  37.     HAL_MspInit();6 m4 ?5 Z4 f! y( g# c. j
  38.   }' c' P" o$ ]& i; l3 V! u
  39. " t" C% G* M8 U+ j
  40.   /* Return function status */( A$ Z$ A0 f; z0 z! A4 m* h. }
  41.   return status;
    ' q2 J& a0 m: I& e
  42. }
复制代码

2 ^6 U* E; A7 Q: Q" i& e这里抽出2个关键函数:; |6 G* u- w* h/ R7 x% l' S( @$ \
HAL_InitTick,HAL_MspInit8 i, E+ k) Q4 \4 P  T  A% H
可以看到mcu一启动则调用HAL_InitTick,它的功能是使用SysTick作为时基源并配置1ms刻度(复位后的默认时钟为MSI)1 t$ Y2 O. ~, j6 u; B3 x0 q
如果该函数出错,则调用HAL_MspInit。2 Q9 a* G& |% v6 K/ F) `
这里提下该函数HAL_MspInit是被__weak修饰,叫做弱函数。被这种修饰的函数,通常需要用户自己去实现。实现的位置在哪里?还记得前面提到msp文件吗,就在那里面,当然你也可以写到你想写的地方,msp这个文件只是为了方面管理整个代码工程中的需要重写的函数。7 o8 Q# G/ x: Y4 T& _/ W, M
0 \6 N0 }, Q/ y+ r1 @1 a
3.2.2 SystemClock_Config()
# w; W* I& x. j4 T! m2 A
  1. /**
    3 k, G9 @) H' y% i7 }
  2.   * @brief System Clock Configuration
    4 p/ V+ D3 g: H, C( }; R  M
  3.   * @retval None
    ) |3 }8 |: x' M4 m  F) A
  4.   */0 b# N( _9 N7 e& j! d( y
  5. void SystemClock_Config(void)
    8 T+ N# y# s8 p: s  n% C
  6. {; `" {9 V$ c7 v# s' D2 K
  7.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};6 `; _% a, f+ `8 ?
  8.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};: r  B, v5 C. f) |! _# h

  9. 6 N9 u6 ]: b; s+ j
  10.   /** Configure the main internal regulator output voltage 1 n: I7 ]5 \: _+ J
  11.   */+ R3 f4 U/ K) b" b  [
  12.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);5 e6 t- Q) v' M; R4 c/ x1 ~
  13.   /** Initializes the CPU, AHB and APB busses clocks 8 m# f- {1 O3 C* C' ]
  14.   */
    ( t2 n0 f" @/ M7 I. E
  15.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    / u2 t/ o' D) `, y- B2 ^
  16.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;3 M! w3 w5 |1 X" }; T1 x0 z
  17.   RCC_OscInitStruct.MSICalibrationValue = 0;/ w! B- l! y, C2 j1 k2 {/ e3 b
  18.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    # Q2 t6 {/ O9 G9 ^
  19.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    6 b4 w. r( h; m/ N' q% ~- [  i/ O! i
  20.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    8 y& k* ^- @/ H% J) n- S8 T" P
  21.   {$ E9 ?! g" V: B2 [$ u6 ]& v
  22.     Error_Handler();/ N. ]7 w  A, ~
  23.   }$ B( A  `9 T3 k9 E4 x$ V
  24.   /** Initializes the CPU, AHB and APB busses clocks
    / D1 b0 Z) i0 C" h
  25.   */" `( W2 l: \! K: w
  26.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK% O8 n( ]( ~) p' w
  27.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;  {5 j% o2 J, v
  28.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
    , u+ r2 A) `  @# j" h3 f' F- W* p) j
  29.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;' s$ J1 l( D2 `' U, U$ e  ^
  30.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;$ \1 i0 m1 ]7 ^9 U# M1 ~* P% E' f
  31.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;& G' w3 q( v9 G, o( ^: \
  32. 2 o  G9 i0 E7 ?1 F
  33.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
    # c) A6 q+ J/ A
  34.   {
    4 f. S6 z6 j3 C: O6 J
  35.     Error_Handler();
    & O6 D0 f6 L* z/ C4 Z6 ~
  36.   }" |* n/ L# E1 @. R7 m6 D
  37. }
复制代码

+ X9 y) P' a6 ]2 X* V这里可以看到对于mcu的时钟选择配置,完全对上刚开始创建工程时的选择。先简单将这个函数分隔下:
# T% X+ V4 F# u( E- O0 i第一步:配置内部主稳压器的输出电压
2 e: U. K' m/ M. J1 J5 X第二步:初始化RCC振荡器。HAL_RCC_OscConfig,这里选择了MSI时钟,频率是4.194Mhz
0 o# y6 c" Y" z) s第三步:初始化CPU,AHB和APB总线时钟,HAL_RCC_ClockConfig+ a  m$ h3 l3 y1 C  q- P- i
如图;1 ^7 v+ U& R. W  {7 w8 P
- n# n4 O$ m1 Z
20191125103747351.png

3 T! B+ f/ G3 S: ^9 g( N; ?3 E% ?
: g# d9 f; T3 _1 w" G+ V# dps:关于STM32l0的时钟相关,可以参考datasheet。也可以往官网下载(英文版)
/ u8 I# Z. L; Y  _
9 ]; ^6 B  g& w% s5 G7 W9 _4 t( ]4 r* m4. 话说在前面系列9 Y3 s8 X0 R- g* l* o" K) N1 D" K
在使用St’m32CubeMx生成代码的时候,后期单独修改代码的时候,需要注意:
# P/ C7 E3 r, _% a- ]5 w9 T1.stm32l0xx_hal_conf.h 头文件指定了哪些文件是否参与编译,文件内是按模块声明的。$ B7 P: t0 U4 h0 j+ u
2.第一次调试测试单独功能的时候,可以使用工具生成单独模块的代码进行单独测试。
3 G& ?+ U+ R5 e+ L* [! E& Y6 d2 i: T1 J! J1 ^, p
  p  c' v" D. {- K; S* o

" H6 _9 v8 c' [% E4 ?
赞 收藏 评论0 发布时间:2021-11-15 21:01

举报

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