文章目录[隐藏]
目录
测速原理
光电传感器有遮挡时,输出高电平;无遮挡,输出低电平。我们接受到一次低电平时,把这个脉冲加一,轮子上有编码圈一圈可以让脉冲累加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
暂无评论