下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人

Posted 花有重开日,人无再少年啊。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人相关的知识,希望对你有一定的参考价值。

目录:

目录浏览:


学习内容:

USART串口的收发,以及串口的协议。
首先我们需要对pintf()函数进行重定位,让我们以后使用他时能够直接从串口打印信息,大大的方便了我们的程序调试。

#include "stdio.h" /* printf函数需要这个头文件  */

/* 下面这段就是对串口的重定位
 *  作用就是将printf打印的信息输出到串口
 */
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 

这里直接添加照搬 。回到正题,我们来配置串口。我们串口接受信息是需要进入中断来完成的,那么我们同时需要编写串口的中断函数,同时我们还需要配置中断函数优先级需要配置NVIC控制器。

1.初始化串口GPIO,
2.配置串口的参数并且初始化,波特率等等
3.配置NVIC使能USART1_IRQn,初始化NVIC
4.打开中断的接收模式 使能中断。

void USART_INIT(u32 borund)
{
	GPIO_InitTypeDef GPIO_Str;/* GPIO结构体初始化GPIO */
	NVIC_InitTypeDef NVIC_Str;/* NVIC控制器结构体 */
	USART_InitTypeDef USART_Str;/* 串口结构体初始化串口 */
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
	//配置GPIO
	GPIO_Str.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_Str.GPIO_Pin=GPIO_Pin_9;
	GPIO_Str.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Str);
	GPIO_Str.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Str.GPIO_Pin=GPIO_Pin_10;
	GPIO_Init(GPIOA,&GPIO_Str);//配置脚管
	
	//配置串口 波特率115200,无奇偶校验,一位停止位,帧长度8
	USART_Str.USART_BaudRate=borund;
	USART_Str.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_Str.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART_Str.USART_Parity=USART_Parity_No;
	USART_Str.USART_StopBits=USART_StopBits_1;
	USART_Str.USART_WordLength=USART_WordLength_8b;
	USART_Init(USART1,&USART_Str);//初始化usart1
	
	//配置中断优先级
	NVIC_Str.NVIC_IRQChannel=USART1_IRQn;
	NVIC_Str.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_Str.NVIC_IRQChannelSubPriority=0;
	NVIC_Str.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_Str);            //中断分租管理初始化
	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//接收终中断模式
	USART_Cmd(USART1,ENABLE);	
}

完成这些我们串口的配置完成了,现在就差中断服务函数的了。我们来编写中断服务函数,注意中断服务函数的名字是固定的,在底层汇编上就叫这个 ,名字不要敲错。附上一张汇编层面中断向量表。在这里插入图片描述

void USART1_IRQHandler(void)       //串口协议 p结束标志         	
{
	u8 Res;
	/* 判断是否接受到信息 */
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
		{	
			/* 接受到就放进Res */
			Res=USART_ReceiveData(USART1);	
			/* 判断Res是不是 ‘p’ */
			if(Res != 'p') //p作为结束标记 
			{
				/* 不是‘p’存进USART_RX_BUF */
				USART_RX_BUF[k] = Res;
				k++;
			}
			/* 是‘p’意味着接受完成 */
			else if(Res == 'p')            
			{
					USART_RX_BUF[k]='\\0';
					b=1; //接收完成标志位
			}
 		}
 }

中断里的接受协议很简单 就是xxxp就行,当然光是一个p只是代表我们接受完成,上位机会传很多坐标,为了防止确实接收到了p但是前面的某些字符没有正确接收,我对每个坐标之间放了个 其他字符进行判断。
例如 d8000s8000e8000p,(不知道为什么现在想想好像没必要)
解析的话直接判断USART_RX_BUF[0] [5] [10],是否分别等于d,s,e。如果是那么接受完全,不是的花就清空。上图:

void data_format(int * road_data_turn,int *road_data_arge,int *led_data)
{
	int road_number_q,road_number_b,road_number_s,road_number_g,road_number;
	int road_sum_q,road_sum_b,road_sum_s,road_sum_g,road_deep_sum;
	int led_sum_q,led_sum_b,led_sum_s,led_sum_g,led_sum;
	if(USART_RX_BUF[0] == 'd' && USART_RX_BUF[5] == 's' && USART_RX_BUF[10] == 'e')
	{
		//printf("ok!!!!!");
		road_number_q = (USART_RX_BUF[1] - '0')*1000;
		road_number_b = (USART_RX_BUF[2] - '0')*100;
		road_number_s = (USART_RX_BUF[3] - '0')*10;
		road_number_g = (USART_RX_BUF[4] - '0')*1;
		road_number = road_number_q+road_number_b+road_number_s+road_number_g;
		*road_data_turn = road_number;
		//printf("road_number = %d ",road_number);
		road_sum_q = (USART_RX_BUF[6] - '0')*1000;
		road_sum_b = (USART_RX_BUF[7] - '0')*100;
		road_sum_s = (USART_RX_BUF[8] - '0')*10;
		road_sum_g = (USART_RX_BUF[9] - '0')*1;
		road_deep_sum = road_sum_q+road_sum_b+road_sum_s+road_sum_g;
		*road_data_arge = road_deep_sum;
		//printf("road_deep_sum = %d ",road_deep_sum);
		led_sum_q = (USART_RX_BUF[11] - '0')*1000;
		led_sum_b = (USART_RX_BUF[12] - '0')*100;
		led_sum_s = (USART_RX_BUF[13] - '0')*10;
		led_sum_g = (USART_RX_BUF[14] - '0')*1;		
		led_sum = led_sum_q+led_sum_b+led_sum_s+led_sum_g;
		*led_data = led_sum;
		//printf("led_sum = %d\\r\\n",led_sum);
	}
}

这里笔者犯傻了当时没想 这么多直接硬刚,其实有很多办法去很简洁的处理字符串数字转十进制。大伙看看就行别和我一样傻。
那么到这里串口和简单的协议也就结束了,我也看了原子的教程上的协议emmm很复杂,就想着自己先弄个简单的能顺利的完成他该完成的任务就行。
下一章节会优先更新个上位机的串口,基于Pyserial,然后再讲讲I2c和6050,有问题的地方请留言。

以上是关于下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人的主要内容,如果未能解决你的问题,请参考以下文章

下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人

下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人

下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人

下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人

下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人

下位机部分-水下管道智能巡检-方案STM32+树梅派+python+opencv—水下机器人