目录
推荐的STM32学习链接:
STM32F103C8T6延时函数和OLED显示屏代码_HX091624的博客-CSDN博客
扫描二维码关注公众号,回复:
14744277 查看本文章
使用舵机带动超声波转动不同角度,完成左右前三个方向的距离测量、判断后完成避障
一、定时器
计数和定时器中断
#include "stm32f10x.h"
//定时器2计数得到时间 计一个数-> 1US
//定时器2主要用在超声波测距
void Timer2_Init(void)
{
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 = 50000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 144 - 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);
}
//定时4中断计时 一次中断1MS
//定时器主要是作为时间基准使用
void Timer4_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_InternalClockConfig(TIM4);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
//运行控制
TIM_Cmd(TIM4, ENABLE);
}
//定时器2启动控制
void TIM2_Run(uint8_t flag)
{
if(flag)
TIM_Cmd(TIM2, ENABLE);
else
TIM_Cmd(TIM2, DISABLE);
}
//获取定时器2计数器的值
uint16_t TIM2_GetCounter(void)
{
uint16_t Counter;
Counter=TIM_GetCounter(TIM2);
return Counter;
}
//设置定时器2计数器的值
void TIM2_SetCounter(uint16_t Count)
{
TIM_SetCounter(TIM2,Count);
}
输出比较(PWM)
#include "stm32f10x.h"
//定时器3PWM调速 周期20MS 计一个数->1US
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //电动机PWM输出 PA6 PA7
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //舵机PWM输出 PB0
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &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 = 20000 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &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_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_Cmd(TIM3, ENABLE);
}
//左右电机输出比较
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM3, Compare);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM3, Compare);
}
//舵机输出比较
void PWM_SetCompare3(uint16_t Compare)
{
TIM_SetCompare3(TIM3, Compare);
}
二、 舵机
#include "stm32f10x.h"
#include "PWM.h"
//SG90舵机
void Servo_Init(void)
{
PWM_Init();
}
//舵机转动 直接输入角度
void Servo_SetAngle(float Angle)
{
//0->500 180->2500 2.5ms
PWM_SetCompare3(Angle / 180 * 2000 + 500);
}
三、超声波测距
超声波测距:完成以下三步即可,同时注意超声波要接5V,否则不工作导致qidongceju函数中的while死循环。
#include "stm32f10x.h"
#include "Servo.h"
#include "Delay.h"
#include "Timer.h"
#include "MotorRun.h"
uint16_t T=0;
unsigned long S=0;
unsigned long S1=0; //存放前方距离值
unsigned long S2=0; //存放右边距离
unsigned long S3=0; //存放左边距离
extern uint16_t time; //延时基准变量
//超声波初始化
void bizhang_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//TRIG
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//ECHO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//超声波测距函数
unsigned long qidongceju(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_2); //TRIG
Delay_ms(20); //20us的信呈
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
while(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3));//判断ECHO是否输出高电平
TIM2_SetCounter(0); //计数器清零
TIM2_Run(1); //开启定时器
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3));
TIM2_Run(0);
T=TIM2_GetCounter(); //ECHO高电平的时长
TIM2_SetCounter(0);
S=(T*1.7)/50; //计算得到距离 CM
return S;
}
//舵机转动测距函数
void COMM(void)
{
//测出左中右三个方向的距离 右->左->中
Servo_SetAngle(30); //舵机向右转
time=0;
while(time<=400); //延时400MS让舵机转到其位置
//启动超声波测距计算距离
S2=qidongceju(); //存储右边距离
Servo_SetAngle(150); //舵机向左转
time=0;
while(time<=400);
S3=qidongceju(); //存储左边距离
Servo_SetAngle(90); //舵机归中
time=0;
while(time<=400);
S1=qidongceju(); //存储正前方距离
if((S2<15)||(S3<15)) //左边或者右边的距离小于15cm
{
backrun(15); //小车后退
time=0;
while(time<=200); //后退一段时间
}
if(S2>S3) //如果右边距离大于左边距离
{
rightrun(20); //车的左边比车的右边距离小,右转
time=0;
while(time<=600);
}
else //如果右边距离小于左边距离
{
leftrun(20); //车的左边比车的右边距离大,左转
time=0;
while(time<=200);
}
}
四、主函数
#include "stm32f10x.h" // Device header
#include "bizhang.h"
#include "OLED.h"
#include "Timer.h"
#include "Servo.h"
#include "Motor.h"
#include "MotorRun.h"
#include "Delay.h"
uint16_t time; //延时基准时间
unsigned long disbance; //距离
float Angle; //舵机转动角度
int main(void)
{
OLED_Init();
Motor_Init();
Servo_Init();
Timer2_Init();
Timer4_Init();
bizhang_Init();
//OLED显示
OLED_ShowString(1,1,"disbance:");
while (1)
{
disbance=qidongceju(); //启动超声波测出前方距离
OLED_ShowNum(1,10,disbance,3);
if(time>=40) //20MS检测启动检测一次
{
Servo_SetAngle(90); //舵机归中
time=0;
disbance=qidongceju(); //启动超声波测出前方距离
OLED_ShowNum(1,10,disbance,3);
if(disbance<15) //如果距离小于15CM
{
stop();
COMM();
}
else
{
run(15);
}
}
}
}
//定时器4中断
void TIM4_IRQHandler(void)
{ //1MS
if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
{
time++; //基准计时
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
}
}