(智能小车)STM32+L298N+光电/霍尔传感器+串口/OLED屏测速,测速值通过IIC可以显示到OLED,亲测。(程序代码注释详细)

目录

测速原理

所需编写的C文件

分享所编写的测速代码

STM32的Keil工程分享


测速原理

光电传感器有遮挡时,输出高电平;无遮挡,输出低电平。我们接受到一次低电平时,把这个脉冲加一,轮子上有编码圈一圈可以让脉冲累加20次。我用了2个定时器和1个外部中断,定时器分别用来仿PWM输出和定时,外部中断用来按键输入控制电机转动。现在PWM输出暂时可以不用管。定时器定时1ms秒,检测是否接受到传感器输入脉冲,计时1S后将脉冲累计的值(该值设为num)num/20返回我们的结果为每秒轮子所转的圈数。将该结果每秒的转速显示到OLED上,因为串口的引脚和定义OLED的引脚有有占用,这儿只用了OLED。当然,也可以自己稍微修改代码用串口输出并显示。

所需编写的C文件

GPIO.c里面定义了传感器输入,L298N的逻辑管脚IN和ENABLE,按键输入,PWM输出,定时器,外部中断和定时中断函数。讲解看注释。OLED.c参考了中景园的例程,里面我添加了一个显示小数函数,不过该程序没有使用到。main.c初始化函数,并且显示OLED屏。

分享所编写的测速代码

GPIO.c

#include "GPio.h"
#include "sys.h"

u16 motorpwmval=500; //初始占空比50%

//触发传感器输入 
void INIT_GD(void) //Key0  
{	 
    GPIO_InitTypeDef GPIO_InitStruct;  //结构体
	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //时钟
	
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_0;   
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD; //下拉
	GPIO_Init(GPIOB, &GPIO_InitStruct);
}

//L298N逻辑管脚
void Motor_GPIO_Init(void) 
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7; //
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP; 
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct); //
	GPIO_ResetBits(GPIOB,GPIO_Pin_7|GPIO_Pin_6);	
}
//按键
void Key_EXTI_Init(void) 
{
    //结构体
	EXTI_InitTypeDef  EXTI_InitStruct; 
    GPIO_InitTypeDef GPIO_InitStruct;  
	NVIC_InitTypeDef  NVIC_InitStruct; 
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); 
	
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU; //上拉
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	//外部中断
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource15|GPIO_PinSource12|GPIO_PinSource13|GPIO_PinSource14);//总线
	EXTI_InitStruct.EXTI_Line=EXTI_Line13|EXTI_Line15|EXTI_Line12|EXTI_Line14;//
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Falling;//
	EXTI_Init(&EXTI_InitStruct);//配置外部中断寄存器参数
	
	//中断控制器
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    NVIC_InitStruct.NVIC_IRQChannel =EXTI15_10_IRQn;//产生外部中断
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//使能
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;//子优先级
	NVIC_Init(&NVIC_InitStruct);//配置
}

//PWM输出若有需要可以去掉注释
/*void TIM3_PWM_init(u32 arr,u32 psc) //PWM输出
{
    //结构体
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //定时器3时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); //复用时钟
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //重映射配置
	
	//配置复用引脚
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5; //
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; //PWM2复用输出
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct); //

	//配置定时器3
    TIM_TimeBaseStruct.TIM_Period=arr;    
	TIM_TimeBaseStruct.TIM_Prescaler=psc; 
	TIM_TimeBaseStruct.TIM_ClockDivision=0; 
	TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up; 
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct); 
	
	//配置PWM输出
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);
	
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); 
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3	
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载器
}*/

 //定时器4
void TIM4_inIt(void)
{
//结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
	 //时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); 
//配置中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //TIM3通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStructure); //配置
	
TIM_TimeBaseStructure.TIM_Period = 999; //重装载寄存器
TIM_TimeBaseStructure.TIM_Prescaler =71; //预分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM4向上计数
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //配置 TIM4
	
TIM_Cmd(TIM4, ENABLE); //使能
//在按键写了控制允许中断,来控制计时
}

//按键中断
void EXTI15_10_IRQHandler(void) 
{ 
	u8  Flag=0; //按键标志,判断按键是否按下
	if(EXTI_GetITStatus(EXTI_Line13|EXTI_Line15|EXTI_Line12|EXTI_Line14) !=RESET) 
	{
		//增加占空比,最大为80%
	if(Key1==0) //按下Key1
	{
		delay_ms(10); //延时消抖
		Flag=1; //按下标志
	}
		if((Key1==1)&&(Flag==1)) //按键恢复
		{
		Flag=0; //清除按键标志
		if(motorpwmval > 200) //判断占空比是否超过80%
	    motorpwmval=motorpwmval-50;
	}
	//减小占空比,最大为30% ,同理Key1
	if(Key2==0) //°´ÏÂKey2
	{
		delay_ms(10);
		Flag=1;
	}
		if((Key1==1)&&(Flag==1))
		{
		  Flag=0;
		if(motorpwmval < 700)
	    motorpwmval=motorpwmval+50;
	  }
	//Key3
	if(Key3==0) //关闭电机
	{
	
		delay_ms(10);
		IN1=1;
		IN2=1;
		TIM_ITConfig(TIM4,TIM_IT_Update,DISABLE ); //关闭定时器4
	}
	if(Key4==0) //开启电机
	{
		delay_ms(10);
		TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //开启定时器4,
		IN1=0;
		IN2=1;
	}
	TIM_SetCompare2(TIM3,motorpwmval); //比较
	EXTI_ClearITPendingBit(EXTI_Line13|EXTI_Line15|EXTI_Line12|EXTI_Line14); //清除中断
 }
}

  float Circle=0; //转速
  float num=0; //传感器脉冲输入
  u32 time=0; 
	int temp=0,temp1=0,temp2=0; //分别是转速的整数,十分位和百分位
	int Temp=0; 
	u8 Len=1; //整数位长度
  u8 flag=0; //传感器触发标志

//进入一次中断1Ms
void TIM4_IRQHandler(void)  
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //1ms
{
	TIM_ClearITPendingBit(TIM4, TIM_IT_Update );
	time++;
 //测每秒的转速,每一秒更新一次
	if(Key0 == 1)
		flag=1;
	if(Key0==0 && flag==1)
	{
		flag=0; //清除标志
		num=num+1; //传感器触发次数
	}
	if(time == 1000) //计时1S,计算转速
	{
		Circle=num/20; //转速
		time=0; 
		num=0;
		temp=Circle; //整数
		temp1=(Circle-temp)*10; //十分位
		temp2=(Circle-temp-(float)(temp1/10))*100; //百分位
        //计算转速整数位长度
		Temp=temp;
		for(;Temp/10>1;Temp/=10)
		Len++;
	}
} 
}

GPIO.h

#ifndef __GPIO_H
#define __GPIO_H 

#include "sys.h"
#include "delay.h"

//定义引脚
#define  Key0   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)
#define  Key1   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)
#define  Key2   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)
#define  Key3   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)
#define  Key4   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)

//L298N
#define  IN1    PBout(6)
#define  IN2    PBout(7)

void INIT_GD(void); //光电传感器
void Motor_GPIO_Init(void); //电机L298N
void TIM3_PWM_init(u32 arr,u32 psc); //PWM输出
void Key_EXTI_Init(void); //按键外部中断
void TIM4_inIt(void); //1ms

#endif

main.c

//              D0   PA5 SCL
//              D1   PA7 SDA            
#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "string.h"
#include "GPio.h"
extern int temp,temp1,temp2;
extern u8 Len;

int main(void)
{
	delay_init(); //初始化延时函数
	Motor_GPIO_Init(); //初始电机
	Key_EXTI_Init(); //初始按键
	TIM3_PWM_init(999,0); //1ms
    TIM4_inIt(); //初始TIIM4
	OLED_Init(); //初始OLED
	INIT_GD(); //初始传感器
	OLED_ColorTurn(0);//正常显示
    OLED_DisplayTurn(0);//正常显示
	while(1)
	{
			//OLED屏上显示
		OLED_ShowChinese(0,0,8,16); //转
		OLED_ShowChinese(16,0,9,16); //速
		OLED_ShowChar(32,0,':',16); //:
		OLED_ShowNum(48,0,temp,Len,16); //整数
		OLED_ShowChar(40+16*Len,0,'.',16); //.
		OLED_ShowNum(32+16*(Len+1),0,temp1,1,16); //十分位
		OLED_ShowNum(24+16*(Len+2),0,temp2,1,16); //百分位
		OLED_ShowChinese(0,24,10,16); //单
		OLED_ShowChinese(16,24,11,16); //Î位
		OLED_ShowChar(32,24,':',16); //:
		OLED_ShowChar(48,24,'r',16); //r
		OLED_ShowChar(56,24,'/',16); //
		OLED_ShowChar(64,24,'s',16); //s
	    OLED_Refresh();
  }
}

STM32的Keil工程分享

 OLED代码自己可以去看中景园的例程,还是比较好用。工程文件链接(12条消息) 智能小车STM32测速.zip-嵌入式文档类资源-CSDN文库https://download.csdn.net/download/m0_54195456/35437032

版权声明:本文为CSDN博主「我是可爱的小朋友」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_54195456/article/details/121042194

生成海报
点赞 0

我是可爱的小朋友

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

STM32学习笔记—ADC

1、adc简介 2、函数配置 3、代码 1、adc简介 在ADC就是模数转换器,将模拟量转换成数字量,举个例子就是将电压转换位数字量,STM32拥有1-3个ADC(模数转换器),这些