【课设分享】使用MSP432-ESP8266实现小车红外测距和数据传输

第一次在CSDN分享自己的课设作业,课设实现的内容为使用MSP432和TI的机器人套装利用红外传感器实时检测距离,然后将距离数据通过串口传给ESP8266模块,再使用8266通过WIFI将数据传送给电脑端,同时小车能根据实时距离控制自己的移动,使自己保持在一个安全的范围内。

软硬件准备

硬件准备

  • 主板:MSP432

  • WIFI模块:ESP8266

  • 红外传感器模块:SHARP 2Y0A21

     (注:TI的机器人套装内以包含MSP432和红外传感器模块。)
    

软件准备

  • Code Compose Studio 9.1(MSP432的开发环境)

  • AiThinkerIDE_V0.5(ESP8266的开发环境)

     (注:这两款软件的安装网上都可以找到很多的教程。)
    

MSP432编程

  1. 头文件
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

导入该头文件需要安装432的SDK,可以在TI的官网上下载到:SDK

  1. 红外传感器的状态定义
// IR Sensor Wall Classification
enum scenario {
    Error = 0,			//错误状态
    CenterRight = 1,		//正确状态
    Straight = 2,		//前进状态
    Back = 3			//后退状态
};
  1. 其他参数定义
#define CENTERMAX 250  // max distance to wall in the front
#define CENTERMIN 150  // min distance to wall in the front

uint8_t TXData1 = 0;   //uart send data1
uint8_t TXData2 = 0;   //uart send data2
uint8_t RXData = 0;    //uart receive data

设置安全区范围为15cm-25cm,并定义2个8位的串口发送数据和1个8位的串口接收数据。

  1. 串口的参数配置
const eUSCI_UART_ConfigV1 uartConfig =
{
        EUSCI_A_UART_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
        26,                                      // BRDIV = 26
        0,                                       // UCxBRF = 0
        111,                                     // UCxBRS = 111
        EUSCI_A_UART_NO_PARITY,                  // No Parity
        EUSCI_A_UART_LSB_FIRST,                  // LSB First
        EUSCI_A_UART_ONE_STOP_BIT,               // One stop bit
        EUSCI_A_UART_MODE,                       // UART mode
        EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION,  // Oversampling
        EUSCI_A_UART_8_BIT_LEN                  // 8 bit data length
};

这里设置波特率为115200,使用48MHz的时钟频率,低位先行,1个停止位,0个校验位,1个数据的长度为8bit。(应该和ESP8266的串口参数匹配)

BRDIV、UCxBRF、UCxBRS这三个参数是根据设置的波特率和时钟频率来计算的,官方提供了一个网页版的计算工具: 计算工具

  1. 串口初始化
// initialize clock
//clock_init_48MHz();
/* Selecting P1.2 and P1.3 in UART mode*/
  MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
              GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
              
/* Setting DCO to 48MHz (upping Vcore) */
  FlashCtl_setWaitState(FLASH_BANK0, 1);
  FlashCtl_setWaitState(FLASH_BANK1, 1);
  MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);
  CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_48);

/* Configuring UART Module */
  MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);

/* Enable UART module */
  MAP_UART_enableModule(EUSCI_A0_BASE);

/* Enabling interrupts */
  MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
  MAP_Interrupt_enableInterrupt(INT_EUSCIA0);
  MAP_Interrupt_enableSleepOnIsrExit();

设置P1.2引脚为TXD和P1.3引脚为RXD,DCO=时钟频率,并为串口分配寄存器,然后启动这个串口和中断。

  1. 读取红外传感器的数据并用串口发送给ESP8266
// the  sending data is 8bit or 16bit
if(ir_data.center<255)
      {
          TXData1 = ir_data.center&0xffffff;
          TXData2 = 0;
          MAP_UART_transmitData(EUSCI_A0_BASE, TXData1);
          MAP_UART_transmitData(EUSCI_A0_BASE, TXData2);
      }
      else
      {
          TXData1 = ir_data.center>>8&0xffff;
          TXData2 = ir_data.center&0xffffff;
          MAP_UART_transmitData(EUSCI_A0_BASE, TXData1);
          MAP_UART_transmitData(EUSCI_A0_BASE, TXData2);
      }

MAP_Interrupt_enableSleepOnIsrExit();
MAP_PCM_gotoLPM0InterruptSafe();

如果距离小于255mm,则只需1个8bit的TXData,因为我设置最高只能检测到800mm,所以最多只需要2个8bit的TXData,发送完数据就进入了等待中断的状态中。

  1. 中断函数
 /* EUSCI A0 UART ISR - receive data from ESP8266 */
   void EUSCIA0_IRQHandler(void)
   {
       uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE);
       if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)
       {
           RXData = MAP_UART_receiveData(EUSCI_A0_BASE);
           MAP_Interrupt_disableSleepOnIsrExit();
       }
   }

当ESP8266发送来应答数据时,就进入到了串口中断函数中,接收完应答数据后,程序退出中断,开始控制小车运动。

  1. 根据距离判断小车状态
scenario_t classify(uint32_t Left, uint32_t Center, uint32_t Right){
  if((Center<0)||(Center>800)) return Error;

if(Center>=CENTERMAX){
    return Straight;
  }

if(Center<=CENTERMIN){
      return Back;
    }

if(Center<CENTERMAX && Center>CENTERMIN){
      return CenterRight;
  }
  return Error; // should happen
}

IR_class = classify(ir_data.left, ir_data.center, ir_data.right);
  1. 根据小车的状态控制小车运动
switch(IR_class)
      {
      case Straight:
          // Move forward with both motors equal
          launchpad_output(LP_GREEN);
          drive_straight();
          break;
      case Back:
          launchpad_output(LP_BLUE);
          drive_back();
          break;
      case CenterRight:
          launchpad_output(LP_RED);
          motor_stop();
      default:
          // This case should not occur, but is included to indicate errors
          launchpad_output(LP_PINK);
          motor_stop();
          break;
      }

小车根据对应的4个状态作出反应:①前进状态:亮绿灯,小车前进;②后退状态:亮蓝灯,小车后退;③正确状态:亮红灯,小车静止;④错误状态:亮粉灯,小车静止。

  1. 以上步骤的6、8、9均包含在循环中,小车可以不停地判断距离,然后移动,使自己处于安全范围中。

ESP8266编程

  1. 相关定义
// 头文件引用
//==================================================================================
#include "user_config.h"  // 用户配置
#include "c_types.h"   // 变量类型
#include "eagle_soc.h"   // GPIO函数、宏定义
#include "ets_sys.h"   // 回调函数
#include "os_type.h"   // os_XXX
#include "osapi.h"     // os_XXX、软件定时器
#include "ip_addr.h"   // 被"espconn.h"使用。在"espconn.h"开头#include"ip_addr.h"或#include"ip_addr.h"放在"espconn.h"之前
#include "espconn.h"   // TCP/UDP接口
#include "user_interface.h"  // 系统接口、system_param_xxx接口、WIFI、RateContro
#include "mem.h"    // 内存申请等函数
#include "driver/uart.h"  //串口
#include "driver/oled.h"  //OLED
//==================================================================================

// 宏定义
//==================================================================================
#define  ProjectName   "MSP432_ESP8266_WIFI_TCP"  // 工程名宏定义

#define  ESP8266_AP_SSID  "ESP8266_WHX"  // 创建的WIFI名
#define  ESP8266_AP_PASS  "123456"   // 创建的WIFI密码

#define  LED_ON    GPIO_OUTPUT_SET(GPIO_ID_PIN(4),0)  // LED亮
#define  LED_OFF    GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1)  // LED灭
//==================================================================================

// 全局变量
//==================================================================================
uint8_t TCPSendData[4]={0};  // TCP发送的数据
os_timer_t OS_Timer_1;   // 定义软件定时器,用于等待WIFI连接
os_timer_t OS_Timer_2;   // 定义软件定时器,用于定时发送数据
struct espconn ST_NetCon;  // 网络连接结构体
struct espconn * dataarg;  // TCP发送数据的指针
//==================================================================================

以下编程涉及到SDK编程,需要提前到乐鑫官网下载esp8266的SDK,否则无法导入头文件"driver/uart.h"和使用串口相关函数。
ESP8266_NONOS_SDK-3.0【提取码:b4y6】

  1. 初始化设置
void ICACHE_FLASH_ATTR user_init(void)
{
	partition_item_t partition_item;
  	if (!system_partition_get_item(SYSTEM_PARTITION_CUSTOMER_PRIV_PARAM, &partition_item)) {
         os_printf("Get partition information fail\n");
     	}
	uart_init(115200,115200); //初始化串口波特率为115200
	os_delay_us(10000);   // 等待串口稳定
	
	// OLED显示初始化
 	//------------------------------------------------------------
	OLED_Init();        // OLED初始化
	OLED_ShowString(0,0,"ESP8266 = Client"); // ESP8266模式	
	OLED_ShowString(0,2,"IP:");     // ESP8266_IP地址
	OLED_ShowString(0,4,"Remote  = Server"); // 远端主机模式
	OLED_ShowString(0,6,"IP:");     // 远端主机IP地址
	//------------------------------------------------------------

	LED_Init_JX();  // LED初始化

	ESP8266_AP_Init_JX();   // 初始化ESP8266_AP模式

	OS_Timer_1_Init_JX(10000,0); // 10秒定时(一次)
}
  1. AP模式的初始化
void ICACHE_FLASH_ATTR ESP8266_AP_Init_JX()
{
 	struct softap_config AP_Config;    // AP参数结构体
	
	wifi_set_opmode(0x02);      // 设置为AP模式,并保存到Flash

	// 结构体赋值(注意:【服务集标识符/密码】须设为字符串形式)
	 //--------------------------------------------------------------------------------------
 	os_memset(&AP_Config, 0, sizeof(struct softap_config)); // AP参数结构体 = 0
 	os_strcpy(AP_Config.ssid,ESP8266_AP_SSID);  // 设置SSID(将字符串复制到ssid数组)
 	os_strcpy(AP_Config.password,ESP8266_AP_PASS); // 设置密码(将字符串复制到password数组)
 	AP_Config.ssid_len=os_strlen(ESP8266_AP_SSID); // 设置ssid长度(和SSID的长度一致)
 	AP_Config.channel=1;                        // 通道号1~13
 	AP_Config.authmode=AUTH_WPA2_PSK;            // 设置加密模式
 	AP_Config.ssid_hidden=0;                    // 不隐藏SSID
 	AP_Config.max_connection=4;                 // 最大连接数
 	AP_Config.beacon_interval=100;              // 信标间隔时槽100~60000 ms
	
	wifi_softap_set_config(&AP_Config);    // 设置soft-AP,并保存到Flash
}

在AP模式初始化函数中,对AP模式的各项参数进行配置,包括SSID,密码,加密模式和最大连接数等。初始化完成后,启动一个10秒的定时器,用于等待WIFI连接。

  1. 定时器1的回调函数
void ICACHE_FLASH_ATTR OS_Timer_1_cb(void)
{
	struct ip_info ST_ESP8266_IP; // IP信息结构体
	u8 ESP8266_IP[4];  // 点分十进制形式保存IP
	wifi_get_ip_info(SOFTAP_IF,&ST_ESP8266_IP); // 查询AP模式下ESP8266的IP地址
	
	if(ST_ESP8266_IP.ip.addr!=0 )    // ESP8266成功获取到IP地址
 	{
 		ESP8266_IP[0] = ST_ESP8266_IP.ip.addr;  // 点分十进制IP的第一个数 <==> addr低八位
  		ESP8266_IP[1] = ST_ESP8266_IP.ip.addr>>8; // 点分十进制IP的第二个数 <==> addr次低八位
  		ESP8266_IP[2] = ST_ESP8266_IP.ip.addr>>16; // 点分十进制IP的第三个数 <==> addr次高八位
  		ESP8266_IP[3] = ST_ESP8266_IP.ip.addr>>24; // 点分十进制IP的第四个数 <==> addr高八位
		// 显示ESP8266的IP地址
  		//-----------------------------------------------------------------------------------------------
  		//os_printf("ESP8266_IP = %d.%d.%d.%d\n",ESP8266_IP[0],ESP8266_IP[1],ESP8266_IP[2],ESP8266_IP[3]);
  		OLED_ShowIP(24,2,ESP8266_IP); // OLED显示ESP8266的IP地址
  		//-----------------------------------------------------------------------------------------------

		os_timer_disarm(&OS_Timer_1); // 关闭定时器

		ESP8266_NetCon_Init_JX();  // 初始化网络连接(TCP通信)
 	}
}

定时器1的10s定时一到就进入到该回调函数中。

  1. 初始化网络连接(TCP通信)
void ICACHE_FLASH_ATTR ESP8266_NetCon_Init_JX()
{
 	// 结构体赋值
 	//--------------------------------------------------------------------------
 	ST_NetCon.type = ESPCONN_TCP ;    // 设置为TCP协议
 	ST_NetCon.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); // 开辟内存
 
 	// 此处需要设置目标IP/端口(ESP8266作为Client,需要预先知道Server的IP/端口)
 	//-------------------------------------------------------------------------
 	ST_NetCon.proto.tcp->local_port = 8266 ; // 设置本地端口
 	ST_NetCon.proto.tcp->remote_port = 8888; // 设置目标端口
 	ST_NetCon.proto.tcp->remote_ip[0] = 192; // 设置目标IP地址
 	ST_NetCon.proto.tcp->remote_ip[1] = 168;
 	ST_NetCon.proto.tcp->remote_ip[2] = 4;
 	ST_NetCon.proto.tcp->remote_ip[3] = 2;

	// 注册连接成功回调函数、异常断开回调函数
 	//--------------------------------------------------------------------------------------------------
 	espconn_regist_connectcb(&ST_NetCon, ESP8266_TCP_Connect_Cb_JX); // 注册TCP连接成功建立的回调函数
 	espconn_regist_reconcb(&ST_NetCon, ESP8266_TCP_Break_Cb_JX);  // 注册TCP连接异常断开的回调函数
	
	// 连接 TCP server
 	//----------------------------------------------------------
 	espconn_connect(&ST_NetCon); // 连接TCP-server
}

在该函数中,设置网络通信协议方式为TCP,同时设置本地端口号和目标服务器的端口号、IP地址,设置完成后,注册TCP连接成功和异常断开的回调函数,然后就可以启动TCP连接服务。

  1. TCP连接成功
void ICACHE_FLASH_ATTR ESP8266_TCP_Connect_Cb_JX(void *arg)
{
 	dataarg = (struct espconn *)arg;
 	espconn_regist_sentcb((struct espconn *)arg, 			ESP8266_WIFI_Send_Cb_JX);   // 注册网络数据发送成功的回调函数
 	espconn_regist_recvcb((struct espconn *)arg, ESP8266_WIFI_Recv_Cb_JX);   // 注册网络数据接收成功的回调函数
 	espconn_regist_disconcb((struct espconn *)arg,ESP8266_TCP_Disconnect_Cb_JX); // 注册成功断开TCP连接的回调函数

	OS_Timer_2_Init_JX(1000,1);
}

如果TCP连接成功,就启动定时器2,这是一个重复的1s定时。

  1. 定时器2的回调函数
void ICACHE_FLASH_ATTR OS_Timer_2_cb(void)
{
 	uint8 idx=0;
 	//数据处理
 	if(uartRxBuffer[1]==0x00)
 	{
  	change_to_dec0(0);		//十六进制转十进制(红外数据只有8位时)
	}
 	else
 	{
  	change_to_dec1(1);		//十六进制转十进制(红外数据有16位时)
 	}
 	
	espconn_send(dataarg,&TCPSendData[0],os_strlen(TCPSendData));//发送TCP数据
	
	//清空TCP发送数据缓存
 	for(idx=0;idx<4;idx++)
 	{
  		TCPSendData[idx]=0;
  		idx++;
	}
	//清空串口接收数据缓存
 	for(idx=0;idx<32;idx++)
 	{
  		uartRxBuffer[idx]=0;
  		idx++;
 	}
 	//向MSP432回复1,表示已成功接收到数据
 	os_printf("1");
}

在WIFI发送数据前,要先对串口接收的数据进行处理,否则服务器端接收到的数据无法正常阅读。

  1. 距离数据类型的转换
void change_to_dec0(uint8 idx)
{
	int a=0;
	if((uartRxBuffer[idx]&0x01)==0x01)
	   a+=1;
	 if((uartRxBuffer[idx]&0x02)==0x02)
	   a+=2;
	 if((uartRxBuffer[idx]&0x04)==0x04)
	   a+=4;
	 if((uartRxBuffer[idx]&0x08)==0x08)
	   a+=8;
	 if((uartRxBuffer[idx]&0x10)==0x10)
	   a+=16;
	 if((uartRxBuffer[idx]&0x20)==0x20)
	   a+=32;
	 if((uartRxBuffer[idx]&0x40)==0x40)
	   a+=64;
	 if((uartRxBuffer[idx]&0x80)==0x80)
	   a+=128;
	 
	 int a1 = a%10;
	 int a2 = ((a-a1)%100)/10;
	 int a3 = a/100;
	 
	 change_to_char(0,a3);	//十进制ASCII编码
	 change_to_char(1,a2);
	 change_to_char(2,a1);
}

void change_to_char(uint8 idx,int a)
{
 	if(a==0)
  		TCPSendData[idx]=0x30;
 	if(a==1)
  		TCPSendData[idx]=0x31;
 	if(a==2)
  		TCPSendData[idx]=0x32;
 	if(a==3)
  		TCPSendData[idx]=0x33;
 	if(a==4)
  		TCPSendData[idx]=0x34;
 	if(a==5)
  		TCPSendData[idx]=0x35;
 	if(a==6)
  		TCPSendData[idx]=0x36;
 	if(a==7)
  		TCPSendData[idx]=0x37;
 	if(a==8)
  		TCPSendData[idx]=0x38;
 	if(a==9)
  		TCPSendData[idx]=0x39;
}

红外传感器测到的数据,将以十六进制的形式通过串口发送给ESP8266,如果不进行数据类型的转换,最后在服务器端看到的将是十六进制的数据,不能直观展示距离大小。

注:16位数据的转换与8位的类似,这里不再贴出。

  1. 串口接收函数的修改
for(idx=0;idx<fifo_len;idx++) {
            d_tmp = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
            uartRxBuffer[idx] = d_tmp;
        }

原本的串口接收函数uart_recvTask,一次接收一位值,并且接收一个就把该值再通过串口发送出去,我这里使用一个数组将接收到值储存起来,方便后续使用。

调试

MSP432和ESP8266的连接

红色为MSP432,黑色为ESP8266 在实物图

结尾

这个课设由本人独立完成,大部分参考了官方例程和一些网络教程,如果有问题,欢迎大家来交流!因为具体代码略长不能全部贴出,完整代码我已上传至下方连接:使用MSP432-ESP8266实现小车红外测距和数据传输

  • 6
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值