基于STM32F103C8T6通过WIFI模块(ESP8266)控制小车

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

        主要想玩一下遥控汽车通过stm32c8t6连接wifi模块控制小车前进、后退、左转、右转。


一、材料准备

硬件:

        1.STM32F103C8T6最小核心板

        2.ESP8266(原子云固件)

        3.L298N驱动

        4.ST-Link下载器

软件:

        1.固件烧写工具

        2.串口助手

        3.网络调试助手

左边马达:
PA8----->ENA      //定时器1引脚
PC14---->IN1
PC15---->IN2

右边马达:
PA0----->ENB    //定时器2引脚
PB12---->IN1
PB13---->IN2

串口3:

PB10---->RX   //RX为esp8266RX引脚
PB11---->TX

二、原子云固件下载

       1. 可以到正点原子官网下载固件以及下载软件。

                http://www.openedv.com/docs/modules/iot/atk-esp.html

        2.这是我打包好的程序源码以及上述所用的软件

                   https://pan.baidu.com/s/1NcFIn4GRzuG9y_DV1aSB6w

                        提取码:1234

三、实验步骤

 1.基本AT指令

     我用的是STA+TCP透传模式:

                AT          //检测wifi模块是否存在

                AT+CWMODE=1  //设置ESP8266为STA模式

                AT+RST             //重启模块

                AT+CWJAP=”wifi名称“,”wifi密码“   //连接wifi

                AT+CIPSTART=”TCP“,”ip地址“,端口       //连接TCP服务器

                AT+CIPMODE=1       //开启透传

           例子:

while(esp8266_send_cmd("AT","OK",100));
    printf("wifi存在!\r\n\r\n");
	
//设置ESP8266为STA模式
while(esp8266_send_cmd("AT+CWMODE=1","OK",50));
	printf("STA模式\r\n\r\n");
	
while(esp8266_send_cmd("AT+RST","ready\r\n",200));
	printf("复位成功\r\n\r\n");

//连接WIFI
while(esp8266_send_cmd("AT+CWJAP=\"www\",\"20020318\"","WIFI GOT IP",300))
{
		printf("wifi连接失败\r\n\r\n");
}
	printf("wifi连接成功\r\n");	

//www          为我的wifi名称
//20020318        为我的wifi密码
//WIFI GOT IP 为原子云固件连接上wifi后返回的答复
//300        为等待时间

while(esp8266_send_cmd("AT+CIPSTART=\"TCP\",\"10.121.35.2\",8080","CONNECT",200)){//这命令要等到手机端与esp8266建立连接后才会返回0,结束循环
		printf("TCP连接失败\r\n");
	}
	  printf("TCP连接成功\r\n\r\n");
	
while(esp8266_send_cmd("AT+CIPMODE=1","OK",200)){//这命令要等到手机端与esp8266建立连接后才会返回0,结束循环
	}
	  printf("透传模式\r\n\r\n");

           ps:一定要注意答复的地方要与原子云固件了的答复一样,否则会连接失败,可以先用usb-ttl与esp8266通过电脑测试一下回复。注意改为自己需要连接的wifi和tcp服务器。

2.串口接收中断

            我使用的是串口3与wifi通信,由于使用cubemx生成代码,所以比较简单,只需要注意开启串口接收中断即可。

///////串口1重定向用于打印信息
int fputc(int ch,FILE *f)
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
	//HAL_UART_Transmit(&huart3,(uint8_t *)&ch,1,0xffff);
	return ch;
}

////////此函数用于向esp8266发送指令
void u3_printf(char* fmt,...)  
{  
	uint16_t i,j; 
	va_list ap; 
	va_start(ap,fmt);
	vsprintf((char*)USART3_TX_BUF,fmt,ap);
	va_end(ap);
	i=strlen((const char*)USART3_TX_BUF);		//此次发送数据的长度
	for(j=0;j<i;j++)							//循环发送数据
	{
		while((USART3->SR&0X40)==0);			//循环发送,直到发送完毕   
		USART3->DR=USART3_TX_BUF[j];  
	} 
}


/////此函数接收esp8266返回的答复
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == USART3)
	{
		if((USART3_RX_STA&0x8000)==0)
		{
			if(USART3_RX_STA<USART_REC_LEN)
			{
				TIM3->CNT = 0;
				if(USART3_RX_STA == 0)
				{
					HAL_TIM_Base_Start_IT(&htim3);
				}
				USART3_RX_BUF[USART3_RX_STA++] = aRxBuffer[0];
			}
			else
			{
				USART3_RX_STA |= 0x8000;
			}
		}
	}
	HAL_UART_Receive_IT(&huart3,(uint8_t *)&aRxBuffer,1);
}

                中间用到定时器的目的是每隔100ms不管接没接收完成,都强制让串口3接收完成。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM3)
	{
		USART3_RX_STA |= 0x8000;
		HAL_TIM_Base_Stop_IT(&htim3);
	}
}

 3.esp8266代码

//向ESP8266发送命令
//cmd:发送的命令字符串;ack:期待的应答结果,如果为空,则表示不需要等待应答;waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果);1,发送失败
u8 esp8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
	u8 res=0; 
	USART3_RX_STA=0;
	u3_printf("%s\r\n",cmd);	//发送命令
	if(ack&&waittime)		//需要等待应答
	{
		while(--waittime)	//等待倒计时
		{
			HAL_Delay(10);
			if(USART3_RX_STA&0X8000)//接收到期待的应答结果
			{
				if(esp8266_check_cmd(ack))
				{
					//printf("ack:%s\r\n",(u8*)ack);
					break;//得到有效数据 
				}
					USART3_RX_STA=0;
			} 
		}
		if(waittime==0)res=1; 
	}
	return res;
} 


//ESP8266发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果;其他,期待应答结果的位置(str的位置)
u8* esp8266_check_cmd(u8 *str)
{
	char *strx=0;
	if(USART3_RX_STA&0X8000)		//接收到一次数据了
	{ 
		USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
		strx=strstr((const char*)USART3_RX_BUF,(const char*)str);
	} 
	return (u8*)strx;
}

strstr()函数:

简单来说就是你传入的参数如果与esp8266发送给串口3的USART3_RX_BUF里字符匹配,则会成功返回。

4.主函数

  while(esp8266_send_cmd("AT","OK",100));
	printf("wifi存在!\r\n\r\n");
	
		//设置ESP8266为STA模式
	while(esp8266_send_cmd("AT+CWMODE=1","OK",50));
	printf("STA模式\r\n\r\n");
	
	while(esp8266_send_cmd("AT+RST","ready\r\n",200));
	printf("复位成功\r\n\r\n");
	
	
	//连接WIFI
	while(esp8266_send_cmd("AT+CWJAP=\"www\",\"20010318\"","WIFI GOT IP",300)){
		printf("wifi连接失败\r\n\r\n");
		
	}
	  printf("wifi连接成功\r\n");
	
	while(esp8266_send_cmd("AT+CIPSTART=\"TCP\",\"10.121.35.19\",8080","CONNECT",200)){//这命令要等到手机端与esp8266建立连接后才会返回0,结束循环
		printf("TCP连接失败\r\n");
	}
	  printf("TCP连接成功\r\n\r\n");
	
	while(esp8266_send_cmd("AT+CIPMODE=1","OK",200)){//这命令要等到手机端与esp8266建立连接后才会返回0,结束循环
	}
	  printf("透传模式\r\n\r\n");
	
  while (1)
  {
		if(USART3_RX_STA & 0x8000) 
		{
			switch(USART3_RX_BUF[0])
			{
				case 'G':run();
								break;
				case 'S':stop();
								break;
				case 'B':back();
								break;
				case 'L':left();
								break;
				case 'R':right();
								break;
			}
				USART3_RX_STA = 0 ; 			
		}
  }

5.电机驱动模块

#include "motor.h"

//pc14/pc15左走前轮  pb12/pb13
void run()
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_RESET);
	
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_RESET);
}

void stop()
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_SET);
	
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);
}

void back()
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_SET);
	
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);
}

void left()
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_RESET);
	
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_RESET);
}

void right()
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_RESET);
	
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_RESET);
}

总结

        其实esp8266还是比较容易应用,多看几遍用户手册和AT指令集,咱就可以简单的入个门了;以下是我遇到的问题:1.串口接收回调函数里面一定不要乱判结束符!!!因为你的数据可能还没有接收完成就被你判结束了。具体可以打断点调试工程。 2.注意固件里每个指令的响应,不然弄错了会连不上你的wifi或者tcp。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值