求一个stm32程序,要求使用l298n驱动电机,通过矩阵键盘设置直流电机期望转速,通过红外传感器测量电机实际转速,测量范围200rpm-3000rpm,最后使用oled显示期望转速和实际转速
时间: 2024-04-23 12:21:58 浏览: 78
好的,以下是一个简单的基于STM32的程序,实现了您的需求。请注意,这只是一个示例程序,您需要根据您的具体硬件和需求进行修改和调试。
```c
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include "oled.h"
#define MOTOR_PIN1 GPIO_Pin_0
#define MOTOR_PIN2 GPIO_Pin_1
#define MOTOR_PWM_PIN GPIO_Pin_2
#define MOTOR_GPIO GPIOB
#define IR_SENSOR_PIN GPIO_Pin_3
#define IR_SENSOR_GPIO GPIOB
#define KEY_ROW1_PIN GPIO_Pin_4
#define KEY_ROW2_PIN GPIO_Pin_5
#define KEY_ROW3_PIN GPIO_Pin_6
#define KEY_ROW4_PIN GPIO_Pin_7
#define KEY_COL1_PIN GPIO_Pin_8
#define KEY_COL2_PIN GPIO_Pin_9
#define KEY_COL3_PIN GPIO_Pin_10
#define KEY_COL4_PIN GPIO_Pin_11
#define KEY_GPIO GPIOA
#define MOTOR_FREQ 20000
#define IR_SENSOR_FREQ 1000
#define IR_SENSOR_MIN_VALUE 200
#define IR_SENSOR_MAX_VALUE 3000
#define MOTOR_MIN_VALUE 0
#define MOTOR_MAX_VALUE 100
volatile uint16_t motor_speed = 0;
volatile uint16_t ir_sensor_value = 0;
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
// Motor GPIO
GPIO_InitStructure.GPIO_Pin = MOTOR_PIN1 | MOTOR_PIN2 | MOTOR_PWM_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(MOTOR_GPIO, &GPIO_InitStructure);
// IR Sensor GPIO
GPIO_InitStructure.GPIO_Pin = IR_SENSOR_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(IR_SENSOR_GPIO, &GPIO_InitStructure);
// Key GPIO
GPIO_InitStructure.GPIO_Pin = KEY_ROW1_PIN | KEY_ROW2_PIN | KEY_ROW3_PIN | KEY_ROW4_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(KEY_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = KEY_COL1_PIN | KEY_COL2_PIN | KEY_COL3_PIN | KEY_COL4_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY_GPIO, &GPIO_InitStructure);
}
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// Motor PWM
TIM_TimeBaseStructure.TIM_Period = MOTOR_FREQ - 1;
TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / MOTOR_FREQ / 100 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_Cmd(TIM3, ENABLE);
// IR Sensor Capture
TIM_TimeBaseStructure.TIM_Period = IR_SENSOR_FREQ - 1;
TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / IR_SENSOR_FREQ / 100 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
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 = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// Motor PWM
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);
// IR Sensor Capture
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM2, TIM_IT_CC4, ENABLE);
}
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
GPIO_SetBits(MOTOR_GPIO, MOTOR_PIN1);
GPIO_ResetBits(MOTOR_GPIO, MOTOR_PIN2);
}
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
static uint16_t last_value = 0;
uint16_t current_value = TIM_GetCapture4(TIM2);
uint16_t period = current_value - last_value;
if (period > 0)
{
ir_sensor_value = IR_SENSOR_FREQ * 60 / period;
}
last_value = current_value;
}
}
void SetMotorSpeed(uint16_t speed)
{
motor_speed = speed;
uint16_t pwm_value = MOTOR_FREQ * motor_speed / MOTOR_MAX_VALUE;
TIM_SetCompare2(TIM3, pwm_value);
}
uint16_t GetKey(void)
{
GPIO_ResetBits(KEY_GPIO, KEY_ROW1_PIN);
GPIO_ResetBits(KEY_GPIO, KEY_ROW2_PIN);
GPIO_ResetBits(KEY_GPIO, KEY_ROW3_PIN);
GPIO_ResetBits(KEY_GPIO, KEY_ROW4_PIN);
if (GPIO_ReadInputDataBit(KEY_GPIO, KEY_COL1_PIN) == RESET)
{
return 1;
}
if (GPIO_ReadInputDataBit(KEY_GPIO, KEY_COL2_PIN) == RESET)
{
return 2;
}
if (GPIO_ReadInputDataBit(KEY_GPIO, KEY_COL3_PIN) == RESET)
{
return 3;
}
if (GPIO_ReadInputDataBit(KEY_GPIO, KEY_COL4_PIN) == RESET)
{
return 4;
}
GPIO_SetBits(KEY_GPIO, KEY_ROW1_PIN);
GPIO_SetBits(KEY_GPIO, KEY_ROW2_PIN);
GPIO_SetBits(KEY_GPIO, KEY_ROW3_PIN);
GPIO_SetBits(KEY_GPIO, KEY_ROW4_PIN);
return 0;
}
int main(void)
{
GPIO_Configuration();
TIM_Configuration();
NVIC_Configuration();
OLED_Init();
OLED_Clear();
while (1)
{
uint16_t key = GetKey();
if (key != 0)
{
uint16_t speed = (key - 1) * MOTOR_MAX_VALUE / 3;
SetMotorSpeed(speed);
}
if (ir_sensor_value >= IR_SENSOR_MIN_VALUE && ir_sensor_value <= IR_SENSOR_MAX_VALUE && motor_speed != 0)
{
char buf[16];
sprintf(buf, "E:%d R:%d", motor_speed, ir_sensor_value);
OLED_ShowString(0, 0, buf);
}
}
}
```
这个程序使用了定时器和GPIO控制电机和红外传感器,使用矩阵键盘获取用户输入的期望转速,并使用OLED显示期望转速和实际转速。程序的具体流程如下:
1. 初始化GPIO、定时器和NVIC。
2. 在TIM3_IRQHandler中实现电机控制逻辑,根据PWM信号控制电机的转速。
3. 在TIM2_IRQHandler中实现红外传感器捕获逻辑,计算出红外传感器输出脉冲信号的频率,根据频率计算出电机实际转速。
4. 实现SetMotorSpeed函数,根据用户输入的期望转速计算出PWM输出,并设置TIM3的比较值。
5. 实现GetKey函数,扫描矩阵键盘按键状态,获取用户输入的期望转速。
6. 在主循环中,获取用户输入的期望转速,并设置电机转速。同时,如果红外传感器输出的频率在范围内,则使用OLED显示期望转速和实际转速。
请注意,这个程序只是一个示例,您需要根据您的具体硬件和需求进行修改和调试。
阅读全文