STM32学习笔记【电赛历险记嵌入式学习心得】

前言

此篇随笔是博主在打电赛(全国大学生电子设计竞赛)中写下的笔记汇总,备赛历程可见:视频

希望对小白有所帮助。

STM32入门

必备知识

概述

什么是 STM32:什么是STM32

STM32 能做什么:STM32能做什么

ST 官方官方网址:ST官网 (st.com)

ST 官方中文网站:STMCU中文官网

型号

STM32 怎么选型:STM32怎么选型

STM32 F1与F4的区别:【经验分享】ST公司STM32F4与STM32F1的区别

学习资源

1、STM32 学习

STM32 标准库开发:STM32入门教程-2023持续更新中

STM32 HAL库开发:【野火】STM32 HAL库开发实战指南 教学视频 手把手教学STM32全系列

2、Kicad

KiCad 是一款 PCB 设计软件,优点是开源、有许多插件可用、有许多快捷键方便操作

学习路径:KiCad | 6.0 | 简体中文 | Documentation | KiCad

PCB(Printed Circuit Board),中文名称为印制电路板,又称印刷线路板,是重要的电子部件,是电子元器件的支撑体,是电子元器件电气相互连接的载体。由于它是采用电子印刷术制作的,故被称为“印刷”电路板。

PCB 可以粗浅的理解为焊接死的面包板,目的是为了防止连线在搬运的过程中松动导致问题

3、部分项目学习

可以通过学习他人的部分项目,深入对开发过程的理解

智能小车入门:STM32智能小车教程-循迹-避障-蓝牙遥控-跟随-stm32f103c8t6-stm32最小系统-手把手入门教程

智能送药小车标准库:电赛培训-基于21年赛题-智能送药小车

智能送药小车HAL库:电赛“智能送药小车”【干货教程】STM32HAL库CubeMX+pid串级控制+OpenMV数字识别

智能送药小车:2021年电赛F题智能送药小车(国二)开源分享

其他智能送药小车:2021全国电赛真题(F)—— 智能送药小车

小车跟随行驶系统:2022电赛省一-小车跟随行驶系统(C题)

电磁炮:2019电赛----模拟电磁曲射炮

滚球:电赛入坑----2017年电赛国赛真题滚球控制系统

4、电机

电机快速初步了解:有刷电机与无刷电机的原理

电机学习:一个视频学完生活中的所有电机

电机驱动:一个视频了解生活中电机的驱动控制及调速方法

以上均为快速了解,作为科普简单留下感性印象,下面的视频能更完善的学习电机

视频地址:【野火】电机系列教学视频,基于STM32硬件(步进电机,直流有刷电机,直流无刷电机,舵机,永磁同步电机PMSM)PID闭环算法

在线文档:【野火】电机应用开发实战指南—基于STM32

5、PID算法

电机中的 野火视频 有讲解,此外还有一些资源

PID理论学习:从不懂到会用!PID从理论到实践~

6、相关模块学习

灰度传感器:一种双灰度传感器巡黑线方案

相关资料

总体

STM32F10xxx参考手册(中文)STM32F103C8T6/STM32F10xxx参考手册(中文)

数据手册:STM32F103C8T6/STM32F103x8B数据手册(中文)

Cortex-M3权威指南:STM32F103C8T6/Cortex-M3权威指南

野火F103 标准库开发指南:野火STM32库开发实战指南——基于野火MINI开发板

野火F103 HAL库开发指南:野火F103 HAL库开发指南

HC-05模块

概述:【常用模块】HC-05蓝牙串口通信模块使用详解(实例:手机蓝牙控制STM32单片机)

双机通信:两个HC-05蓝牙互相连接方法

所有AT指令:HC-05 嵌入式蓝牙串口通讯模块 AT 指令集

如果接收乱码,注意看波特率是否正确,默认值为9600!

STM32 接受蓝牙信息代码如下:

#include "stm32f10x.h"void My_USART1_Init(void)
{GPIO_InitTypeDef GPIO_InitStrue;USART_InitTypeDef USART_InitStrue;NVIC_InitTypeDef NVIC_InitStrue;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //GPIO端口使能  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);  //串口端口使能  GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;  // 模式: 复用输出GPIO_InitStrue.GPIO_Pin=GPIO_Pin_9;  // 引脚: A9GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;  // 速度: 10MHzGPIO_Init(GPIOA,&GPIO_InitStrue);GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING;  // 模式: 浮空输入GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10;  // 引脚: A10GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;  // 速度: 10MHzGPIO_Init(GPIOA,&GPIO_InitStrue);USART_InitStrue.USART_BaudRate=9600;  // 波特率: 9600USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  // 硬件流控制: 无USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;  // 串口模式: 接受与发送USART_InitStrue.USART_Parity=USART_Parity_No;  // 极性: 无USART_InitStrue.USART_StopBits=USART_StopBits_1;  // 停止位: 1位USART_InitStrue.USART_WordLength=USART_WordLength_8b;  // 数据位长度: 8位USART_Init(USART1,&USART_InitStrue);USART_Cmd(USART1,ENABLE);  //使能串口1USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);  //开启接收中断NVIC_InitStrue.NVIC_IRQChannel=USART1_IRQn;NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=1;  // 优先中断级别: 1NVIC_InitStrue.NVIC_IRQChannelSubPriority=1;  // 普通中断级别: 1NVIC_Init(&NVIC_InitStrue);
}void USART1_IRQHandler(void)
{u8 res;if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET){res= USART_ReceiveData(USART1);USART_SendData(USART1,res);}
}int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);My_USART1_Init();while(1);
}

电机控制

电机驱动与编码器:TB6612与电机编码器

超声波跟随

HC-SR04模块:超声波原理及测距

超声波跟随小车:超声波跟随小车

调试

串口调试:USART-FlyMcu下载程序

配合蓝牙模块可实现无线烧录功能

红外遥控

介绍:STM32 红外遥控器详解

STM32标准库学习

stm32 固件库函数介绍

1、RCC

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

2、GPIO 相关函数

void GPIO_AFIODeInit(void);							// 复位AFIO外设
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);		// 锁定 GPIO 配置
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);	// 配置AFIO事件输出功能
void GPIO_EventOutputCmd(FunctionalState NewState);				// 配置AFIO事件输出功能
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);	// 进行引脚重映射
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);	// 配置AFIO的数据选择器
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);		// 与以太网有关

3、EXTI 相关函数

void EXTI_DeInit(void);					// 清除 EXTI 配置
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);	// 初始化 EXTI
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);// 给EXTI结构体赋默认值
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);	// 软件触发EXTI外部中断
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);	// 获取标志位
void EXTI_ClearFlag(uint32_t EXTI_Line);		// 清空标志位
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);		// 获取中断标志位
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);	// 清空中断标志位

4、中断向量表

中断向量表位于启动文件(start/startup_stm32f10x.md.s)

__Vectors       DCD     __initial_sp               ; Top of StackDCD     Reset_Handler              ; Reset HandlerDCD     NMI_Handler                ; NMI HandlerDCD     HardFault_Handler          ; Hard Fault HandlerDCD     MemManage_Handler          ; MPU Fault HandlerDCD     BusFault_Handler           ; Bus Fault HandlerDCD     UsageFault_Handler         ; Usage Fault HandlerDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     SVC_Handler                ; SVCall HandlerDCD     DebugMon_Handler           ; Debug Monitor HandlerDCD     0                          ; ReservedDCD     PendSV_Handler             ; PendSV HandlerDCD     SysTick_Handler            ; SysTick Handler; External InterruptsDCD     WWDG_IRQHandler            ; Window WatchdogDCD     PVD_IRQHandler             ; PVD through EXTI Line detectDCD     TAMPER_IRQHandler          ; TamperDCD     RTC_IRQHandler             ; RTCDCD     FLASH_IRQHandler           ; FlashDCD     RCC_IRQHandler             ; RCCDCD     EXTI0_IRQHandler           ; EXTI Line 0DCD     EXTI1_IRQHandler           ; EXTI Line 1DCD     EXTI2_IRQHandler           ; EXTI Line 2DCD     EXTI3_IRQHandler           ; EXTI Line 3DCD     EXTI4_IRQHandler           ; EXTI Line 4DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7DCD     ADC1_2_IRQHandler          ; ADC1_2DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TXDCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1DCD     CAN1_SCE_IRQHandler        ; CAN1 SCEDCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5DCD     TIM1_BRK_IRQHandler        ; TIM1 BreakDCD     TIM1_UP_IRQHandler         ; TIM1 UpdateDCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and CommutationDCD     TIM1_CC_IRQHandler         ; TIM1 Capture CompareDCD     TIM2_IRQHandler            ; TIM2DCD     TIM3_IRQHandler            ; TIM3DCD     TIM4_IRQHandler            ; TIM4DCD     I2C1_EV_IRQHandler         ; I2C1 EventDCD     I2C1_ER_IRQHandler         ; I2C1 ErrorDCD     I2C2_EV_IRQHandler         ; I2C2 EventDCD     I2C2_ER_IRQHandler         ; I2C2 ErrorDCD     SPI1_IRQHandler            ; SPI1DCD     SPI2_IRQHandler            ; SPI2DCD     USART1_IRQHandler          ; USART1DCD     USART2_IRQHandler          ; USART2DCD     USART3_IRQHandler          ; USART3DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI LineDCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
__Vectors_End

5、NVIC 相关函数

/* 注意:中断分支整个项目只能进行一次 */
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);				// 中断分组void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);					// 初始化 NVIC
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);			// 设置中断向量表
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);		// 系统低功耗配置

6、TIM 相关函数

基本函数:

/* 初始化配置 */
void TIM_DeInit(TIM_TypeDef* TIMx);								// 恢复缺省配置
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);	// 时基单元初始化void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);			// 时基单元结构体变量赋默认值void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);					// 使能计数器void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);		// 使能中断输出信号void TIM_InternalClockConfig(TIM_TypeDef* TIMx);						// 选择内部时钟
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);		// 选择其他定时器的时钟
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);			// 选择TIx捕获通道的时钟
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);						// 选择 ETR 通过外部时钟模式1输入的时钟
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);		// 选择 ETR 通过外部时钟模式2输入的时钟
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);							// 配置 ETR 预分频器、极性、滤波器等参数/* 更改参数 */
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);	// 更改预分频值
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);			// 改变计数模式
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);				// 改变计数器的预装功能设置
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);					// 给计数器写入值
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);					// 给自动重装器写入值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);							// 获取当前计数器的值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);							// 获取当前预分频的值/* 获取与清除标志位 */
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);	// 获取标志位
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);		// 清空标志位
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);		// 获取中断标志位
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);		// 清空中断标志位

输出比较函数:

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);	// 配置输出比较模块
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);	// 配置输出比较模块
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);	// 配置输出比较模块
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);	// 配置输出比较模块
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);			// 输出结构体赋默认值
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);		// 配置强制输出模式,强制输出高电平或低电平
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);		// 配置强制输出模式,强制输出高电平或低电平
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);		// 配置强制输出模式,强制输出高电平或低电平
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);		// 配置强制输出模式,强制输出高电平或低电平
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);		// 配置 CCR 预装值功能
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);		// 配置 CCR 预装值功能
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);		// 配置 CCR 预装值功能
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);		// 配置 CCR 预装值功能
void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);			// 配置快速使能
void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);			// 配置快速使能
void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);			// 配置快速使能
void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);			// 配置快速使能
void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);			// 外部事件时清除 REF 信号
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);			// 外部事件时清除 REF 信号
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);			// 外部事件时清除 REF 信号
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);			// 外部事件时清除 REF 信号
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);		// 设置输出比较的极性
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);	// 设置输出比较的极性(互补通道
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);		// 设置输出比较的极性
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);	// 设置输出比较的极性(互补通道
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);		// 设置输出比较的极性
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);	// 设置输出比较的极性(互补通道
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);		// 设置输出比较的极性
void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);	// 修改输出使能
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);	// 修改输出使能
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);// 修改输出比较模式
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);			// 更改 CCR 寄存器的值
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);			// 更改 CCR 寄存器的值
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);			// 更改 CCR 寄存器的值
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);			// 更改 CCR 寄存器的值

输入捕获函数:

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);	// 输入捕获单元初始化
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);	// 初始化输入捕获单元,快速配置两个通道,配置为PWMI模式
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);// 输入捕获结构体赋默认值
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);	// 选择输入触发源(从模式的触发源)
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);	// 选择输出触发源TRGO(主模式输出)
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);	// 选择从模式
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);	// 配置1通道的分频器
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);	// 配置2通道的分频器
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);	// 配置3通道的分频器
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);	// 配置4通道的分频器
void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD);
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);	// 读取1通道的CCR
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);	// 读取2通道的CCR
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);	// 读取3通道的CCR
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);	// 读取4通道的CCR

编码器接口函数:

void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);	// 编码器接口配置

7、ADC相关函数

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);	// 配置 ADC_CLK 分频器
void ADC_DeInit(ADC_TypeDef* ADCx);							// 恢复缺省配置
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);			// 初始化 ADC
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);					// ADC结构体初始化
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);				// 开启 ADC
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);				// 开启 DMA 输出信号
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);	// 中断输出控制
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);		// 软件触发 ADC
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);				// 获取软件开始转换状态(软件触发后立刻从1清零)(一般不用)
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);			// 配置每隔几个通道间断一次
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);			// 启用间断模式
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);	// ADC规则组通道配置
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);		// ADC 外部触发转换控制
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);					// ADC 获取转换值
uint32_t ADC_GetDualModeConversionValue(void);						// ADC 获取双模式转换值/* 校准相关配置 */
void ADC_ResetCalibration(ADC_TypeDef* ADCx);			// 复位校准
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);	// 获取复位校准状态
void ADC_StartCalibration(ADC_TypeDef* ADCx);			// 开始校准
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);		// 获取开始校准状态/* 注入组相关配置 */
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);/* 模拟看门狗相关配置 */
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);					// 是否启动模拟看门狗
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);	// 配置高低阈值
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);				// 配置看门通道void ADC_TempSensorVrefintCmd(FunctionalState NewState);		// ADC 温度传感器,内部电压控制FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);	// 获取标志位状态
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);		// 清空标志位
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);		// 获取中断状态
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);		// 清空中断挂起位

8、DMA 相关函数

void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);							// 恢复缺省配置
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);			// 初始化 DMA
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);							// DMA 结构体初始化
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);				// 使能 DMA
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);	// 中断输出使能void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber);	// DMA 设置当前数据寄存器
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);			// DMA 获取当前数据寄存器FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);	// 获取标志位状态
void DMA_ClearFlag(uint32_t DMAy_FLAG);			// 清空标志位
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);		// 获取中断状态
void DMA_ClearITPendingBit(uint32_t DMAy_IT);		// 清空中断挂起位

9、USART

void USART_DeInit(USART_TypeDef* USARTx);							// 恢复缺省配置
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);			// 初始化 USART
void USART_StructInit(USART_InitTypeDef* USART_InitStruct);					// USART 结构体初始化
void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);	// 配置同步时钟输出
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct);			// 同步时钟输出结构体初始化
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);				// 开启 USART
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);	// 开启中断
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);	// 开启USART到DMA的触发通道
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);		// 发送数据
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);			// 接收数据
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);	// 获取标志位状态
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);		// 清空标志位
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);		// 获取中断状态
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);		// 清空中断挂起位

基础模块设计

GPIO

具体步骤

  • RCC 开启时钟
  • GPIO_Init() 初始化 GPIO
  • 使用输出或输入函数控制 GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

EXTI 外部中断

EXTI基本结构

具体步骤

  • RCC 开启时钟(GPIO、AFIO)
  • 配置 GPIO 为输入模式
  • 配置 AFIO,选择我们使用的一路GPIO
  • 配置 EXTI,选择边沿触发方式、触发响应方式(中断响应、事件响应)
  • 配置 NVIC,选择优先级
void CountSensor_Init(void)
{/* RCC 开启时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);/* 配置 GPIO  */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);/* 配置 AFIO */GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);/* 配置 EXTI */EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line14;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);/* 配置 NVIC,中断分组 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);/* 配置 NVIC,设置优先级 */NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);
}void EXTI15_10_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line14) == SET){EXTI_ClearITPendingBit(EXTI_Line14);}
}

EXTI 与 NVIC 的时钟不需手动开启

Timer 定时中断

定时中断基本结构

  • 具体步骤

    • RCC 开启时钟
    • 选择时基单元的时钟源(定时中断选择内部时钟源)
    • 配置时基单元
    • 配置输出中断控制,允许更新中断到 NVIC
    • 配置 NVIC,打开定时器中断通道,分配优先级
    • 运行控制
void Timer_Init(void)
{/* RCC 开启时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);/* 选择时基单元的时钟源,内部时钟源 */TIM_InternalClockConfig(TIM2);/* 配置时基单元 */TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2, TIM_FLAG_Update);TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);		// 使能中断/* 配置 NVIC,中断分组 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);/* 配置 NVIC,配置优先级 */NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);/* 启动计时器 */TIM_Cmd(TIM2, ENABLE);
}void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}

PWM 输出

PWM基本结构

  • 具体步骤
    • RCC 开启时钟
    • 配置时基单元
    • 配置输出比较单元
    • 配置 GPIO
    • 运行控制,启动计数器
#include "stm32f10x.h"                  // Device headervoid PWM_Init(void)
{/* RCC 开启时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* 配置 GPIO */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 选择时基单元的时钟源,内部时钟源 */TIM_InternalClockConfig(TIM2);/* 配置时基单元 */TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;		//PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);/* 配置输出比较单元 */TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;		//CCRTIM_OC3Init(TIM2, &TIM_OCInitStructure);/* 运行控制,启动计数器 */TIM_Cmd(TIM2, ENABLE);
}// 设置占空比
void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2, Compare);
}// 设置预分频值
void PWM_SetPrescaler(uint16_t Prescaler)
{TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}

IC 输入捕获

输入捕获基本结构

主从触发模式

  • 具体步骤
    • RCC 开启时钟
    • GPIO 初始化为输入模式(上拉或浮空)
    • 配置时基单元
    • 配置输入捕获单元,包括滤波器、极性、直连通道还是交叉通道、分频器这些参数
    • 选择从模式的触发源(TI1FP1)
    • 选择触发后执行的操作(Reset操作)
    • 运行控制,启动计时器
#include "stm32f10x.h"                  // Device headervoid IC_Init(void)
{/* RCC 开启时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* GPIO 初始化为输入模式(上拉或浮空) */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 选择时基单元的时钟源,内部时钟源 */TIM_InternalClockConfig(TIM3);/* 配置时基单元 */TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);/* 配置输入捕获单元 */TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter = 0xF;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInit(TIM3, &TIM_ICInitStructure);/* 选择从模式的触发源,选择触发后执行的操作 */TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);/* 运行控制,启动计时器 */TIM_Cmd(TIM3, ENABLE);
}uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}

PWMI 模式

PWMI基本结构

  • 具体步骤
    • RCC 开启时钟
    • GPIO 初始化为输入模式(上拉或浮空)
    • 配置时基单元
    • 配置输入捕获单元
    • 选择从模式的触发源(TI1FP1)
    • 选择触发后执行的操作(Reset操作)
    • 运行控制,启动计时器
#include "stm32f10x.h"                  // Device headervoid IC_Init(void)
{/* RCC 开启时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* GPIO 初始化为输入模式(上拉或浮空) */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 选择时基单元的时钟源,内部时钟源 */TIM_InternalClockConfig(TIM3);/* 配置时基单元 */TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);/* 配置输入捕获单元 */TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter = 0xF;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);/* 选择从模式的触发源,选择触发后执行的操作 */TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);/* 运行控制,启动计时器 */TIM_Cmd(TIM3, ENABLE);
}uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}uint32_t IC_GetDuty(void)
{return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}

编码器接口测速

编码器接口基本结构

  • 具体步骤
    • RCC 开启时钟
    • GPIO 初始化为输入模式
    • 配置时基单元
    • 配置输入捕获单元,包括滤波器、极性参数
    • 配置编码器接口模式
    • 运行控制,启动计时器
#include "stm32f10x.h"                  // Device headervoid Encoder_Init(void)
{/* RCC 开启时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* GPIO 初始化为输入模式 */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 配置时基单元 */TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	// 没用TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);/* 配置输入捕获单元,包括滤波器、极性参数 */TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICStructInit(&TIM_ICInitStructure);TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter = 0xF;TIM_ICInit(TIM3, &TIM_ICInitStructure);TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;TIM_ICInitStructure.TIM_ICFilter = 0xF;TIM_ICInit(TIM3, &TIM_ICInitStructure);/* 配置编码器接口模式 */TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);/* 运行控制,启动计时器 */TIM_Cmd(TIM3, ENABLE);
}int16_t Encoder_Get(void)
{int16_t Temp;Temp = TIM_GetCounter(TIM3);TIM_SetCounter(TIM3, 0);return Temp;
}

ADC

ADC基本结构

  • 具体步骤
    • RCC 开启时钟(ADC和GPIO),配置 ADC_CLK 分频器
    • GPIO 配置为模拟输入模式
    • 配置多路开关
    • 配置 ADC 转换器
    • 配置看门狗(可选)
    • 开启中断,配置 NVIC(可选)
    • 开启 ADC
    • 对 ADC 进行校准(建议)
#include "stm32f10x.h"                  // Device headervoid AD_Init(void)
{/* RCC 开启时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* 配置 ADC_CLK 分频器 */RCC_ADCCLKConfig(RCC_PCLK2_Div6);/* GPIO 配置为模拟输入模式 */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 配置多路开关 */ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);/* 配置 ADC 转换器 */ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC_InitStructure);/* 开启 ADC */ADC_Cmd(ADC1, ENABLE);/* 对 ADC 进行校准 */ADC_ResetCalibration(ADC1);		// 复位校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);	// 等待复位校准完成ADC_StartCalibration(ADC1);		// 开始校准while (ADC_GetCalibrationStatus(ADC1) == SET);		// 等待校准完成
}uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE);			// 软件触发转换while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	// 等待转换完成return ADC_GetConversionValue(ADC1);			// 读取 ADC 转换结果
}

DMA

DMA基本结构

  • 具体步骤
    • RCC 开启时钟
    • 初始化 DMA(包括外设和存储器的各个数据、方向、传输计数器、是否需要自动重装、选择触发源、通道优先级)
    • 若为硬件触发,开启对应 DMA 输出(可选)
    • 开启中断输出,配置 NVIC(可选)
    • 开启 DMA

改变传输寄存器时需先失能,写入值后再使能

#include "stm32f10x.h"                  // Device headeruint16_t MyDMA_Size;void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
{MyDMA_Size = Size;/* RCC 开启时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* 初始化 DMA */DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;			// 外设起始地址DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;	// 外设数据宽度DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;		// 外设是否自增DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;;				// 存储器起始地址DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;;	// 存储器数据宽度DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;;		// 存储器是否自增DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	// 传输方向DMA_InitStructure.DMA_BufferSize = Size;		// 缓冲区大小,即传输寄存器DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;		// 传输模式,即是否使用自动重装DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;		// 选择是否存储器到存储器,即选择硬件触发或软件触发DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;	// 优先级DMA_Init(DMA1_Channel1, &DMA_InitStructure);/* 开启 DMA */DMA_Cmd(DMA1_Channel1, DISABLE);
}void MyDMA_Transfer(void)
{/* DMA失能、设置当前数据寄存器、DMA使能 */DMA_Cmd(DMA1_Channel1, DISABLE);DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);DMA_Cmd(DMA1_Channel1, ENABLE);/* 等待转运完成、清除转运完成标志位 */while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);DMA_ClearFlag(DMA1_FLAG_TC1);
}

USART 串口

USART基本结构

  • 具体步骤
    • RCC 开启时钟(USART和GPIO)
    • GPIO设置(TX配置为复用输出、RX配置为输入)
    • 配置USART
    • 开启中断、配置NVIC(可选)
    • 开启USART
  1. 发送数据

初始化函数:

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>void Serial_Init(void)
{/* RCC 开启时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* GPIO设置 */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 配置USART */USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;						// 波特率USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		// 硬件流控制USART_InitStructure.USART_Mode = USART_Mode_Tx;						// 串口模式USART_InitStructure.USART_Parity = USART_Parity_No;					// 校验位USART_InitStructure.USART_StopBits = USART_StopBits_1;					// 停止位USART_InitStructure.USART_WordLength = USART_WordLength_8b;				// 字长USART_Init(USART1, &USART_InitStructure);/* 开启USART */USART_Cmd(USART1, ENABLE);
}

相关函数封装:

/*** @brief  发送一个字节* @param  Byte: 要发送的字节数据* @retval None*/
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte);while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}/*** @brief  发送一个数组* @param  Array: 数组的首地址,必须为 uint8_t 类型的数组* @param  Length: 数组的长度*   This parameter can be any combination of GPIO_Pin_x where x can be (0..15).* @retval None*/
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Array[i]);}
}/*** @brief  发送字符串* @param  String: 字符串的首地址* @retval None*/
void Serial_SendString(char *String)
{uint8_t i;for (i = 0; String[i] != '\0'; i ++){Serial_SendByte(String[i]);}
}/*** @brief  指数函数,即X的Y次方* @param  X:底数* @param  Y:指数* @retval None*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result = 1;while (Y --){Result *= X;	// 1 乘以X Y次}return Result;
}/*** @brief  发送数字* 	本质将数字手动转为字符串然后发送* @param  Number* @param  Length* @retval None*/
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');	// 发送Number的每一位(高位先行)'0'->偏移}
}/*** @brief  fputc重定向* @param  * @retval */
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}/*** @brief  模拟printf重写打印字符串函数* @retval None*/
void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_SendString(String);
}

printf 重定向方法3:

	char String[100];sprintf(String, "\r\nNum3=%d", 333);Serial_SendString(String);
  1. 接收数据
#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>uint8_t Serial_RxData;
uint8_t Serial_RxFlag;void Serial_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	// 上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_Init(USART1, &USART_InitStructure);/* 开启中断 */USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);/* NVIC 分组 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);/* NVIC 配置 */NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);USART_Cmd(USART1, ENABLE);
}/*** @brief  获取标志位* @param  Nonw* @retval None*/
uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}/*** @brief  获取串口数据* @param  None* @retval None*/
uint8_t Serial_GetRxData(void)
{return Serial_RxData;
}/*** @brief  串口1中断函数* @param  None* @retval None*/
void USART1_IRQHandler(void)
{if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){Serial_RxData = USART_ReceiveData(USART1);	// 获取数据Serial_RxFlag = 1;				// 标志位置1USART_ClearITPendingBit(USART1, USART_IT_RXNE);	// 清空终端挂起位}
}
  1. 收发 HEX 数据包
/*** @brief  发送数据包* @param  None* @retval None*/
void Serial_SendPacket(void)
{Serial_SendByte(0xFF);Serial_SendArray(Serial_TxPacket, 4);Serial_SendByte(0xFE);
}/*** @brief  中断程序中接收数据包* @param  None* @retval None*/
void USART1_IRQHandler(void)
{static uint8_t RxState = 0;		// 当前状态static uint8_t pRxPacket = 0;		// 接收到第几个数据if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){uint8_t RxData = USART_ReceiveData(USART1);if (RxState == 0)		// 状态0:包头{if (RxData == 0xFF){RxState = 1;	// 进入状态1pRxPacket = 0;	// 接收数据指针置零}}else if (RxState == 1)				// 状态1:数据{Serial_RxPacket[pRxPacket] = RxData;	// 接收数据pRxPacket ++;				// 指针后移if (pRxPacket >= 4){RxState = 2;		// 进入状态3}}else if (RxState == 2)			// 状态2:包尾{if (RxData == 0xFE){RxState = 0;		// 重新进入状态0Serial_RxFlag = 1;	// 置接收标志位为1}}USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}

STM32 CubeMX及HAL库学习

入门

在拥有固件库开发的基础上,观看 Z小旋的博客-CSDN博客,能够快速上手 HAL 库。

下面对大佬的博客进行排序,方便查找。

这里推荐: 【STM32】_Z小旋的博客-CSDN博客

【STM32】HAL库 STM32CubeMX教程一---安装教程

【STM32】HAL库 STM32CubeMX教程二---基本使用(新建工程点亮LED灯)

【STM32】HAL库 STM32CubeMX教程三---外部中断(HAL库GPIO讲解)_hal_gpio_exti_callback

【STM32】HAL库 STM32CubeMX教程四---UART串口通信详解_hal_uart_transmit

【STM32】HAL库 STM32CubeMX教程五---看门狗(独立看门狗,窗口看门狗)_stm32看门狗

【STM32】HAL库 STM32CubeMX教程六---定时器中断_hal_tim_irqhandler

【STM32】HAL库 STM32CubeMX教程七---PWM输出(呼吸灯)_stm32 hal pwm输出

【STM32】HAL库 STM32CubeMX教程八---定时器输入捕获_hal_tim_readcapturedvalue

【STM32】HAL库 STM32CubeMX教程九---ADC_stm32cubemx adc

【STM32】HAL库 STM32CubeMX教程十---DAC

【STM32】HAL库 STM32CubeMX教程十一---DMA (串口DMA发送接收)_cubemx spi dma

【STM32】HAL库 STM32CubeMX教程十二---IIC(读取AT24C02 )_cubemx iic

【STM32】HAL库 STM32CubeMX教程十三---RTC时钟_stm32 hal库的时钟

【STM32】HAL库 STM32CubeMX教程十四---SPI_cubemx spi

【STM32】HAL库 STM32CubeMX教程十五---FMC-SDRAM(一)_stm32cubemx fmc

【STM32】HAL库 STM32CubeMX教程十五---FMC-SDRAM(二)

提高

1、串口

初步写自己的具体逻辑,主要是串口,可以观看 STM32系列视频(CubeMX+MDK5+HAL库+库函数一站式学习) 进行学习。

这个视频主要是标准库和 HAL库 函数都有,面向电源题类的。

2、PID控制

编码器测速:【STM32】使用HAL库进行电机测速,原理、代码、滤波

PID速度环:【STM32】使用HAL库进行电机速度环PID控制,代码+调参

PID位置环:【STM32】使用HAL库进行电机PID位置环控制,代码+调参

3、PID调参

VOFA+调参:使用VOFA+上位机进行PID调参(附下位机代码)

VOFA+官网:VOFA+

4、江科大OLED移植

基于HAL库的stm32的OLED显示屏显示:基于HAL库的stm32的OLED显示屏显示(模拟I2C,四脚,0.96寸)

其他

大佬的笔记整理:【单片机学习笔记】上传一整年的自学电子笔记,互相交流,共同进步

电赛国一大佬的方案:2021年全国大学生电子设计大赛F题——智能送药小车,全方位解决方案+程序代码(详细注释)山东赛区国奖

STM32中的预编译

#define

1、不带参宏定义

#define,宏定义命令,它也是C语言预处理命令的一种。

所谓宏定义,就是用一个标识符来表示一个字符串,如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。

例如

#define N 100

在编译过程中遇到 N 时,会直接替换为 100。

2、带参公定义

宏定义可以携带参数。

例如

#define M(y) y*y+3*y  //宏定义int main()
{// 以下命令解释为 5*5+3*5int a = M(5);
}

3、防止头文件重复包含

如下所示

#ifndef __HEADER_One_H__ // 意思是:宏开始行,如果还没有定义 __HEADER_One_H__ 则 进入,否则退出
#define __HEADER_One_H__ // 定义 __HEADER_One_H__// header1.h 头文件内容#endif // 宏结束行

模版:

#ifndef __x_H__
#define __x_H__#endif // 宏结束行

#if 与 #if defined

1、#if

#if的意思是如果宏条件符合,编译器就编译这段代码,否则,编译器就忽略这段代码而不编译,如

#define  A 0  // 把A定义为0#if (A > 1)printf("A > 1");  // 编译器没有编译该语句,该语句不生成汇编代码
#elif (A == 1)printf("A == 1"); // 编译器没有编译该语句,该语句不生成汇编代码
#elseprintf("A < 1");   // 编译器编译了这段代码,且生成了汇编代码,执行该语句
#endif

模版:

#if x#else#endif
#if x#elif x#else#endif

2、#if defined

#if defined (x)...code...
#endif

这个#if defined它不管里面的 x 的逻辑是“真”还是“假”。它只管这个程序的前面的宏定义里面有没有定义 x 这个宏,如果定义了 x 这个宏,那么,编译器会编译中间的 …code…,否则会直接忽视中间的 …code… 代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/881919.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【K8S安全】浅析K8S各种未授权攻击方法

免责声明: 本篇文章仅用于技术交流,请勿利用文章内的相关技术从事非法测试,由于传播、利用本文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本文作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢…

卷积神经网络(1)初步了解

先介绍一个简单的例子 要手动实现一个简单的卷积神经网络(CNN)来判断手写数字(1-10),我们可以使用 Python 和 TensorFlow(或其他深度学习框架)。以下是一个简单的实现思路,其中包含了手动构建卷积层、池化层、全连接层等。 假设你已经有了手写数字数据集,比如 MNIST 数…

RocketMQ实战—9.营销系统代码初版

大纲 1.基于条件和画像筛选用户的业务分析和实现 2.全量用户促销活动数据模型分析以及创建操作 3.Producer和Consumer的工程代码实现 4.基于抽象工厂模式的消息推送实现 5.全量用户促销活动消息推送的流程和缺陷分析 6.全量用户促销活动推送引入MQ进行削峰 7.全量用户发优惠券业…

Qwen2.5 Max:最有可能是DeepSeek R1的平替

新年还没过,推理大模型就开始了卷了,除夕当天Qwen就发布了重磅的Qwen2.5 Max推理模型,一、Qwen2.5 Max2025年1月28日,qwen团队发布了Qwen2.5 Max,总体来说,还是很不错的。下面是摘抄他们发表的信息:We evaluate Qwen2.5-Max alongside leading models, whether propriet…

第一课 通用流程

其中\(\text{KNN}\)使用已经很少了,\(\text{SVM}\)在中小型数据集上表现很好目录了解场景和目标了解评估准则认识数据数据预处理数据清洗数据采样特征工程特征处理数值型类别型时间类文本型统计型组合特征特征选择过滤法包装法嵌入法模型融合BaggingStackingBoosting 了解场景…

DeepSeek本地化部署超简单,比装个office还简单

一、背景 最近DeepSeek太火了,以至于每位伙伴都想尝试,都想说上几句。作为一名程序员,不仅想使用这个DeeptSeek的AI工具,还是用其做更多的事情,比如本地化部署、构建自己的知识库,或者其他的应用。 本以为DeepSeek本地化部署有多难,实际上验证后很简单,任何普通人只要会…

【CTF】内存取证分析

免责声明: 此文转载自Tide安全团队原创文章,转载请声明出处!文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途给予盈利等目的,否则后果自行承担!一、基本概念 内存取证是指从计算机内存(RAM)中提取和分析数据的过程。当计算机运…

如何轻松保存或导出 Windows 聚焦图片

转自:https://www.sysgeek.cn/save-windows-spotlight-images/ Windows 聚焦功能可以让桌面和锁屏界面每天都呈现新的风景。如果你看到某张特别喜欢的图片,想要长期使用,要怎么找到图片在哪儿呢?本指南将教你如何在 Windows 11 和 Windows 10 上,轻松找到并保存 Windows 聚…

2025/2/10课堂记录

树上依赖背包,分组背包,vector邻接表,选课,树上dp,叶子的染色,链式前向星邻接表,数字转换,树的直径目录选课 叶子的染色 数字转换选课分组背包题 这次是自己写的代码了,也就瞟了标准答案几眼,真的就几眼用的也是vector邻接表#include<iostream> #include<ve…

3.4 什么是浮点数

很多编程语言中都提供了两种表示小数的数据类型,分别为双精度浮点数和单精度浮点数 双精度浮点数类型用64位、单精度浮点数类型用32位来表示全体小数。 在C语言中,双精度浮点数类型和单精度浮点数类型分别用double和float来表示 浮点数是指用符号、尾数、基数和指数这四部分来…

响应

ResponseBody注解 位置:controll类和方法 作用:将方法返回值直接相应,如果是实体对象和集合转成Json形式再相应、 统一响应格式 result里有静态方法

并行计算架构和编程 | 目录

from pixiv JW资源汇总 前言 开新坑了,尽量完成它吧. 此篇博客为目录章节,主要汇总学习过程中用到的资料,记录时间线。 SourceCS自学指南 CMU 15-418/Stanford CS149: Parallel Computing 了解此课程的主要起始地,下面的评论含有价值的信息 PKUFlyingPig/CS149-parallel-co…