技术日志——第二篇

HWT101数据处理

过程

记录一个今天挖到的坑,使用stm32CubeMx生成代码的时候不要有中文路径,今天我按照昨天设置好的Cube文档生成到了一个中文路径里,在我改好程序后找了很久发现没有Hex文件,幸亏我反映的快,应该是中文路径的问题,换了一个中文路径就成功了,要不又要浪费很多时间了。

还有一个点是,昨天一个朋友告诉我,使用CubeMx生成代码,只要把用户自定义的代码写在规定好的位置里,在生成代码的时候就不会覆盖掉

好了,HWT101的数据处理方法上次已经记录过了,收到的数据主要有两部分,角速度和角度:
在这里插入图片描述
在这里插入图片描述
可以看出角速度前的标志位是0x55和0x52而角度的标志位是0x55和0x53
观察通讯协议之后,我更改了一下代码变成了这样:
首先是自定义变量:

uint8_t RxByte;//串口每接收一个数据,就存入RxByte中
uint8_t RxBuff[256];
uint16_t Rx_Count;
float Angle;
bool start1=false;
bool start2=false;

回调函数的内容如下:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  UNUSED(huart);
  
	if(RxByte==0x55)
	{
		start1=true;
		return;
	}
	
	if(start1==true && RxByte==0x53)	start2=true;
	else start1=false;
	
	if(start2==true)
	{
		if(Rx_Count<=9)	RxBuff[Rx_Count++]=RxByte;
		else
		{
			Rx_Count=0;
			start1=false;
			start2=false;
			
			Angle = (((short)RxBuff[6]<<8)|RxBuff[5])/32768.0*180.0;
			
		}
	}
	if(Rx_Count>=254)
	{
		Rx_Count=0;
	}
	while(HAL_UART_Receive_IT(&huart2,&RxByte,1)==HAL_OK);
}

这段代码的意思是,当检测到这次收到的数据是0x55时,跳出回调函数,直接记录下一个数据,如果下一个数据不是0x53那么上次记录无效,需要重新记录,如果是0x53,那么证明有两个连续的0x55和0x53,说明目前是在记录角度,再记录9个数据到数组里,取第5号和第6号作为z轴角度数据,再把6号左移8位转为有符号的short类型,与5号并在一起,转变成float后就是角度数据了。

但实际上上面的程序没有任何输出结果,应该是条件太苛刻了,或者出现了判断交叉的环节,我又换了另一种方式:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  UNUSED(huart);
  
	
	if(RxByte==0x55)
	{
		start1=true;
	}
	
	if(start1==true)
	{
		if(Rx_Count<=7)	RxBuff[Rx_Count++]=RxByte;
		else
		{
			Rx_Count=0;
			start1=false;
			
			Angle = (((short)RxBuff[6]<<8)|RxBuff[5])/32768.0*180.0;

		}
		
		if(Rx_Count>2)
		{
			if(RxBuff[1]!=0x53)
			{
				Rx_Count=0;
				start1=false;	
			}		
		}
	}
	
	if(Rx_Count>=254)
	{
		Rx_Count=0;
	}
	while(HAL_UART_Receive_IT(&huart2,&RxByte,1)==HAL_OK);
}

其实我完全可以只要检测到0x53之后就向后去5号和6号位置的数据,但主要是担心5号和6号位置本身就含有0x53或者是最后的sum位含有0x53或者其他位置也有,这样的话就乱了,而0x55和0x53并在一起连着的情况在其他位置出现的概率几乎没有,所以就稍微麻烦一点,以免出现错误处理的数据。

理论上来讲,这样处理完数据之后应该没有问题了,但是我看不到结果是否正确,我试图调用HAL_UART_Transmit这个HAL库自带的串口发送函数,但是这个函数只能发送u8类型的数据,我需要一个float转u8的函数,于是写了下面的函数:

void FloatToUint8(uint8_t * char_array,float data)
{
uint8_t i;
for(i=0;i<4;i++)
	{
	char_array[i] = ((uint8_t*)(&data))[i];
	}
}

这个函数可以把float转成4位的u8类型数据,我使用了这个函数后,报错也没有了,但是串口监视器上的数据实在是可读性太差了,满屏幕的十六进制
在这里插入图片描述
而且也无法直接关闭16进制显示,这个我目前也没有明白为什么有的数据可以直接关闭16进制显示后,就可以显示字符串了,反而这个数据不可以。

关闭16进制显示后出现一堆憨憨 -.-
在这里插入图片描述
这个时候还是printf好用,要想用printf必须要做printf的重定向将printf的输出目标定向到uart1上。
首先在main.c中添加头文件:

#include "stdio.h"

之后在main.c中重写fputc和fgetc,主要是fputc:

int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
    return ch;
}
int fgetc(FILE *f)
{
    uint8_t ch = 0;
    HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
    return ch;
}

这样子的话可以直接调用printf函数了,同时也可以在串口监视器上观察到结果:

printf("Angle = %f\n",Angle);

不清楚为什么没有换行,但关键还在于结果有跳变,在静止的时候也有跳变
在这里插入图片描述
没有找到原因在哪里,又更改了一下代码,这次屈服了,为了赶工作进度,只检测了0x53,这次成功了,但是在剧烈变化的时候会冒出0这个数据,但是似乎只出现这个数据,我就单独把这个数据滤掉
代码如下(简化了许多):

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  UNUSED(huart);
  
	
	if(RxByte==0x53)	start_u2=true;
	if(start_u2==true)
	{
		RxBuff[Rx_Count++]=RxByte;
		if(Rx_Count>=7)
		{
			Rx_Count=0;
			start_u2=false;
			if(((((short)RxBuff[6]<<8)|RxBuff[5])/32768.0*180.0)!=0)	Angle = (((short)RxBuff[6]<<8)|RxBuff[5])/32768.0*180.0;
			printf("Angle = %f\n",Angle);
		}
	}
	if(Rx_Count>=254)
	{
		Rx_Count=0;
	}
	while(HAL_UART_Receive_IT(&huart2,&RxByte,1)==HAL_OK);
}

在这里插入图片描述

最终代码

#include "stdbool.h"
#include "string.h"
#include "stdio.h"

uint8_t RxByte;//串口每接收一个数据,就存入RxByte中
uint8_t RxBuff[256];
uint16_t Rx_Count;
float Angle;
bool start_u2=false;

HAL_UART_Receive_IT(&huart2,&RxByte,1);//串口2每接收到一个数据存入RxByte中,并调用一次回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  UNUSED(huart);
  
	
	if(RxByte==0x53)	start_u2=true;
	if(start_u2==true)
	{
		RxBuff[Rx_Count++]=RxByte;
		if(Rx_Count>=7)
		{
			Rx_Count=0;
			start_u2=false;
			if(((((short)RxBuff[6]<<8)|RxBuff[5])/32768.0*180.0)!=0)	Angle = (((short)RxBuff[6]<<8)|RxBuff[5])/32768.0*180.0;
			printf("Angle = %f\n",Angle);
		}
	}
	if(Rx_Count>=254)
	{
		Rx_Count=0;
	}
	while(HAL_UART_Receive_IT(&huart2,&RxByte,1)==HAL_OK);
}
//printf重定向到串口1
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
    return ch;
}
int fgetc(FILE *f)
{
    uint8_t ch = 0;
    HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
    return ch;
}

遗留问题

有一个比较重要的遗留问题,在我之前使用arduino连接HWT101的时候,结果是有正负之分的,但是现在的结果被映射到了0~360°,在0°和360°之间会有一个突变,这在后续的数据处理中是一个问题,有待被解决。

PWM波驱动直流电机

过程

目前还在测试阶段,真正应用应该是回学校或者等机械臂设计好之后才会正式安装,现在各种连接方式都是为了方便测试连接的。并且蓝丁胶和粗导线没有到货,我的3D打印机也没有回来,零件安装板也不方便安装,所以就没有办法组装机器。

而对于电机的测试,编码器和驱动板都需要5V电压,我打算直接从stm32F4的板子上的5V引出来,这样的话总输入的12V就无须接变压器转5V了,12V直接接到驱动板上,先测试一个电机。

首先是记录几个坑
第一个坑是商家程序的pwm波频率用了10kHz,所以我也改成了10kHz
在这里插入图片描述
但是以上改法是完全错误的,这样改的结果是Counter Period这个值是0,而更改占空比,也就是更改CCR寄存器的值,是无效的
比较合适的改法如下:
在这里插入图片描述
这样改过之后频率还是10kHz,占空比的变动范围是0~99

第二个坑是我以前用的是TIM9~TIM14来输出PWM,但我惊奇的发现CubeMx里这几个定时器的接口在stm32上根本找不到,所以很尴尬我改成了TIM3和TIM4,但是这样的话编码器接口就不够用了。
注:我已经把第一篇的电机部分连接更改了
但是昨天和同学交流的时候他之前为了节省定时器,编码器用的是输入中断的方式连接,所以现在的情况是我也只能用输入中断的方式来连接了。

接下来是程序部分,一次成功,没有更改过程。

最终代码

使能8个电机的PWM通道:

HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);//使能8个电机pwm通道
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_4);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4);

引入商家给的motor.c和motor.h并做一些更改:

#include "moto.h"


/**************************************************************************
函数功能:电机的正反转
入口参数:
	  moto:电机  1=电机A,0=电机B
	  pwm1:IN1的PWM的CRR寄存器赋值占空比 就是pwm1/7200
		pwm2:IN2的PWM的CRR寄存器赋值占空比 就是pwm2/7200
返回  值: 无
   a=pwm1-pwm2
  |a|  的大小决定转速度
   a   的符号决定转速
**************************************************************************/

void control(int moto, int pwm1, int pwm2)
{
	if(moto==1)
	{
	 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, pwm1);    //修改比较值,修改占空比pwm1/7200
	 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwm2);    //修改比较值,修改占空比pwm2/7200
	}
	
	if(moto==2)
	{
	 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_3, pwm1);    //修改比较值,修改占空比pwm1/7200
	 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, pwm2);    //修改比较值,修改占空比pwm2/7200
	}
	
	if(moto==3)
	{
	 __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_1, pwm1);    //修改比较值,修改占空比pwm1/7200
	 __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_2, pwm2);    //修改比较值,修改占空比pwm2/7200
	}
	
	if(moto==4)
	{
	 __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, pwm1);    //修改比较值,修改占空比pwm1/7200
	 __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, pwm2);    //修改比较值,修改占空比pwm2/7200
	}

}

#ifndef __MOTO_H
#define	__MOTO_H

#include "tim.h"


void control(int moto, int pwm1, int pwm2);


#endif

用control这个函数控制电机正反转以及调速:

control(1,0,50); 
control(2,0,50); 
control(3,0,50); 
control(4,0,50); 

胡乱接线
在这里插入图片描述
输出成功pwm波
在这里插入图片描述
电机转动
在这里插入图片描述

总结

目前做的工作还都是非常非常简单和基础的,并没有把各个模块结合起来,其实理论上来讲没有什么难度,但是还是用了不少时间,还是因为我自己的stm32基础差,不太行啊

安排下一步任务

  • 完成激光测距

以上都完成后就可以写底盘总程序了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值