目录
1. 蓝牙控制小车
2. 蓝牙控制并测速小车
3. wifi控制测速小车
4. 4g控制小车
5.语音控制小车
5.1语音模块配置:
5.2 语音控制小车开发和调试代码
串口透传技术:
代码实现:
整合前面串口控制小车代码,接入蓝牙模块
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();
原理:
使用蓝牙模块和测速模块,将两者代码整合
代码实现:
usart.c
#include "usart.h"
#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;
}
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);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
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;
}
}
main.c
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,"speed:%2d cm/s",speedCnt);//串口数据的字符串拼装,speed是格子,每个格子1cm
Oled_Show_Str(2,2,speedMes);
speedCnt = 0;
}
AT指令介绍:
硬件接线
使用方法:
Wifi模块-ESP-01s_esp01s波特率-CSDN博客
原理:运用EC03-DNC4G通信模块
模块介绍:
代码不做修改,直接基于蓝牙小车整合, 4g模块只要做好外网透传就可以了
使用SU-03T / LD3320
具体介绍看我之前写过的博客:SU-03T语音模块的使用_罗小白的干爹的博客-CSDN博客
硬件接线:
循迹小车:
跟随小车:
避障小车:
OLED模块:
语音模块:
代码示例:
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"
#include "sg90.h"
#include "sr04.h"
#include "motor.h"
#include "oled.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 A25 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)
#define A26 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13)
#define A27 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14)
void SystemClock_Config(void);
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();
initSG90();
HAL_Delay(1000);
dir = MIDDLE;
Oled_Init();
Oled_Screen_Clear();
Oled_Show_Str(2,2,"-----Ready----");
while (1)
{
//满足寻迹模式的条件
if(A25 == 1 && A26 == 1 && A27 == 0){
if(mark != XJ){
Oled_Screen_Clear();
Oled_Show_Str(2,2,"-----XunJi----");
}
mark = XJ;
xunjiMode();
}
//满足跟随模式的条件
if(A25 == 0 && A26 == 1 && A27 == 1){
if(mark != GS){
Oled_Screen_Clear();
Oled_Show_Str(2,2,"-----GenSui----");
}
mark = GS;
gensuiMode();
}
//满足避障模式的条件
if(A25 == 1 && A26 == 0 && A27 == 1){
if(mark != BZ){
Oled_Screen_Clear();
Oled_Show_Str(2,2,"-----BiZhang----");
}
mark = BZ;
bizhangMode();
}
}
}