(三)stm32巡线小车首尝试 测速篇
#采用stm32f103c8t6芯片
这回是测速篇了!越来越难了,呜呜呜。
这里的测速,指的是测量轮子的转速,来确定车子前进的方向,同时方便控制小车的转向。我手上的测速元件是u型的光电传感器,型号是moc70t3。我可以通过传感器被遮挡的时间与次数,来计算小车车轮的速度。
遮挡的元件大概长这样:
与红外线模块一样,这个传感器是三个输出的引脚,控制也差不多,所以我直接把红外线的工程复制,做了模板。不过,需要注意的是,这个模块的输出逻辑和红外线是反的[烦恼]!接收到信号时是高电平,信号被遮挡时是低电平。
有了测速元件,可是怎么测速呢?我的想法是,轮子开始转动,检测到第一个空隙时(第一个下降沿)开始计时,检测到下一个上升沿时停止计时,计时器清零。两者时间差便是通过一片遮挡片时的时间,这样子就可以衡量轮子旋转的速度了。
好的,不多说,开始撸代码!
我在红外线的模板上做了一些稍微的改动。光电传感器的初始化我用了两个而不是一个.c文件,这主要的原因是参数初始化加入了结构体,如果不使用两个c文件进行容纳,会导致主函数的代码量变多,也不利于后期对于参数的调整需求。
测速结构:
SPEED_Set主要是一些光电传感器的基础支持函数,包括使能时钟等,包含在speed.c中,在speed.h中声明。
#speed.c 未完成#include "speed.h"
#include "stm32f10x.h"void SPEED_Set(MySPEED_InitTypedef* input_speed_set)
{GPIO_InitTypeDef GPIO_init_set;if (input_speed_set->input_GPIOx == GPIOA)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);else if (input_speed_set->input_GPIOx == GPIOB)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);else if (input_speed_set->input_GPIOx == GPIOC)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);else if (input_speed_set->input_GPIOx == GPIOD)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);GPIO_init_set.GPIO_Mode = GPIO_Mode_IPU;GPIO_init_set.GPIO_Pin = input_speed_set->Pin;GPIO_init_set.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(input_speed_set->input_GPIOx, &GPIO_init_set);
}
而SPEED_Init则是无参数函数,负责真正的初始化。在SPEED_Init中设置好四个光电传感器结构体的参数,然后分别传入SPEED_Set中进行初始化。SPEED_Init函数在SPEED_Init.c中,并由SPEED_init.h声明。其中我还打算将速度获取放置至speed_init.c中。
继续写了!
在SPEED_Set函数中我仅仅配置了中断,接下来还需配置中断设置,紧接着还需要配置中断服务函数,才可以完成整体的框架。加油!
中断的配置比较简单,需要GPIO_EXTILineConfig来设置io与中断线映射,然后通过EXTI_Init配置相应的中断线。其中io映射需要输入对应gpio与pin,配置中断线需要确定配置哪一根中断线,因此,我将这三个参数写进了结构体中。
最终的结构体便是这样的:
typedef struct
{GPIO_TypeDef* input_GPIOx; // 光电传感器传入数据GPIOuint16_t Pin; // 光电传感器具体引脚uint32_t EXTI_Line_set; // 中断线设置,与Pin对应uint8_t GPIO_port_source; // 设置中断线对应GPIOx, EXTI_Inituint8_t GPIO_pin_source; // 设置中断线GPIO_pin, EXTI_Tnit
} MySPEED_InitTypedef;
之后,便是配置nvic了,我出于简单考虑,将中断地抢占与响应优先级均设置为1,并且针对不同不同地EXTI_Line写了不同地nvic配置,用以适应不同地结构体输入。
SPEED_Set中的配置基础函数都已经完成了,接下来便是在speed_init.c中完成具体设置了。
首先,定义结构体变量并填入参数,这个比较简单,就不赘述了。然后开始写中断服务函数(不要忘掉清除中断标志位啊!!!)。
中断函数的具体思路是,到达第一个下降沿获取并记录时间,到达第一个上升沿再获取一个新的时间,两个时间相减便可以获得经过一个遮挡的时间间隔,进而获得旋转速度。其中时间由定时器中断提供,定时器每溢出一次,定义的整型变量就会加1,通过获取变量的值就可以做出一个准确的计时器。这样,通过下降沿和上升沿的时间差,取倒数,便可以获得轮子的速度(注意这里只是衡量表准,单位并不是标准的m/s之类的)。
框架建立完成了,接下来的优化问题,我会在小车整体实验的时候仔细考虑。
好了,就先写到这,附上代码!
计时器代码:
#timer.h#ifndef __TIMER_H
#define __TIMER_H#include "stm32f10x.h"#define TIMER_base 719, 99 // 分别是arr和psc,即计数器初值和预分频系数,1ms溢出一次
#define TIMER_reset_ENABLE 0 // 定时器重置为0
#define TIMER_reset_DISABLE 1 // 定时器不重置// 向上计数
void TIMER_Init(TIM_TypeDef* input_TIMx);
int TIME_calculate(void); // 若arr或psc更改,该函数必须更改
void TIMER_Stop(TIM_TypeDef* input_TIMx, int flag); // 时钟停止,flag决定是否重置
void TIMER_Start(TIM_TypeDef* input_TIMx);#endif
#timer.c#include "timer.h"
#include "stm32f10x.h"
volatile unsigned int timer2_counter = 0; // 防止编译器优化导致进入中断造成错误void TIME_BaseInit(TIM_TypeDef* base_input_TIMx, u16 arr, u16 psc)
{// arr计时器初值,psc分频系数TIM_TimeBaseInitTypeDef TIM_base_init_set;TIM_base_init_set.TIM_ClockDivision = TIM_CKD_DIV1;TIM_base_init_set.TIM_CounterMode = TIM_CounterMode_Up;TIM_base_init_set.TIM_Period = arr;TIM_base_init_set.TIM_Prescaler = psc;TIM_TimeBaseInit(base_input_TIMx, &TIM_base_init_set);
}void TIMER_Init(TIM_TypeDef* input_TIMx)
{NVIC_InitTypeDef NVIC_init_set;if (input_TIMx == TIM2)RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);else if (input_TIMx == TIM3)RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);else if (input_TIMx == TIM4)RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);TIME_BaseInit(input_TIMx, TIMER_base); // 基准设置TIM_ITConfig(input_TIMx, TIM_IT_Update, ENABLE); // 使能计时器中断NVIC_init_set.NVIC_IRQChannelPreemptionPriority = 1;NVIC_init_set.NVIC_IRQChannelSubPriority = 1;NVIC_init_set.NVIC_IRQChannelCmd = ENABLE;if (input_TIMx == TIM2)NVIC_init_set.NVIC_IRQChannel = TIM2_IRQn;else if (input_TIMx == TIM3)NVIC_init_set.NVIC_IRQChannel = TIM3_IRQn;else if (input_TIMx == TIM4)NVIC_init_set.NVIC_IRQChannel = TIM4_IRQn;NVIC_Init(&NVIC_init_set);TIM_Cmd(input_TIMx, ENABLE);
}int TIME_calculate(void)
{// 如果大于1ms的溢出时间可能会出错return timer2_counter;
}void TIMER_Stop(TIM_TypeDef* input_TIMx, int flag)
{TIM_Cmd(input_TIMx, DISABLE);if (flag == TIMER_reset_ENABLE)TIM_SetCounter(input_TIMx, 0);
}void TIMER_Start(TIM_TypeDef* input_TIMx)
{TIM_Cmd(input_TIMx, ENABLE);
}void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){// 注意可能会溢出,虽然溢出时间很长,但终归有可能溢出timer2_counter++;TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
光电传感器:
#speed.h// 速度传感器,接收到信号时高电平,被遮挡时低电平#ifndef __SPEED_H
#define __SPEED_H#include "stm32f10x.h"typedef struct
{GPIO_TypeDef* input_GPIOx; // 光电传感器传入数据GPIOuint16_t Pin; // 光电传感器具体引脚uint32_t EXTI_Line_set; // 中断线设置,与Pin对应uint8_t GPIO_port_source; // 设置中断线对应GPIOx, EXTI_Inituint8_t GPIO_pin_source; // 设置中断线GPIO_pin, EXTI_Tnit
} MySPEED_InitTypeDef;void SPEED_Set(MySPEED_InitTypeDef* input_speed_set);#endif
#speed.c// 光电传感器基础配置服务
#include "speed.h"
#include "stm32f10x.h"void SPEED_Set(MySPEED_InitTypeDef* input_speed_set)
{GPIO_InitTypeDef GPIO_init_set;EXTI_InitTypeDef EXTI_init_set;NVIC_InitTypeDef NVIC_init_set;if (input_speed_set->input_GPIOx == GPIOA)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);else if (input_speed_set->input_GPIOx == GPIOB)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);else if (input_speed_set->input_GPIOx == GPIOC)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);else if (input_speed_set->input_GPIOx == GPIOD)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);// 光电传感器所需gpio配置GPIO_init_set.GPIO_Mode = GPIO_Mode_IPU;GPIO_init_set.GPIO_Pin = input_speed_set->Pin;GPIO_init_set.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(input_speed_set->input_GPIOx, &GPIO_init_set);GPIO_EXTILineConfig(input_speed_set->GPIO_port_source, input_speed_set->GPIO_pin_source); // io与中断线映射// 初始化,设置触发方式等EXTI_init_set.EXTI_Line = input_speed_set->EXTI_Line_set; // 中断线设置EXTI_init_set.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_init_set.EXTI_Trigger = EXTI_Trigger_Rising_Falling;EXTI_init_set.EXTI_LineCmd = ENABLE;// 中断使能NVIC_init_set.NVIC_IRQChannelPreemptionPriority = 2;NVIC_init_set.NVIC_IRQChannelSubPriority = 1;NVIC_init_set.NVIC_IRQChannelCmd = ENABLE;if (input_speed_set->EXTI_Line_set == EXTI_Line0)NVIC_init_set.NVIC_IRQChannel = EXTI0_IRQn;else if (input_speed_set->EXTI_Line_set == EXTI_Line1)NVIC_init_set.NVIC_IRQChannel = EXTI1_IRQn;else if (input_speed_set->EXTI_Line_set == EXTI_Line2)NVIC_init_set.NVIC_IRQChannel = EXTI2_IRQn;else if (input_speed_set->EXTI_Line_set == EXTI_Line3)NVIC_init_set.NVIC_IRQChannel = EXTI3_IRQn;else if (input_speed_set->EXTI_Line_set == EXTI_Line4)NVIC_init_set.NVIC_IRQChannel = EXTI4_IRQn;NVIC_Init(&NVIC_init_set);EXTI_Init(&EXTI_init_set);
}
#speed_init.h#ifndef __SPEED_INIT_H
#define __SPEED_INIT_H#include "speed.h"void SPEED_Init(void); // 初始化四个光电传感器(虽然目前只写了一个)
float speed_calculate1(void); // 第一个光电传感器测量
void SPEED_Stop(void); // 停止四个速度测量
void SPEED_Start(void); // 开始四个速度测量// 配置光电传感器定时时钟
#define SPEED_TIMER TIM2// SPEED1 设置
#define SPEED1_GPIO GPIOA
#define SPEED1_Pin GPIO_Pin_1
#define SPEED1_GPIO_port_source GPIO_PortSourceGPIOA
#define SPEED1_GPIO_pin_source GPIO_PinSource1
#define SPEED1_EXTI_Line EXTI_Line1
#define SPEED1_input GPIO_ReadInputDataBit(SPEED1_GPIO, SPEED1_Pin)#endif
#speed_init.c#include "speed_init.h"
#include "stm32f10x.h"
#include "timer.h"float car_speed_calculate1;void SPEED_Init(void)
{MySPEED_InitTypeDef speed_init_set1, speed_init_set2, speed_init_set3, speed_init_set4;// 第一个设置speed_init_set1.input_GPIOx = SPEED1_GPIO;speed_init_set1.Pin = SPEED1_Pin;speed_init_set1.GPIO_port_source = SPEED1_GPIO_port_source;speed_init_set1.GPIO_pin_source = SPEED1_GPIO_pin_source;speed_init_set1.EXTI_Line_set = SPEED1_EXTI_Line;SPEED_Set(&speed_init_set1);
}void SPEED_Stop(void)
{TIMER_Stop(SPEED_TIMER, TIMER_reset_ENABLE);
}void SPEED_Start(void)
{TIMER_Start(SPEED_TIMER);
}void EXTI1_IRQHandler(void)
{static int odd_even = 0;static int time1 = 0;static int time_difference = 0;if (odd_even == 0 && SPEED1_input == 0){time1 = TIME_calculate();odd_even = 1;}else if (odd_even == 1 && SPEED1_input == 1){time_difference = TIME_calculate() - time1;// 判断合理性if (time_difference >= 0){// 速度计算,乘系数car_speed_calculate1 = 10000.0/(TIME_calculate() - time1);}odd_even = 0;}EXTI_ClearITPendingBit(EXTI_Line1);
}float speed_calculate1(void)
{return car_speed_calculate1;
}
主程序:
#include "stm32f10x.h"
#include "led.h"
#include "speed_init.h"
#include "timer.h"void initSet(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);LED_Init();LED1_PC13_Off;SPEED_Init();TIMER_Init(SPEED_TIMER);
}int main(void)
{float speed;initSet();while(1){speed = speed_calculate1();}
}
(三)stm32巡线小车首尝试 测速篇相关推荐
- stm32 电磁巡线小车
stm32 电磁巡线小车 一 可实现功能 使用陀螺仪,根据俯仰角变化在下坡后停车 . 通过三路电感,实现小车巡线,可循 s弯 ,d形弯,8字弯,环岛. 可在不同的地方巡线,有学习能力. 红外光电开关判 ...
- Arduino案例实操 -- 智能巡防小车(三)图形化巡线小车编程
巡防小车的巡线功能同时可以用图形化编程软件来实现.博主这里用的图形化编程软件是KRobot. 三.图形化巡线小车编程 3.1 编程环境配置 3.1.1 下载编程软件 3.1.2 安装编程软件 3.2 ...
- Arduino案例实操 -- 智能巡防小车(三)Arduino IDE巡线小车编程
三.Arduino IDE巡线小车编程 3.1 Arduino开发环境 下载免安装ZIP包 下载IDE安装包 3.2 Arduino IDE 3.3 Blink项目实例 打开内置案例 进行程序上传 3 ...
- 基于STM32F103智能巡线小车
项目描述: 巡线小车是我作为新手入手的第一个项目,基本巡线功能是使用红外传感器循迹模块判断黑线的路径来确定转向方向,同时控制单片机配置PWM占空比波控制小车前进的L298N电机模块,实现前后退,左 ...
- 基于STC89C52RC模块的巡线小车
基于STC89C52RC模块的巡线小车 在STC89C52RC的基础上使用电机驱动使小车完成巡线,停站,避障,掉头等多功能智能小车 所需头文件: #include <reg52.h> #i ...
- OpenMV:14巡线小车
文章目录 追小球的小车 巡线小车 这个例子展示了在OpenMV Cam上使用get_regression()方法获得ROI的线性回归.使用这种方法,可以轻松让机器人跟踪所有指向相同大致方向的线. 本例 ...
- 巡线小车学习笔记(arduino 四路循迹)
巡线小车代码学习笔记 红外布局原理 中间两路巡线一直在黑线上,小车会直行,当任意一个出来,小车会自动纠正.如果最外面的检测到黑线.则小车以更大速度纠正到黑线上去.在算法上,优先处理锐角,直角等外围传感 ...
- 从零开始制作OV7670摄像头巡线小车
大家想不想自己动手制作如下一款摄像头巡线小车呢? 摄像头寻迹小车,你们想要不? 这款硬件原理图如下所示: 需要的主要材料清单有: 1.STM32F411核心板 2.OV7670摄像头 3.A4988步 ...
- STM32之增量式编码器电机测速
STM32之增量式编码器电机测速 编码器 编码器种类 按监测原理分类 光电编码器 霍尔编码器 按输出信号分类 增量式编码器 绝对式编码器 编码器参数 分辨率 精度 最大响应频率 信号输出形式 编码器倍 ...
最新文章
- Qt动画框架The Animation Framework
- GLUT键盘控制(glutKeyboardFunc和glutSpecialFunc)
- API 版本控制的几种方式
- Hibernate插入错误:GenericJDBCException: could not insert:
- ip数据报首部校验和的计算
- xaas_从XaaS到Java EE – 2012年哪款该死的云最适合我?
- lingo解题报告内容解释
- oracle日志文件大小规则,修改oracle日志文件大小
- ATL WTL 实现分析(四)
- carplay是否可以用安卓系统,carplay能连接安卓手机吗
- Form表单做调查表
- 常见的计算机专业相关词汇汇总
- Web two days
- 错误:is quoted with which must be escaped when used within the value
- 不怕得罪人地推荐这9本黑客书籍
- c语言 注册商标标志,什么是标识符?
- 按照高等代数的传统解法编写c++程序实现N(N256)元的线性方程组的求解
- 生活中的算法的实际举例_c语言问题: 什么是算法?试从日常生活中找3个例子,描述它们的算法。 详细点,谢谢!...
- 跃迁:成为高手的技术
- AV1 编解码器编译以及使用
热门文章
- App Store--心酸的上线路,说说那些不可思议的被拒理由
- 去除stackoverflow页面上关不掉的cookie弹窗
- MyBaitsPlus快速入门
- Elasticsearch在Linux中的单节点部署和集群部署
- python整形变量赋初值_为了给整型变量a、b、c赋初值10,下面正确的python语句是...
- python 如何使用 pandas 在 flask web 网页中分页显示 csv 文件数据
- 微信扫码登录实战(附代码)
- RAD Studio Delphi C++ Builder 2020年11月开发路线图PPT:研发Delphi WebAssembly编译器
- 【node】windows使用 npm i -g报错operation not permitted解决方法
- 位置 2 的索引无效。数组索引必须为正整数或逻辑值。