前言
stm32F103c8t6 最小系统板(基础入门)
片上资源/外设
一、 使用GPIO 口
首先,从APB2总线 引出,RCC_APB2PeriphClockCmd(GPIO口的名字,状态)
如GPIOA 使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
其次, 我们看一下,GPIO 初始化函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
第一个参数 GPIO口的名字 如GPIOA
第二个参数 GPIO的结构体地址 如&GPIO_InitStructure
stuuct 关键字 定义结构体变量 用途:数据打包,不同类型的变量打包,如
因为结构体变量类型较长,所以通常用typedef更改变量类型名
typedef 关键字 用途:将一个比较长的变量类型名换个名字
比如:
将 结构体变量struct{} 换一个别名叫GPIO_InitTypeDef
于是 ,我们用
GPIO_InitTypeDef GPIO_InitStructure;
来定义了一个名为GPIO_InitStructure的结构体变量
我们将其地址存入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure 有三个参数
GPIO_InitStructure.GPIO_Mode
GPIO_InitStructure.GPIO_Pin
GPIO_InitStructure.GPIO_Speed
第一个Mode有8种模式
GPIO_Mode_AIN(Analog IN)//模拟输入
GPIO_Mode_IN_FLOATING //浮空输入
GPIO_Mode_IPD (In Pull Down) //下拉输入
GPIO_Mode_IPU (In Pull Up) //上拉输入
GPIO_Mode_OUT_OD(Out Open Drain) //开漏输出
GPIO_Mode_PP_OD(Out Push Pull) //推挽输出
GPIO_Mode_AF_OD(Atl Open Drain) //复用开漏
GPIO_Mode_AF_PP(Atl Push Pull) //复用推挽
第二个GPIO_InitStructure.GPIO_Pin 的选择
第三个GPIO_InitStructure.GPIO_Speed的选择
我们一般选50MHz
整个步骤如下
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
这样我们就把GPIOA 上所有引脚都初始化好了。
关于GPIO口的常用函数
将GPIO口置 1 和 置零 操作
GPIO_ResetBits(GPIOA, GPIO_Pin_0); //将PA0口置0
Delay_ms(500);
GPIO_SetBits(GPIOA, GPIO_Pin_0);//将PA0口置1
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);//Bit_RESET设置低电平
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);//强制转换BitAction类型 0 1
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
Delay_ms(500);
读取GPIO上 电平操作
GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);//读取PB13上引脚输入 一般是接一个按键 读它的输入 即是否按下
GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1)//读取PA1上引脚输出 一般接光敏传感器 读它的AO口输出 即是否被遮挡
流水灯例程
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);////692行3个
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//开漏模式 高电平没有驱动能力
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
while (1)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
Delay_ms(500);
GPIO_SetBits(GPIOA, GPIO_Pin_0);
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);//Bit_RESET设置低电平
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
Delay_ms(500);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);//强制转换BitAction类型 0 1
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
Delay_ms(500);
}
}
其中Delay.c
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
Delay.h
#ifndef __DELAY_H
#define __DELAY_H
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);
#endif
封装函数操作
//灯的打开
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
//灯的熄灭
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
//灯的翻转
void LED1_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
}
二、使用AFIO外部中断引脚选择
使能APB2总线上的AFIO时钟
比如 : 我们将PB12设为中断引脚
首先,使能APB2总线上的AFIO时钟和初始化PB12 引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能gpio时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//使能afio时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入 exit 上拉 下拉 都行
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //配置gpio
中断初始化
其次,选择中断引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource11);//AFIO 中断引脚选择
然后中断初始化
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
类似于GPIO初始化
EXTI_InitTypeDef EXTI_InitStructure;
//有四个参数
EXTI_InitStructure.EXTI_Line //EXIT_Line0 ~19 其中line16 ~line19 是 PVD(电压检测器) RTC(实时时钟) USB ETH(以太网)
EXTI_InitStructure.EXTI_LineCmd //ENABLE FALSE 开启关闭
EXTI_InitStructure.EXTI_Mode // EXTI_Trigger_Rising 上边沿触发 EXTI_Trigger_Falling 下边沿触发 EXTI_Trigger_Rising_Falling 双边沿触发
EXTI_InitStructure.EXTI_Trigger // EXTI_Mode_Interrupt 中断触发 EXTI_Mode_Event 事件触发
NVIC初始化
然后选择NVIC优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组2 2抢占 2 响应
抢占 相当于 重症直接进icu
响应 相当于 插队到下一个
5-9 中断线 共用一个中断通道 EXTI9_5_IRQn
10-15中断线 共用一个中断通道 EXIT15_10IRQn
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //指定中断通道来开启或关闭 //每个f1型号不一样,c8是MD中等型号 10-15 都在EXTI15_10_IRQn里 //EXTI0_IRQn
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级 2组 0-3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级 0-3
NVIC_Init(&NVIC_InitStructure);//
中断函数
最后写中断函数
//中断函数里查看清除状态
EXTI_GetITStatus(EXTI_Line11)
EXTI_ClearITPendingBit(EXTI_Line11)
//主程序里查看清除状态
EXTI_GetFlagStatus()
EXTI_ClearFlag()
void EXTI15_10_IRQHandler(void)///EXTI0_IRQHandler //中断函数不需要申明,因为自动执行
{
if (EXTI_GetITStatus(EXTI_Line11) == SET) //判断中断线是否是1
{
CountSensor_Count ++;
EXTI_ClearITPendingBit(EXTI_Line11);//不清楚中断标志位 ,就一直置1
}
}
以下为全代码
void CountSensor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能gpio时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//使能afio时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入 exit 上拉 下拉 都行
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //配置gpio
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource11);//AFIO 中断引脚选择
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line11; //PB11 中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //开启中断
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
EXTI_Init(&EXTI_InitStructure);//配置中断
//nvic在misc.h里
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组2 2抢占 2 响应
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //指定中断通道来开启或关闭 //每个f1型号不一样,c8是MD中等型号 10-15 都在EXTI15_10_IRQn里 //EXTI0_IRQn
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级 2组 0-3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级 0-3
NVIC_Init(&NVIC_InitStructure);//
}
void EXTI15_10_IRQHandler(void)///EXTI0_IRQHandler //中断函数不需要申明,因为自动执行
{
if (EXTI_GetITStatus(EXTI_Line11) == SET) //判断中断线是否是11
{
CountSensor_Count ++;
EXTI_ClearITPendingBit(EXTI_Line11);//不清楚中断标志位 ,就一直置1
}
}
三、使用定时器/计数器
选择时钟
内部时钟和外部时钟
//选择内部时钟
TIM_InternalClockConfig(TIM2);
//通过ETR引脚的外部时钟模式2配置
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);
//TIM_ExtTRGPSC_OFF 不需要分频 TIM_ExtTRGPolarity_NonInverted极性,高电平或上升沿有效
内部时钟当定时器用
ARR 自动重装的值
PSC 预分频器的值
1MHz=1000 000Hz
//计数器计数频率 CK_CNT = CK_PSC/(PSC+1)
//计数器溢出频率 CK_CNT_OV = CK_PSC/(PSC+1)/(ARR+1)
//预分频给少点 自动重装给多点 以一个比较高的频率计比较多的数
//预分频给多点 自动重装给少点 以一个低的频率计比较少的数
//计数器计数频率 CK_CNT = CK_PSC/(PSC+1)
10k的计数频率 计10000的数 即 1s 加1
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1; //周期 ARR自动重装器的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //PSC预分频器的值 10k的计数频率 计10000的数
计数方式
TIM_TimeBaseInitStructure.TIM_CounterMode
TIM_CounterMode_Up //向上计数 从零计到到目标值之后变零
TIM_CounterMode_Down//向下计数 从目标值计到目标值之后回到目标值
TIM_CounterMode_CenterAligned1 //自动对齐 到目标值 到零 均更新中断
TIM_CounterMode_CenterAligned2
TIM_CounterMode_CenterAligned3
一般选用向上计数
初始化时基单元
//初始化时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //配置时基单元
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //指定时钟分频 /1分频 影响不大
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1; //周期 ARR自动重装器的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //PSC预分频器的值 10k的计数频率 计10000的数
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值 //高级定时器才有 这里通用计时器 不用
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
中断方式选择 更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能中断 update 更新中断
以下为全部代码
#include "stm32f10x.h" // Device header
//extern uint16_t Num; //引用其他文件(主函数)的Num变量
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//TIM2 APB1总线上的外设
TIM_InternalClockConfig(TIM2); //选择内部时钟
//初始化时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //配置时基单元
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //指定时钟分频 /1分频 影响不大
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1; //周期 ARR自动重装器的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //PSC预分频器的值 10k的计数频率 计10000的数
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值 //高级定时器才有 这里通用计时器 不用
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);//手动把更新中断标志位清除一下 防止 reset直接到1
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能中断 update 更新中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //优先级分组
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) //定时器2 的中断函数
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//看更新中断标志位
{
Num++;
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
*/
外部时钟当计数器用
#include "stm32f10x.h" // Device header
//PA0 TIM2的ETR引脚
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//通过ETR引脚的外部时钟模式2配置
//TIM_ExtTRGPSC_OFF 不需要分频 TIM_ExtTRGPolarity_NonInverted极性,高电平或上升沿有效 0x00不用滤波器
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1; //从0计到9
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 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_PriorityGroupConfig(NVIC_PriorityGroup_2);
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);
}
uint16_t Timer_GetCounter(void)
{
return TIM_GetCounter(TIM2);
}
/*
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
*/
TIM函数
中断函数里
//看更新中断标志位 清除标志位
TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
TIM_ClearITPendingBit(TIM2, TIM_IT_Update)
主程序里
TIM_GetFlagStatus()
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
四、OC输出比较器(PWM)
OC (output compare) 输出比较 比较CNT 和 CCR 寄存器的关系
IC (input compare) 输入捕获
CC (capture compare)输入捕获 和输出比较单元
TIM_OCInitTypeDef TIM_OCInitStructure;//初始化输出比较单元
TIM_OCStructInit(&TIM_OCInitStructure); //给结构体赋初始值 里面定义默认给的初始值,防止高级定时器出错
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM1模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出比较极性 高级性 极性不翻转 有效电平为高电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR寄存器的值
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//PA0口对应第一个输出比较通道
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);//单独更改通道1的CCR的值的
}
五、使用AFIO复用功能引脚重映射
重映射方式和引脚对应关系 ,选择重映射方式 查看参考手册
gpio.c 选择重映射方式
GPIO_PartialRemap1_TIM2 //部分重映射1
GPIO_PartialRemap2_TIM2//部分重映射2
GPIO_FullRemap_TIM2//完全重映射
最小系统板引脚定义 最后一列为重映射
GPIO_PinRemapConfig()重映射函数
方式1
// 解除JTACK调试端口复用 PA15 PB3 PB14 变回GPIO
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //打开AFIO时钟
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
方式2
// 重映射定时器 或者其他外设的复用引脚
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //引脚重映射 选择部分重映射1 方式
方式3
//重映射引脚正好是调试端口的引脚 那都加上
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //引脚重映射 选择部分重映射1 方式
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//解除JTACK调试端口复用 PA15 PB3 PB14 变回GPIO
有了这三句 我们定时器的通道1 , 就从PA0 挪到PA15了
那么我们初始化的是GPIO口是应该是PA15 了
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出 想用定时器来控制引脚 复用 引脚控制权才能交给片上外设 //不然是输出数据寄存器控制
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
最后附上引脚定义图
六、tb6612 的使用
VM 接5v
STBY 待机控制脚 ,不需要待机 直接接逻辑电源正3.3V
A01 A02 接两个电机 接线不分正反 对调两根线 电机旋转的方向就会反过来
AIN1 AIN2 是方向控制 任意接两个GPIO 就行了
PWMA 是速度控制 需要接PWM的输出脚 这里接的是PA2 PA2 对应的是TIM2的通道3 ,到时候初始化通道3就行了