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

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

[复制链接]
STMCU小助手 发布时间:2021-11-15 21:01
1.前言" X; F1 y  @& x! A3 o/ V
一直没有正经从完全无知开始去接触了解一款新的stm型号芯片。趁着这次11月份的新项目的开端需要用到stm32L0系列的单片机,搭载lora模块进行项目开发。这里开个系列博客记录下学习过程和调试过程。7 J( A* |: b+ P! L2 i9 i* E+ _

! k2 k4 p* l! ^6 F; n! n2.开发工具
3 l+ O( F7 }/ \" W, j! o1 W以前做stm32的开发都是基本用的stm32F系列,代码结构也是套用的公司以前的模板。+ K3 r& f# z9 H- [& P" ]
本次L0系列采用了st公司提供的一个新的(对笔者来说是新的,之前没用过,其实以前出来比较久了)开发代码生成工具-STMCubeMx。
2 [( t0 i8 n1 v0 _4 ]3 g! U% l( P5 P3 T! d* x8 a$ w, ^2 [1 N
20191125101556652.png

# B* s6 j6 r$ N0 V' D9 }4 g+ k1 Q4 _7 p9 Y
这个就是安装完后的工具图标。具体安装下载过程这里不做赘述,不了解的朋友可自行百度。
4 E3 u- v: @, O0 D( |$ a, s) x0 \8 @2 R1 ^2 Q' N- F
3.简述开发工具生成的代码结构
5 d. _' R: x' `1 J8 o
Stm32CubeMx自动用户所选的IC型号以及需要用到的mcu资源,外设等自动生成相应的代码,生成的代码使用HAL库。其代码结构基本不需要进行什么修改(用户所选所设置皆正确的情况下),仅仅需要对一些HAL中的回调进行重写(如果你需要)。
6 @: r1 D# |+ R: C6 b
20191125102002856.png
# B& @6 C  |" a; S
) z4 \% J! I; G5 H
如图,代码编译工具还是使用keil软件,根据图中代码结构可以很清晰的看到整个代码分为* P+ d2 U: U: g  ~7 Q0 d
Application和Drivers(附加CMSIS)0 W! `$ e& d1 \5 R- M* n
Application里分为MDK-ARM和User。
! ?9 y4 O2 i' bMDK-ARM是代码工程的一个目录(基于编译,比如编译生成文件,中间文件.o之类的)- \' w& |% }" M$ c) o8 l9 U* ~
User是用户程序的主入口,如main.c等。  V. e2 r' g( T5 |; |4 S
需要注意的是User中还包含除main.c之外的两个文件,其中一个msp文件是工具自动生成的,后面分析。ic文件则是和中断回调相关的,这个相比都比较清楚。6 }8 o) K5 ~% \

0 ^2 J7 }" k/ N0 U# p% K
20191125102405305.png
" B/ _# {, X8 e1 x- J0 F3 u0 B

7 T3 r3 }1 ]' A) S在Drivers中包含HAL_Driver和CMSIS.
$ R7 D2 w5 _1 c: o! BCMSIS则是和内核相关的,如M0,M3等之类的内核。
+ d9 x* z: F, L4 K7 `: EHAL_Driver则是st给用户提供一些接口,如flash,rtc等的操作接口。# @# ~( d" v: |! e2 u6 z; g

9 h) k7 P/ p$ u( l* v! P6 B7 ~; X3.1 main.c简析
- f( u! O! t$ ~) P最简单main.c里面的代码至少包括三部分:HAL_Init,SystemClock_Config,while(1);
# b+ p! o, |- r; Z3 W) ^+ ~' |7 d! e! F  [9 K
  1. int main(void)
    4 L8 L9 {7 Y% Z5 _, j+ |; j: n3 w. V
  2. {) q- Z; [% X6 I" P5 k  q5 B4 r
  3.         HAL_Init(); //HAL库的初始化
    % y7 I1 O$ F* D: e4 t2 G
  4.         SystemClock_Config();//系统时钟配置初始化
    3 T) w- r/ o  f) T
  5.         while(1)//主程序的运行
    7 u3 r, n  c. j9 z" ~& ~7 s
  6.         {
    " [  E# K6 x# ?. O' x1 ]* b! n9 Q
  7.         }
    ! G7 Z) K/ j; N0 O. k1 u4 p
  8. }
复制代码
3 a" T  r/ L6 R# G
3.2 代码运行流程以及HAL库的调用结构5 m; R. u0 m0 D( t# x& H& J
3.2.1 HAL_Init()
3 a4 b% j1 ]& u
  1. /**
    $ |* h% z" r% \4 v* ?' ?2 L. f/ t5 u
  2.   * @brief This function configures the Flash prefetch, Flash preread and Buffer cache,/ r, W& E0 H( s+ S" m" e1 k
  3.   *        Configures time base source, NVIC and Low level hardware3 j; v+ I9 J' K# `
  4.   * @note This function is called at the beginning of program after reset and before
    9 Q- ]: x" f" e
  5.   *       the clock configuration1 n  e3 e  `+ z' [. u
  6.   * @note The time base configuration is based on MSI clock when exiting from Reset.4 T# F8 }6 n. K$ k4 |$ n
  7.   *       Once done, time base tick start incrementing.) u1 t  a7 C9 f, }0 K/ L8 v
  8.   *        In the default implementation,Systick is used as source of time base." I# M4 x% o/ q
  9.   *        the tick variable is incremented each 1ms in its ISR.
    - G7 m& H1 g, Z" J) N: B3 x
  10.   * @retval HAL status
    1 w3 b' `2 w8 p" E9 X, r
  11.   */
    ! ]( v6 H. Q* J1 v3 E# a0 _8 [
  12. HAL_StatusTypeDef HAL_Init(void)
    ( i- y% Y; J# t$ x
  13. {
    - F  {# s, Z- u  a4 N
  14.   HAL_StatusTypeDef  status = HAL_OK;
    + x2 l1 }, V6 h

  15. / `  Z4 h1 G* M0 r, K6 O8 o
  16.   /* Configure Buffer cache, Flash prefetch,  Flash preread */7 W$ ]; M7 I" S* s. d; b* P
  17. #if (BUFFER_CACHE_DISABLE != 0)
    1 h6 B8 S4 D/ v/ f- ^
  18.   __HAL_FLASH_BUFFER_CACHE_DISABLE();- ?: F( m; \& Y- a: }$ o" R5 H
  19. #endif /* BUFFER_CACHE_DISABLE */& y( A1 `$ D/ K2 c1 w0 v8 f

  20. 7 W$ P4 w9 q/ c; u  ~( g
  21. #if (PREREAD_ENABLE != 0)
    - D. ~" @; e! e$ s
  22.   __HAL_FLASH_PREREAD_BUFFER_ENABLE();3 l2 M! z: S- i0 @8 I7 u! ]8 s& W. @
  23. #endif /* PREREAD_ENABLE */, _* l& f  P/ n" n8 }' H

  24. 7 E+ v2 h6 {; }7 T; b+ \
  25. #if (PREFETCH_ENABLE != 0)6 f( V; g# s- |
  26.   __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
    9 z" u$ u" U& G9 p
  27. #endif /* PREFETCH_ENABLE */
    ; J0 T8 o: F; e& M& Y6 [4 S

  28. 5 @& E, A/ }4 B; o7 R
  29.   /* Use SysTick as time base source and configure 1ms tick (default clock after Reset is MSI) */
    ( t# E- v- H6 X" E% Y$ G3 E* C0 k
  30.   if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
    1 W5 L& s. [, W6 R
  31.   {
    6 ?8 C! Q: s9 C
  32.     status = HAL_ERROR;) Q6 `  R; ]: Q# D7 m
  33.   }" H9 z7 H3 F" ~0 K- u7 `# B
  34.   else! q: \4 _* w" D" }" t: V9 ^0 c8 ?
  35.   {
    ( Y) Y# r/ r1 e3 N
  36.     /* Init the low level hardware */, A" ^+ o/ h( \- F# l
  37.     HAL_MspInit();) T: O. o% P5 b# I& }
  38.   }
    ; h) ^6 y: y$ O1 f( D. O& q
  39.   p; q  h$ P* z$ d/ O
  40.   /* Return function status */2 g; z( f' m% Y& G* X
  41.   return status;7 B( q# _- |0 P: f+ F- o3 Y1 p  J2 L
  42. }
复制代码
5 G! a& Y6 _# x3 F$ {( \8 o
这里抽出2个关键函数:* @' V6 f% X$ R9 p6 G3 N
HAL_InitTick,HAL_MspInit
% y6 G; ?8 b% x* F9 V: A可以看到mcu一启动则调用HAL_InitTick,它的功能是使用SysTick作为时基源并配置1ms刻度(复位后的默认时钟为MSI)& G( D( ^2 \  @) W- A3 s  v& K
如果该函数出错,则调用HAL_MspInit。
* |3 a% C* w) w' D这里提下该函数HAL_MspInit是被__weak修饰,叫做弱函数。被这种修饰的函数,通常需要用户自己去实现。实现的位置在哪里?还记得前面提到msp文件吗,就在那里面,当然你也可以写到你想写的地方,msp这个文件只是为了方面管理整个代码工程中的需要重写的函数。
! l: f. t0 ~" o6 a
! [2 u2 E! t% i" G4 @1 {: ]: s; l3.2.2 SystemClock_Config()! D1 a! k) P5 h+ Z1 D
  1. /**
    7 R! o! _0 ~# `% x  w0 O
  2.   * @brief System Clock Configuration; @6 O8 J1 ~( [5 g% O" ^2 F
  3.   * @retval None
    % f0 v: A) v- H( E# V7 |
  4.   */7 S" {2 T/ h* Z( q, w% h% V
  5. void SystemClock_Config(void)* c! o) x  \; `
  6. {) P& n) m, e5 I/ [3 p
  7.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};1 S: y+ }% A( F
  8.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};+ @* z/ B6 }& h8 c5 p
  9. + x" ?6 J* L; ~1 P/ V7 p; P
  10.   /** Configure the main internal regulator output voltage % j( I* F: B* Y  s' ?! }
  11.   */
    2 v4 A9 \. q8 r3 ^1 Y
  12.   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);9 P4 Q  d: j/ `0 |" T" U, U4 l1 J
  13.   /** Initializes the CPU, AHB and APB busses clocks
    5 C, a: `/ C  A$ ]6 u6 f6 P
  14.   */$ C. x5 k# e7 \
  15.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;7 O5 _2 S$ I! R0 i+ v0 v
  16.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;+ U# H' j$ B$ y9 Z8 s, z
  17.   RCC_OscInitStruct.MSICalibrationValue = 0;7 l9 ~- _# N& K7 ^6 F% ?  w5 P
  18.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;5 }% W. i2 ^& M3 l% d
  19.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    * ^; m9 L  o% t  @, |
  20.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)2 [$ h! \' X% G
  21.   {
    # P! t+ u# L7 q- ]" N, v
  22.     Error_Handler();
    2 V. C9 ^9 p9 U# p$ g; p/ B+ m" c
  23.   }
    , ^, j, \9 o0 ?1 [: d7 F% t) F
  24.   /** Initializes the CPU, AHB and APB busses clocks
    2 ]$ S1 `  M7 P
  25.   */
    5 s0 Q) h* I1 |5 ~
  26.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    ' w/ h; D1 O# G  f& w
  27.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    6 v7 P8 d, V3 I9 X) b% Y
  28.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;" S- v( a5 d. w! b6 g
  29.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    # e" d3 B7 B  [
  30.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    : s: [! L6 \7 i
  31.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  h- Z* P/ s( d, R
  32. ; ?/ w! s2 ~! H! ?: Z4 W& t  z
  33.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
    7 e. O! l$ e# ?9 D- m7 ~& U
  34.   {+ G. z; G0 v' G3 V
  35.     Error_Handler();8 y( N8 _! G/ X- n) L  `; [0 J; C
  36.   }
    2 H; H8 B+ {& M
  37. }
复制代码
, R# ?, u  [+ ^% K
这里可以看到对于mcu的时钟选择配置,完全对上刚开始创建工程时的选择。先简单将这个函数分隔下:5 m2 k% v/ x8 x" z0 W- b# f
第一步:配置内部主稳压器的输出电压6 X6 F, l: Z1 J! n' f7 [
第二步:初始化RCC振荡器。HAL_RCC_OscConfig,这里选择了MSI时钟,频率是4.194Mhz
8 f. P, q3 c" a" w第三步:初始化CPU,AHB和APB总线时钟,HAL_RCC_ClockConfig
/ Y5 h- M& @- _- F如图;. N: c+ k8 ?% t6 g) s1 F& `
& G6 s; ?0 Q( F; o1 L; b
20191125103747351.png
9 I! w3 n' n! _
0 {: Y2 S8 N- e
ps:关于STM32l0的时钟相关,可以参考datasheet。也可以往官网下载(英文版)
4 `* P% j: j  h  U3 }9 [
4 u% M$ s, O# q% f  Z% V. L4. 话说在前面系列
$ C) M% t  d* H/ w( D  ~& t& [在使用St’m32CubeMx生成代码的时候,后期单独修改代码的时候,需要注意:
* @: K' z) E8 a1.stm32l0xx_hal_conf.h 头文件指定了哪些文件是否参与编译,文件内是按模块声明的。
4 h; V. F$ G, P  G  T5 k2.第一次调试测试单独功能的时候,可以使用工具生成单独模块的代码进行单独测试。5 \& Z/ o6 p3 S5 Q* g1 q3 N

* |$ Y7 n; |: Q/ g, v6 h( p, {/ e3 V' D+ k

& ^! b$ D0 D" C' F$ J8 m
收藏 评论0 发布时间:2021-11-15 21:01

举报

0个回答

所属标签

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