STM32

STM32

一.看门狗

1.独立看门狗

1.1介绍

c 复制代码
	在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造
成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会
造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测
的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称"看门狗"
(watchdog) 。独立看门狗工作在主程序之外,能够完全独立工作,它的时钟是专用的低速时钟(LSI),由
VDD 电压供电, 在停止模式和待机模式下仍能工作。
c 复制代码
	本质是一个 12 位的递减计数器,当计数器的值从某个值一直减到0的时候,系统就会产生一个复
位信号,即 IWDG_RESET 。
如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们
经常说的喂狗。
c 复制代码
	独立看门狗的时钟由独立的RC振荡器LSI提供,即使主时钟发生故障它仍然有效,非常独立。启用
IWDG后,LSI时钟会自动开启。LSI时钟频率并不精确,F1用40kHz。
	LSI经过一个8位的预分频器得到计数器时钟
c 复制代码
	重装载寄存器是一个12位的寄存器,用于存放重装载值,低12位有效,即最大值为4096,这个值
的大小决定着独立看门狗的溢出时间
c 复制代码
	键寄存器IWDG_KR可以说是独立看门狗的一个控制寄存器,主要有三种控制方式,往这个寄存器
写入下面三个不同的值有不同的效果。

1.2实验

c 复制代码
	开启独立看门狗,溢出时间为1秒,使用按键1进行喂狗。
	溢出时间计算:
	PSC=64,RLR=625
c 复制代码
#include "string.h"
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_IWDG_Init();
  MX_USART1_UART_Init();
  HAL_UART_Transmit(&huart1,(const unsigned char*)"程序启动...\n",strlen("程序启动...\n"),100);
  while (1)
  {
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){
        HAL_IWDG_Refresh(&hiwdg);
        HAL_Delay(50);
    }
  }
}

2.窗口看门狗

2.1介绍

c 复制代码
	窗口看门狗用于监测单片机程序运行时效是否精准,主要检测软件异常,一般用于需要精准检测
程序运行时间的场合。
	窗口看门狗的本质是一个能产生系统复位信号和提前唤醒中断的6位计数器
c 复制代码
产生复位条件:
	当递减计数器值从 0x40 减到 0x3F 时复位(即T6位跳变到0)
	计数器的值大于 W[6:0] 值时喂狗会复位。
产生中断条件:
	当递减计数器等于 0x40 时可产生提前唤醒中断 (EWI)。


在窗口期内重装载计数器的值,防止复位,也就是所谓的喂狗。





c 复制代码
	Tout是WWDG超时时间(没喂狗)
	Fwwdg是WWDG的时钟源频率(最大36M)
	4096是WWDG固定的预分频系数
	2^WDGTB是WWDG_CFR寄存器设置的预分频系数值
	T[5:0]是WWDG计数器低6位,最多63

2.2实验

c 复制代码
	开启窗口看门狗,计数器值设置为 0X7F ,窗口值设置为 0X5F ,预分频系数为 8 。程序启动时点
亮 LED1 ,300ms 后熄灭。在提前唤醒中断服务函数进行喂狗,同时翻转 LED2 状态。
c 复制代码
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
    HAL_WWDG_Refresh(hwwdg);
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
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();
  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
  HAL_Delay(300);
  MX_WWDG_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
      HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
      HAL_Delay(40);;
      
  }
  /* USER CODE END 3 */
}

3.总结

二.DMA

1.介绍

c 复制代码
数据搬运工-代替cpu搬运数据
代替 CPU 搬运数据,为 CPU 减负。
1. 数据搬运的工作比较耗时间;
2. 数据搬运工作时效要求高(有数据来就要搬走);
3. 没啥技术含量(CPU 节约出来的时间可以处理更重要的事)。
c 复制代码
搬运存储器、外设数据
	这里的外设指的是spi、usart、iic、adc 等基于APB1 、APB2或AHB时钟的外设,
	而这里的存储器包括自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问地源或者目的
c 复制代码
三种搬运方式:
存储器→存储器(例如:复制某特别大的数据buf)
存储器→外设 (例如:将某数据buf写入串口TDR寄存器)
外设→存储器 (例如:将串口RDR寄存器写入某数据buf)



c 复制代码
	STM32F103有2个 DMA 控制器,
	DMA1有7个通道,DMA2有5个通道。
	一个通道每次只能搬运一个外设的数据!! 如果同时有多个外设的 DMA 请求,则按照优先级进行响应。


c 复制代码
DMA及通道优先级
优先级管理采用软件+硬件:
	软件: 每个通道的优先级可以在DMA_CCRx寄存器中设置,有4个等级最高级>高级>中级>低级
	硬件: 如果2个请求,它们的软件优先级相同,则较低编号的通道比较高编号的通道有较高的优先权。
	比如:如果软件优先级相同,通道2优先于通道4

DMA传输方式
	DMA_Mode_Normal(正常模式)
		一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次
	DMA_Mode_Circular(循环传输模式)
		当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。 也就是多次传输模式
	指针递增模式
		外设和存储器指针在每次传输后可以自动向后递增或保持常量。
		当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值。

2.实验

c 复制代码
HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)

参数一:DMA_HandleTypeDef *hdma,DMA通道句柄
参数二:uint32_t SrcAddress,源内存地址
参数三:uint32_t DstAddress,目标内存地址
参数四:uint32_t DataLength,传输数据长度。注意:需要乘以sizeof(uint32_t)
返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)

__HAL_DMA_GET_FLAG
#define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__) (DMA1->ISR & (__FLAG__))
参数一:HANDLE,DMA通道句柄
参数二:FLAG,数据传输标志。DMA_FLAG_TCx表示数据传输完成标志
返回值:FLAG的值(SET/RESET)

2.1内存搬运到内存

c 复制代码
	实验:
		使用DMA的方式将数组A的内容复制到数组B中,搬运完之后将数组B的内容打印到屏幕。
	代码:
		1. 开启数据传输
		2. 等待数据传输完成
		3. 打印数组内容
c 复制代码
#define BUF_SIZE 16
// 源数组
uint32_t srcBuf[BUF_SIZE] = {
	0x00000000,0x11111111,0x22222222,0x33333333,
	0x44444444,0x55555555,0x66666666,0x77777777,
	0x88888888,0x99999999,0xAAAAAAAA,0xBBBBBBBB,
	0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF
};
// 目标数组
uint32_t desBuf[BUF_SIZE];
int fputc(int ch, FILE *f)
{
	unsigned char temp[1]={ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);
	return ch;
}
main函数里:
// 开启数据传输
HAL_DMA_Start(&hdma_memtomem_dma1_channel1,
(uint32_t)srcBuf, (uint32_t)desBuf, sizeof(uint32_t) * BUF_SIZE);
// 等待数据传输完成
while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1, DMA_FLAG_TC1) == RESET);
// 打印数组内容
for (i = 0; i < BUF_SIZE; i++)
	printf("Buf[%d] = %X\r\n", i, desBuf[i]);

2.1内存搬运到外设

c 复制代码
	使用DMA的方式将内存数据搬运到串口1发送寄存器,同时闪烁LED1。
c 复制代码
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData,uint16_t Size)

参数一:UART_HandleTypeDef *huart,串口句柄
参数二:uint8_t *pData,待发送数据首地址
参数三:uint16_t Size,待发送数据长度
返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)
c 复制代码
int main(void)
{
  /* USER CODE BEGIN 1 */
    int i = 0;
  /* 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 */
  for(i=0;i<BUF_SIZE;i++){
    sendBuf[i] = 'A';
  }
  //将数据发送到串口
  HAL_UART_Transmit_DMA(&huart1,sendBuf,BUF_SIZE);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    
    /* USER CODE BEGIN 3 */
      HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
      HAL_Delay(100);
  }
  /* USER CODE END 3 */
}

2.1外设搬运到内存

c 复制代码
使用DMA的方式将串口接收缓存寄存器的值搬运到内存中,同时闪烁LED1。
c 复制代码
#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((((__INTERRUPT__) >> 28U)
== UART_CR1_REG_INDEX)? ((__HANDLE__)->Instance->CR1 |= ((__INTERRUPT__) &
UART_IT_MASK)): \
(((__INTERRUPT__) >> 28U)
== UART_CR2_REG_INDEX)? ((__HANDLE__)->Instance->CR2 |= ((__INTERRUPT__) &
UART_IT_MASK)): \
((__HANDLE__)->Instance-
>CR3 |= ((__INTERRUPT__) & UART_IT_MASK)))

参数一:HANDLE,串口句柄
参数二:INTERRUPT,需要使能的中断
c 复制代码
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData,uint16_t Size)
参数一:UART_HandleTypeDef *huart,串口句柄
参数二:uint8_t *pData,接收缓存首地址
参数三:uint16_t Size,接收缓存长度
返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)
c 复制代码
#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->SR &
(__FLAG__)) == (__FLAG__))

参数一:HANDLE,串口句柄
参数二:FLAG,需要查看的FLAG
返回值:FLAG的值
c 复制代码
#define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__) __HAL_UART_CLEAR_PEFLAG(__HANDLE__)
参数一:HANDLE,串口句柄
返回值:无
c 复制代码
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
参数一:UART_HandleTypeDef *huart,串口句柄
返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)
c 复制代码
#define __HAL_DMA_GET_COUNTER(__HANDLE__) ((__HANDLE__)->Instance->CNDTR)
参数一:HANDLE,串口句柄
返回值:未传输数据大小
c 复制代码
如何判断串口接收是否完成?如何知道串口收到数据的长度?
	使用串口空闲中断(IDLE)!
	串口空闲时,触发空闲中断;
	空闲中断标志位由硬件置1,软件清零
	利用串口空闲中断,可以用如下流程实现DMA控制的任意长数据接收:
	1. 使能IDLE空闲中断;
	2. 使能DMA接收中断;
	3. 收到串口接收中断,DMA不断传输数据到缓冲区;
	4. 一帧数据接收完毕,串口暂时空闲,触发串口空闲中断;
	5. 在中断服务函数中,清除中断标志位,关闭DMA传输(防止干扰);
	6. 计算刚才收到了多少个字节的数据。
	7. 处理缓冲区数据,开启DMA传输,开始下一帧接收
c 复制代码
//main.c
uint8_t rcvBuff[BUF_SIZE];  //接收数据缓存数组
uint8_t rcvLen = 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 */
  __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);   //使能空闲中断
  HAL_UART_Receive_DMA(&huart1,rcvBuff,rcvLen); //使能DMA接收中断
  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
      HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
      HAL_Delay(100);
  }
  /* USER CODE END 3 */
}
c 复制代码
//stm32f1xx_it.c
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
  if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) == SET){   //判断IDLE标志位
    __HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除标志位
    HAL_UART_DMAStop(&huart1);   //停止dma传输防止干扰
    uint8_t temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);  //获取没有发送完的数据
    rcvLen = BUF_SIZE - temp;   //计算已经发送的数据
    HAL_UART_Transmit_DMA(&huart1,rcvBuff,rcvLen);  //发送数据
    HAL_UART_Receive_DMA(&huart1,rcvBuff,BUF_SIZE);
  }
  /* USER CODE END USART1_IRQn 1 */
}

三.ADC

1.介绍

c 复制代码
	模拟/数字转换器
c 复制代码
ADC特性
	12位精度下转换速度可高达1MHZ
	供电电压:V SSA :0V,V DDA :2.4V~3.6V
	ADC输入范围:VREF- ≤ VIN ≤ VREF+
	采样时间可配置,采样时间越长, 转换结果相对越准确, 但是转换速度就越慢
	ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中
c 复制代码
ADC通道
	总共2个ADC(ADC1,ADC2),每个ADC有18个转换通道: 16个外部通道、 2个内部通道(温度传感器、内部参考电压)
	外部的16个通道在转换时又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路。
	规则通道:正常排队的人
	注入通道:有特权的人
c 复制代码
ADC转换顺序
	每个ADC只有一个数据寄存器,16个通道一起共用这个寄存器,所以需要指定规则转换通道的转
换顺序。
	规则通道中的转换顺序由三个寄存器控制:SQR1、SQR2、SQR3,它们都是32位寄存器。SQR寄
存器控制着转换通道的数目和转换顺序,只要在对应的寄存器位SQx中写入相应的通道,这个通
道就是第x个转换
c 复制代码
	和规则通道转换顺序的控制一样,注入通道的转换也是通过注入寄存器来控制,只不过只有一个JSQR寄存器来控制,控制关系如下:
c 复制代码
	注入序列的转换顺序是从JSQx[ 4 : 0 ](x=4-JL[1:0])开始。只有当JL=4的时候,注入通道的转换顺序才会按照JSQ1、JSQ2、JSQ3、JSQ4的顺序执行。
c 复制代码
ADC触发方式
	1. 通过向控制寄存器ADC-CR2的ADON位写1来开启转换,写0停止转换。
	2. 也可以通过外部事件(如定时器)进行转换。
c 复制代码
ADC转化时间
	ADC是挂载在APB2总线(PCLK2)上的,经过分频器得到ADC时钟(ADCCLK),最高 14 MHz。
	转换时间=采样时间+12.5个周期
	12.5个周期是固定的,一般我们设置 PCLK2=72M,经过 ADC 预分频器能分频到最大的时钟只能是 12M,采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us
c 复制代码
ADC转换模式
扫描模式
	关闭扫描模式:只转换ADC_SQRx或ADC_JSQR选中的第一个通道
	打开扫描模式:扫描所有被ADC_SQRx或ADC_JSQR选中的所有通道
单次转换/连续转换
	单次转换:只转换一次
	连续转换:转换一次之后,立马进行下一次转换

2.实验

c 复制代码
使用ADC读取烟雾传感器的值
c 复制代码
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      HAL_ADC_Start(&hadc1);    //启动ADC1
      HAL_ADC_PollForConversion(&hadc1,50); //等待ADC转换完成
      uint32_t somkeValue = HAL_ADC_GetValue(&hadc1);
      //printf("somkeValue = %d\r\n", somkeValue);
      printf("smoke_value = %f\r\n", 3.3/4096 * smoke_value);
      HAL_Delay(500);
  }

三.IIC

c 复制代码
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c,
					uint16_t DevAddress,
					uint16_t MemAddress,
					uint16_t MemAddSize,
					uint8_t *pData,
					uint16_t Size,
					uint32_t Timeout)
参数一:I2C_HandleTypeDef *hi2c,I2C设备句柄
参数二:uint16_t DevAddress,目标器件的地址,七位地址必须左对齐
参数三:uint16_t MemAddress,目标器件的目标寄存器地址
参数四:uint16_t MemAddSize,目标器件内部寄存器地址数据长度
参数五:uint8_t *pData,待写的数据首地址
参数六:uint16_t Size,待写的数据长度
参数七:uint32_t Timeout,超时时间
返回值:HAL_StatusTypeDef,HAL状态(OK,busy,ERROR,TIMEOUT)
c 复制代码
向OLED写命令的封装
void Oled_Write_Cmd(uint8_t dataCmd)
{
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT,&dataCmd, 1, 0xff);
}
c 复制代码
向OLED写数据的封装:
void Oled_Write_Data(uint8_t dataData)
{
HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,&dataData, 1, 0xff);
}

四.SPI

1.介绍

c 复制代码
	SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,
	并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,越来越多的芯片集成了这种通信协议,比如AT91RM9200 。
c 复制代码
SPI 包含 4 条总线,SPI 总线包含 4 条总线,分别为SS、SCK、MOSI、MISO。它们的作用介绍如
下 :
	(1) MISO -- Master Input Slave Output,主设备数据输入,从设备数据输出 
	(2) MOSI -- Master Output Slave Input,主设备数据输出,从设备数据输入 
	(3) SCK -- Serial Clock,时钟信号,由主设备产生 
	(4) CS -- Chip Select,片选信号,由主设备控制
c 复制代码
工作原理
c 复制代码
SPI工作模式
时钟极性(CPOL):
	没有数据传输时时钟线的空闲状态电平 
	0:SCK在空闲状态保持低电平 
	1:SCK在空闲状态保持高电平
时钟相位(CPHA):
	时钟线在第几个时钟边沿采样数据 
	0:SCK的第一(奇数)边沿进行数据位采样,数据在第一个时钟边沿被锁存 
	1:SCK的第二(偶数)边沿进行数据位采样,数据在第二个时钟边沿被锁存
c 复制代码
模式0和模式3时序图
模式0:橙色的线处采样
模式3:橙色的线处采样

2.W25Q128

c 复制代码
	W25Q128 是华邦公司推出的一款 SPI 接口的 NOR Flash 芯片,其存储空间为 128 Mbit,相当于16M 字节。
	Flash 是常用的用于储存数据的半导体器件,它具有容量大,可重复擦写、按"扇区/块"擦除、掉电后数据可继续保存的特性。
	Flash 是有一个物理特性:只能写 0 ,不能写 1 ,写 1 靠擦除。(里面默认是1)
c 复制代码
256个块,一个块16个扇区,一个扇区16页,每页256个字节
一般按扇区(4k)进行擦除。
可以按 章 -- 节 -- 页 -- 字 进行理解。
c 复制代码
W24Q128常用命令
c 复制代码
写使能 (06H)
	执行页写,扇区擦除,块擦除,片擦除,写状态寄存器等指令前,需要写使能。
	拉低CS片选 → 发送06H → 拉高CS片选

读状态寄存器(05H)
	拉低CS片选 → 发送05H→ 返回SR1的值 → 拉高CS片选

读时序(03H)
	拉低CS片选 → 发送03H→ 发送24位地址 → 读取数据(1~n) → 拉高CS片选

页写时序 (02H)
	页写命令最多可以向FLASH传输256个字节的数据。
	拉低CS片选 → 发送02H→ 发送24位地址 → 发送数据(1~n) → 拉高CS片选


扇区擦除时序(20H)
	写入数据前,检查内存空间是否全部都是 0XFF ,不满足需擦除。
	拉低CS片选 → 发送20H→ 发送24位地址 → 拉高CS片选



c 复制代码
	等待空闲:等待写入完成
	写操作
c 复制代码
无校验的写
相关推荐
space62123272 小时前
在SpringBoot项目中集成MongoDB
spring boot·后端·mongodb
xuxg20053 小时前
4G 模组 AT 命令解析框架课程正式发布
stm32·嵌入式·at命令解析框架
全栈前端老曹4 小时前
【MongoDB】Node.js 集成 —— Mongoose ORM、Schema 设计、Model 操作
前端·javascript·数据库·mongodb·node.js·nosql·全栈
CODECOLLECT4 小时前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件
BackCatK Chen5 小时前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
全栈游侠8 小时前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件
Lsir10110_8 小时前
【Linux】中断 —— 操作系统的运行基石
linux·运维·嵌入式硬件
深圳市九鼎创展科技10 小时前
瑞芯微 RK3399 开发板 X3399 评测:高性能 ARM 平台的多面手
linux·arm开发·人工智能·单片机·嵌入式硬件·边缘计算
辰哥单片机设计10 小时前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件
風清掦11 小时前
【江科大STM32学习笔记-05】EXTI外部中断11
笔记·stm32·学习