1. 让小车动起来
对应源代码:smartCar_project1
硬件接线
B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10
其余接线参考C51小车项目。
代码实现
motor.c
#include "motor.h"
void goForward(void)
{
// 左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
// 右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void goBack(void)
{
// 左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
// 右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
}
void goLeft(void)
{
// 左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
// 右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void goRight(void)
{
// 左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
// 右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void stop(void)
{
// 左轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
// 右轮
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
motor.h
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "main.h"
void goForward(void);
void goBack(void);
void goLeft(void);
void goRight(void);
void stop(void);
#endif
main.c
#include "motor.h"
//main函数的while循环部分:
while (1)
{
/* USER CODE END WHILE */
goForward();
HAL_Delay(1000);
goBack();
HAL_Delay(1000);
goLeft();
HAL_Delay(1000);
goRight();
HAL_Delay(1000);
stop();
HAL_Delay(1000);
/* USER CODE BEGIN 3 */
}
2. 串口控制小车
对应源代码:smartCar_project2 代码实现 usart.c
#include "string.h"#include "stdio.h"#include "motor.h"
//串口接收缓存(1字节)
uint8_t buf = 0;
//定义最大接收字节数 200,可根据需求调整
#define UART1_REC_LEN 200
// 接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint8_t UART1_RX_Buffer[UART1_REC_LEN];
// 接收状态
// bit15, 接收完成标志
// bit14, 接收到0x0d
// bit13~0, 接收到的有效字节数目
uint16_t UART1_RX_STA = 0;
#define SIZE 12
char buffer[SIZE];
// 接收完成回调函数,收到一个数据后,在这里处理
void HAL_UART_RxCpltCallback(UART_HandleTypeDef * huart) {
// 判断中断是由哪个串口触发的
if (huart - >Instance == USART1) {
// 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
if ((UART1_RX_STA & 0x8000) == 0) {
// 如果已经收到了 0x0d (回车),
if (UART1_RX_STA & 0x4000) {
// 则接着判断是否收到 0x0a (换行)
if (buf == 0x0a) {
// 如果 0x0a 和 0x0d 都收到,则将 bit15 位置为1
UART1_RX_STA |= 0x8000;
// 灯控指令
if (!strcmp(UART1_RX_Buffer, "M1")) goForward();
else if (!strcmp(UART1_RX_Buffer, "M2")) goBack();
else if (!strcmp(UART1_RX_Buffer, "M3")) goLeft();
else if (!strcmp(UART1_RX_Buffer, "M4")) goRight();
else stop();
memset(UART1_RX_Buffer, 0, UART1_REC_LEN);
UART1_RX_STA = 0;
} else
// 否则认为接收错误,重新开始
UART1_RX_STA = 0;
} else // 如果没有收到了 0x0d (回车)
{
//则先判断收到的这个字符是否是 0x0d (回车)
if (buf == 0x0d) {
// 是的话则将 bit14 位置为1
UART1_RX_STA |= 0x4000;
} else {
// 否则将接收到的数据保存在缓存数组里
UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf;
UART1_RX_STA++;
// 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
if (UART1_RX_STA > UART1_REC_LEN - 1) UART1_RX_STA = 0;
}
}
}
// 重新开启中断
HAL_UART_Receive_IT( & huart1, &buf, 1);
}
}
int fputc(int ch, FILE * f)
{
unsigned char temp[1] = {ch};
HAL_UART_Transmit( & huart1, temp, 1, 0xffff);
return ch;
}
main.c
#include "motor.h"
extern uint8_t buf;
//main函数
HAL_UART_Receive_IT(&huart1, &buf, 1);
3. 点动控制小车
对应源代码:smartCar_project3
代码实现 usart.c
if (!strcmp(UART1_RX_Buffer, "M1"))
{
goForward();
HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M2"))
{
goBack();
HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M3"))
{
goLeft();
HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M4"))
{
goRight();
HAL_Delay(10);
}
else
stop();
main.c
// main函数里
HAL_NVIC_SetPriority(SysTick_IRQn,0,0); //或者通过cubeMX配置
while(1)
{
stop();
}
4. 硬件PWM调速
对应源代码:smartCar_project4 硬件接线
B-1A -- PA0 B-1B -- PB1 A-1A -- PA1 A-1B -- PB10
其余接线参考上官一号小车项目。
cubeMX配置
TIM2配置如下图。
这两节里配置有误,正确的应该是PSC=7199,ARR=199,大家注意修正!! 设置 PSC=71 ,ARR=19,PWM 周期则为 20ms 。
将控制车轮的4个 GPIO 口配置修改如下,否则小车动不起来。
原因:L9110每个控制口需要一高一低才可以动起来,如果PWM有效电平为高电平,则另一个 GPIO口则需要输出低电平才可以驱动轮子。
代码实现
main.c
// main函数里
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
while (1)
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 8);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 8);
HAL_Delay(1000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 10);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 10);
HAL_Delay(1000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 15);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 15);
HAL_Delay(1000);
}
5. 左右轮各自调速
对应源代码:smartCar_project5
代码实现
main.c
// main函数里
while (1)
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,8);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,15);
HAL_Delay(1000);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,15);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,8);
HAL_Delay(1000);
}
6. 循迹小车
对应源代码:smartCar_project6
硬件接线
B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10
循迹模块(左) -- PB3 循迹模块(右) -- PB4 其余接线参考c51小车项目。
代码实现
#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
// main函数里
while (1)
{
if (LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
goForward();
if (LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
goLeft();
if (LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
goRight();
if (LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET)
stop();
}
7. 循迹小车解决转弯平滑问题
对应源代码:smartCar_project7
硬件接线
B-1A -- PA0 B-1B -- PB1 A-1A -- PA1 A-1B -- PB10
循迹模块(左) -- PB3 循迹模块(右) -- PB4
其余接线参考c51小车项目。
代码实现
#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
// main函数里
while (1) {
if (LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET) {
__HAL_TIM_SetCompare( & htim2, TIM_CHANNEL_1, 19);
__HAL_TIM_SetCompare( & htim2, TIM_CHANNEL_2, 19);
}
if (LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET) {
__HAL_TIM_SetCompare( & htim2, TIM_CHANNEL_1, 15);
__HAL_TIM_SetCompare( & htim2, TIM_CHANNEL_2, 8);
}
if (LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET) {
__HAL_TIM_SetCompare( & htim2, TIM_CHANNEL_1, 8);
__HAL_TIM_SetCompare( & htim2, TIM_CHANNEL_2, 15);
}
if (LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET) {
__HAL_TIM_SetCompare( & htim2, TIM_CHANNEL_1, 0);
__HAL_TIM_SetCompare( & htim2, TIM_CHANNEL_2, 0);
}
}
8. 跟随小车
对应源代码:smartCar_project8
硬件接线
B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10 跟随模块(左) -- PB5 跟随模块(右) -- PB6 其余接线参考c51小车项目
代码实现
#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)
// main函数里
while (1)
{
if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
goForward();
if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
goRight();
if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
goLeft();
if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET)
stop();
}
9. 摇头避障小车
对应源代码:smartCar_project9
9.1 封装摇头功能
对应源代码:smartCar_project9_1
硬件接线
sg90 -- PB9
cubeMX配置
代码实现
sg90.c
#include "sg90.h"
#include "gpio.h"
#include "tim.h"
void initSG90(void) {
HAL_TIM_PWM_Start( & htim4, TIM_CHANNEL_4); //启动定时器4
__HAL_TIM_SetCompare( & htim4, TIM_CHANNEL_4, 17); //将舵机置为90度
}
void sgMiddle(void) {
__HAL_TIM_SetCompare( & htim4, TIM_CHANNEL_4, 17); //将舵机置为90度
}
void sgRight(void) {
__HAL_TIM_SetCompare( & htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
}
void sgLeft(void) {
__HAL_TIM_SetCompare( & htim4, TIM_CHANNEL_4, 25); //将舵机置为180度
}
sg90.h
#ifndef __SG90_H__
#define __SG90_H__
void initSG90(void);
void sgMiddle(void);
void sgRight(void);
void sgLeft(void);
#endif
main.c
initSG90();
HAL_Delay(1000);
while (1)
{
sgLeft();
HAL_Delay(1000);
sgMiddle();
HAL_Delay(1000);
sgRight();
HAL_Delay(1000);
sgMiddle();
HAL_Delay(1000);
}
9.2 封装超声波传感器
对应源代码:smartCar_project9_2
硬件接线
请注意,超声波模块的接线与垃圾桶项目有所不同!
超声波模块:
Trig -- PB7 Echo -- PB8
cubeMX配置
代码实现
sr04.c
#include "sr04.h"
#include "gpio.h"
#include "tim.h"
//使用TIM2来做us级延时函数
void TIM2_Delay_us(uint16_t n_us) {
/* 使能定时器2计数 */
__HAL_TIM_ENABLE( & htim2);
__HAL_TIM_SetCounter( & htim2, 0);
while (__HAL_TIM_GetCounter( & htim2) < ((1 * n_us) - 1));
/* 关闭定时器2计数 */
__HAL_TIM_DISABLE( & htim2);
}
double get_distance(void) {
int cnt = 0;
//1. Trig ,给Trig端口至少10us的高电平
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); //拉高
TIM2_Delay_us(20);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); //拉低
//2. echo由低电平跳转到高电平,表示开始发送波
//波发出去的那一下,开始启动定时器
while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_RESET); //等待输入电平拉高
HAL_TIM_Base_Start( & htim2);
__HAL_TIM_SetCounter( & htim2, 0);
//3. 由高电平跳转回低电平,表示波回来了
while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_SET); //等待输入电平变低
//波回来的那一下,我们开始停止定时器
HAL_TIM_Base_Stop( & htim2);
//4. 计算出中间经过多少时间
cnt = __HAL_TIM_GetCounter( & htim2);
//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
return (cnt * 340 / 2 * 0.000001 * 100); //单位:cm
}
sr04.h
#ifndef __SR04_H__
#define __SR04_H__
double get_distance(void);
#endif
main.c
while (1) {
if (dir != MIDDLE) {
sgMiddle();
dir = MIDDLE;
HAL_Delay(300);
}
disMiddle = get_distance();
if (disMiddle > 35) {
//前进
} else {
//停止
//测左边距离
sgLeft();
HAL_Delay(300);
disLeft = get_distance();
sgMiddle();
HAL_Delay(300);
sgRight();
dir = RIGHT;
HAL_Delay(300);
disRight = get_distance();
}
}
9.3 封装电机驱动
对应源代码:smartCar_project9_3
硬件接线
与 “让小车动起来” 完全一样 B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10
代码实现
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (dir != MIDDLE) {
sgMiddle();
dir = MIDDLE;
HAL_Delay(300);
}
disMiddle = get_distance();
if (disMiddle > 35) {
//前进
goForward();
} else if (disMiddle < 10) {
goBack();
} else {
//停止
stop();
//测左边距离
sgLeft();
HAL_Delay(300);
disLeft = get_distance();
sgMiddle();
HAL_Delay(300);
sgRight();
dir = RIGHT;
HAL_Delay(300);
disRight = get_distance();
if (disLeft < disRight) {
goRight();
HAL_Delay(150);
stop();
}
if (disRight < disLeft) {
goLeft();
HAL_Delay(150);
stop();
}
}
HAL_Delay(50);
}
10. 小车测速
对应源代码:smartCar_project10
硬件接线
测速模块: VCC -- 3.3V 不能接5V,否则遮挡一次会触发3次中断 OUT -- PB14
cubeMX配置
代码实现
unsigned int speedCnt;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_14)
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)
speedCnt++;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
printf("speed: %d\r\n", speedCnt);
speedCnt = 0;
}
main函数里:
HAL_TIM_Base_Start_IT(&htim2);
11. 串口控制小车并使用Oled显示速度
对应源代码:smartCar_project11
硬件接线
SCL -- PB6 SDA -- PB7
封装Oled模块
对应源代码:smartCar_project11_1
实现测速并使用Oled显示速度
对应源代码:smartCar_project11_2
代码实现 很很长,大家直接去看源代码吧。。
来看看最后成果吧