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

【经验分享】STM32F103单片机读取芯片自身ID

[复制链接]
STMCU小助手 发布时间:2022-3-19 20:31
  每一个STM32单片机出厂的时候都有全球唯一的ID,当在数据安全性比较高的地方,需要对每一个接入系统的芯片进行身份验证,那么这个芯片自身的ID号就可以作为它的身份信息。
$ m0 l* ]6 P9 |% Z7 \- ~* k
6 ~+ Y" f& O% a4 \8 `/ V, Y产品唯一的身份标识非常适合:
& B& \* l% S  x8 v) G0 {( Y
$ `4 i( d, d& b3 _% ~' n用来作为序列号(例如USB字符序列号或者其他的终端应用)
; \1 a6 r# H/ D6 h用来作为密码,在编写闪存时,将此唯一标识与软件加解密算法结合使用,提高代码在闪存存储器内的安全性。
' w2 z* y6 m2 R0 M( |& U% g8 E5 u用来激活带安全机制的自举过程! W* E! C8 t. M
  96位的产品唯一身份标识所提供的参考号码对任意一个STM32微控制器,在任何情况下都是唯一的。用户在何种情况下,都不能修改这个身份标识。
) B5 S  C0 \9 @  [1 q1 z$ C$ |
$ Q& {8 S7 P2 O+ ?7 H8 `, t2 B6 U6 x0 q* n4 f
这个96位的产品唯一身份标识,按照用户不同的用法,可以以字节(8位)为单位读取,也可以以
; J# a" u8 P/ [  \" b) \半字(16位)或者全字(32位)读取。
! i: b; a+ T( t- f
2 K9 x6 f4 r) c# A$ A TCCR6_EQ2Q]W`LGB0[YY`BD.png
8 v0 @. ^( B7 ^  w5 V! p/ g" P8 B' N# t" q; }/ i* X1 }
T(FCKE]YS9SGM5$OE4Z6W`I.png ; F4 G) a6 T8 v* z
3 K/ p" q' T. ]4 k, E
) ~1 G; K& d. R" Q+ K* V! M' u
  不仅可以读取到芯片的ID,还能读出芯片的存储器容量。
3 e% \3 U6 |" w3 @2 U1 w
( g: G. f' f. I8 D$ a' | {1KDBWLIE@9}VB(6VA`5V}K.png
: F" }# R7 j6 {9 S( r) h& U' U% v( G1 f+ J1 E+ Z( x8 D) c
  芯片型号也同样可以读出来。  j) y4 ^1 c# P$ t; n
1 H) z; F; F7 e3 A, r5 r# l6 D" [
GSG3KSD[V%D@[BC)7YM3@QL.png $ F5 M2 F7 l6 m

2 @0 q/ `# q4 g5 H+ I: Z: [8 Q1 _  o 02$EDL`NO9{{`SAFBLT{4.png   h7 E& v. p$ z+ s# |( r& v: ~

) `' v) b) K% Z7 X' C$ T: U1 O下面就通过代码来读取这几个数据。
) a) J! c1 K. ~; y" Q
3 F$ E  m& L( u- H
  1. //读取芯片ID
    0 _! D% ~# A. i
  2. void GetChipID ( void )" r. n% b, A  ~7 i( ?
  3. {/ E% I4 O! Z4 i! F. x' E! e
  4.     u32 CpuID[3];                                                        //小端模式
    $ w: z8 w% k; P- h; J( t2 P: `/ H
  5.     CpuID[0] = * ( vu32 * ) ( 0x1ffff7e8 ); //高32位地址3 ^, W0 o- G  G8 ]# d/ ]% D% _
  6.     CpuID[1] = * ( vu32 * ) ( 0x1ffff7ec ); //中32位地址- A" t/ I7 S# \2 M, O7 Z
  7.     CpuID[2] = * ( vu32 * ) ( 0x1ffff7f0 ); //低32位地址
    ; q& }5 t. P( k
  8.     printf ( "此芯片唯一ID为:0x%x-%x-%x \r\n", CpuID[0], CpuID[1], CpuID[2] );
    % L( A2 h3 e* Q) t/ V/ d* i
  9. }& |- a/ N5 t' d, m
  10. //获取芯片Flash大小* N  V. y; Q2 e+ x- U5 ^1 L
  11. void GetFlashSize ( void )' f7 q- b6 R1 F2 }/ [
  12. {
    , r, A! j$ B% |! F+ Y
  13.     u16 stm32_Flash_Size;4 d2 t2 n( F1 `
  14.     stm32_Flash_Size = * ( u16 * ) ( 0x1FFFF7E0 ); //闪存容量寄存器. I6 p( R2 X1 P; f1 x) T  p8 V4 p
  15.     printf ( "芯片闪存容量大小为:%x \r\n", stm32_Flash_Size );+ I# E5 K0 Q% D0 b8 Z
  16. }
    4 J2 W, x; y$ i; K) `! U: U: S
  17. 5 X, z: |2 Q' V8 M
  18. //读取芯片型号- O' j' L3 s' S* V6 c- Y2 W! n
  19. void Main_Chip_Type(void)
    6 N- j3 q. o) w9 i& ]  k" Y
  20. {" @/ E) F$ _/ Q) S, T
  21.         u32 type;
    ( }% y3 G8 p/ l$ O0 |# r" d
  22.         type = *( unsigned  int * )( 0xE0042000 );        //MCU ID
    ; F1 X$ k1 |- G5 ~" p$ i
  23.         printf ( "芯片型号为:0x%x \r\n", type );
    # E$ Y9 O9 ~) p
  24. }) i! a( i+ T) h: }. @; \2 n0 [& W

  25. + G. a$ I, M( ~  \8 h; S& o* C( Z6 J
  26. int main ( void )
    4 d4 M% `/ n' Q( I6 i- n4 s
  27. {
    6 }8 }. Z9 N) i3 Q
  28.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 );
    : F' a9 W) e8 q2 b3 w) x! R
  29.     uart_init ( 115200 );6 e; F) X, U0 T0 m. [( S% a
  30.     delay_init();       //延时函数初始化( [. b. o2 O% U4 m+ I/ D  i3 q' K
  31.     LED_Init();         //初始化与LED连接的硬件接口7 ]$ A( L9 R$ B+ f2 k' O9 \$ p

  32. " ]( s& ]: x9 E8 d) Q' K
  33.     GetChipID();
    * J" O# P3 L9 m+ v2 i, D7 ?9 `
  34.     GetFlashSize();! t  w3 s. `" L) u- C& ?
  35.     Main_Chip_Type();
    # m; B8 _! h. h( J' ^; A8 }
  36. : R. \( X% L: v0 B# W6 `1 g
  37.     while(1);
    # K: h& R! |3 l. @
  38. }
复制代码
) u5 G( o% G4 g: B
通过串口打印出芯片的ID* J* I+ H" j+ Y8 Z) P/ F# V* J

; r; C3 o7 \+ u9 V此芯片唯一ID为: 0x66eff51-51578248-87074312 * P2 T" s; b6 x0 f& c: N
芯片闪存容量大小为:   40 + G/ E, C) j) B" r; @9 D* g, b$ z
芯片型号为:  0x20036410 : E) P* x+ E0 U  z
. M" a) ?$ ]4 W4 z
C6O6@4XG{N8D_{@9PS9((`I.png
) Q4 v# `6 s5 ?# w' o- l0 C9 D# [% E7 i  J) Z
然后通过单步调试,直接观察内存中的数据。
2 R1 t, o. e- T. ^; ]
& m! t' I: a# H- H% E3 g6 d$ \ ]TQO}J}_SX`SSE@{T`~OVBQ.png
. l; {" l* [! w$ ^9 ~5 y" b# n" }) H1 t2 s
然后观察内存中地址0x1FFFF7E0开始的数据6 ?+ x1 h. d8 R8 g) Y& R2 e# Q
& N# \# z. n4 k/ K- L
4)MQ[NI@B[Q1K5IFT{K17~D.png * w7 p$ |; F  s7 ^+ M' h2 L/ Y
5 t2 E1 E. E& f+ Q/ L' D8 `1 ~
可以看出0x1FFFF7E0开始的16位数据为0x0040换算为10进制数据就是64,说明当前用的芯片的容量是64K。接下来从0x1ffff7e8地址开始的12个字节,也就是96位存储的就是芯片的ID。内存中ID号存储为低位在前高位在后,而打印出来的数据是高位在前,低位在后。打印的前32位是 06 6e ff 51对应在内存中的存储顺序51应该是第一位,06是最后一位。' d* z0 N2 H) O1 F3 l' C' a
$ Y- m' \) m8 ?) _3 D) Y: K, s
最后在0xE0042000地址查看单片机的型号。
8 k8 y  @# z; K/ b$ I& _
, b. [# e/ L( y- f, t 92W40PWD8{H98F`UP(TAI@2.png 2 s& z, ]3 V- N5 V
" Y* V- |2 o, C2 a3 y; P5 O
低12位数据是 0x410,也就是设备编码为0x410,通过对比文档可以看出这个是中容量产品。高16位是0x2003,对比文档可以看出,这个是中容量产品,版本号为Y。
+ V% S3 ^; S1 i* |
$ h9 ~6 M3 p2 p7 O+ p4 P由于这些ID号都存储在指定的内存地址中,而系统没有提供专用的读取这些ID号的函数,所以读取数据的时候,只能通过指针的方式去读取,首先将数据加一级指针转换为地址,然后加二级指针,表示读取当前地址中存储的内容。这种操作方法在库函数的头文件中使用的比较多。比如在stm32f10x.h中就可以看到对GPIOA的定义。* Q! R, G" s* `% c* C7 ~! M6 y
: z7 F3 `, b( k7 z! k5 U9 v. P5 [
  1. #define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
    % J6 \* s" @: B. h* [3 M" ?, A0 h
  2. % |, C' v1 L) j
  3. #define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
    ' s2 V* j5 k/ f$ O7 k
  4. & t0 Z2 L2 M7 x- M$ N
  5. #define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)3 X% |: z7 X% ?- N* T
  6. 2 z+ O" L% a+ N( D  @/ `% D9 R$ L
  7. #define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
    " B8 s  n- @( l8 h2 v5 x

  8. 3 P' m# c- d) u( @5 V6 I. w
  9. typedef struct
    3 r0 U; z& [1 U1 S
  10. {' P( r- Q0 h4 h& @: r/ T/ J2 X5 P
  11.   __IO uint32_t CRL;
    1 |1 T; O4 }; Y  x$ e3 A
  12.   __IO uint32_t CRH;$ O. L  K6 y$ S( p6 t6 \4 W
  13.   __IO uint32_t IDR;
    " {+ Y7 |8 t% I; `
  14.   __IO uint32_t ODR;) P# m& Z+ U" o2 ?
  15.   __IO uint32_t BSRR;
    - Y5 N/ S% |. _, z0 y
  16.   __IO uint32_t BRR;
    # F8 K9 T. }0 r( b0 ]
  17.   __IO uint32_t LCKR;, W/ A* }/ F9 u
  18. } GPIO_TypeDef;
复制代码
  U* a) \5 [1 C# C- O- ]. d
将地址值逐个替换后为 #define GPIOA ((GPIO_TypeDef *) 0x4001 0800),相当于在 0x4001 0800 地址处定义了GPIOA的结构体。查阅芯片资料可知,GPIOA的起始地址就是0x4001 0800。
! R& C/ Q+ K. E# P9 Z4 H; X3 ^* q* {# ~0 X+ X8 k
WBSDS9BWYF(G[EBRZG}46.png
  F8 w4 i6 B: R& F' _2 c: s3 V; R3 S3 v2 f4 h3 d, Z9 P5 v' i. ^
这样操作GPIOA的的时候就和上面读取ID的方法是一样的,相当于直接读写对应地址中的值。. K& [) a! e9 N2 S7 j. W

: x+ g7 w6 P4 y* u" j8 V: ~& ]$ g: f
3 ~( B* _7 f; P  _/ c
赞 收藏 评论0 发布时间:2022-3-19 20:31

举报

0个回答

所属标签

相似技术帖

官网相关资源

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