FOC系列(五)----STM32F405RGT6控制板焊接与初步编写代码

news2025/1/20 14:53:45

   声明:本人水平有限,博客可能存在部分错误的地方,请广大读者谅解并向本人反馈错误。
   首先祝大家新年快乐,因为我也快放假了,驱动板只能是开学之后再去测试了,本篇博客应该是本专栏年前的最后一篇了

一、 硬件部分

1.1 原理图

  废话就先不多说了,原理图如下:
在这里插入图片描述
  原理图和上一版的原理图最大的改变是修改了MCU芯片,由103改为了405;并且继续保留了CAN芯片和FLASH芯片,对后续的开发肯定有用。

1.2 PCB

在这里插入图片描述
在这里插入图片描述
  今天刚刚焊接起来,测试时出现了一点问题,就是在使用keil下载时会出现"Cannot load flash programming algorithm"问题,这个问题困扰了我一下午。尝试了许多方法,最后把原本下载的F4xx固件2.17.1版本卸载,安装了2.17.0版本,并且在keil下载按如下配置:
在这里插入图片描述
在这里插入图片描述
  其实也没有做什么特殊的设置,然后就好了…

二、软件部分

2.1 代码

  具体的代码我会在整体都做完之后进行开源的,下面我就说一下整体的代码功能:

  1. 使用ESP32的BLE功能,接收手机发送的指令
  2. ESP32会将接收的指令转化为通信协议发送给STM32
  3. STM32解析指令,并根据不同的指令进行不同的功能(目前实现的功能是切换OLED的显示界面)

2.2 部分效果展示

  手机发送"speed"指令:
在这里插入图片描述
  ESP32会将"speed"指令在OLED上显示,并且发送指令给STM32:
在这里插入图片描述
  STM32接收到指令会显示速度的波形(图片看不出来,所以波形不是很明显)
  还有其他指令,比如:

  • focfb->STM32显示反馈的数据,比如电流、转速、角度、转矩
  • Acurrent->显示A相采集的电流值
  • Bcurrent->显示B相采集的电流值
  • setpid->设置PID的参数(目前还不成熟,后续开发)

  下面再放几个截图:
在这里插入图片描述
在这里插入图片描述

2.3 部分代码

  在这先放上main函数和中断等部分函数:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_TIM1_Init();
  MX_TIM6_Init();
  MX_ADC1_Init();
  MX_TIM3_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
	
	// OLED 初始化
	OLED_GPIO_Init();
	OLED_Init();
	OLED_Display_On();
	OLED_Set_Pos(0,0);
	OLED_Clear();
	
	HAL_UART_Receive_IT(&huart2, rxBuffer,RX_CMD_LEN);	// 中断方式接收RX_CMD_LEN个字符
	
	// 初始化定时器
	HAL_TIM_Base_Start_IT(&htim6);  // 中断方式启动tim2
	HAL_Delay(100);
	
	
	// 开启PWM输出
	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
	HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);

	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2); // 输出PWM波形
	HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2);

	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
	HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3);
	
	HAL_Delay(100);
	
	// 显示菜单
	Mune(Open);  // 显示菜单
	HAL_Delay(200);
	
	// 逆时针旋转
	// COUNTER_CLOCKWISE_ROTE;

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(defaultOledPage) Mune(defaultOledPage);  // 显示默认画面
	  else Mune(selectionOledPage);
  }
  /* USER CODE END 3 */
}

  timer中断:

void TIM6_DAC_IRQHandler(void)
{
  /* USER CODE BEGIN TIM6_DAC_IRQn 0 */

  /* USER CODE END TIM6_DAC_IRQn 0 */
  HAL_TIM_IRQHandler(&htim6);
  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */
	htim1.Instance->CCR1 = 100;
	htim1.Instance->CCR2 = 50;
	htim1.Instance->CCR3 = 80;
		
	Programe_Run();// 获取角度
	
  /* USER CODE END TIM6_DAC_IRQn 1 */
}

  解析角度与速度:

void Programe_Run(void)
{
	uint8_t dect= 0;
	float preAngel = 0.0;
	float nowAngel = 0.0;
	float dT = 0.01;
	
	preAngel = degress;
	
	dect = detectMagnet();

	rawdata = getRawAngle();

	degress = convertRawAngleToDegrees(rawdata);
	
	velocity = Velocity(preAngel,degress,dT,counterclockwise);
}

  解析通信协议指令:

void	on_UART_IDLE(UART_HandleTypeDef *huart) //检测IDLE中断事件并处理
{
//注意,这里不能使用函数	__HAL_UART_GET_FLAG(),因为上位机连续发5个字节,串口接收到1个字节后虽然打开了IDLE中断,
//	但是因为后续连续发送数据,所以IDLE中断挂起标志位并不会被置位
	if(__HAL_UART_GET_IT_SOURCE(huart,UART_IT_IDLE) == RESET) //判断IDLE中断是否被开启
		return;

	__HAL_UART_CLEAR_IDLEFLAG(huart); 	//清除IDLE标志
	__HAL_UART_DISABLE_IT(huart, UART_IT_IDLE); 	//禁止IDLE中断
	
	if (rxCompleted)	//接收到了1个字符
	{
		uint8_t  ch=rxBuffer[0];
		if (ch==0x6A)	//起始符
			rxBufPos=0;		//存储位置复位

		if (rxBufPos<PRO_CMD_LEN) //PRO_CMD_LEN=5
		{
			proBuffer[rxBufPos]=ch;		//存储到处理指令缓存区
			rxBufPos++;		//存储位置移动
			if (ch==0x70)	//结束符
			{
				parseCMD();  // 解析数据
				// HAL_UART_Transmit(huart,proBuffer,strlen(proBuffer),200); //上传接收到的指令
				// HAL_Delay(10);  	//需适当延时,否则updateRTCTime()函数处理可能出错
			}
		}
		rxCompleted = RESET;
		HAL_UART_Receive_IT(huart, rxBuffer,RX_CMD_LEN); //再次接收
	}
}
/*数据格式:<0x6A><0x61><0x6D><总数据字节数><指令序列><对应指令><...><...><0x70>*/
void parseCMD(void)
{
	int i=0;
	// 将数据指令保存起来
	dateSumNumber = proBuffer[1];  // 数据长度
	
	// rxCmdBuf数组从序列号开始保存
	for(i=0;i<(dateSumNumber-3);i++)  rxCmdBuf[i] = proBuffer[i+2]; // 指令解析
	cmdSequence = rxCmdBuf[0];  // 序列号
	// 根据序列号选择不同的指令
	switch(cmdSequence){
		case 0x01: {    // FOC反馈显示
			defaultOledPage = 0; //不再显示默认界面
			selectionOledPage = rxCmdBuf[1]; // 根据指令修改OLED界面
		};break;  
		
		case 0x02: {    // 电流页面显示
			defaultOledPage = 0; //不再显示默认界面
			selectionOledPage = rxCmdBuf[1]; // 根据指令修改OLED界面
		};break;  
		
		case 0x03:{     // 速度页面显示
			defaultOledPage = 0; //不再显示默认界面
			selectionOledPage = rxCmdBuf[1]; // 根据指令修改OLED界面
		};break;  
		
		case 0x04:{     // 修改PID参数
			defaultOledPage = 0; //不再显示默认界面
			selectionOledPage = rxCmdBuf[1]; // 根据指令修改OLED界面
		};break;  
	}
}

  OLED切换界面:

void Mune(int Page)
{
//	int i = 0;
	switch(Page){
		case 0: {  // 开机页面
			oledClearMulPage(Page);
			
			OLEDDisBinBMP(60,128,gImage_Jam,Middle,Normal_Color);  //  
			HAL_Delay(1000); // 延时3s
			OLED_Clear();
			
			OLEDDisBinBMP(63,64,gImage_Laugh_HLL,Middle,Inverse_Color);
			HAL_Delay(1000); // 延时3s
			OLED_Clear();
			oled_print_chinese(0,0,16,UPC[0],8,Inverse_Color);
			oled_print_chinese(0,2,16,KongZhiXueYUan[0],7,Normal_Color);
			oled_print_chinese(0,4,16,AI[0],4,Inverse_Color);
			oled_print_chinese(0,6,16,Name[0],3,Normal_Color);
			HAL_Delay(1500); // 延时3s
			OLED_Clear();

		};break;
		
		case 1:{  // 显示FOC的反馈值
			// 清OLED
			oledClearMulPage(Page);
			oled_print_chinese(0,0,16,Speed[0],2,Normal_Color);
			oled_print_chinese(0,2,16,Current[0],2,Inverse_Color);
			oled_print_chinese(0,4,16,Angle[0],2,Normal_Color);
			oled_print_chinese(0,6,16,Torque[0],2,Inverse_Color);
			// 测试使用
			OLED_ShowNum(36,0,velocity,4,16);
			OLED_ShowNum(36,2,aFinalValue,4,16);
			OLED_ShowNum(36,4,degress,4,16);
			OLED_ShowNum(36,6,cFinalValue,4,16);
			// OLED_ShowNum(36,6,cmdSequence,4,16); // 接收序列号

			OLEDDisBinBMP(58,58,gImage_Kong_Long,Right,Normal_Color); // 
			if(count<1000) count += 50;
			else count = 0;
			HAL_Delay(10);
		};break;
		
		case 2:{	 // 显示电流采集值
			oledClearMulPage(Page);
			
			if(rxCmdBuf[2]==0x0A)
			{
				// 坐标
				OLEDDisBinBMP(58,128,gImage_Current_A,Middle,Inverse_Color);
				
				for(x=10;x<118;x=(x+1)%128)//若测高频,改为x=(x+8)号128,注意由于没进行信号发生器验证可能出现bug
				{
					float count=0.015295*aFinalValue+8;			
					OLED_DrawWave(x,count);
				
				}
			}
			
			if(rxCmdBuf[2]==0x0B)
			{
				// 坐标
				OLEDDisBinBMP(58,128,gImage_Current_B,Middle,Inverse_Color);
				
				for(x=10;x<118;x=(x+1)%128)//若测高频,改为x=(x+8)号128,注意由于没进行信号发生器验证可能出现bug
				{
					float count=0.015295*bFinalValue+8;			
					OLED_DrawWave(x,count);
				}
			}
		};break;
		
		case 3: {  // 显示速度返回值
			oledClearMulPage(Page);
			OLEDDisBinBMP(59,128,gImage_Velocity,Middle,Inverse_Color);
			
			for(x=10;x<118;x=(x+1)%128)//若测高频,改为x=(x+8)号128,注意由于没进行信号发生器验证可能出现bug
			{
					float count = velocity + 8;			
					OLED_DrawWave(x,count);
			}
		};break;
		
		case 4:{  // 显示解析出来的数据
		oledClearMulPage(Page);
		// if(clearOLEDFlag==0) { OLED_Clear();clearOLEDFlag=1;}
		oled_print_chinese(0,0,16,Byte[0],2,Normal_Color);
		oled_print_chinese(0,2,16,Sequence[0],2,Inverse_Color);
		oled_print_chinese(0,4,16,Parameter[0],2,Normal_Color);
		oled_print_chinese(0,6,16,Parameter[0],2,Inverse_Color);
			
		oled_print_chinese(64,0,16,Parameter[0],2,Normal_Color);
		oled_print_chinese(64,2,16,Parameter[0],2,Inverse_Color);
		oled_print_chinese(64,4,16,Parameter[0],2,Normal_Color);
		oled_print_chinese(64,6,16,Parameter[0],2,Inverse_Color);
			
		// 测试使用
		OLED_ShowNum(34,0,dateSumNumber,3,16);
		OLED_ShowNum(34,2,cmdSequence,3,16);
		OLED_ShowNum(34,4,rxCmdBuf[1],3,16);
		OLED_ShowNum(34,6,rxCmdBuf[2],3,16);
			
		OLED_ShowNum(98,0,rxCmdBuf[3],3,16);
		OLED_ShowNum(98,2,rxCmdBuf[4],3,16);
		OLED_ShowNum(98,4,rxCmdBuf[5],3,16);
		OLED_ShowNum(98,6,rxCmdBuf[6],3,16); // 接收序列号

	};break;
		
	}
}

三、往期回顾

FOC系列(一)----DRV8301芯片的学习
FOC系列(二)----继续学习DRV8301芯片
FOC系列(三)----AS5600磁编码器
FOC系列(四)----重新绘制DRV8301驱动板

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1416061.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT 范例阅读:Vector Deformation

效果图&#xff1a; 主要代码&#xff1a; 实现放大镜效果QPainter painter;//两种方式if (1) {m_lens_image QImage(bounds.size(), QImage::Format_ARGB32_Premultiplied);m_lens_image.fill(0);painter.begin(&m_lens_image);} else {m_lens_pixmap QPixmap(bounds.si…

GEE数据集——2024 年日本海地震的紧急观测数据

2024 年日本海地震的紧急观测数据 2024 年日本海地震发生在 2024 年 1 月 1 日下午 4:00 后&#xff08;日本时间&#xff09;&#xff0c;造成了重大损失&#xff0c;包括多处建筑物倒塌、山体滑坡和火灾。应日本国内防灾机构的请求&#xff0c;JAXA 利用 ALOS-2 对灾害发生当…

计算机网络-编制与调制(基带信号 基带传输 宽度信号 宽度传输 编码 调制 )

文章目录 基带信号与宽带信号编码与调制数字数据编码为数字信号数字数据调制为模拟信号模拟数据编码为数字信号模拟数据调制为模拟信号小结 基带信号与宽带信号 信道上传输的信号除了可以分为数字信号和模拟信号&#xff0c;也可以分为基带信号和宽带信号&#xff0c;只是分类…

安利6款免费又高清的视频转GIF方法,值得收藏

前言 平时我们在聊天的时候会发的很多有趣表情包&#xff0c;其实有些就是视频里面的画面&#xff0c;觉得好玩有趣就被网友转换成了GIF&#xff0c;聊天的时候就可以用这些表情包来代表当时的心情。 如何将视频转成GIF动图&#xff1f;对于还不知道怎么将视频转成GIF的朋友&a…

vmware-VCSA6.0部署

下载vcsa的iso包&#xff0c;解压后首先安装VMware-ClientIntegrationPlugin-6.0.0-6823256.exe 如果不配置域名配置成ip地址也可以 https://172.16.51.202/

我爱这夜色茫茫

夜来香 - 李香兰 那南风吹来清凉 那夜莺啼声细唱月下的花儿都入梦 只有那夜来香 吐露着芬芳 我爱这夜色茫茫 也爱这夜莺歌唱 更爱那花一般的梦 拥抱着夜来香 吻着夜来香夜来香我为你歌唱 夜来香我为你思量 啊~啊我为你歌唱 我为你思量 我爱这夜色茫茫 也爱这夜莺歌唱更爱那花…

Python 使用重构重命名一键更改变量名的方法

一个变量有多处引用的情况下&#xff0c;需要重命名&#xff0c;可以使用重构重命名进行一键更改。 方法是:选择变量名–>右键–>Refactor–>Rename&#xff08;也可以使用快捷&#xff1a;选择变量后按下ShiftF6&#xff09;&#xff0c;然后直接输入新的变量名即可…

【GitHub项目推荐--GitHub开源项目排行榜】【转载】

GitHub Ranking GitHub Ranking 是最近 Star 陡增的开源项目&#xff0c;这是一个 GitHub Stars 和 Forks 的排行榜&#xff0c;包含 Github Top 100 Star 的开源项目&#xff0c;根据不同编程语言进行分类&#xff0c;会每天更新。 开源地址&#xff1a;https://github.com/…

支付宝开通GPT4.0,最新经验分享

ChatGPT是由OpenAI开发的一种生成式对话模型&#xff0c;具有生成对话响应的能力。它是以GPT&#xff08;Generative Pre-trained Transformer&#xff09;为基础进行训练的&#xff0c;GPT是一种基于Transformer架构的预训练语言模型&#xff0c;被广泛用于各种自然语言处理任…

vue项目如何打包,java项目如何打包

目录 vue项目如何打包 java项目如何打jar包 使用Maven打包为JAR&#xff08;方式一&#xff09;视图&#xff1a; 先双击clean再双击package即可打包 使用Maven打包为JAR&#xff08;方式二&#xff09;命令&#xff1a; 1、确保你已经安装了Maven&#xff0c;并且配置了相应…

2. HarmonyOS应用开发DevEcoStudio准备-1

2. HarmonyOS应用开发DevEcoStudio准备-1 下载 DevEco Studio 进入HUAWEI DevEco Studio产品页产品页。 单击下载列表右侧的按钮&#xff0c;下载 DevEco Studio。 安装 DevEco Studio 下载完成后&#xff0c;双击下载的 deveco-studio-xxxx.exe&#xff0c;进入 DevEco St…

Python魔法函数和迭代器

文章目录 引入魔法函数 和for循环原理iter和next函数 刷完这60个标准库模块&#xff0c;成为Python骨灰级玩家 引入 每个Pythoner对for...in这种循环都很熟悉&#xff0c;其使用方法如下 for i in [1,2,3,4,5]:print(i)输出如下 1 2 3 4 5 1\\2\\3\\4\\5 12345 上述代码非常…

elasticsearch8.x版本docker部署说明

前提&#xff0c;当前部署没有涉及证书和https访问 1、环境说明,我采用三个节点&#xff0c;每个节点启动两个es&#xff0c;用端口区分 主机角色ip和端口服务器Amaster192.168.2.223:9200服务器Adata192.168.2.223:9201服务器Bdata,master192.168.2.224:9200服务器Bdata192.1…

【服务器】宝塔面板的使用手册

目录 &#x1f337;概述 &#x1f33c;1. 绑定域名 &#x1f33c;2. 添加端口 &#x1f33c;3. 安装docker配置docker​​​​​​​ &#x1f33c;4. 软件商店 &#x1f33c;5. 首页 &#x1f337;概述 宝塔面板的安装教程&#xff1a;【服务器】安装宝塔面板 &#x1f…

【计算机网络】深入掌握计算机网络的核心要点(面试专用)

写在前面 前言四层模型网络地址管理Linux下设置ipARP请求包总结 前言 计算机网络是指将分散的计算机设备通过通信线路连接起来&#xff0c;形成一个统一的网络。为了使得各个计算机之间能够相互通信&#xff0c;需要遵循一定的协议和规范。OSI参考模型和TCP/IP参考模型是计算机…

【数据结构1-2】二叉树

树形结构不仅能表示数据间的指向关系&#xff0c;还能表示出数据的层次关系&#xff0c;而有很明显的递归性质。因此&#xff0c;我们可以利用树的性质解决更多种类的问题。 但是在平常的使用中&#xff0c;我们并不需要使用这么复杂的结构&#xff0c;只需要建立一个包含int r…

可视化 |【d3】力导向关系图

文章目录 &#x1f4da;目标效果&#x1f4da;html和css&#x1f4da;js&#x1f407;整体框架&#x1f407;细说创建部分 &#x1f4da;目标效果 力导向关系图 人物详情 子图高亮 &#x1f4da;html和css html放一个div框&#xff1a;<div class"network">…

2023年全球软件开发大会(QCon广州站2023):核心内容与学习收获(附大会核心PPT下载)

在全球化的科技浪潮中&#xff0c;软件开发行业日新月异&#xff0c;持续推动着社会经济的飞速发展。本次峰会以“引领未来&#xff0c;探索无限可能”为主题&#xff0c;聚焦软件开发领域的最新技术、最佳实践和创新思想。来自世界各地的顶级专家、企业领袖和开发者齐聚一堂&a…

大脑的漏洞:你是如何走向狭隘和顽固的?

在这篇文章的最开始&#xff0c;我想请大家思考一个问题&#xff1a; 为什么谣言的传播总是非常容易&#xff0c;但辟谣却一点也不容易呢&#xff1f; 有一个非常简单的答案&#xff0c;你或许立刻就能想到&#xff1a;因为谣言一般都非常简单&#xff0c;但辟谣一般都不怎么简…

深度学习之处理多维特征的输入

我们首先来看一个糖尿病的数据集&#xff1a; 在数据集中&#xff0c;我们称每一行叫做sample&#xff0c;表示一个样本&#xff0c;称每一列是feature&#xff0c;也就是特征在数据库里面这就是一个关系表&#xff0c;每一行叫做记录&#xff0c;每一列叫做字段。 每一个样本都…