STM32F103C8学习
1.新建工程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w8ejH9ix-1670863229262)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221021022650914.png)]
APB2和APB1外设
STM32参考手册搜索“系统架构”或者“系统结构”,即可查看外设挂在哪个时钟下,也就知道开启哪个时钟了。
APB1上面连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、USART2、USART3、UART4、UART5、SPI2、SP3等;
而APB2上面连接的是高速外设,包括UART1、SPI1、Timer1、ADC1、ADC2、ADC3、所有的普通I/O口(PA-PE)、第二功能I/O(AFIO)口等。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4qVPLMwY-1670863229263)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221021232648050.png)]
2.寄存器和库函数电灯
#include "stm32f10x.h" // Device header
int main()//配置寄存器,会影响其他端口的原有配置
{
// RCC->APB2ENR = 0x00000010;//APB2外设时钟使能寄存器,打开GPIOC的时钟
// GPIOC->CRH = 0x00300000;
// //给PC13口输出数据
// //端口输出寄存器
// GPIOC->ODR = 0x00002000;//低电平带点亮,给ODR全为0为亮,0x00002000为灭//库函数点灯//使能时钟函数,参数1:选择外设,参数2:选择新的状态RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//配置GPIOC外部时钟//配置端口模式//定义一个结构体GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//模式:通用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;//端口:13GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度:50MHzGPIO_Init(GPIOC,&GPIO_InitStructure);//参数1:选择哪个GPIO,参数2:参数的结构体的地址//设置端口的高电平函数GPIO_SetBits(GPIOC,GPIO_Pin_13);//参数1:哪个端口,参数2:哪个位置//设置端口的低电平函数
// GPIO_ResetBits(GPIOC,GPIO_Pin_13);//参数1:哪个端口,参数2:哪个位置while(1){}
}
3.GPIO
GPIO(General Purpose Input Output)通用输入输出口可配置为8种输入输出模式引脚电平:0V~3.3V,部分引脚可容忍5V输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等
GPIO八种工作模式
模式名称 | 性质 | 特征 |
---|---|---|
浮空输入 | 数字输入 | 可读取引脚电平,若引脚悬空,则电平不确定 |
上拉输入 | 数字输入 | 可读取引脚电平,内部连接上拉电阻,悬空时默认高电平 |
下拉输入 | 数字输入 | 可读取引脚电平,内部连接下拉电阻,悬空时默认低电平 |
模拟输入 | 模拟输入 | GPIO无效,引脚直接接入内部ADC |
开漏输出 | 数字输出 | 可输出引脚电平,高电平为高阻态,低电平接VSS |
推挽输出 | 数字输出 | 可输出引脚电平,高电平接VDD,低电平接VSS |
复用开漏输出 | 数字输出 | 由片上外设控制,高电平为高阻态,低电平接VSS |
复用推挽输出 | 数字输出 | 由片上外设控制,高电平接VDD,低电平接VSS |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BUAvCdRe-1670863229263)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221021044453852.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F1qGPERJ-1670863229264)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221021044527493.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BMgVmMwG-1670863229264)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221021044543701.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q5dZ3cH6-1670863229264)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221021044552671.png)]
typedef enum
{ GPIO_Mode_AIN = 0x0,//模拟输入GPIO_Mode_IN_FLOATING = 0x04,//浮空输入GPIO_Mode_IPD = 0x28,//下拉输入GPIO_Mode_IPU = 0x48,//上拉输入GPIO_Mode_Out_OD = 0x14,//开漏输出GPIO_Mode_Out_PP = 0x10,//推挽输出GPIO_Mode_AF_OD = 0x1C,//复用开漏GPIO_Mode_AF_PP = 0x18//复用推挽
}GPIOMode_TypeDef;
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//输出高电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//输出低电平
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);//
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);//写入
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//锁定GPIO配置
LED闪烁
#include "stm32f10x.h"// Device header
#include "Delay.h"
int main()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//APB2外设时钟控制函数,开启GPIOA时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//GPIO_ResetBits(GPIOA,GPIO_Pin_0);//PA0输出低电平//GPIO_SetBits(GPIOA,GPIO_Pin_0);//PA0输出高电平//GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);//输出低电平while(1){GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);//输出低电平Delay_ms(100);GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);//输出低电平Delay_ms(100);}
}
利用或选中8个GPIOA端口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
利用或选中GPIOA,GPIOB,GPIOC等等端口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);//APB2外设时钟控制函数,开启GPIOA,GPIOB,GPIOB时钟
注意:A15,B3,B4这三个端口不要选是调试端口,想要做普通端口还需设置。
C语言知识补充
关键字 | 位数 | 表示范围 | stdint****关键字 | ST****关键字 |
---|---|---|---|---|
char | 8 | -128 ~ 127 | int8_t | s8 |
unsigned char | 8 | 0 ~ 255 | uint8_t | u8 |
short | 16 | -32768 ~ 32767 | int16_t | s16 |
unsigned short | 16 | 0 ~ 65535 | uint16_t | u16 |
int | 32 | -2147483648 ~ 2147483647 | int32_t | s32 |
unsigned int | 32 | 0 ~ 4294967295 | uint32_t | u32 |
long | 32 | -2147483648 ~ 2147483647 | ||
unsigned long | 32 | 0 ~ 4294967295 | ||
long long | 64 | -(2^64)/2 ~ (2^64)/2-1 | int64_t | |
unsigned long long | 64 | 0 ~ (2^64)-1 | uint64_t | |
float | 32 | -3.4e38 ~ 3.4e38 | ||
double | 64 | -1.7e308 ~ 1.7e308 |
蜂鸣器
#include "stm32f10x.h"// Device header
#include "Delay.h"
int main()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//APB2外设时钟控制函数,开启GPIOA时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);//GPIO_ResetBits(GPIOA,GPIO_Pin_0);//PA0输出低电平//GPIO_SetBits(GPIOA,GPIO_Pin_0);//PA0输出高电平//GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);//输出低电平while(1){GPIO_ResetBits(GPIOB,GPIO_Pin_12);//输出低电平Delay_ms(500);GPIO_SetBits(GPIOB,GPIO_Pin_12);//输出低电平Delay_ms(500);}
}
GPIO读取函数
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//读取输入寄存器某一位值
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);//读取整个输入寄存器值
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//读取输出寄存器某一位值
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);//读取输出整个输出寄存器值
蜂鸣器模块函数封装
void Buzzer_Init()//初始化函数
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB时钟GPIO_InitTypeDef GPIO_InStructture;GPIO_InStructture.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出GPIO_InStructture.GPIO_Pin = GPIO_Pin_12;//选中PB12GPIO_InStructture.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InStructture);GPIO_SetBits(GPIOB,GPIO_Pin_12);
}void Buzzer_ON()//打开
{GPIO_ResetBits(GPIOB,GPIO_Pin_12);//设置12口为低电平
}void Buzzer_OFF()//关闭
{GPIO_SetBits(GPIOB,GPIO_Pin_12);//设置12口为高电平
}void Buzzer_Turn()//翻转
{if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_12) == 0)//如果Buzzer是响着{GPIO_SetBits(GPIOB,GPIO_Pin_12);//把PB12置1}else{GPIO_ResetBits(GPIOB,GPIO_Pin_12);//把PB12置0}
}
独立按键模块函数封装
void Key_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);
}uint8_t Key_GetNum()//返回按键键码
{uint8_t KeyNum = 0;if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){Delay_ms(20);//消除按键抖动while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)Delay_ms(20);KeyNum = 1;}if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0){Delay_ms(20);//消除按键抖动while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0)Delay_ms(20);KeyNum = 2;}return KeyNum;
}
光敏电阻传感器函数封装
void Key_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);
}uint8_t Key_GetNum()//返回按键键码
{uint8_t KeyNum = 0;if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){Delay_ms(20);//消除按键抖动while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)Delay_ms(20);KeyNum = 1;}if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0){Delay_ms(20);//消除按键抖动while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0)Delay_ms(20);KeyNum = 2;}return KeyNum;
}
OLED显示屏函数
由SCL和SDA插在GPIO任意位置都可以
函数 | 作用 |
---|---|
OLED_Init(); | 初始化 |
OLED_Clear(); | 清屏 |
OLED_ShowChar(1, 1, ‘A’); | 显示一个字符 |
OLED_ShowString(1, 3, “HelloWorld!”); | 显示字符串 |
OLED_ShowNum(2, 1, 12345, 5); | 显示十进制数字 |
OLED_ShowSignedNum(2, 7, -66, 2); | 显示有符号十进制数字 |
OLED_ShowHexNum(3, 1, 0xAA55, 4); | 显示十六进制数字 |
OLED_ShowBinNum(4, 1, 0xAA55, 16); | 显示二进制数字 |
外部中断
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
分组方式 | 抢占优先级 | 响应优先级 |
---|---|---|
分组0 | 0位,取值为0 | 4位,取值为0~15 |
分组1 | 1位,取值为0~1 | 3位,取值为0~7 |
分组2 | 2位,取值为0~3 | 2位,取值为0~3 |
分组3 | 3位,取值为0~7 | 1位,取值为0~1 |
分组4 | 4位,取值为0~15 | 0位,取值为0 |
NVIC基本结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4qb7GCyF-1670863229265)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221022021227593.png)]
NVIC优先级分组
NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
分组方式 | 抢占优先级 | 响应优先级 |
---|---|---|
分组0 | 0位,取值为0 | 4位,取值为0~15 |
分组1 | 1位,取值为0~1 | 3位,取值为0~7 |
分组2 | 2位,取值为0~3 | 2位,取值为0~3 |
分组3 | 3位,取值为0~7 | 1位,取值为0~1 |
分组4 | 4位,取值为0~15 | 0位,取值为0 |
EXTI基本结构
EXTI(Extern Interrupt)外部中断EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序支持的
触发方式:上升沿/下降沿/双边沿/软件触发
支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发
中断通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
触发响应方式:中断响应/事件响应
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ftpFQNi-1670863229265)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221022021416493.png)]
配置AFIO
void GPIO_AFIODeInit(void);//复位AFIO外设
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);//配置AFIO的事件输出功能的
void GPIO_EventOutputCmd(FunctionalState NewState);
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);//可以进行引脚重映射,参数:重映射的方式,参数2:参数新的状态
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);//可以选择AFIO的数据选择器,选择想要的中断引脚
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uLqxLZTI-1670863229265)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221022030748114.png)]
配置EXTI
void EXTI_DeInit(void);//清除EXTI的配置,回复成上电默认的状态
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);//根据这个结构体的参数配置EXTI的外设
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);//可以把参数传递的结构体变量赋一个默认值
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);//软件出发外部中断
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);//获取指定的标志位是否被置1
void EXTI_ClearFlag(uint32_t EXTI_Line);//对置1的标志位进行清除(主程序中判断)
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);//获取中断标志位是否被置1(中断中判断)
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);//清除中断挂起标志位
配置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);//系统低功耗配置
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
旋转编码器原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NsNxKjg4-1670863229266)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221022040256620.png)]
红外对射传感器计数中断的应用
#include "stm32f10x.h" // Device header
uint16_t CountSensor_Count;
void CountSensor_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//打开GPIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//打开AFIO时钟//EXTI和NVIC的时钟默认打开,不需要打开,NVIC是内核的外设,内核的外设不需要开启时钟//配置初始化GPIOB的外设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的.h文件中GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);//AFIO外设中断引脚选择//配置EXTIEXTI_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_Rising;//下降沿触发EXTI_Init(&EXTI_InitStructure);//配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn ;//设置中断通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//开启NVICNVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//只有一个中断优先级随便NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);
}
uint16_t CountSensor_Get()
{return CountSensor_Count;
}void EXTI15_10_IRQHandler()//不需要声明
{if(EXTI_GetITStatus(EXTI_Line14)==SET)//判断14位中断标志位是否为1,即是否是14位发生了中断{CountSensor_Count++;EXTI_ClearITPendingBit(EXTI_Line14);//清除中断标志位}}
定时器
TIM(Timer)定时器定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
定时器类型
类型 | 编号 | 总线 | 功能 |
---|---|---|---|
高级定时器 | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 |
通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 |
基本定时器 | TIM6、TIM7 | APB1 | 拥有定时中断、主模式触发DAC的功能 |
STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4
定时器中断基本结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aQoNCf8p-1670863229266)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221022195815138.png)]
void TIM_DeInit(TIM_TypeDef* TIMx);//恢复缺省配置
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//时基单元初始化
//参数1:定时器,参数2:结构体
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);//使能中断输出信号
//参数1:选择定时器,参数2:选择要配置哪个中断输出,参数3:使能还是失能
//下列六个函数是时基单元的时钟选择部分
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);//选择内部时钟
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);//选择ITRx其他定时器的时钟
//参数1:选择定时器,参数2:选择要接入哪个其他的定时器
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);//选择TIx捕获通道的时钟
//参数1:选择哪个时钟,参数2:选择TIx具体的某个引脚,参数3:输入的极性,参数4:滤波器
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);//选择ETR外部时钟模式1输入的时钟
//参数1:外部触发预分频器,参数2:输入的极性,参数3:滤波器
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);//
配置定时器
#include "stm32f10x.h" // Device headerextern uint16_t Num;
void Timer_Init()
{//开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启时基本单元的时钟(内部时钟)TIM_InternalClockConfig(TIM2);//配置时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructre;TIM_TimeBaseInitStructre.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分频TIM_TimeBaseInitStructre.TIM_CounterMode = TIM_CounterMode_Up;//设置计数模式位向上计数//下面两个函数决定定时时间//定时1s定时频率为1HzTIM_TimeBaseInitStructre.TIM_Period = 10000 - 1;//ARR自动重装器的值//CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)//在10k的频率下记10000个数,就是1sTIM_TimeBaseInitStructre.TIM_Prescaler = 7200 - 1;//PSC预分频器的值,定时频率=72M/(PSC+1)/(ARR+1)//得到10K的计数频率//上面两个函数决定定时时间TIM_TimeBaseInitStructre.TIM_RepetitionCounter = 0;//重复计数器的值,高级计数器特有不需要用给0TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructre);TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清除中断标志位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启了更新中断到NVIC的通路NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC中断优先级分组NVIC_InitTypeDef NVIC_InitStructre;//NVIC_InitStructre.NVIC_IRQChannel = TIM2_IRQn;//通道NVIC_InitStructre.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructre.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级NVIC_InitStructre.NVIC_IRQChannelSubPriority = 1;//响应优先级NVIC_Init(&NVIC_InitStructre);TIM_Cmd(TIM2,ENABLE);//打开定时器
}//void TIM2_IRQHandler()
//{
// if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)//
// {
// Num++;
// TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
// }//}
TIM输出比较
OC(Output Compare)输出比较
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出的功能
PWM
PWM(Pulse Width Modulation)脉冲宽度调制
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
PWM参数:
频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ys8xSerm-1670863229266)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023032040213.png)]
(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023032438904.png)]
输出比较模式
模式 | 描述 |
---|---|
冻结 | CNT=CCR时,REF保持为原状态 |
匹配时置有效电平 | CNT=CCR时,REF置有效电平 |
匹配时置无效电平 | CNT=CCR时,REF置无效电平 |
匹配时电平翻转 | CNT=CCR时,REF电平翻转 |
强制为无效电平 | CNT与CCR无效,REF强制为无效电平 |
强制为有效电平 | CNT与CCR无效,REF强制为有效电平 |
PWM模式1 | 向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平 |
PWM模式2 | 向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平 |
计数器,预分频器,自动重载,重复计数器。通用定时器是由一个可编程预分频器驱动的16位自动装载计数器构成,定时器中的PSC、ARR、CNT、CCR寄存器,分别存放计数器,预分频器,自动重载,重复计数器。
PWM的基本结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QR8kaeG4-1670863229267)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023033812126.png)]
控制CCR的大小控制占空比
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLmSDejT-1670863229267)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023034313502.png)]
ARR越大CRR的范围就越大,对应分辨率就越大
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WNj69asN-1670863229267)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023035524236.png)]
舵机
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hu2gk9jz-1670863229267)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023035854641.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3fb1fngI-1670863229268)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023040053048.png)]
直流电机
直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转
直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作
TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ttEtuCwQ-1670863229268)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023040531049.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q2MtDL0B-1670863229268)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023041247523.png)]
配置输出比较模块
//一个函数配置一个单元,output compare输出比较
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);
//配置CCR寄存器的预装功能(影子寄存器)
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
//设置极性
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);
//更改CCR寄存器值的函数(重要)
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
//仅高级定时器使用,需要调用这个函数使能主要输出,否则PWM不能正常输出
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
#define TIM_OCMode_Timing //冻结模式
#define TIM_OCMode_Active //相等时置有效电平
#define TIM_OCMode_Inactive //相等时置无效电平
#define TIM_OCMode_Toggle //相等时电平翻转
#define TIM_OCMode_PWM1 //PWM模式1
#define TIM_OCMode_PWM2 //PWM模式2
#define TIM_OCNPolarity_High //高极性,极性不翻转,有效电平是高电平
#define TIM_OCNPolarity_Low //低极性,极性反转,有效电平为低电平
#define IS_TIM_OCN_POLARITY(POLARITY)
pwm控制直流电机
pwm.c
#include "stm32f10x.h" // Device header
void PWM_Init()
{//配置GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA时钟GPIO_InitTypeDef GPIO_InStructture;GPIO_InStructture.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出GPIO_InStructture.GPIO_Pin = GPIO_Pin_2;//重映射为PA15GPIO_InStructture.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InStructture);//开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启时基本单元的时钟(内部时钟)TIM_InternalClockConfig(TIM2);//配置时基单元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructre;TIM_TimeBaseInitStructre.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分频TIM_TimeBaseInitStructre.TIM_CounterMode = TIM_CounterMode_Up;//设置计数模式位向上计数//下面两个函数决定定时时间//定时1s定时频率为1Hz//ARRTIM_TimeBaseInitStructre.TIM_Period = 100 - 1;//ARR自动重装器的值//CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)//在10k的频率下记10000个数,就是1s//PSC TIM_TimeBaseInitStructre.TIM_Prescaler = 720 - 1;//PSC预分频器的值,定时频率=72M/(PSC+1)/(ARR+1)//得到10K的计数频率//上面两个函数决定定时时间TIM_TimeBaseInitStructre.TIM_RepetitionCounter = 0;//重复计数器的值,高级计数器特有不需要用给0TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructre);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值,给TIM_OCInitStructure,赋值再更改想改的值TIM_OCInitStructure.TIM_OCIdleState = 0;//高级定时器TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置输出比较的模式TIM_OCInitStructure.TIM_OCNIdleState = 0;//带N的是高级定时器才能用到的TIM_OCInitStructure.TIM_OCNPolarity = 0;//高级定时器TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High;//设置输出比较的极性TIM_OCInitStructure.TIM_OutputNState = 0;//高级定时器TIM_OCInitStructure.TIM_OutputState = ENABLE;//设置输出使能TIM_OCInitStructure.TIM_Pulse = 90;//设置CCRTIM_OC3Init(TIM2,&TIM_OCInitStructure);TIM_Cmd(TIM2,ENABLE);//打开定时器
}void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2,Compare);}
motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"void Motor_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA时钟GPIO_InitTypeDef GPIO_InStructture;GPIO_InStructture.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出GPIO_InStructture.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_11|GPIO_Pin_12 ;//选中PA1和PA2GPIO_InStructture.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InStructture);PWM_Init();}void Motor_SetSpeed(int8_t Speed)
{if(Speed>=0){GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);GPIO_SetBits(GPIOA,GPIO_Pin_11);GPIO_ResetBits(GPIOA,GPIO_Pin_12);PWM_SetCompare3(Speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);GPIO_ResetBits(GPIOA,GPIO_Pin_11);GPIO_SetBits(GPIOA,GPIO_Pin_12);PWM_SetCompare3(-Speed);}}
输入捕获
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ihBks48V-1670863229268)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023190616213.png)]
频率测量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fP4sUUYe-1670863229269)(C:\Users\puheliang\AppData\Roaming\Typora\typora-user-images\image-20221023191352257.png)]
uctture.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InStructture.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_11|GPIO_Pin_12 ;//选中PA1和PA2
GPIO_InStructture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InStructture);
PWM_Init();
}
void Motor_SetSpeed(int8_t Speed)
{
if(Speed>=0)
{
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
GPIO_SetBits(GPIOA,GPIO_Pin_11);
GPIO_ResetBits(GPIOA,GPIO_Pin_12);
PWM_SetCompare3(Speed);
}
else
{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);GPIO_ResetBits(GPIOA,GPIO_Pin_11);GPIO_SetBits(GPIOA,GPIO_Pin_12);PWM_SetCompare3(-Speed);
}
}
### 输入捕获[外链图片转存中...(img-ihBks48V-1670863229268)]### 频率测量[外链图片转存中...(img-fP4sUUYe-1670863229269)]