项目目标:
最近写了个车辆的辅助系统,现将系统几个主要部分做一个刨析记录,希望对有同等记录的同学,有个帮助!
基于Stm32F103VET6的车辆辅助系统,主要分为以下几个部分:
- 直流电机控制(A4950&TB6612驱动)
- 直流电机测速(A4950&TB6612驱动)
- 中科微GPS测试
- 超声波撞车报警
- 开机密码设置(红外遥控按键输入)
主控板子用的是野火家的
资料链接:野火产品资料下载中心 — 野火产品资料下载中心 文档 (embedfire.com)
(红外遥控按键输入)开机密码设置:
使用的红外遥控、主控板(野火stm32F103vet6,目前此板子已经更新换代,没有这么老板子了,有部分缺陷,不方便指出,不建议大家使用,建议大家使用最新板子,连客服都说已经没有这种老板子的资料了)
本文编写的是一个六位数的密码输入(类似于一个密码锁),当密码输入正确,进入主页面,密码输入错误时,文字飘红警告,且可以重新输入密码。
红外遥控作为输入设备,以下提供一点思路代码,无法将整个工程贴给大家,所以贴部分代码:
/* 密码 输入*/
void Bicycle_EnterLCD(void)
{
static int key_E = 0,a = 0,sum = 0,key_b = 0,key_c = 0,count = 0;
static int i;
static int Ent_b = 0;
static char dispBuff[100];
unsigned char pswd[6] = {"123456"};
char in_pswd[6] = {"000000"};
int Ment = 1; //判断是否密码正确 1-正确 0-错误
while(1)
{
key_E = Inf_KeyScan();
switch(key_E)
{
case 0: key_b = 0;break;
case 1: key_b = 1;break;
case 2: key_b = 2;break;
case 3: key_b = 3;break;
case 4: key_b = 4;break;
case 5: key_b = 5;break;
case 6: key_b = 6;break;
case 7: key_b = 7;break;
case 8: key_b = 8;break;
case 9: key_b = 9;break;
default: key_b = 100;break;
}
if( key_E == 11)
key_c = 11;
if(key_b >= 0 && key_b<= 9 && key_c == 11)
{
a = key_b;
switch(Ent_b)
{
case 0:a*=100000;ILI9341_DispStringLine_EN_CH(LINE(5)," Pswd:* ");break;
case 1:a*=10000;ILI9341_DispStringLine_EN_CH(LINE(5)," Pswd:** ");break;
case 2:a*=1000;ILI9341_DispStringLine_EN_CH(LINE(5)," Pswd:*** ");break;
case 3:a*=100;ILI9341_DispStringLine_EN_CH(LINE(5)," Pswd:**** ");break;
case 4:a*=10;ILI9341_DispStringLine_EN_CH(LINE(5)," Pswd:***** ");break;
case 5:a*=1;ILI9341_DispStringLine_EN_CH(LINE(5)," Pswd:****** ");break;
}
sum += a;
sprintf(in_pswd,"%d",sum);
Ent_b+=1;
a = 0;
key_c = 0;
if(Ent_b == 6)
{
for(i=0;i<6;i++)
{
if(in_pswd[i] == pswd[i])
{
count = 1;
}
else
{
count = 2;
}
}
if(count == 1)
{
ILI9341_DispStringLine_EN_CH(LINE(10)," ");
ILI9341_DispStringLine_EN_CH(LINE(10)," Congratulations! Correct password!");
Car_Flag = 3;
delay_ms(1500);
LCD_SetColors(WHITE,BLACK);
ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH); /* 清屏,显示全黑 */
break;
}
if(count == 2)
{
LCD_SetTextColor(RED);
ILI9341_DispStringLine_EN_CH(LINE(10)," ");
ILI9341_DispStringLine_EN_CH(LINE(10)," What a pity! Wrong password!");
delay_ms(1500);
Ent_b = 0;
count = 0;
sum = 0;
for (i = 0; i < strlen(in_pswd); i++)
in_pswd[i] = '\0' ;
LCD_SetColors(WHITE,BLACK);
ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH); /* 清屏,显示全黑 */
Bicyle_TwoLCD();
Bicycle_EnterLCD();
}
}
}
if(count == 0)
{
/* 提醒 用户输入密码 */
LCD_SetColors(MAGENTA,BLACK);
LCD_SetFont(&Font8x16);
ILI9341_DispStringLine_EN_CH(LINE(10)," Please enter Pswd -> Main Page!!");
}
LCD_SetTextColor(GREEN);
sprintf(dispBuff,"%d ",key_E);
LCD_ClearLine(LINE(0));
ILI9341_DispStringLine_EN_CH(LINE(0),dispBuff);
}
}
红外遥控程序(部分程序,占主要部分,有参考价值):
#include "stdio.h"
#include "./IrDa/bsp_irda.h"
#include "./systick/bsp_SysTick.h"
#include "./led/bsp_led.h"
uint32_t frame_data=0; /* 一帧数据缓存 */
uint8_t frame_cnt=0;
uint8_t frame_flag=0; /* 一帧数据接收完成标志 */
/**
* @brief 配置嵌套向量中断控制器NVIC
* @param 无
* @retval 无
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置P[A|B|C|D|E]11为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = IRDA_EXTI_IRQN;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/* 初始化红外接收头1838用到的IO */
void IrDa_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/* config the extiline clock and AFIO clock */
RCC_APB2PeriphClockCmd(IRDA_GPIO_CLK | RCC_APB2Periph_AFIO,ENABLE);
/* config the NVIC */
NVIC_Configuration();
/* EXTI line gpio config */
GPIO_InitStructure.GPIO_Pin = IRDA_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(IRDA_GPIO_PORT, &GPIO_InitStructure);
/* EXTI line mode config */
GPIO_EXTILineConfig(IRDA_GPIO_PORT_SOURCE, IRDA_GPIO_PIN_SOURCE);
EXTI_InitStructure.EXTI_Line = IRDA_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿中断
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
/* 获取高电平的时间 */
uint8_t Get_Pulse_Time(void)
{
uint8_t time = 0;
while( IrDa_DATA_IN() )
{
time ++;
Delay_us(2); // 延时 20us
if(time == 250)
return time; // 超时溢出
}
return time;
}
/*
* 帧数据有4个字节,第一个字节是遥控的ID,第二个字节是第一个字节的反码
* 第三个数据是遥控的真正的键值,第四个字节是第三个字节的反码
*/
uint8_t IrDa_Process(void)
{
uint8_t first_byte, sec_byte, tir_byte, fou_byte;
first_byte = frame_data >> 24;
sec_byte = (frame_data>>16) & 0xff;
tir_byte = frame_data >> 8;
fou_byte = frame_data;
/* 记得清标志位 */
frame_flag = 0;
if( (first_byte==(uint8_t)~sec_byte) && (first_byte==IRDA_ID) )
{
if( tir_byte == (u8)~fou_byte )
return tir_byte;
}
return 0; /* 错误返回 */
}
/*********************************************END OF FILE**********************/
如对代码有所疑惑,可以联系博主一起探讨技术,或有不对之处,请指出,立即改正!!!
直流电机控制(A4950&TB6612驱动):
博主本人在最开始的时候,是准备以TB6612驱动来做,结果买成了A4950驱动,于是两个驱动都研究了一下,基本控制了车子的驱动。
以上接线框图来自于官方的例程,如果与本文提供程序不符请谅解!由于野火开发板个别引脚未引出,导致定时器未能使用,于是导致程序引脚定义与接线框图不一致!
不能提供官方所给程序,于是贴自己的,请大家尊重知识,尊重编写程序的每一个程序员!
以下程序如有引脚不一致的地方,请忽略,本人亲测代码无问题:
电机驱动代码(TB6612):
#include "tb6612.h"
//***************************TB6612配置***************************//
void TB6612_Init(void)
{
TB6612_PWM_Init(3600, 1);//PWM频率初始化20KHz
TB6612_GPIO_Config(); //电机驱动IO配置
}
//***************************PWM频率及占空比初始化***************************//
//=====初始化PWM 20KHZ 高频可以防止电机低频时的尖叫声
// ARR= 3599 时频率为20Khz
//PB0控制PWMA--left motor,PB1控制PWMB--right motor。STBY直接拉高
//arr:自动重装寄存器,psc分频系数
//PWM的频率 = 72MHz/ARR/PCS 例如 20K = 72M/3600/1 = 20K
void TB6612_PWM_Init(u32 arr, int psc)
{
TIM_OCInitTypeDef TIM_OCInitSructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//配置pwm输出端口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8| GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//初始化定时器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_TimeBaseStructure.TIM_Period = arr-1; //自动重新装载寄存器周期的值澹ㄥ计数值澹)
TIM_TimeBaseStructure.TIM_Prescaler = psc-1; //时钟分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //对外部时钟进行采样的时钟分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure); //参数初始化
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
//设置通道3 pwm参数
TIM_OCInitSructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitSructure.TIM_OutputState= TIM_OutputState_Enable;
TIM_OCInitSructure.TIM_Pulse = 0; //占空比=
TIM_OCInitSructure.TIM_OCPolarity = TIM_OCPolarity_High; //当定时器计数值小于CCR1_Val时为高电平
TIM_OC3Init(TIM4, &TIM_OCInitSructure); //参数初始化
TIM_OC3PolarityConfig(TIM4, TIM_OCPreload_Enable); //开始输出pwm
//设置通道4 pwm参数
TIM_OCInitSructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitSructure.TIM_OutputState= TIM_OutputState_Enable;
TIM_OCInitSructure.TIM_Pulse = 0; //占空比=
TIM_OCInitSructure.TIM_OCPolarity = TIM_OCPolarity_High; //当定时器计数值小于CCR1_Val时为高电平
TIM_OC4Init(TIM4, &TIM_OCInitSructure); //参数初始化
TIM_OC4PolarityConfig(TIM4, TIM_OCPreload_Enable); //开始输出pwm
TIM_ARRPreloadConfig(TIM4, ENABLE); //启动自动重装
TIM_Cmd(TIM4, ENABLE); //启动定时
}
//***************************占空比调节***************************//
//占空比 = TIMx_CCRx / TIMx_ARR
//moto_r:右轮电机,moto_l:左轮电机. 数值 0-3600
void TB6612_PWM_Out(u16 moto_l, u16 moto_r)
{
TIM_OCInitTypeDef TIM_OCInitSructure;
TIM_OCInitSructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitSructure.TIM_OutputState= TIM_OutputState_Enable;
//CH3 左电机
TIM_OCInitSructure.TIM_Pulse = moto_l; //占空比= ccr/3600
TIM_OC3Init(TIM4, &TIM_OCInitSructure); //参数初始化
TIM_OC3PolarityConfig(TIM4, TIM_OCPreload_Enable); //开始输出pwm
//CH4 右电机
TIM_OCInitSructure.TIM_Pulse = moto_r; //占空比= ccr /3600
TIM_OC4Init(TIM4, &TIM_OCInitSructure); //参数初始化
TIM_OC4PolarityConfig(TIM4, TIM_OCPreload_Enable); //开始输出pwm
TIM_ARRPreloadConfig(TIM4, ENABLE); //启动自动重装
}
void TB6612_GPIO_Config(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); /*开启GPIO的外设时钟*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; /*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*设置引脚速率为50MHz */
GPIO_Init(GPIOB, &GPIO_InitStructure); /*调用库函数,初始化GPIO*/
}
//以下单独定义每个轮子运动状态,如果不对可以修改里面的参数
//比如左轮前进,AIN1(0),AIN2(1).如果往后转了,就改成AIN1(1),AIN2(0)
void Motor_Left(u8 state)
{
if(state == GO) //左电机前进
{
AIN1(0);
AIN2(1);
}
if(state == BACK) //左电机后退
{
AIN1(1);
AIN2(0);
}
if(state == STOP) //停转
{
AIN1(1);
AIN2(1);
}
}
void Motor_Right(u8 state)
{
if(state == GO) //右电机前进
{
BIN1(0);
BIN2(1);
}
if(state == BACK) //右电机后退
{
BIN1(1);
BIN2(0);
}
if(state == STOP) //停转
{
BIN1(1);
BIN2(1);
}
}
//以下定义了小车整体的运动方向。转弯靠左右电机差速实现。
void Car_Go(void)
{
//小车前进
//左电机前进 右电机前进
Motor_Left(GO); Motor_Right(GO);
}
void Car_Back(void)
{
//小车后退
//左电机后退 右电机后退
Motor_Left(BACK); Motor_Right(BACK);
}
void Car_Right(void)
{
//小车右转圈
//左电机前进 右电机后退
Motor_Left(GO); Motor_Right(BACK);
}
void Car_Left(void)
{
//小车左转圈
//左电机后退 右电机前进
Motor_Left(BACK); Motor_Right(GO);
}
void Car_Stop(void)
{
//小车停车
//左电机停止 右电机停止
Motor_Left(STOP); Motor_Right(STOP);
}
电机驱动代码(A4950):
#include "AT4950.h"
//***************************AT4950配置***************************//
void AT4950_Init(void)
{
AT4950_PWM_Init(3600, 1);//PWM频率初始化20KHz
AT4950_GPIO_Config(); //电机驱动IO配置
}
//***************************PWM频率及占空比初始化***************************//
//=====初始化PWM 20KHZ 高频可以防止电机低频时的尖叫声
// ARR= 3599 时频率为20Khz
//PB0控制PWMA--left motor,PB1控制PWMB--right motor。STBY直接拉高
//arr:自动重装寄存器,psc分频系数
//PWM的频率 = 72MHz/ARR/PCS 例如 20K = 72M/3600/1 = 20K
void AT4950_PWM_Init(u32 arr, int psc)
{
TIM_OCInitTypeDef TIM_OCInitSructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//配置pwm输出端口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8| GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//初始化定时器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_TimeBaseStructure.TIM_Period = arr-1; //自动重新装载寄存器周期的值澹ㄥ计数值澹)
TIM_TimeBaseStructure.TIM_Prescaler = psc-1; //时钟分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //对外部时钟进行采样的时钟分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure); //参数初始化
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
//设置通道3 pwm参数
TIM_OCInitSructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitSructure.TIM_OutputState= TIM_OutputState_Enable;
TIM_OCInitSructure.TIM_Pulse = 0; //占空比=
TIM_OCInitSructure.TIM_OCPolarity = TIM_OCPolarity_High; //当定时器计数值小于CCR1_Val时为高电平
TIM_OC3Init(TIM4, &TIM_OCInitSructure); //参数初始化
TIM_OC3PolarityConfig(TIM4, TIM_OCPreload_Enable); //开始输出pwm
//设置通道4 pwm参数
TIM_OCInitSructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitSructure.TIM_OutputState= TIM_OutputState_Enable;
TIM_OCInitSructure.TIM_Pulse = 0; //占空比=
TIM_OCInitSructure.TIM_OCPolarity = TIM_OCPolarity_High; //当定时器计数值小于CCR1_Val时为高电平
TIM_OC4Init(TIM4, &TIM_OCInitSructure); //参数初始化
TIM_OC4PolarityConfig(TIM4, TIM_OCPreload_Enable); //开始输出pwm
TIM_ARRPreloadConfig(TIM4, ENABLE); //启动自动重装
TIM_Cmd(TIM4, ENABLE); //启动定时
}
//***************************占空比调节***************************//
//占空比 = TIMx_CCRx / TIMx_ARR
//moto_r:右轮电机,moto_l:左轮电机. 数值 0-3600
void AT4950_PWM_Out(u16 moto_l, u16 moto_r)
{
TIM_OCInitTypeDef TIM_OCInitSructure;
TIM_OCInitSructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitSructure.TIM_OutputState= TIM_OutputState_Enable;
//CH3 左电机
TIM_OCInitSructure.TIM_Pulse = moto_l; //占空比= ccr/3600
TIM_OC3Init(TIM4, &TIM_OCInitSructure); //参数初始化
TIM_OC3PolarityConfig(TIM4, TIM_OCPreload_Enable); //开始输出pwm
//CH4 右电机
TIM_OCInitSructure.TIM_Pulse = moto_r; //占空比= ccr /3600
TIM_OC4Init(TIM4, &TIM_OCInitSructure); //参数初始化
TIM_OC4PolarityConfig(TIM4, TIM_OCPreload_Enable); //开始输出pwm
TIM_ARRPreloadConfig(TIM4, ENABLE); //启动自动重装
}
void AT4950_GPIO_Config(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); /*开启GPIO的外设时钟*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 ; /*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*设置引脚速率为50MHz */
GPIO_Init(GPIOB, &GPIO_InitStructure); /*调用库函数,初始化GPIO*/
}
//以下单独定义每个轮子运动状态,如果不对可以修改里面的参数
//比如左轮前进,AIN1(0),AIN2(1).如果往后转了,就改成AIN1(1),AIN2(0)
//***************************占空比调节***************************//
//占空比 = TIMx_CCRx / TIMx_ARR
//moto_r:右轮电机,moto_A:左轮电机. 数值 0-3600
void A4950_PWM_OutA(u16 motorA)
{
TIM4 -> CCR3 = motorA;
}
void A4950_PWM_OutB(u16 motorB)
{
TIM4 -> CCR4 = motorB;
}
//以下单独定义每个轮子运动状态,如果不对可以修改里面的参数
void MotorA_Control(u8 state,u16 pwm)
{
if(state == GO) //电机1前进
{
A4950_PWM_OutA(pwm);
AIN1(0);
}
if(state == BACK) //电机1后退
{
A4950_PWM_OutA(3600-pwm);
AIN1(1);
}
if(state == STOP) //停转
{
A4950_PWM_OutA(0);
AIN1(0);
}
}
void MotorB_Control(u8 state,u16 pwm)
{
if(state == GO) //电机2前进
{
A4950_PWM_OutB(pwm);
BIN1(1);
}
if(state == BACK) //电机2后退
{
A4950_PWM_OutB(3600-pwm);
BIN1(0);
}
if(state == STOP) //停转
{
A4950_PWM_OutB(0);
BIN1(0);
}
}
代码亲测有效,请大家耐心测试!!!
直流电机测速(硬件图如上文):
直流电机测速,首先是用的官方的程序,官方是那定时器2和定时器3来测电机编码器的编码器值,由于野火板子的问题,无法驱动,后我将引脚去修修改改也是能跑。‘
官方:定时器2、定时器3来控制计数两个电机的编码器值,定时器1来控制时间,最后用编码器值和时间来测得速度!
我自己:由于无法使用两个定时器,于是只用了定时器2,用的是PA0、PA1引脚,控制在5ms中算定时器的编码器值,然后用编码器的值和固定的5ms来算出速度,以下提供的自己的代码只是一个dome,希望大家完善一下,个人不提供太完整!
官方程序:
#include "Encoder.h"
//***************************定时器2初始化 ,使用编码器功能***************************//
//左电机编码器计数
//PA15----接 编码器A相 或者电机驱动的B1A标识
//PB3 ----接 编码器B相 或者电机驱动的B1B标识
void Encoder_Init_TIM2(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//GPIO功能时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //禁用JTAG
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);
//配置IO口为复用功能-定时器通道
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度100MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//TIM时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
//Timer configuration in Encoder mode
TIM_DeInit(TIM2);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // No prescaling
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
//Reset counter
TIM2->CNT = 0;
TIM_Cmd(TIM2, ENABLE);
}
//***************************定时器3初始化 ,使用编码器功能***************************//
//左电机编码器计数
//PB4----接 编码器A相 或者电机驱动的B2A标识
//PB5----接 编码器B相 或者电机驱动的B2B标识
void Encoder_Init_TIM3(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//GPIO功能时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
//配置IO口为复用功能-定时器通道
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度100MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
//TIM时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 , ENABLE); //这个就是重映射功能函数
//Timer configuration in Encoder mode
TIM_DeInit(TIM3);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // No prescaling
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
//Reset counter
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3, ENABLE);
}
/**************************************************************************
函数功能:单位时间读取编码器计数
入口参数:定时器
返回 值:速度值
**************************************************************************/
int Read_Encoder(u8 TIMX)
{
int Encoder_TIM;
switch(TIMX)
{
case 2: Encoder_TIM= (short)TIM2 -> CNT; TIM2 -> CNT=30000;break;
case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=30000;break;
//case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=30000;break;
// case 5: Encoder_TIM= (short)TIM5 -> CNT; TIM5 -> CNT=30000;break;
default: Encoder_TIM=0;
}
return Encoder_TIM;
}
//定时器1:
#include "car.h"
u8 temp1=0;
u8 OLED_Timer1=0;//时间片,更新ADC
u8 OLED_Timer2=0;//时间片,更新速度
u8 Encoder_Timer = 0;
u8 OLED_ADC_Flag=0;
u8 OLED_Speed_Flag=0;
u16 ADC_BAT_Val,ADC_BAT_temp;
u16 ADC_SYS_Val,ADC_SYS_temp;
int Encoder_L,Encoder_R;
//Time1定时器1中断服务函数
//10ms定时
void TIM1_UP_IRQHandler(void)
{
if(TIM_GetFlagStatus(TIM1, TIM_IT_Update) != RESET) //时间到了
{
TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update);//清中断
LED_Flash(50);//500ms闪烁一次
temp1++;
OLED_Timer1++;
OLED_Timer2++;
Encoder_Timer++;
ADC_BAT_temp += Get_BAT_ADC();//ADC 采样 电池电压
ADC_SYS_temp += Get_SYS_ADC();//aDC 采样 系统电压
if(Encoder_Timer>=5)//电机转速50ms采样一次
{
Encoder_Timer = 0;
Encoder_R=Read_Encoder(2)-30000; //读取编码器,计算出变化量
Encoder_L=-((Read_Encoder(3)-30000)); //读取编码器,计算出变化量,负号是因为两个电机 相对位置180°
if(Encoder_R < 0)
{
Encoder_R = -Encoder_R;
}
if(Encoder_L < 0)
{
Encoder_L = -Encoder_L;
}
}
if(temp1>=10)//100ms
{
temp1=0;
ADC_BAT_Val = ADC_BAT_temp/10;
ADC_SYS_Val = ADC_SYS_temp/10;
ADC_BAT_temp = 0;
ADC_SYS_temp = 0;
}
if(OLED_Timer1 >= 100)//1S 更新一次ADC
{
OLED_Timer1=0;
OLED_ADC_Flag = 1;
}
}
}
个人*(希望对你有所帮助):
#include "Encoder.h"
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { // 定时器更新中断
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) { // 输入捕获中断
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
encoder_count++;
}
else if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET) { // 输入捕获中断
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
encoder_count++;
}
else{
encoder_count = 0;
}
printf("encoder_count : %d\n",encoder_count);
}
void TIM2_Encoder_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 配置PA0/PA1为TIM2的通道1/2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 65535; // 自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 预分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频因子
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 重复计数器值
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); // 编码器模式
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitStructure.TIM_Prescaler = 0; // 定时器2预分频系数为1
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 0xFFFF; // 定时器2计数器每计一个数就会溢出,自动重装载到0xFFFF
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); // CH1和CH2通道作为编码器输入
TIM_SetCounter(TIM2, 0); // 定时器2计数器清零
TIM_Cmd(TIM2, ENABLE); // 启动定时器2
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; // GPIOA的PIN0和PIN1作为编码器输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
附图(电路图):
中科微GPS测试:
GPS主要是一个串口的利用,对串口进行一个读取数据。PA9与PA10,波特率一般为9600。
#include "sys.h"
#include "usart.h"
char rxdatabufer;
u16 point1 = 0;
_SaveData Save_Data;
//
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h" //ucos 使用
#endif
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
int _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
/*使用microLib的方法*/
/*
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
return ch;
}
int GetKey (void) {
while (!(USART1->SR & USART_FLAG_RXNE));
return ((int)(USART1->DR & 0x1FF));
}
*/
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
char USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
void uart_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART1, ENABLE); //使能串口
CLR_Buf();//清空缓存
}
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
#ifdef OS_TICKS_PER_SEC //如果时钟节拍数定义了,说明要使用ucosII了.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
if(Res == '$')
{
point1 = 0;
}
USART_RX_BUF[point1++] = Res;
if(USART_RX_BUF[0] == '$' && USART_RX_BUF[4] == 'M' && USART_RX_BUF[5] == 'C') //确定是否收到"GPRMC/GNRMC"这一帧数据
{
if(Res == '\n')
{
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空
memcpy(Save_Data.GPS_Buffer, USART_RX_BUF, point1); //保存数据
Save_Data.isGetData = true;
point1 = 0;
memset(USART_RX_BUF, 0, USART_REC_LEN); //清空
}
}
if(point1 >= USART_REC_LEN)
{
point1 = USART_REC_LEN;
}
// USART_RX_STA|=0x8000; //接收完成了
// if((USART_RX_STA&0x8000)==0)//接收未完成
// {
// if(USART_RX_STA&0x4000)//接收到了0x0d
// {
// if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
// else USART_RX_STA|=0x8000; //接收完成了 //bit31表明是否接收到0x0a(\n)
// }
// else //还没收到0X0D
// {
// if(Res==0x0d)USART_RX_STA|=0x4000; //bit30表明是否接收到0x0d(\r)
// else
// {
// USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
// USART_RX_STA++;
// if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
// }
// }
// }
}
#ifdef OS_TICKS_PER_SEC //如果时钟节拍数定义了,说明要使用ucosII了.
OSIntExit();
#endif
}
u8 Hand(char *a) // 串口命令识别函数
{
if(strstr(USART_RX_BUF,a)!=NULL)
return 1;
else
return 0;
}
void CLR_Buf(void) // 串口缓存清理
{
memset(USART_RX_BUF, 0, USART_REC_LEN); //清空
point1 = 0;
}
void clrStruct()
{
Save_Data.isGetData = false;
Save_Data.isParseData = false;
Save_Data.isUsefull = false;
memset(Save_Data.GPS_Buffer, 0, GPS_Buffer_Length); //清空
memset(Save_Data.UTCTime, 0, UTCTime_Length);
memset(Save_Data.latitude, 0, latitude_Length);
memset(Save_Data.N_S, 0, N_S_Length);
memset(Save_Data.longitude, 0, longitude_Length);
memset(Save_Data.E_W, 0, E_W_Length);
}
#endif
读取经纬度:
void printGpsBuffer()
{
static char dispBuff[100];
if (Save_Data.isParseData)
{
Save_Data.isParseData = false;
printf("Save_Data.UTCTime = ");
printf(Save_Data.UTCTime);
printf("\r\n");
if(Save_Data.isUsefull)
{
Save_Data.isUsefull = false;
printf("Save_Data.latitude = "); //纬度
printf(Save_Data.latitude);
//LCD显示纬度
LCD_SetTextColor(GREEN);
sprintf(dispBuff," latitud-> %s",Save_Data.latitude);
LCD_ClearLine(LINE(6));
ILI9341_DispStringLine_EN_CH(LINE(6),dispBuff);
printf("\r\n");
printf("Save_Data.N_S = ");
printf(Save_Data.N_S);
printf("\r\n");
printf("Save_Data.longitude = "); //经度
printf(Save_Data.longitude);
printf("\r\n");
//LCD显示经度
LCD_SetTextColor(GREEN);
sprintf(dispBuff," longitude-> %s",Save_Data.longitude);
LCD_ClearLine(LINE(7));
ILI9341_DispStringLine_EN_CH(LINE(7),dispBuff);
printf("Save_Data.E_W = ");
printf(Save_Data.E_W);
printf("\r\n");
}
else
{
printf("GPS DATA is not usefull!\r\n");
LCD_SetTextColor(RED);
sprintf(dispBuff," longitude-> ERROR",0.0);
LCD_ClearLine(LINE(7));
ILI9341_DispStringLine_EN_CH(LINE(7),dispBuff);
sprintf(dispBuff," latitud-> ERROR",0.0);
LCD_ClearLine(LINE(6));
ILI9341_DispStringLine_EN_CH(LINE(6),dispBuff);
}
}
}
超声波撞车报警:
倒车报警使用的是超声波测距,当距离小于10的时候,蜂鸣器鸣叫!使用的是定时器3来计算距离,具体使用步骤,大家可以参考具体数据手册(stm32f103vet6的定时器3)
引脚是PA5、PA6
#include "car.h"
/* 超声波设置 */
#define Echo GPIO_Pin_6 //HC-SR04模块的Echo脚接GPIOB6
#define Trig GPIO_Pin_5 //HC-SR04模块的Trig脚接GPIOB5
uint64_t time=0; //声明变量,用来计时
uint64_t time_end=0; //声明变量,存储回波信号时间
void HC_SR04_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //启用GPIOB的外设时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置GPIO口为推挽输出
GPIO_InitStructure.GPIO_Pin = Trig; //设置GPIO口5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置GPIO口速度50Mhz
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置GPIO口为下拉输入模式
GPIO_InitStructure.GPIO_Pin = Echo; //设置GPIO口6
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB
GPIO_WriteBit(GPIOB,GPIO_Pin_5,0); //输出低电平
Delay_us(15); //延时15微秒
}
int16_t sonar_mm(void) //测距并返回单位为毫米的距离结果
{
uint32_t Distance,Distance_mm = 0;
GPIO_WriteBit(GPIOB,Trig,1); //输出高电平
Delay_us(15); //延时15微秒
GPIO_WriteBit(GPIOB,Trig,0); //输出低电平
while(GPIO_ReadInputDataBit(GPIOB,Echo)==0); //等待低电平结束
time=0; //计时清零
while(GPIO_ReadInputDataBit(GPIOB,Echo)==1); //等待高电平结束
time_end=time; //记录结束时的时间
if(time_end/100<38) //判断是否小于38毫秒,大于38毫秒的就是超时,直接调到下面返回0
{
Distance=(time_end*320)/2; //计算距离,25°C空气中的音速为346m/s
Distance_mm=Distance/100; //因为上面的time_end的单位是10微秒,所以要得出单位为毫米的距离结果,还得除以100
}
return Distance_mm; //返回测距结果
}
float sonar(void) //测距并返回单位为米的距离结果
{
uint32_t Distance,Distance_mm = 0;
float Distance_m=0;
GPIO_WriteBit(GPIOB,Trig,1); //输出高电平
Delay_us(15);
GPIO_WriteBit(GPIOB,Trig,0); //输出低电平
while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);
time=0;
while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);
time_end=time;
if(time_end/100<38)
{
Distance=(time_end*346)/2;
Distance_mm=Distance/100;
Distance_m=Distance_mm/1000;
}
return Distance_m;
}
void TIM3_IRQHandler(void) //更新中断函数,用来计时,每10微秒变量time加1
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //获取TIM3定时器的更新中断标志位
{
time++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除更新中断标志位
}
}
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体,配置定时器
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体,配置中断优先级
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //启用TIM3时钟
TIM_InternalClockConfig(TIM3); //设置TIM3使用内部时钟
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置1分频(不分频)
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数模式为向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1; //设置最大计数值,达到最大值触发更新事件,因为从0开始计数,所以计数10次是10-1,每10微秒触发一次
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //设置时钟预分频,72-1就是每 时钟频率(72Mhz)/72=1000000 个时钟周期计数器加1,每1微秒+1
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器(高级定时器才有,所以设置0)
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //初始化TIM3定时器
TIM_ClearFlag(TIM3, TIM_FLAG_Update); //清除更新中断标志位
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //开启更新中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级分组
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //指定中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //设置响应优先级
NVIC_Init(&NVIC_InitStructure); // https://blog.zeruns.tech
TIM_Cmd(TIM3, ENABLE); //开启定时器
}
测距亲测可用!
联系我们:
公众号:嵌入式up(源码工程提供)
文毕,文章篇幅较大,希望对大家有所帮助!谢谢支持和阅览!!!