//重定向 串口一
int fputc(int ch,FILE *stream)
{
HAL_UART_Transmit(&huart1,( uint8_t *)&ch,1,0xFFFF);
return ch;
}
//typedef struct __FILE FILE; 使用printf时要加上 #include<stdio.h>;
2.串口中断回调函数
uint8_t g_ucUsart3ReceiveData; //保存串口三接收的数据 main.c
HAL_UART_Receive_IT(&huart3,&g_ucUsart3ReceiveData,1); //串口三接收数据 main.c中开启
//在it.c 重新实现串口中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if( huart == &huart3)//判断中断源
{
if(g_ucUsart3ReceiveData == 'A') motorPidSetSpeed(1,1);//前运动
HAL_UART_Receive_IT( &huart3, &g_ucUsart3ReceiveData, 1);//继续进行中断接收
}
}
//在usart.c中声明外部变量
extern uint8_t g_ucUsart3ReceiveData; //保存串口三接收的数据
3.pwm
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//开启定时器1 通道1 PWM输出
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);//开启定时器1 通道4 PWM输出
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 40);//修改占空比
4.电平配置
HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_RESET);//设置AIN1 PB13为 低电平
HAL_GPIO_WritePin(BIN1_GPIO_Port,BIN1_Pin,GPIO_PIN_SET); //设置BIN1 PB3为高电平
HAL_Delay(1000);
//两次会使得电机反向。
HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_SET);//设置AIN1 PB13为 高电平
HAL_GPIO_WritePin(BIN1_GPIO_Port,BIN1_Pin,GPIO_PIN_RESET); //设置BIN1 PB3为低电平
5.电机
//防重定义函数
#ifndef MOTOR_H__
#define MOTOP_H__
#endif
//定义宏方便移植
#define AIN1_RESET HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_RESET)//设
置AIN1 PB13为 低电平
#define AIN1_SET HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_SET)//设置
AIN1 PB13为 高电平
#define BIN1_RESET HAL_GPIO_WritePin(BIN1_GPIO_Port,BIN1_Pin,GPIO_PIN_RESET)
//设置BIN1 PB3为低电平
#define BIN1_SET HAL_GPIO_WritePin(BIN1_GPIO_Port,BIN1_Pin,GPIO_PIN_SET)//设置
AIN1 PB13为 高电平
//电机工作原理
void Motor_Set (int motor1,int motor2)
{
//根据参数正负 设置选择方向
if(motor1 < 0) BIN1_SET;
else BIN1_RESET;
if(motor2 < 0) AIN1_SET;
else AIN1_RESET;
//motor1 设置电机B的转速
if(motor1 < 0)
{
if(motor1 < -99) motor1 = -99;//超过PWM幅值
//负的时候绝对值越小 PWM占空比越大
//现在的motor1 -1 -99
//给寄存器或者函数 99 1
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (100+motor1));//修改定时器1
通道1 PA8 Pulse改变占空比
}
else{
if(motor1 > 99) motor1 = 99;
//现在是 0 1 99
//我们赋值 0 1 99
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor1);//修改定时器1 通道1
PA8 Pulse改变占空比
}
//motor2 设置电机A的转速
if(motor2 < 0)
{
if(motor2 < -99) motor2 = -99;//超过PWM幅值
//负的时候绝对值越小 PWM占空比越大
//现在的motor2 -1 -99
//给寄存器或者函数 99 1
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, (100+motor2));//修改定时器1 通
道4 PA11 Pulse改变占空比
}
else{
if(motor2 > 99) motor2 = 99;
//现在是 0 1 99
//我们赋值 0 1 99
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, motor2);//修改定时器1 通道4
PA11 Pulse改变占空比
}
}
6.OLED:
OLED的两个引脚
7.为编码器测速开启定时器和定时中断
HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL);//开启定时器2 编码器测速
HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL);//开启定时器4
HAL_TIM_Base_Start_IT(&htim2); //开启定时器2 中断
HAL_TIM_Base_Start_IT(&htim4); //开启定时器4 中断
HAL_TIM_Base_Start_IT(&htim1); //开启定时器1 中断
//放在stm32f1xx_it.c中的定义变量
short Encode1Count = 0;//
short Encode2Count = 0;
float Motor1Speed = 0.00;
float Motor2Speed = 0.00;
uint16_t TimerCount=0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim1)//htim1 500HZ 2ms 中断一次
{
TimerCount++;
if(TimerCount %5 == 0)//每10ms执行一次
{
Encode1Count = (short)__HAL_TIM_GET_COUNTER(&htim4);
Encode2Count = (short)__HAL_TIM_GET_COUNTER(&htim2);
__HAL_TIM_SET_COUNTER(&htim4,0);
__HAL_TIM_SET_COUNTER(&htim2,0);
Motor1Speed = (float)Encode1Count*100/9.6/11/4;
Motor2Speed = (float)Encode2Count*100/9.6/11/4;
TimerCount=0;
}
}
}
8.重定向fputc
int fputc(int ch,FILE *stream)
{
HAL_UART_Transmit(&huart1,( uint8_t *)&ch,1,0xFFFF);
return ch;
}
9.蓝牙控制速度
extern uint8_t g_ucUsart3ReceiveData; //保存串口三接收的数据
int InitSpeed = 50;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart3)
{
if(g_ucUsart3ReceiveData == 'U')
{
InitSpeed += 5;
if(InitSpeed >= 100) InitSpeed=100;
MotorGo(InitSpeed);
}
if(g_ucUsart3ReceiveData == 'D')
{
InitSpeed -= 5;
if(InitSpeed <= 0) InitSpeed=0;
MotorGo(InitSpeed);
}
HAL_UART_Receive_IT( &huart3, &g_ucUsart3ReceiveData, 1);//继续进行中断接收
}
}
10.pid调参:
//.h文件中的
#ifndef __PID_H
#define __PID_H
//声明一个结构体类型
typedef struct
{
float target_val;//目标值
float actual_val;//实际值
float err;//当前偏差
float err_last;//上次偏差
float err_sum;//误差累计值
float Kp,Ki,Kd;//比例,积分,微分系数
} tPid;
//声明函数
float P_realize(tPid * pid,float actual_val);
void PID_init(void);
float PI_realize(tPid * pid,float actual_val);
float PID_realize(tPid * pid,float actual_val);
#endif
//.c文件中的
#include "pid.h"
//定义一个结构体类型变量
tPid pidMotor1Speed;
//给结构体类型变量赋初值
void PID_init()
{
pidMotor1Speed.actual_val=0.0;
pidMotor1Speed.target_val=5;
pidMotor1Speed.err=0.0;
pidMotor1Speed.err_last=0.0;
pidMotor1Speed.err_sum=0.0;
pidMotor1Speed.Kp=10;
pidMotor1Speed.Ki=5;
pidMotor1Speed.Kd=0;
}
// PID控制函数
float PID_realize(tPid * pid,float actual_val)
{
pid->actual_val = actual_val;//传递真实值
pid->err = pid->target_val - pid->actual_val;当前误差=目标值-真实值
pid->err_sum += pid->err;//误差累计值 = 当前误差累计和
//使用PID控制 输出 = Kp*当前误差 + Ki*误差累计值 + Kd*(当前误差-上次误差)
pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum + pid->Kd*(pid->err - pid->err_last);
//保存上次误差: 这次误差赋值给上次误差
pid->err_last = pid->err;
return pid->actual_val;
}
//中断函数中的
if(TimeCount %10 ==0)//每20ms一次
{
MotorGo(PID_realize(&pidMotor1Speed,MotorSpeed));
TimeCount=0;
}
extern tPid pidMotor1Speed;//声明结构体变量
PID_init();//.c文件中初始化