第四章-V1.5舵机 舵机角度控制 PWM控制红外对管和按键控制 STM32驱动舵机控制 SG90控制 超声波支架 STM32智能小车 舵机控制 江科大同款笔记单片机笔记嵌入式课程STM32嵌入式控制
当前视频版本V1.5.0
现在有两个版本小车
V1.5.0-STM32智能小车
视频链接:
[stm32入门教程][STM32实战项目]STM32智能小车V1.5-stm32f103c8t6-stm32最小系统-手把手入门教程-嵌入式开发-嵌入式学习
V3.3.0-STM32智能小车
视频链接
介绍:
V1.5.0:库函数开发。功能:循迹、避障、跟随、遥控、电池电压显示等。
V3:HAL库开发、功能:PID速度控制、PID循迹、PID跟随、遥控、避障、PID角度控制、视觉控制。
舵机控制
查看原理图
芯片手册
使用上节移植的定时器三例程
不需要开启部分重映射,
//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射
TIM3_CH2->PB5
初始化函数为
//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//使能对应时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
//使能GPIO外设和AFIO复用功能模块时钟
//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射
TIM3_CH2->PB5
//设置该引脚为复用输出功能,输出TIM3 CH1的PWM脉冲波形 GPIOA.6
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //TIM_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
//初始化TIM1
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄
存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中
指定的参数初始化TIMx的时间基数单位
//初始化TIM3 Channel1 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调
制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比
较极性高
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC1
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR1上的预装载寄
存器
TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
让舵机摇摇头
调用初始化函数和改变占空比
TIM3_PWM_Init(999,1439); //时钟源为72MHZ 故72 000 000 /
(1439+1)/(999+1)=50HZ
TIM_SetCompare1(TIM3,32); //舵机向右
delay_ms(900);
TIM_SetCompare1(TIM3,80); //舵机向前
delay_ms(900);
TIM_SetCompare1(TIM3,130); //舵机向左
delay_ms(900);
然后
按键与红外对管
按键外部中断实验
让我们先实现按键控制灯的亮灭
查看原理图
这里发现翻车,呜呜呜
由于C8T6小板子的PA12接了上拉电阻,所以使用PA12的时候要注意。而且如果我们用Mrico USB供电可能会影响PA11。
现在我们的原理图是这样的 KEY1-PA7 KEY2-PA12
配置按键端口模式
通过原理图知:KEY1(PA7)应该配置成下拉输入、上升沿触发。
KEY2(PA12)应该配置成上拉输入、下降沿触发。
//按键初始化函数
void KEY_Init(void) //IO初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA7设置成输入,默认下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.12
}
配置中断线和配置外部通道
//KEY外部中断服务程序
void KEY_EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
KEY_Init(); // 按键端口初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
//GPIOA.7 中断线以及中断初始化配置 上升沿触发 PA7 KEY_1
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource7); //选择GPIO引脚作为
中断线
EXTI_InitStructure.EXTI_Line=EXTI_Line7; //线路选择
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //事件选择
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //触发模式 上升沿触发
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设
EXTI寄存器
//GPIOA.5 中断线以及中断初始化配置 下降沿触发PA12 KEY_2
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource12);
EXTI_InitStructure.EXTI_Line=EXTI_Line12;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设
EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能按键KEY1所在
的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子
优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设
NVIC寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能按键KEY0
所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子
优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设
NVIC寄存器
}
相关宏定义 读取按键状态
#define KEY_1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)//读取按键KEY_1
#define KEY_2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)//读取按键KEY_2
编写响应中断函数
void EXTI9_5_IRQHandler(void)//按键KEY_1 和KEY_2的中断服务函数
{
delay_ms(10);//消抖
if(KEY_1 == 1) //判断按键KEY_1 是否被按下
{
LED =! LED;
EXTI_ClearITPendingBit(EXTI_Line7); //清除LINE7上的中断标志位
}
}
void EXTI15_10_IRQHandler(void)//按键KEY_SW1 和KEY_SW2的中断服务函数
{
delay_ms(10);//消抖
if(KEY_2 == 0) //判断按键KEY_2 是否被按下
{
LED =! LED;
EXTI_ClearITPendingBit(EXTI_Line12); //清除LINE7上的中断标志位
}
}
调用初始化函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先
级,2位响应优先级
//如果没有设置中断优先级分组要先设置
KEY_EXTIX_Init(); //初始化外部中断输入
烧录调试
观察现象
红外对管硬件使用方法
详见:系统硬件设计->红外循迹模块
可以把红外对管看成’按键’,当前面有黑色时候为高电平,前面白色低电平。
红外对管的驱动
红外对管这里使用查询的方式,通过GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)函数获得对应端口的电平
查看原理图 红外对管依次连接 PB5 、PB4 、PB3 、PA15
红外管GPIO初始化
注意:这里我们需要使用的PB3、PB4、PA15是单片机的’特殊引脚
我们打开数据手册:STM32F103x8B_DS_CH_V10,在引脚定义章节,说明了复位后的主功能和默认复用功能以及重定义功能。
在参考手册:STM32中文参考手册_V10, 在8.3.5 JTAG/SWD复用功能重映射中,说明了引脚使用
所以我们需要关闭JTAG-DP 启用SW-DP ,我们重映射配置应写为
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
//红外循迹TCRT5000初始化函数
void TCRT5000_Init(void) //IO初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);//使
能PORTA,PORTB时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
//重映射配置关闭JTAG-DP 启用SW-DP从而可以使用PA15 PB3 PB4
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA15 设置成下拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.15
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_4|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 设置成下拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB 5 4 3
}
一些宏定义,利用函数读取电平
#define HW_1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)//读取 PB5 电平
#define HW_2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)//读取 PB4
#define HW_3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_3)//读取 PB3
#define HW_4 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)//读取 PA15
调用初始化函数
TCRT5000_Init();
红外对管控制小灯
while(1){
if(HW_1 == 1 && HW_2==0 && HW_3 == 1 && HW_4 == 0 )//当第一个和第三
个前面是黑色时候板子小灯亮,其他情况板子小灯灭
{
LED =0;
}
else{
LED =1;
}
}
练一练–红外对管循迹
while(1)
{
if(HW_1 == 0 && HW_2 == 0 && HW_3 == 0 && HW_4 == 0)
{
Forward();
delay_ms(50);
}
if(HW_1 == 0 && HW_2 == 1 && HW_3 == 0 && HW_4 == 0)
{
Rightward();
delay_ms(150);
}
if(HW_1 == 1 && HW_2 == 0 && HW_3 == 0 && HW_4 == 0)
{
Rightward();
delay_ms(250);
}
if(HW_1 == 1 && HW_2 == 1 && HW_3 == 0 && HW_4 == 0)
{
Rightward();
delay_ms(300);
}
if(HW_1 == 0 && HW_2 == 0 && HW_3 == 1 && HW_4 == 0)
{
Leftward();
delay_ms(150);
}
if(HW_1 == 0 && HW_2 == 0 && HW_3 == 0 && HW_4 == 1)
{
Leftward();
delay_ms(250);
}
if(HW_1 == 0 && HW_2 == 0 && HW_3 == 1 && HW_4 == 1)
{
Leftward();
delay_ms(300);
}
}