|
前言
此篇随笔是博主在打电赛(全国大学生电子设计竞赛)中写下的笔记汇总,备赛历程可见:视频
希望对小白有所帮助。
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; // 引脚: A9 GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz; // 速度: 10MHz GPIO_Init(GPIOA,&GPIO_InitStrue); GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING; // 模式: 浮空输入 GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10; // 引脚: A10 GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz; // 速度: 10MHz GPIO_Init(GPIOA,&GPIO_InitStrue); USART_InitStrue.USART_BaudRate=9600; // 波特率: 9600 USART_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); //使能串口1 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //开启接收中断 NVIC_InitStrue.NVIC_IRQChannel=USART1_IRQn; NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=1; // 优先中断级别: 1 NVIC_InitStrue.NVIC_IRQChannelSubPriority=1; // 普通中断级别: 1 NVIC_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); // 初始化 EXTIvoid 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 Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler ; External Interrupts DCD WWDG_IRQHandler ; Window Watchdog DCD PVD_IRQHandler ; PVD through EXTI Line detect DCD TAMPER_IRQHandler ; Tamper DCD RTC_IRQHandler ; RTC DCD FLASH_IRQHandler ; Flash DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line 0 DCD EXTI1_IRQHandler ; EXTI Line 1 DCD EXTI2_IRQHandler ; EXTI Line 2 DCD EXTI3_IRQHandler ; EXTI Line 3 DCD EXTI4_IRQHandler ; EXTI Line 4 DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1 DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2 DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3 DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4 DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5 DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6 DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7 DCD ADC1_2_IRQHandler ; ADC1_2 DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0 DCD CAN1_RX1_IRQHandler ; CAN1 RX1 DCD CAN1_SCE_IRQHandler ; CAN1 SCE DCD EXTI9_5_IRQHandler ; EXTI Line 9..5 DCD TIM1_BRK_IRQHandler ; TIM1 Break DCD TIM1_UP_IRQHandler ; TIM1 Update DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare DCD TIM2_IRQHandler ; TIM2 DCD TIM3_IRQHandler ; TIM3 DCD TIM4_IRQHandler ; TIM4 DCD I2C1_EV_IRQHandler ; I2C1 Event DCD I2C1_ER_IRQHandler ; I2C1 Error DCD I2C2_EV_IRQHandler ; I2C2 Event DCD I2C2_ER_IRQHandler ; I2C2 Error DCD SPI1_IRQHandler ; SPI1 DCD SPI2_IRQHandler ; SPI2 DCD USART1_IRQHandler ; USART1 DCD USART2_IRQHandler ; USART2 DCD USART3_IRQHandler ; USART3 DCD EXTI15_10_IRQHandler ; EXTI Line 15..10 DCD RTCAlarm_IRQHandler ; RTC Alarm through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend__Vectors_End5、NVIC 相关函数
/* 注意:中断分支整个项目只能进行一次 */void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup); // 中断分组void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct); // 初始化 NVICvoid 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通道的CCRuint16_t TIM_GetCapture2(TIM_TypeDef* TIMx); // 读取2通道的CCRuint16_t TIM_GetCapture3(TIM_TypeDef* TIMx); // 读取3通道的CCRuint16_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); // 初始化 ADCvoid ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct); // ADC结构体初始化void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); // 开启 ADCvoid 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); // 软件触发 ADCFlagStatus 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); // 初始化 DMAvoid DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct); // DMA 结构体初始化void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState); // 使能 DMAvoid 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); // 初始化 USARTvoid 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); // 开启 USARTvoid 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 外部中断
具体步骤
- 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 输出
- 具体步骤
- 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; //ARR TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; //PSC TIM_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; //CCR TIM_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; //ARR TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC TIM_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 模式
- 具体步骤
- 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; //ARR TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC TIM_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; //ARR TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //PSC TIM_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
- 具体步骤
- 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
- 具体步骤
- 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 串口
- 具体步骤
- RCC 开启时钟(USART和GPIO)
- GPIO设置(TX配置为复用输出、RX配置为输入)
- 配置USART
- 开启中断、配置NVIC(可选)
- 开启USART
初始化函数:
#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); }}/** * @brief 发送字符串 * @param String: 字符串的首地址 * @retval None */void Serial_SendString(char *String){ uint8_t i; for (i = 0; String != '\0'; i ++) { Serial_SendByte(String); }}/** * @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);#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; // 标志位置1 USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清空终端挂起位 }}/** * @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; // 进入状态1 pRxPacket = 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; // 重新进入状态0 Serial_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*5 int 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"); // 编译器没有编译该语句,该语句不生成汇编代码#else printf("A < 1"); // 编译器编译了这段代码,且生成了汇编代码,执行该语句#endif模版:
#if x#else#endif#if x#elif x#else#endif2、#if defined
#if defined (x) ...code...#endif这个#if defined它不管里面的 x 的逻辑是“真”还是“假”。它只管这个程序的前面的宏定义里面有没有定义 x 这个宏,如果定义了 x 这个宏,那么,编译器会编译中间的 …code…,否则会直接忽视中间的 …code… 代码。 |
|