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

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

[复制链接]
STMCU小助手 发布时间:2021-11-15 21:01
1.前言% B+ C' q% s" k# J% N, l7 t
一直没有正经从完全无知开始去接触了解一款新的stm型号芯片。趁着这次11月份的新项目的开端需要用到stm32L0系列的单片机,搭载lora模块进行项目开发。这里开个系列博客记录下学习过程和调试过程。) K( P; t: U3 z, @# b

6 v6 B7 z& s" Y) u2.开发工具; z8 E  i, C8 m0 C; x. G% S/ X, w, ~9 t
以前做stm32的开发都是基本用的stm32F系列,代码结构也是套用的公司以前的模板。7 m- N; Z2 K5 t  ~+ q" L
本次L0系列采用了st公司提供的一个新的(对笔者来说是新的,之前没用过,其实以前出来比较久了)开发代码生成工具-STMCubeMx。$ W3 Z+ _" n4 O( T" x. c9 s

6 @2 k9 Q: V$ ]. o1 ]
20191125101556652.png

' w% y8 V3 o5 @. n# [% I( n; G7 J8 V* [& L9 T+ Y/ C  Q+ h9 K. a
这个就是安装完后的工具图标。具体安装下载过程这里不做赘述,不了解的朋友可自行百度。
: ]9 ]+ h0 {$ n) _3 j9 H, n, F) S. H1 V7 a2 l8 q
3.简述开发工具生成的代码结构

* m- _( E$ U! \3 RStm32CubeMx自动用户所选的IC型号以及需要用到的mcu资源,外设等自动生成相应的代码,生成的代码使用HAL库。其代码结构基本不需要进行什么修改(用户所选所设置皆正确的情况下),仅仅需要对一些HAL中的回调进行重写(如果你需要)。
9 o4 |( g2 Y1 ^6 C! @
20191125102002856.png

, j6 u9 K  I4 O6 W
8 N+ l/ {" m9 \/ Y3 k如图,代码编译工具还是使用keil软件,根据图中代码结构可以很清晰的看到整个代码分为4 L! _  J& `/ H9 T" A/ }; w5 N
Application和Drivers(附加CMSIS)- ?! Q; M7 E: q' x) L6 h/ q" X* K
Application里分为MDK-ARM和User。
/ N& U) e, T3 S3 X# ]MDK-ARM是代码工程的一个目录(基于编译,比如编译生成文件,中间文件.o之类的). Q* H* a% Y6 Z/ Z
User是用户程序的主入口,如main.c等。
1 o% c- l5 ]/ S5 B* Z需要注意的是User中还包含除main.c之外的两个文件,其中一个msp文件是工具自动生成的,后面分析。ic文件则是和中断回调相关的,这个相比都比较清楚。& z2 i. J# {5 |9 J" g* h: s
) m% X9 M# [4 r1 f2 I& }
20191125102405305.png
% W- G( |8 e( E2 d: E
% l) L* q2 i% V, u" z
在Drivers中包含HAL_Driver和CMSIS.' |0 S& M( K% M0 U" G
CMSIS则是和内核相关的,如M0,M3等之类的内核。
& T6 z' N& h4 P) v  m4 vHAL_Driver则是st给用户提供一些接口,如flash,rtc等的操作接口。! ]9 P' s( c! z, |5 V
3 A9 }1 J; G, I+ t, B5 j2 u
3.1 main.c简析1 c  o" n. H1 |% w2 w8 G' \
最简单main.c里面的代码至少包括三部分:HAL_Init,SystemClock_Config,while(1);
$ |0 o. p3 {8 Y3 ~
, N5 k* `3 E! d4 g# K# X
  1. int main(void)8 |( ?' c5 Y0 G# S8 P# }
  2. {
    . C1 \* h; N* E; l. x0 s
  3.         HAL_Init(); //HAL库的初始化
    # }5 }' K# V8 ^; X- I' t2 m& P
  4.         SystemClock_Config();//系统时钟配置初始化, y9 T' M0 t% |+ B& k" L  q
  5.         while(1)//主程序的运行6 {% ~* u% v4 {8 w% m
  6.         {
    % X) [" o4 u& G, c  E
  7.         }
    3 Y% C/ k+ J" K  ]0 ]' R( u
  8. }
复制代码
: r9 K+ O2 B2 \7 O4 _2 M( e
3.2 代码运行流程以及HAL库的调用结构
* G1 Z7 W% l( O1 F6 f+ g# U3.2.1 HAL_Init()
1 X2 Y8 ^* q) {$ V/ \
  1. /**
    $ f0 d1 a! V' E/ q- D
  2.   * @brief This function configures the Flash prefetch, Flash preread and Buffer cache,9 O) r9 N& `2 @( t4 M6 S! P1 @
  3.   *        Configures time base source, NVIC and Low level hardware6 Z# y+ m) M2 o+ ^# r9 V
  4.   * @note This function is called at the beginning of program after reset and before+ \  d& H. s: m* a
  5.   *       the clock configuration
    1 b9 _! C) r) ^& v
  6.   * @note The time base configuration is based on MSI clock when exiting from Reset.( _7 x2 P) \* l3 k
  7.   *       Once done, time base tick start incrementing., {% P9 s' C  N  o
  8.   *        In the default implementation,Systick is used as source of time base.2 h! ^) d+ o& L& R0 K( e9 u# R
  9.   *        the tick variable is incremented each 1ms in its ISR.3 A8 J/ q# k/ w" @) t3 g
  10.   * @retval HAL status
    # Y: M, T6 r( i/ A
  11.   */7 [" @, T: k5 L
  12. HAL_StatusTypeDef HAL_Init(void)# Z) b+ _8 F4 Y2 T0 w" n& F
  13. {# J0 [  J1 A6 Q* V
  14.   HAL_StatusTypeDef  status = HAL_OK;
    - M# v$ d  D# |  N8 ~$ g0 L

  15. . T* V; P3 s  Q  g6 }# s- r9 h
  16.   /* Configure Buffer cache, Flash prefetch,  Flash preread */
    , k8 \' |. x2 l8 X  j/ }7 S
  17. #if (BUFFER_CACHE_DISABLE != 0)
    - b- g% ~- f" Y0 J; l9 m
  18.   __HAL_FLASH_BUFFER_CACHE_DISABLE();
    + o, x, G# F' ^( A! a2 f
  19. #endif /* BUFFER_CACHE_DISABLE */
    : X% q1 e( _5 F0 u% s! N! H

  20. $ f4 Q- S: D6 B6 |4 k) d
  21. #if (PREREAD_ENABLE != 0)
    # g( ~) Q5 e, E' ^7 ~/ j' W
  22.   __HAL_FLASH_PREREAD_BUFFER_ENABLE();, R- D4 Z7 T5 U0 l0 M
  23. #endif /* PREREAD_ENABLE */
    2 h' e; w& w! A/ f6 L) X' k

  24. # P+ a# s1 c( W
  25. #if (PREFETCH_ENABLE != 0): Z$ z3 ^/ i# w
  26.   __HAL_FLASH_PREFETCH_BUFFER_ENABLE();8 n' R, Z/ o2 |3 y* Y. `# L
  27. #endif /* PREFETCH_ENABLE */4 b9 s5 |$ R0 u. b2 j; N4 a& L

  28. + H1 W0 f6 `" j3 g
  29.   /* Use SysTick as time base source and configure 1ms tick (default clock after Reset is MSI) */  k4 ^  b& I4 T& c* p
  30.   if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
    & Z  }+ i4 x: W
  31.   {7 h8 T! P2 v4 d5 V, C8 g5 d
  32.     status = HAL_ERROR;: @0 v+ Z3 I3 Z& C! {0 n$ {3 B9 f5 \
  33.   }
    : J- N- E& v  p: V( J
  34.   else3 D9 w, b8 \- [( L
  35.   {3 n7 k7 W9 F$ y8 B' ~& w
  36.     /* Init the low level hardware */
    $ x' p/ N0 D$ W2 b: l- x
  37.     HAL_MspInit();
    ( G+ a& g; S. q9 p2 O2 F
  38.   }
    $ |! C2 {& c, x

  39. 2 `, M* Z" X7 Y* D
  40.   /* Return function status */
    / E6 H4 \4 z5 }" M
  41.   return status;3 ^. x- q6 q2 B
  42. }
复制代码

- G$ t4 a3 m3 H7 w这里抽出2个关键函数:
1 y9 g: l6 L" ~0 [2 i4 NHAL_InitTick,HAL_MspInit
6 b$ l3 X, Y: n' T可以看到mcu一启动则调用HAL_InitTick,它的功能是使用SysTick作为时基源并配置1ms刻度(复位后的默认时钟为MSI)) D, Q/ M0 z; D+ L# {
如果该函数出错,则调用HAL_MspInit。
" s7 A9 p6 X4 A4 Y2 m* L$ z6 Z7 {( U这里提下该函数HAL_MspInit是被__weak修饰,叫做弱函数。被这种修饰的函数,通常需要用户自己去实现。实现的位置在哪里?还记得前面提到msp文件吗,就在那里面,当然你也可以写到你想写的地方,msp这个文件只是为了方面管理整个代码工程中的需要重写的函数。
* n# V6 \, W8 x6 c, M/ A. M: f( i: V' [" q" C  q
3.2.2 SystemClock_Config()
! j: {& Q+ f6 R. I
  1. /**. Y$ v! q" t9 r) H4 J4 a8 E% F
  2.   * @brief System Clock Configuration
      c3 A7 s8 z, p5 F  K. P8 q
  3.   * @retval None6 i9 h+ X# S! l- Q( n
  4.   */
    + c& R$ V9 W, q( j
  5. void SystemClock_Config(void)
    & V; L" j, L+ |$ ~! E9 K. }- k+ ]) s
  6. {
    " \; p6 b2 W8 o0 \
  7.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};* K9 a- x! ~2 f- v' A
  8.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};3 p) w0 t; S" p% c! @& |7 f3 t

  9. # }9 m3 P# B/ o( J0 B
  10.   /** Configure the main internal regulator output voltage
    6 o9 O: q0 n1 L/ p; f4 K7 \( w% H
  11.   */
    8 _5 o, U5 w7 C6 u! e
  12.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    4 ^# w% w' N2 s% ^2 h- ]# O
  13.   /** Initializes the CPU, AHB and APB busses clocks & ^% k, }6 W8 g7 }, P
  14.   */
    # g0 ^9 `  l+ C% E# \( \
  15.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;. g8 ?, q& t' a" N
  16.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    6 n( Z7 G/ @9 d! I
  17.   RCC_OscInitStruct.MSICalibrationValue = 0;
    ' U& S9 e+ b9 j
  18.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;( y8 I$ W7 F1 k0 o9 [6 C
  19.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;5 v9 X! J. q# I
  20.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    ( \  f- o9 v( \! \
  21.   {% \$ R( J) k/ D- p5 J; r8 a' _# }
  22.     Error_Handler();
    - L; B+ E% Z" _! W; Z" T
  23.   }
    7 T& ~1 n! ?& l% Q7 E6 _9 V
  24.   /** Initializes the CPU, AHB and APB busses clocks
    ) e3 i3 V3 h8 ]' t9 t' V& \% A
  25.   */! o3 V" c: W* k- P& D/ a/ V
  26.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    ' F$ e$ {. y& R6 l0 S, j" Q  e
  27.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    " R5 q1 G2 ^* K8 R, `
  28.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;; a* X) @" s$ {$ h' [
  29.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    & |+ W, s7 N) j
  30.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    / |5 X/ c( w" T' }6 h; F0 n
  31.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;3 P4 T' c; H1 [9 f% ^
  32. 6 W2 _* \. Z! x" `3 Z
  33.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
    4 T3 c# G8 r6 r* g4 J% `* q
  34.   {
    & w+ I$ C% n, M" G# L+ l/ v8 |- G
  35.     Error_Handler();
      ]! W# `: V- `1 J4 k7 ]" w  v5 e1 C
  36.   }0 o+ J1 M& A" ]3 S2 R. Z! S
  37. }
复制代码
# m7 C/ @" |3 w, X% W$ z; l
这里可以看到对于mcu的时钟选择配置,完全对上刚开始创建工程时的选择。先简单将这个函数分隔下:
: \! b/ {( R+ t第一步:配置内部主稳压器的输出电压# a9 B  o* I  o9 }
第二步:初始化RCC振荡器。HAL_RCC_OscConfig,这里选择了MSI时钟,频率是4.194Mhz+ U" Q9 F1 B3 [7 E5 n: {3 n
第三步:初始化CPU,AHB和APB总线时钟,HAL_RCC_ClockConfig* |/ F1 C7 y$ g+ U: Q1 @
如图;- @* l$ F4 q4 p4 _7 K

* ?" x4 w7 ?: o5 T: M* J: t
20191125103747351.png

1 o3 x( f( m$ V) ?( m( |. e# {  c3 Q1 o- i9 l. o6 I
ps:关于STM32l0的时钟相关,可以参考datasheet。也可以往官网下载(英文版)
: G' H& ~0 l, C: ]8 k9 Z* e" j5 t$ w- {4 }: ?( v% @
4. 话说在前面系列
  Y* k- }; s+ v9 w* E2 Z在使用St’m32CubeMx生成代码的时候,后期单独修改代码的时候,需要注意:0 I' m3 M& [  E6 J7 U* e% L
1.stm32l0xx_hal_conf.h 头文件指定了哪些文件是否参与编译,文件内是按模块声明的。# G+ R. h) ^# G% M: G/ U" Y
2.第一次调试测试单独功能的时候,可以使用工具生成单独模块的代码进行单独测试。! P! k' y  \$ y
# U0 z- P/ V0 |$ }9 a; ]" ]

$ D5 _! ^. z) L. J3 s# `- Z0 Q1 k
7 R) o# G- ~: _- w. O* ?; }. r
收藏 评论0 发布时间:2021-11-15 21:01

举报

0个回答

所属标签

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