STM32开发(13)----获取唯一设备标识符UID


前言

这一章节介绍如何获取STM32芯片中的唯一的ID号的两种方法。


一、什么是UID

在许多项目中,识别设备是必要的。从简单的设备描述到更复杂的设备,如 USB 串行命名、安全密钥、加密密钥等。有许多方法可以在微控制器中实现唯一ID。从简单的硬编码到固件中,单独刷新信息闪存到设备首次运行时随机生成。当谈到STM32 MCU时,还有另一种更简单,更清晰的可能性。在制造过程中,96位ID被编码到微控制器上。

所谓的唯一 ID 由 3 个部分组成:

  1. 晶圆上的 X 和 Y 坐标以 BCD 格式表示
  2. 批号
  3. 晶圆编号

对于 UID 访问,您只需在指定地址读取内存。请记住,不同的MCU线在内存中具有此数据扇区的不同位置。在这篇文章的最后,我将总结其中的大部分。

由于STM32是32位处理器,我们必须执行三次32位偏移的读出,以获得完整的92位ID。当然,我们只能使用其中的一部分。

例如,STM32F0处理器的起始地址是0x1FFFF7AC。因此,要读取完整的 UID,我们必须读取以下地址:

#define ID1 (*(unsigned long *)0x1FFFF7AC)
#define ID2 (*(unsigned long *)0x1FFFF7B0)
#define ID3 (*(unsigned long *)0x1FFFF7B4)

我们还可以将起始地址定义为数组的开头:

unsigned long *id = (unsigned long *)0x1FFFF7AC;
id[0]
id[1]
id[2]

由于STM32中的无符号长整型是一个32位变量,因此按索引访问数组会导致索引*32位偏移与起始地址。
您可以在下面找到大多数STM32微控制器的唯一ID起始地址。
在这里插入图片描述

二、实验过程

这里Cubex配置非必须,主要是为了打印出UID,所以可以使用前面实验的代码

1.CubeMx配置

选择芯片stm32f103c6t6,新建工程

在这里插入图片描述

设置时钟源,最小系统外部晶振8Mhz,作为外部高速HSE时钟源。由于没有外接外部低速晶振,这里低速时钟源选择旁路时钟源。

在这里插入图片描述

配置时钟树,这里使用官方推荐的配置

在这里插入图片描述

CubeMX配置如下:
在这里插入图片描述
USART1的参数配置如下,波特率115200,传输数据长度为8 Bit,奇偶检验无,停止位1.其他参数默认
在这里插入图片描述

SYS选项卡中Debug选项选择串口(这个选项可以设置,不会有影响)
在这里插入图片描述

Code Generator中设置只拷贝使用到的库,分离.c和.h文件

在这里插入图片描述

设置好项目名称和路径,点击GENERATE CODE即可,生成后使用keil5 IDE打开。

在这里插入图片描述

2.代码实现

在usart.c文件后面添加如下代码,代码中添加了#ifdef宏定义进行条件编译,如果使用GUNC编译,则PUTCHAR_PROTOTYPE 定义为int __io_putchar(int ch)函数,否则定义为int fputc(int ch, FILE *f)函数。

/* USER CODE BEGIN 0 */
#include "stdio.h"
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
 
  return ch;
}
/* USER CODE END 0 */

两种获取方式如下:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  
  /* USER CODE BEGIN 2 */
	//方法一
    uint32_t uid[3];
		
		uid[0] = (uint32_t)(READ_REG(*((uint32_t *)UID_BASE)));
		uid[1] = (uint32_t)(READ_REG(*((uint32_t *)(UID_BASE + 4U))));
		uid[2] = (uint32_t)(READ_REG(*((uint32_t *)(UID_BASE + 8U))));
    for(int8_t i = 0; i < 3; i++) {
        printf("%x \r\n", uid[i]);
    }   
		printf("===========================================\r\n"); 
		//方法二
    uint32_t *id = (uint32_t *)0x1FFFF7E8;
    for(int8_t i = 0; i < 3; i++) {
        printf("%x \r\n", *uint8_t *(id+i));
    }   
    printf("\r\n"); 
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}

3.实验结果

这里打印的结果大家可能不同,这是正常的,相同才不正常

46528358 
46528358 

总结

本章简单介绍了获取STM32唯一设备标识符UID的方法。

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
您好!对于STM32F407和ETH LWIP,我可以为您提供一些关于TCP client客户端的开发方面的信息。 首先,您需要使用STM32CubeMX软件来配置STM32F407的ETH和LWIP库。在STM32CubeMX中,您可以配置以太网接口和选择使用LWIP协议栈。确保在配置期间启用TCP/IP协议。 一旦配置完成并生成代码,您可以在生成的代码中找到LWIP库的API函数以及以太网驱动程序的相关函数。在这里,您将能够设置和管理TCP连接。 以下是一个简单的TCP客户端示例代码,用于向服务器发送数据: ```c #include "lwip/api.h" #define SERVER_IP "192.168.0.100" #define SERVER_PORT 8080 void tcp_client_task(void *arg) { struct netconn *conn; err_t err; // 创建TCP连接 conn = netconn_new(NETCONN_TCP); if (conn != NULL) { ip_addr_t server_addr; // 设置服务器IP地址和端口 IP4_ADDR(&server_addr, 192, 168, 0, 100); // 连接服务器 err = netconn_connect(conn, &server_addr, SERVER_PORT); if (err == ERR_OK) { const char *data = "Hello, server!"; struct netbuf *send_buf; // 创建发送数据包 send_buf = netbuf_new(); if (send_buf != NULL) { // 将数据添加到发送数据包中 netbuf_ref(send_buf, data, strlen(data)); // 发送数据包 err = netconn_send(conn, send_buf); // 释放发送数据包 netbuf_delete(send_buf); } } // 关闭连接 netconn_close(conn); netconn_delete(conn); } vTaskDelete(NULL); } ``` 请注意,此示例代码仅用于演示目的,您可能需要根据您的具体需求进行修改。另外,还要确保正确初始化LWIP协议栈和以太网接口。 希望这些信息对您有所帮助!如果您有任何进一步的问题,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LinfineEdu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值