Keil MDK STM32系列

这篇和Keil MDK没什么关系, 但是HAL库和开发方式是一样的, 也放在这个系列下吧

PlatformIO

PlatformIO是VSCode的一个扩展, 主要面向的是嵌入式的开发, 因为VSCode的跨平台属性, PlatformIO也是跨平台的. 这里主要介绍在Ubuntu20.04下的PlatformIO环境.

安装, 略

PlatformIO下的STM32烧录工具

对于STM32, PlatformIO支持的烧录工具有 blackmagic, cmsis-dap, dfu, jlink, serial, stlink, 直接选stlink就可以了.

PlatformIO下的STM32封装库

在PlatformIO下, 在Platforms中安装ST STM32, 这个Platform中包含了多个适用于STM32开发的framework

Libopencm3

没找到安装路径... 这是一套面向ARM Cortex-M架构微处理器的开源固件库, 支持STM32, Atmel SAM3x, NXP LPC, TI LM4F等系列的MCU, 对这个不熟就不介绍了

Arduino

依托于Arduino的库环境, 使用Arduino的封装接口操作STM32, 适合初学者

package的路径在 [user home]/.platformio/packages/framework-arduinoststm32 , 大小接近500MB

Cmsis

这部分类似于Keil MDK下的SPL库, 包含多个package

  • cmsis核心库的安装路径是 /home/[your user]/.platformio/packages/framework-cmsis, 大小103MB

    • 对应了STM32Cube完整库 Drivers/CMSIS/ 路径下的内容
    • 多了一个Driver目录
  • stm32f4-framework库文件安装路径是 /home/[your user]/.platformio/packages/framework-cmsis-stm32f4, 大小30MB
    • 这个库只是STM32Cube MCU Full Package 的核心定义部分, 在Github上的仓库地址: https://github.com/STMicroelectronics/cmsis_device_f4
    • 这个库有自己的版本号v2.6.x, 容易与完整库的版本号混淆, 其与CMSIS CoreFull MCU package的对应关系在README.md的表格中, 现在最新的是v2.6.7, 对应的完整库版本为v1.26.2
    • 这个库与Windows Keil5 MDK下使用的标准外设库Standard peripherals library不兼容, 后者已经不再更新, 最高版本到1.8.0
  • STM32Cube完整库的仓库

综上, STM32F4的CMSIS环境下是没有可用的标准外设库(Standard peripherals library)的, 尝试过用1.8.0的标准外设库, 编译有不少错误, 所以用这个开发的话

  1. 要么自己修订标准外设库, 使其兼容v2.6.x的CMSIS核心库, 这个需要对各外设的变量和结构体很熟, 我这样刚入门的估计是搞不定
  2. 要么不用标准外设库, 纯使用核心库变量开发. 这个难度也不小, 类似于回到8051开发的模式了, 每写一步都要查寄存器手册.
  3. 要么直接用STM32Cube的完整外设库. 不过既然都用了STM32Cube的库了, 为什么不直接选framework时就选STM32Cube呢?

Stm32cube

文档: https://docs.platformio.org/en/latest/frameworks/stm32cube.html

和Windows下的STM32CubeMX使用了相同的HAL库, package路径 [user home]/.platformio/packages/framework-stm32cubef4 , 大小 78.3MB

这个package下的内容, 就是STM32CubeF4仓库的内容, 当前版本是1.26.2.

使用STM32CubeF4开发的项目, 用这个Framework是可以直接编译的.

STM32CubeF4 的文件结构

这个库有三个目录

STM32CubeF4/Drivers

这里包含了核心库 CMSIS, HAL库 STM32F4xx_HAL_Driver, 还有众多的外设支持, 简直是个宝库

├── Drivers
│   ├── BSP
│   │   ├── Adafruit_Shield
│   │   ├── Components
│   │   │   ├── ampire480272
│   │   │   ├── ampire640480
│   │   │   ├── Common
│   │   │   ├── cs43l22
│   │   │   ├── exc7200
│   │   │   ├── ft6x06
│   │   │   ├── i3g4250d
│   │   │   ├── ili9325
│   │   │   ├── ili9341
│   │   │   ├── l3gd20
│   │   │   ├── lis302dl
│   │   │   ├── lis3dsh
│   │   │   ├── ls016b8uy
│   │   │   ├── lsm303agr
│   │   │   ├── lsm303dlhc
│   │   │   ├── mfxstm32l152
│   │   │   ├── n25q128a
│   │   │   ├── n25q256a
│   │   │   ├── n25q512a
│   │   │   ├── nt35510
│   │   │   ├── otm8009a
│   │   │   ├── ov2640
│   │   │   ├── ov5640
│   │   │   ├── s25fl512s
│   │   │   ├── s5k5cag
│   │   │   ├── st7735
│   │   │   ├── st7789h2
│   │   │   ├── stmpe1600
│   │   │   ├── stmpe811
│   │   │   ├── ts3510
│   │   │   └── wm8994
│   │   ├── STM32412G-Discovery
│   │   ├── STM32446E_EVAL
│   │   ├── STM32469I-Discovery
│   │   ├── STM32469I_EVAL
│   │   ├── STM324x9I_EVAL
│   │   ├── STM324xG_EVAL
│   │   ├── STM32F401-Discovery
│   │   ├── STM32F411E-Discovery
│   │   ├── STM32F413H-Discovery
│   │   ├── STM32F429I-Discovery
│   │   ├── STM32F4-Discovery
│   │   ├── STM32F4xx-Nucleo
│   │   └── STM32F4xx_Nucleo_144
│   ├── CMSIS
│   │   ├── Core
│   │   ├── Core_A
│   │   ├── Device
│   │   ├── DSP
│   │   ├── Include
│   │   ├── Lib
│   │   │   └── GCC
│   │   ├── NN
│   │   ├── RTOS
│   │   └── RTOS2
│   └── STM32F4xx_HAL_Driver
│   ├── Inc
│   └── Src

STM32CubeF4/Middlewares

这个目录下是USB功能封装和一些常用的第三方库, 例如FatFS, LwIP等

├── Middlewares
│   ├── ST
│   │   ├── STemWin
│   │   ├── STM32_Audio
│   │   │   └── Addons
│   │   │   └── PDM
│   │   ├── STM32_USB_Device_Library
│   │   ├── STM32_USB_Host_Library
│   │   └── TouchGFX
│   └── Third_Party
│   ├── FatFS
│   ├── FreeRTOS
│   ├── LibJPEG
│   ├── LwIP
│   └── mbedTLS

STM32CubeF4/Utilities

这里是一些工具和字体

└── Utilities
├── CPU
├── Fonts
├── Log
└── Media
├── Audio
├── Pictures
└── Video

使用Stm32cube创建项目

打开PlatformIO:Home, 如果没装 Platform:ST STM32 的, 先在 Platform 里装一下

  1. 点击 New Project,
  2. 填入项目名称,
  3. 在 Board 中输入 stm32f401 在过滤结果的列表中, 选择 stm32f401cc, 如果是常见的 WeAct Studio BlackPill, 可以直接在底下找到对应的专门的board
  4. 选择 Framework 为 STM32Cube
  5. 如果不希望建在默认目录的话, 取消 Use Default Location 勾选, 指定位置, PlatformIO 会创建项目目录

platformio.ini

这个文件的内容如下, 一个项目里可以有多个env, 可以指定一个默认的, 在使用快捷键时, 会执行默认env的编译和写入.

[env:blackpill_f401cc]
platform = ststm32
board = blackpill_f401cc
framework = stm32cube ;通用的 stm32f401cc 配置
[env:stm32f401cc]
platform = ststm32
board = genericSTM32F401CC
framework = stm32cube
upload_protocol = stlink
board_build.stm32cube.custom_config_header = yes

参数说明:

  • upload_protocol 用于指定不同的写入方式
  • board_build.stm32cube.custom_config_header = yes 禁止platformio自动生成stm32f4xx_hal_conf.h. 默认情况下, 在项目启动或编译时, platformio会自动在库文件目录, 基于stm32f4xx_hal_conf_template.h复制创建stm32f4xx_hal_conf.h, 而HAL项目中这个配置文件一般是和main.c一起放在用户代码目录下的, 如果按默认的方式, 编译时会优先使用库目录下的文件, 用户自己配置的就失效了. 加上这个选项可以禁止platformio自己生成这个文件.

.vscode/c_cpp_properties.json

这个文件很重要, 因为任何 include 的错误, 都可以在这里检查. 这个文件是 PlatformIO 自动生成的, 所以不需要去改它, 如果发现你修改了platformio.ini 后它没有更新, 重新打开 VS Code 就可以了.

stm32f4xx_hal_conf.h

从 [user home]/.platformio/packages/framework-stm32cubef4/Drivers/STM32F4xx_HAL_Driver/Inc 中复制 stm32f4xx_hal_conf_template.h 到 src 目录, 并重命名为 stm32f4xx_hal_conf.h

需要修改的两处

  1. 模块启用部分. define xxxx ENABLED 这部分只需要保留下面的这些, 其它全部注释掉, 只有用到的才需要取消注释
#define HAL_MODULE_ENABLED

#define HAL_GPIO_MODULE_ENABLED
#define HAL_EXTI_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
  1. 设置外部晶振频率, 设置成板载晶振的频率
#define HSE_VALUE    8000000U /*!< Value of the External oscillator in Hz */

项目文件

以下文件都直接在 src 目录下创建, 演示A6, A7两个PIN连接的LED间隔2秒闪灯

main.c


#include "main.h" void SystemClock_Config(void);
void SystemClock_Config_HSE_84MHz(void);
static void MX_GPIO_Init(void); int main(void)
{
HAL_Init();
SystemClock_Config_HSE_84MHz();
MX_GPIO_Init();
while (1)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6 | GPIO_PIN_7, GPIO_PIN_SET);
HAL_Delay(2000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6 | GPIO_PIN_7, GPIO_PIN_RESET);
HAL_Delay(2000);
}
} void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 84;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
} void SystemClock_Config_HSE_84MHz(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; __HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
} RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
} static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET); /*Configure GPIO pins : PA6 PA7 */
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
} #ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

main.h

#ifndef __MAIN_H
#define __MAIN_H #ifdef __cplusplus
extern "C" {
#endif /* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h" void Error_Handler(void); #ifdef __cplusplus
}
#endif #endif /* __MAIN_H */

stm32f4xx_hal_msp.c

#include "stm32f4xx_hal.h"

void HAL_MspInit(void)
{
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
}

stm32f4xx_it.c

#include "stm32f4xx_hal.h"
#include "stm32f4xx_it.h" /******************************************************************************/
/* Cortex-M4 Processor Interruption and Exception Handlers */
/******************************************************************************/ void NMI_Handler(void)
{
while (1)
{
}
} void HardFault_Handler(void)
{
while (1)
{
}
} void MemManage_Handler(void)
{
while (1)
{
}
} void BusFault_Handler(void)
{
while (1)
{
}
} void UsageFault_Handler(void)
{
while (1)
{
}
} void SVC_Handler(void)
{ } void DebugMon_Handler(void)
{
} void PendSV_Handler(void)
{
} void SysTick_Handler(void)
{
HAL_IncTick();
}

stm32f4xx_it.h

#ifndef __STM32F4xx_IT_H
#define __STM32F4xx_IT_H #ifdef __cplusplus
extern "C" {
#endif /* Exported functions prototypes ---------------------------------------------*/
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void); #ifdef __cplusplus
}
#endif #endif /* __STM32F4xx_IT_H */

STM32F401CCxx 可用的 SystemClock_Config()

配置不正确的系统时钟会导致系统卡死, 下面两个方法是测试可用的

/**
* Generated by STM32Cube 1.26.x
* *) Enable HSE(25MHz), No LSE(32.768KHz)
* *) No PLL, No prescaler, HSE->SYSCLK->PHBPrescaler=1->AHB,APB1,APB2...
*/
void SystemClock_Config_HSE_25MHz(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; __HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
} RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
//RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // Make APB2 12.5MHz if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
} /**
* Generated by STM32Cube 1.26.x
* *) Enable HSE(25MHz), No LSE(32.768KHz)
* *) Enable PLL
* *) HSE->PLL->/25->*168->/2->PPLCLK->SYSCLK(84MHz)->APB1 /2-> APB1
*/
void SystemClock_Config_HSE_84MHz(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; __HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
} RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}

用UART输出printf的宏定义

因为sdcc和keil5 mdk下的编译工具不一样, 所以这部分的定义也不一样, 可以用下面的宏语句统一处理

#if defined(__GNUC__)
int _write(int fd, char *ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 0xFFFF);
return len;
}
#elif defined (__ICCARM__)
size_t __write(int handle, const unsigned char * buffer, size_t size)
{
HAL_UART_Transmit(&huart1, (uint8_t *) buffer, size, HAL_MAX_DELAY);
return size;
}
#elif defined (__CC_ARM)
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
#endif

或者

#ifdef __GNUC__
#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
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}

参考

Keil MDK STM32系列(十) Ubuntu下的PlatformIO开发环境的更多相关文章

  1. Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  2. Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  3. Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  4. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  5. Keil MDK STM32系列(四) 基于抽象外设库HAL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  6. Keil MDK STM32系列(五) 使用STM32CubeMX创建项目基础结构

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  7. Keil MDK STM32系列(六) 基于抽象外设库HAL的ADC模数转换

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  8. Keil MDK STM32系列(七) STM32F4基于HAL的PWM和定时器

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  9. Keil MDK STM32系列(八) STM32F4基于HAL的PWM和定时器输出音频

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  10. Ubuntu下的PHP开发环境架设

    Ubuntu下的PHP开发环境架设   今天重新装了ubuntu那么就吧过程记录下. 打开终端,也就是命令提示符. 我们先来最小化组建安装,按照自己的需求一步一步装其他扩展.命令提示符输入如下命令: ...

随机推荐

  1. Redis-键

  2. CAP-BASE

  3. [转帖]JVM性能调优工具2之jcmd详解(覆盖全网最全的jcmd命令与说明文档)

    上篇文章里<JVM常用性能调优工具详解1>我们已经探究了jps.jstat等监控工具,以及jinfo.jmap.jstack.jhat等故障排查工具,这里我单独拿出一篇文章,特别介绍jcm ...

  4. [转帖]win10多网卡指定ip走某个网卡的方案

    https://zhuanlan.zhihu.com/p/571614314 我的电脑上有两个网卡,一个网卡A(网线),一个是网卡B(WIFI). 需求:网卡A和网卡B是不同的网络,网卡A已经把338 ...

  5. [转帖]AMD Zen CPU 架构以及不同CPU性能大PK

    https://plantegg.github.io/2021/08/13/AMD_Zen_CPU%E6%9E%B6%E6%9E%84/ 前言 本文先介绍AMD Zen 架构,结合前一篇文章<C ...

  6. 【转帖】Alpaca 7B:斯坦福从LLaMA-7B微调的语言模型

    https://www.jianshu.com/p/f8f8f660d2c3 https://crfm.stanford.edu/2023/03/13/alpaca.html https://crfm ...

  7. 【转帖】PyCharm---Django简单例子--基础1

    https://www.cnblogs.com/kllay/p/7286701.html 环境: python 2.7 Django 1.11.2    查看版本:python -m django - ...

  8. [转帖]Linux Page cache和Buffer cache

    https://www.cnblogs.com/hongdada/p/16926655.html free 命令常用参数 free 命令用来查看内存使用状况,常用参数如下: -h human-read ...

  9. [转帖]关于iostat的问题,svctm数据不可信

    使用FIO对磁盘进行压力测试,使用1个线程对磁盘进行随机读,设置单次read的数据块分别为128KB和1M,数据如下: (1)单次IO数据块为128KB (2)单次IO数据块为1M 从上面的数据可以看 ...

  10. 简单进行Springboot Beans归属模块单元的统计分析方法

    简单进行Springboot Beans归属模块单元的统计分析方法 背景 基于Springboot的产品变的复杂之后 启动速度会越来越慢. 公司同事得出一个结论. beans 数量过多会导致启动速度逐 ...