STM32智能小车项目

1、小车电机驱动

1.接线:L90110S的MOTORA控制小车左轮电机

               L9110S的MOTORB控制小车右轮电机     

引脚设计: B-1A -- PB0          B-2A -- PB1      A-1A -- PB2          A-1B -- PB10

2.STM32CubeMX创建工程,设置PB0,PB1,PB2,PB10引脚为OUTPUT,并拉高电平。

3.在项目目录的/Core/Src新建motor.c,/Core/Inc新建motor.h,添加进工程。

5.motor.h

#ifndef __MOTOR_H__
#define __MOTOR_H__

void goForward(void);
void goBack(void);
void goLeft(void);
void goRight(void);
void stop(void);

#endif

motor.c

#include "motor.h"
#include "gpio.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_RESET);
	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);
}

main.c测试:

#include "motor.h"
 
//main函数部分:
while (1)
  {
         goForward();
		HAL_Delay(1000);
		goBack();
		HAL_Delay(1000);
		goLeft();
		HAL_Delay(1000);
		goRight();
		HAL_Delay(1000);
        stop();
        HAL_Delay(1000);
      
  }

2、串口控制小车

STM32CUBEMX打开串口USART1和串口1中断

usart.c:重写fputc和串口接收中断回调函数

#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、点动控制小车

STM32CUBEMX提高滴答定时器的优先级:

 修改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();
						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();
					
					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;
}

mian.c

// main函数里
HAL_NVIC_SetPriority(SysTick_IRQn,0,0); //或者通过cubeMX配置
while(1)
{
stop();
}

4、PWM调速

硬件接线 B-1A -- PA0          B-2A -- PB1         A-1A -- PA1         A-1B -- PB10

STM32CUBEMX打开TM2的PWM:

 PSC配置7199,ARR配置199,T=20ms;

将PB0 PB1 PB2 PB10 改为低电平(电机需要一高一低才可以驱动);

main.c

//main函数:    
    
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,80);
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,80);
		HAL_Delay(1000);
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,100);
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,100);
		HAL_Delay(1000);
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,150);
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,150);
		HAL_Delay(1000);
  }

5、左右轮各自调速

//main函数:	
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,80);
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,150);
		HAL_Delay(1000);
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,150);
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,80);
		HAL_Delay(1000);
  }

6、循迹小车

引脚设计: B-1A -- PB0         B-2A -- PB1         A-1A -- PB2         A-1B -- PB10

循迹模块左:PB3 

循迹模块右:PB4

循迹模块发射红外线,黑色有较强的吸收能力,

遇到黑线,没有红外返回,输出高电平,LED灭;

遇到白线,有红外返回,输出低电平,LED亮;

main.c

#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)

//main函数:
 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		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. 循迹小车解决转弯平滑问题

硬件接线:       B-1A -- PA0          B-2A -- PB1         A-1A -- PA1         A-1B -- PB10

循迹模块(左) PB3

循迹模块(右) PB4

 PSC配置7199,ARR配置199,T=20ms;

将PB0 PB1 PB2 PB10 改为低电平(电机需要一高一低才可以驱动);

#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)


// main函数里


HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);


while (1)
{
if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,190);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,190);
}
if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,150);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,80);
}
if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,80);
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,150);
}
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. 跟随小车

硬件接线 B-1A -- PB0          B-2A -- PB1         A-1A -- PB2         A-1B -- PB10

跟随模块(左) -- PB5

跟随模块(右) -- PB6

原理跟循迹模块相同,循迹模块红外发出朝下,跟随模块是朝前;

有物体时,红外返回,输出低电平,LED亮;

没有物体,红外不返回,输出高电平,LED灭

#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. 摇头避障小车

9.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, 15); //将舵机置为90度
}
void sgMiddle(void)
{
__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15); //将舵机置为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 封装超声波传感器

超声波模块: 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


#define MIDDLE 0
#define LEFT 1
#define RIGHT 2

char dir;
double disMiddle;
double disLeft;
double disRight;


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 封装电机驱动

main.c

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. 小车测速

在项目2的基础上修改:

测速模块: VCC -- 3.3V 不能接5V,否则遮挡一次会触发3次中断 OUT -- PB14

 

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显示速度

在项目10基础上修改:添加oled.c oled.h oledfont.h

硬件接线 SCL -- PB6 SDA -- PB7

oled.c

#include "oled.h"
#include "i2c.h"
#include "oledfont.h"

void Oled_Write_Cmd(uint8_t dataCmd)
{
	
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT,
										&dataCmd, 1, 0xff);
}

void Oled_Write_Data(uint8_t dataData)
{
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,
										&dataData, 1, 0xff);
}

void Oled_Init(void){
	Oled_Write_Cmd(0xAE);//--display off
	Oled_Write_Cmd(0x00);//---set low column address
	Oled_Write_Cmd(0x10);//---set high column address
	Oled_Write_Cmd(0x40);//--set start line address  
	Oled_Write_Cmd(0xB0);//--set page address
	Oled_Write_Cmd(0x81); // contract control
	Oled_Write_Cmd(0xFF);//--128   
	Oled_Write_Cmd(0xA1);//set segment remap 
	Oled_Write_Cmd(0xA6);//--normal / reverse
	Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
	Oled_Write_Cmd(0x3F);//--1/32 duty
	Oled_Write_Cmd(0xC8);//Com scan direction
	Oled_Write_Cmd(0xD3);//-set display offset
	Oled_Write_Cmd(0x00);//
	
	Oled_Write_Cmd(0xD5);//set osc division
	Oled_Write_Cmd(0x80);//
	
	Oled_Write_Cmd(0xD8);//set area color mode off
	Oled_Write_Cmd(0x05);//
	
	Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
	Oled_Write_Cmd(0xF1);//
	
	Oled_Write_Cmd(0xDA);//set com pin configuartion
	Oled_Write_Cmd(0x12);//
	
	Oled_Write_Cmd(0xDB);//set Vcomh
	Oled_Write_Cmd(0x30);//
	
	Oled_Write_Cmd(0x8D);//set charge pump enable
	Oled_Write_Cmd(0x14);//
	
	Oled_Write_Cmd(0xAF);//--turn on oled panel		
}

void Oled_Screen_Clear(void){
	char i,n;
	Oled_Write_Cmd (0x20);                    //set memory addressing mode
	Oled_Write_Cmd (0x02);                    //page addressing mode

	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xb0+i);               //éè??ò3μ??·£¨0~7£?
		Oled_Write_Cmd(0x00);                 //éè????ê??????aáDμíμ??·
		Oled_Write_Cmd(0x10);                 //éè????ê??????aáD??μ??·   
		for(n=0;n<128;n++)Oled_Write_Data(0x00); 			
	}	
}

void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2
	unsigned int  i;
	Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0
	Oled_Write_Cmd(0x00+(col&0x0f));                          //low
	Oled_Write_Cmd(0x10+(col>>4));                            //high	
	for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){
		Oled_Write_Data(F8X16[i]);                            //写数据oledTable1
	}

	Oled_Write_Cmd(0xb0+(row*2-1));                           //page 1
	Oled_Write_Cmd(0x00+(col&0x0f));                          //low
	Oled_Write_Cmd(0x10+(col>>4));                            //high
	for(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){
		Oled_Write_Data(F8X16[i]);                            //写数据oledTable1
	}		
}


/******************************************************************************/
// 函数名称:Oled_Show_Char 
// 输入参数:oledChar 
// 输出参数:无 
// 函数功能:OLED显示单个字符
/******************************************************************************/
void Oled_Show_Str(char row,char col,char *str){
	while(*str!=0){
		Oled_Show_Char(row,col,*str);
		str++;
		col += 8;	
	}		
}

oled.h

#ifndef __OLED_H__
#define __OLED_H__

void Oled_Init(void);
void Oled_Screen_Clear(void);
void Oled_Show_Char(char row,char col,char oledChar);
void Oled_Show_Str(char row,char col,char *str);

#endif

olefont.h


const unsigned char F8X16[]=	  
{
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
  0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
  0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
  0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
  0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
  0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
  0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
  0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
  0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
  0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
  0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
  0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
  0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
  0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
  0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
  0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
  0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
  0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
  0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
  0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
  0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
  0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
  0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
  0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
  0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
  0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
  0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
  0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
  0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
  0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
  0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
  0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
  0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
  0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
  0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
  0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
  0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
  0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
  0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
  0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
  0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
  0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
  0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
  0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
  0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
  0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
  0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
  0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
  0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
  0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
  0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
  0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
  0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
  0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
  0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
  0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
  0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
  0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
  0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
  0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
  0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
  0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
  0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
  0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
  0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
  0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
  0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
  0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
  0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
  0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
  0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
  0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
  0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
  0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};

mian.c

#include "motor.h"
#include "stdio.h"
#include "oled.h"
extern uint8_t buf;

unsigned int speedCnt=0;
char speedMes[24];

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);//每一秒钟打印一次速度
	sprintf(speedMes,"%2d cm/s",speedCnt);

	Oled_Show_Str(2,2,speedMes);
	speedCnt = 0;
}


HAL_UART_Receive_IT(&huart1,&buf,1);
HAL_TIM_Base_Start_IT(&htim2);//开启定时器
Oled_Init();
Oled_Screen_Clear();

12. Wi-Fi测速小车并本地Oled显示

硬件接线 把esp8266插进串口1

提高滴答定时器的优先级:

 

添加esp8266.c,esp8266.h

#ifndef __ESP8266_H__
#define __ESP8266_H__

void initWifi_AP(void);
void waitConnect(void);

#endif
#include "esp8266.h"
#include "stdio.h"
#include "usart.h"

//工作在路由模式
char LYMO[]="AT+CWMODE=2\r\n";
//使能多链接
char DLJ[]="AT+CIPMUX=1\r\n";
//建立TCPServer
char JLFW[]="AT+CPISERVER=1\r\n";
//发送数据
char FSSJ[]="AT+CPISEND=0,5\r\n";

char AT_OK_Flag = 0;
char AT_Connect_Net_Flag=0;
char Client_Connect_Flag =0;

void initWifi_AP()
{
	printf(LYMO);
	while(!AT_OK_Flag) HAL_Delay(50);
	AT_OK_Flag=0;
	printf(DLJ);
	while(!AT_OK_Flag) HAL_Delay(50);
	AT_OK_Flag=0;
}


void waitConnect()
{
	printf(JLFW);
	while(!Client_Connect_Flag) HAL_Delay(50);
	AT_OK_Flag=0;
}
usart.c


#include "string.h"
#include "stdio.h"
#include "motor.h"
 #include "esp8266.h"
extern char AT_OK_Flag ;
extern char AT_Connect_Net_Flag;
extern char Client_Connect_Flag ;
//串口接收缓存(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,"WIFI GOT UP"))
						AT_Connect_Net_Flag=1;
					if(!strcmp(UART1_RX_Buffer,"OK"))
						AT_OK_Flag =1;
					if(!strcmp(UART1_RX_Buffer,"0,CONNECT"))
						AT_Connect_Net_Flag=1;
					
					// 控制指令
					if(!strcmp(UART1_RX_Buffer, "+IPD,0,4:M1"))
						goForward();
					else if(!strcmp(UART1_RX_Buffer, "+IPD,0,4:M2"))
						goBack();
					else if(!strcmp(UART1_RX_Buffer, "+IPD,0,4:M3"))
						goLeft();
					else if(!strcmp(UART1_RX_Buffer, "+IPD,0,4:M4"))
						goRight();
					else if((!strcmp(UART1_RX_Buffer, "+IPD,0,4:M0")))
						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"
#include "stdio.h"
#include "oled.h"
#include "esp8266.h"
extern char FSSJ[];
extern uint8_t buf;

unsigned int speedCnt=0;
char speedMes[24];

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(FSSJ);
	HAL_Delay(50);
	sprintf(speedMes,"%2d cm/s",speedCnt);
	printf(speedMes);
	Oled_Show_Str(2,2,speedMes);
	speedCnt = 0;
}

main函数:

HAL_UART_Receive_IT(&huart1,&buf,1);
HAL_TIM_Base_Start_IT(&htim2);//开启定时器
Oled_Init();
Oled_Screen_Clear();
HAL_Delay(1000);
initWifi_AP();
waitConnect();

13. 语音控制小车

 硬件接线 循迹小车: 循迹模块(左) -- PB3         循迹模块(右) -- PB4

                跟随小车: 跟随模块(左) -- PA8         跟随模块(右) -- PA9

                避障小车: sg90:PB9         Trig:PA10         Echo:PA11

                OLED模块: SCL -- PB6         SDA -- PB7

                语音模块: A25 -- PA15 (跟随)         A26 -- PA13 (避障)     A27 -- PA14 (循迹)

CUBEMX配置:

 SU-03配置:

#include "sg90.h"
#include "sr04.h"
#include "motor.h"
#include "oled.h"
#include "string.h"
#define MIDDLE 0
#define LEFT 1
#define RIGHT 2
#define BZ 1
#define XJ 2
#define GS 3
#define LeftWheel_Value_XJ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value_XJ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
#define LeftWheel_Value_GS HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8)
#define RightWheel_Value_GS HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9)
#define XJ_VALUE HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14)
#define GS_VALUE HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)
#define BZ_VALUE HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13)
char dir;
void xunjiMode()
{
if(LeftWheel_Value_XJ == GPIO_PIN_RESET && RightWheel_Value_XJ == GPIO_PIN_RESET)
goForward();
if(LeftWheel_Value_XJ == GPIO_PIN_SET && RightWheel_Value_XJ == GPIO_PIN_RESET)
goLeft();
if(LeftWheel_Value_XJ == GPIO_PIN_RESET && RightWheel_Value_XJ == GPIO_PIN_SET)
goRight();
if(LeftWheel_Value_XJ == GPIO_PIN_SET && RightWheel_Value_XJ == GPIO_PIN_SET)
stop();
}
void gensuiMode()
{
if(LeftWheel_Value_GS == GPIO_PIN_RESET && RightWheel_Value_GS == GPIO_PIN_RESET)
goForward();
if(LeftWheel_Value_GS == GPIO_PIN_SET && RightWheel_Value_GS == GPIO_PIN_RESET)
goRight();
if(LeftWheel_Value_GS == GPIO_PIN_RESET && RightWheel_Value_GS == GPIO_PIN_SET)
goLeft();
if(LeftWheel_Value_GS == GPIO_PIN_SET && RightWheel_Value_GS == GPIO_PIN_SET)
stop();
}
void bizhangMode()
{
double disMiddle;
double disLeft;
double disRight;
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);
}
int main(void)
{
int mark = 0;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM4_Init();
MX_TIM2_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
initSG90();
HAL_Delay(1000);
dir = MIDDLE;
Oled_Init();
Oled_Screen_Clear();
Oled_Show_Str(2,2,"-----Ready----");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//满足循迹模式的条件
if(XJ_VALUE == GPIO_PIN_RESET && GS_VALUE == GPIO_PIN_SET && BZ_VALUE ==
GPIO_PIN_SET)
{
if(mark != XJ)
{
Oled_Screen_Clear();
Oled_Show_Str(2,2,"-----XunJi----");
}
mark = XJ;
xunjiMode();
}
//满足跟随模式的条件
if(XJ_VALUE == GPIO_PIN_SET && GS_VALUE == GPIO_PIN_RESET && BZ_VALUE ==
GPIO_PIN_SET)
{
if(mark != GS)
{
Oled_Screen_Clear();
Oled_Show_Str(2,2,"-----GenSui----");
}
mark = GS;
gensuiMode();
}
//满足避障模式的条件
if(XJ_VALUE == GPIO_PIN_SET && GS_VALUE == GPIO_PIN_SET && BZ_VALUE ==
GPIO_PIN_RESET)
{
if(mark != BZ)
{
Oled_Screen_Clear();
Oled_Show_Str(2,2,"-----BiZhang----");
}
mark = BZ;
bizhangMode();
}
HAL_Delay(50);
}
/* USER CODE END 3 */
}

  • 3
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值