IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Openmv与stm32通信笔记 -> 正文阅读

[嵌入式]Openmv与stm32通信笔记

Openmv与stm32通信笔记:


首先,用个例子来简单理理通信的步骤:

? 假如我现在想要识别红杆,先要在主函数里写入对应的发送模式(这里假设 写入Mode = 0x12为识别红杆),然后stm32会根据你写入的发送函数,将Mode = 0x12的数据包发送给Openmv执行,在Openmv里得到你识别红杆需要的数据,然后再在Openmv中选择对应的发送模式,将我们需要的数据打包后以包的形式发送过来(这里要注意,根据所需数据的不同,包的形式也不同,具体看个人对包怎么创建),然后Stm32再一个一个将数据拿出,用switch的方式选择接收的数据存到哪些变量中,再把变量调用回主函数。

注意:数据包的发送和接收是按我们规定的时间间隔执行的。

1.Uart等初始化及配置

#include "Basic.h"
#include "drv_Uart2.h"
#include "Quaternion.h"
#include "MeasurementSystem.h"
#include "STS.h"
#include "Sensors_Backend.h"
#include "RingBuf.h"
#include "TM4C123GH6PM.h"
#include "uart.h"
#include "sysctl.h"
#include "gpio.h"
#include "pin_map.h"
#include "interrupt.h"
#include "hw_ints.h"
#include "hw_gpio.h"
#include "Timer.h"
#include "udma.h"
#include "drv_LED.h"
#include "InteractiveInterface.h"
/*引入各头文件*/
#define Uart0_BUFFER_SIZE 64  /*缓存空间大小*/
//串口中断
static void UART0_Handler();

/*发送缓冲区*/
	static uint8_t Uart0_tx_buffer[Uart0_BUFFER_SIZE]; //64位发送数据缓存区
	static RingBuf_uint8_t Uart0_Tx_RingBuf; //定义环形缓存输出
/*发送缓冲区*/

/*接收缓冲区*/
	static uint8_t Uart0_rx_buffer[Uart0_BUFFER_SIZE]; //64位发送数据接收区
	static RingBuf_uint8_t Uart0_Rx_RingBuf;//定义环形缓存接收
/*接收缓冲区*/

static bool SDI_RCTrigger( unsigned int Task_ID );  //声明触发函数及接收、发送主函数
static void SDI_Server( unsigned int Task_ID );

static bool SDI_TXTrigger( unsigned int Task_ID );
static void SDI_Tx_model_contrl( unsigned int Task_ID );

void init_drv_Uart0()
{
	//使能Uart0引脚(Rx:PA0 Tx:PA1)
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	//使能UART0
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
	
	//配置GPIO
	GPIOPinConfigure(GPIO_PA0_U0RX);
	GPIOPinConfigure(GPIO_PA1_U0TX);
	GPIOPinTypeUART(GPIOA_BASE, GPIO_PIN_0 | GPIO_PIN_1);//GPIO的UART模式配置
		
	//配置Uart
	UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet() , 115200,			
	                   (UART_CONFIG_WLEN_8 
										| UART_CONFIG_STOP_ONE 
										|	UART_CONFIG_PAR_NONE));	
	
	//初始化缓冲区
	RingBuf_uint8_t_init( &Uart0_Tx_RingBuf , Uart0_tx_buffer , Uart0_BUFFER_SIZE );
	RingBuf_uint8_t_init( &Uart0_Rx_RingBuf , Uart0_rx_buffer , Uart0_BUFFER_SIZE );
	
	//配置串口接收中断
	UARTIntEnable( UART0_BASE , UART_INT_RX | UART_INT_RT);
	UARTIntRegister( UART0_BASE , UART0_Handler );
	
	//配置DMA发送                通道             
	uDMAChannelControlSet( UDMA_PRI_SELECT | UDMA_CH9_UART0TX , \
	UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1 );
    //8位字节     发送地址(源地址)按8位增加   接收地址(目标地址)按0位增加   总线使用带宽1。
	UARTDMAEnable( UART0_BASE , UART_DMA_TX ); //使能Tx
	UARTIntRegister( UART0_BASE , UART0_Handler );	 //注册中断
	uDMAChannelAssign(UDMA_CH9_UART0TX  );	 //分配通道9给Tx
	
	//打开中断
	IntPrioritySet( INT_UART0 , INT_PRIO_7 );
	IntEnable( INT_UART0 ); 
	
	
	//添加简单二次开发协议解析任务
	STS_Add_Task( STS_Task_Trigger_Mode_Custom , 0 , SDI_RCTrigger , SDI_Server );//接收openmv串口数据任务
	STS_Add_Task( STS_Task_Trigger_Mode_Custom , 0 , SDI_TXTrigger , SDI_Tx_model_contrl );//发送给openmv串口数据任务
}//           	自定义函数触发       		 时间间隔为0     自定义函数   主函数类型   

? 以上是对stm32串口的简单配置,具体配置可按个人具体要求来改动,其中两个STS_Add_Task()函数则是进行数据的接收与发送(Rx、Tx),第一个变量设置触发函数类型(具有多种触发类型)为自定义函数触发,第二个变量为触发的时间间隔,第三个变量则是自己定义的触发函数,第四个变量为触发以后将会执行的主函数。

2.控制Openmv执行指令

uint8_t SDI_mode_contrl = 0;//初始化openmv识别模式  由M35控制
uint8_t SDI_tc_mode = 0;//暂存 SDI_mode_contrl  控制Openmv,选择将要发送的控制模式

static bool SDI_TXTrigger( unsigned int Task_ID ) //将SDI_mode_contrl存入SDI_tc_mode中
{
	if( SDI_mode_contrl != 0 )
	{
		SDI_tc_mode = SDI_mode_contrl;
		SDI_mode_contrl = 0;//执行一次发送任务即关闭发送
		return true;
	}
	return false; //发送失败,返回错误
}

static void SDI_Tx_model_contrl( unsigned int Task_ID )  //给予Tx控制模式
{  	//以下为openmv工作模式控制
	uint8_t tc_buf[6] = {0};  //数据缓存到tc_buf[]中,等数据输入完毕以包的形式发送
	uint8_t tc_cnt = 0;
	uint8_t sum = 0;
	uint16_t tc_data_buf = 0;
	
	tc_buf[0] = 0xAA;//包头1
	tc_buf[1] = 0x55;//包头2
	//包头的存在用于openmv识别,openmv部分会设定接收包头1、2,只有当双方包头一致时,才会进行接收数据
	tc_buf[2] = 0x18;//模式位24
	tc_buf[3] = 0x02;//发送数据长度
	switch(SDI_tc_mode) 
	{//openmv指令控制
		case 0xff:
		{
			tc_buf[4] = 0xff;//不识别模式
		}break;
		
		case 33://蓝杆测距
		{
			tc_buf[4] = 0x16;
		}break;
		
		case 23://识别蓝杆
		{
			tc_buf[4] = 0x2C;
		}break;
		
		case 3://起飞后发送33找橙杆
		{
			tc_buf[4] = 0x21;//开始
		}break;
		
		case 13:																														//B方案3模式:让openmv进入13模式
		{//  发送11 进入绕杆 橙杆
			tc_buf[4] = 0x0B;//绕杆测距返回距离
		}break;
     
		case 43:
		{//			巡地线			
			tc_buf[4] = 55;
		}break;
     
		case 101:
		{//起飞完成  可以开始识别色块转弯
			tc_buf[4] = 101;
		}break;
     
		case 103:
		{																								//B方案3模式:绕弯B杆后,开始3区巡线
			tc_buf[4] = 103;
		}break;
	}
	tc_buf[5] = (tc_buf[0] + tc_buf[1] + tc_buf[2] + tc_buf[3] + tc_buf[4])%256;
 //        求和取余作为数据校验位
	Uart0_Send(tc_buf,6);  //将缓存区的数据输出
}


? 本段代码先是定义SDI_tc_mode()用于发送我们想让openmv执行的模式(以switch的方式选择,便于后期添加或删除模式),然后再定义tc_buf[6]将包头等数据全部打包,在最后用Uart0_Send(tc_buf,6)将数据以包的形式输出openmv。 注意:包头、包尾是自己喜好定义的,而数据位和数据长度则是按自己对于通信的要求来定义,任务内容也是按自己需要编写,最后的tc—buf[5]是采取求和取余的方式来校验数据是否打包完成。

3.控制输入

static bool SDI_RCTrigger( unsigned int Task_ID )   //接收触发位
{
	if( Uart0_DataAvailable() )
		return true;
	return false;
}

//以下按是自己需求编写的函数变量
uint8_t SDI_west = 0;//为1无人机开始向左移动
uint8_t SDI_color = 0;//为1第一根杆为红色 为2第一根杆为绿色
uint8_t SDI_sequence = 0;//为1时寻第二个杆 向右移动  ;为2时寻第二个杆 向左移动  ;
uint8_t SDI_area_block=0;//中心区域色块大小
uint8_t SDI_area_cx=0;//中心区域色块
uint8_t SDI_forward=0;//为1无人机向前移动
int8_t SDI_delta_x=0;//离杆中心的x轴距离
uint8_t SDI_line_coordinate[3] = {0};//第一位前方y坐标,第二位是中心y坐标,第三位是后方y坐标
int8_t line_angle=0;//拟合的直线角度
uint16_t SDI_poles_distance=0;//飞机与杆的距离
uint16_t SDI_find_pole=0;//为1时表示找到杆
uint16_t msg_pack1;
uint16_t msg_pack2;

static void SDI_Server ( unsigned int Task_ID )
{
	
	/*状态机变量*/
		static uint8_t rc_step1 = 0;	//0:接收包头'A' 'C'
	
		#define MAX_SDI_PACKET_SIZE 11       //最大数据包内数据数量
		static uint8_t msg_type;             //数据种类
		static uint8_t msg_length;           //数据长度
		ALIGN4 static uint8_t msg_pack[MAX_SDI_PACKET_SIZE]={0}; //初始化数据包
		static uint8_t sumB;  //求和校验
		#define reset_SDI_RC ( rc_step1 = rc_step2 = 0 ) 
	/*状态机变量*/
	uint8_t rc_buf[20];  	//接收包,原理跟发送包一致
	uint8_t length = read_Uart0( rc_buf , 20 );  //函数在代码末尾有说明
	for( uint8_t i = 0 ; i < length ; ++i )
	{
		uint8_t r_data = rc_buf[i];    
		switch( rc_step1 )
		{
			case 0 :
				sumB=0;
				if(r_data == 0xAA)
				{
					sumB += r_data;
					rc_step1 = 1;
				}
				break;
			case 1:
				if(r_data == 0x55)
				{
					sumB += r_data;
					rc_step1 = 2;
				}
				else reset_SDI_RC;
				break;
			case 2:
				//接收消息类别
				if(r_data > 0x09 && r_data < 0x30)
				{
					msg_type = r_data; //接收模式类型
					sumB += r_data;
					rc_step1 = 3;
					rc_step2 = 0;
				}
				else reset_SDI_RC;
				break;
			
			case 3:
				//接收消息长度
				if( r_data > MAX_SDI_PACKET_SIZE )
				{
					reset_SDI_RC;
					break;
				}
				msg_length = r_data;
				sumB += r_data;
				rc_step1 = 4;
				rc_step2 = 0;
				break;
				
			case 4:
				//接收数据包
				msg_pack[ rc_step2 ++] = r_data;
				sumB += r_data;
				if( rc_step2 >= msg_length )
				{
					rc_step1 = 5;
					rc_step2 = 0;
				}
				break;			
				
				
			  case 5:
				//接收校验位
				if(sumB == r_data)
				{
						 if(msg_type == 0x18)//告诉我找到杆
					{
						  Find_redpole1 = msg_pack[0];
					}
					
					else if(msg_type == 0x19)//告诉我找到杆
					{  
						  Find_redpole = msg_pack[2];
						  SDI_delta_x = msg_pack[1];
						  pole_distance = msg_pack[0];
					}
					
				}
	
				
				reset_SDI_RC;		
					
				break;
		}
	}
}

	
//以下是Uart_send的设置
void Uart0_Send( const uint8_t* data , uint16_t length )
{
	IntDisable( INT_UART0 );
	
	//获取剩余的缓冲区空间
	int16_t buffer_space = RingBuf_uint8_t_get_Freesize( &Uart0_Tx_RingBuf );
	//获取DMA中待发送的字节数
	int16_t DMA_Remain = uDMAChannelSizeGet( UDMA_CH9_UART0TX );
	
	//计算要发送的字节数
	int16_t max_send_count = buffer_space - DMA_Remain;
	if( max_send_count < 0 )
		max_send_count = 0;
	uint16_t send_count = ( length < max_send_count ) ? length : max_send_count;
	
	//将待发送字节压入缓冲区
	RingBuf_uint8_t_push_length( &Uart0_Tx_RingBuf , data , send_count );
//	for( uint8_t i = 0 ; i < send_count ; ++i )
//		RingBuf_uint8_t_push( &Uart0_Tx_RingBuf , data[i] );
	
	//获取DMA发送是否完成
	if( uDMAChannelIsEnabled( UDMA_CH9_UART0TX ) == false )
	{
		//DMA已完成
		//可以继续发送
		uint16_t length;
		uint8_t* p = RingBuf_uint8_t_pop_DMABuf( &Uart0_Tx_RingBuf , &length );
		if( length )
		{
			uDMAChannelTransferSet( UDMA_PRI_SELECT | UDMA_CH9_UART0TX , \
				UDMA_MODE_BASIC , p , (void*)&UART0->DR , length );
			uDMAChannelEnable( UDMA_CH9_UART0TX );
		}
	}
	IntEnable( INT_UART0 );
}

static void UART0_Handler()
{
	UARTIntClear( UART0_BASE , UART_INT_OE );
	UARTRxErrorClear( UART0_BASE );
	while( ( UART0->FR & (1<<4) ) == false	)
	{
		//接收
		uint8_t rdata = UART0->DR;
		RingBuf_uint8_t_push( &Uart0_Rx_RingBuf , rdata );
	}
	
	if( uDMAChannelIsEnabled( UDMA_CH9_UART0TX ) == false )
	{
		uint16_t length;
		uint8_t* p = RingBuf_uint8_t_pop_DMABuf( &Uart0_Tx_RingBuf , &length );
		if( length )
		{
			uDMAChannelTransferSet( UDMA_PRI_SELECT | UDMA_CH9_UART0TX , \
				UDMA_MODE_BASIC , p , (void*)&UART0->DR , length );
			uDMAChannelEnable( UDMA_CH9_UART0TX );
		}
	}
}

uint16_t read_Uart0( uint8_t* data , uint16_t length )
{
	IntDisable( INT_UART0 );
	uint8_t read_bytes = RingBuf_uint8_t_pop_length( &Uart0_Rx_RingBuf , data , length );
	IntEnable( INT_UART0 );
	return read_bytes;
}

uint16_t Uart0_DataAvailable()
{
	IntDisable( INT_UART0 );
	uint16_t bytes2read = RingBuf_uint8_t_get_Bytes2read( &Uart0_Rx_RingBuf );
	IntEnable( INT_UART0 );
	return bytes2read;
}

? 接收原理与发送原理一致,首先是识别包头,然后确定接收到的模式,用于接收对应模式所需要传达的信息。

7.26学习笔记
bytes = RingBuf_uint8_t_pop_length( &Uart0_Rx_RingBuf , data , length );
IntEnable( INT_UART0 );
return read_bytes;
}

uint16_t Uart0_DataAvailable()
{
IntDisable( INT_UART0 );
uint16_t bytes2read = RingBuf_uint8_t_get_Bytes2read( &Uart0_Rx_RingBuf );
IntEnable( INT_UART0 );
return bytes2read;
}


?		接收原理与发送原理一致,首先是识别包头,然后确定接收到的模式,用于接收对应模式所需要传达的信息。

7.26学习笔记
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-29 09:31:07  更:2021-08-29 09:33:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:01:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码