第四章-V1.5 舵机 舵机角度控制 PWM控制红外对管和按键控制 STM32驱动舵机控制 SG90控制

描述

功能介绍放开头, 使用便捷无需愁。

这是全网最详细、性价比最高的STM32实战项目入门教程,通过合理的硬件设计和详细的视频笔记介绍,硬件使用STM32F103主控资料多方便学习,通过3万字笔记、12多个小时视频、20多章节代码手把手教会你如何开发和调试。让你更快掌握嵌入式系统开发。

V1.5.0-STM32智能小车

V1.5.0:库函数开发。功能:循迹、避障、跟随、遥控、电池电压显示等。

视频合集链接推荐观看

[https://www.bilibili.com/video/BV1SY411L7rJ/?spm_id_from=333.337.search-card.all.click]

**V3.3.0-STM32智能小车 **

V3:HAL库开发、功能:PID速度控制、PID循迹、PID跟随、遥控、避障、PID角度控制、视觉控制、电磁循迹、RTOS等功能。

视频合集链接推荐观看

[https://www.bilibili.com/video/BV16x4y1M7EN/?spm_id_from=333.337.search-card.all.click]

舵机控制

查看原理图

舵机

芯片手册

舵机
使用上节移植的定时器三例程
舵机
不需要开启部分重映射,

//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);
}
}

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分