STM32CubeMX配置工程移植dmp库配合匿名四轴上位机三维动态显示测试

STM32CubeMX配置工程移植dmp库配合匿名四轴上位机三维动态显示测试

  • ✨该工程代码匹配的是匿名四轴上位机软件的2.6版本通讯协议,所以支持使用2.6版本的,最新的版本不支持
  • 🔖STM32CubeMX默认配置的是stm32F103C8T6
  • 📺演示效果:
    在这里插入图片描述

🌼STM32CubeMX工程配置说明

  • 🌿使用STM32CubeMX仅配置了串口1和I2C1。

在这里插入图片描述

🛠接线说明

匿名四轴上位机软件是通过对串口1数据进行解析后才能正确读取和显示出来的。

stm32 ------ MPU6050
PB6(SCL)  ----  SCL
PB7(SDA)  ----  SDA
 VCC 	----  VCC(3.3V)
 GND  	----  GND
 -------
 串口1:PA9 、 PA10

📑匿名四轴上位机2.6版本通讯协议介绍

通讯代码都是基于通讯协议编写的,就好像对暗号一样,暗号正确才会进行数据传输。

  • 🎉通讯协议可以打开匿名上位机软件,按F12查看,以下是2.6版本通讯协议的全部内容:
一 :基本收发

1:收码和发码格式均可设为HEX或者CHR。
2:定时发送功能可以精确到毫秒,但是不能太快(发送为独占式,数据不发送完函数不会返回),如果上一帧
数据还没发送完毕就发送下一帧数据会出错。
3:请使用ft232串口芯片或支持高波特率的芯片,否则波特率无法设置过高。

二:高级收码
  1. 收码显示为HEX格式。
  2. 下位机发送自定义数据,格式为:0x88+FUN+LEN+DATA+SUM
    FUN可以是 0xA1到0xAA,共10个;LEN为DATA的长度(不包括0x88、FUN、LEN、SUM)。
    SUM是0x88一直到DATA最后一字节的和,uint8格式。(记得打开需要使用帧的开关,更改设置后点击保存设置使设置生效)
  3. 数据可以是uint8、int16、uint16、int32、float这几个常用格式,多字节数据高位在前。
  4. 共有20个数据存储器,每个存储器的数据可以分别设置为来自10个自定义帧的30个数据。
  5. 高速通讯时(2ms一帧数据或者更快),请关闭高级收码页面的数据显示按钮和基本收码,否则更新过快有可能会造成程序卡死。
  6. 飞控显示对应的帧FUN为0xAF,(帧格式:0x88+0xAF+0x1C+ACC DATA+GYRO DATA+MAG DATA+ANGLE DATA + 0x00 0x00 + 0x00 0x00+SUM,共32字节,ACC/GYRO/MAG/ANGLE(roll/pitch/yaw)数据为int16格式,其中ANGLE的roll和pitch数据为实际值乘以100以后得到的整数值,yaw为乘以10以后得到的整数值,上位机在显示时再 除以100和10)。
  7. 遥控,电机pwm,电压显示对应的帧FUN为0xAE,(帧格式:0x88+0xAE+0x12+THROT YAW ROLL PITCH+AUX1 2 3 4 5 + PWM:1 2 3 4 + VOTAGE + SUM,共28字节),数据为uint16格式,遥控数据最小在1000左右,最大在2000左右。数据都为uint16格式,其中pwm范围1-100,votage为实际值*100。
    小技巧:如果高速通讯时是为了画波形,就只开波形显示,并只保留需要观察的波形,如果是为了观察数据,就关闭波形显示,只保留收码显示,这样可以加快程序响应速度。
  8. 最快通讯速度测试过下位机用500K波特率,每1ms发送32字节的数据,上位机显示其中6条波形,OK!(有可能和电脑配置有关)
三:波形显示

1:共有20条波形,对应20个数据存储器。
2:双击波形绘制区域,可以打开波形显示开关。
3:按住Ctrl用鼠标左键点击某一条波形,可以显示数据标签,再次点击隐藏。
4:按住鼠标左键,在绘图区域从一点向右下方拖动,然后松开,可以放大显示框住的波形区域,可以多次放大;
5:按住鼠标左键,在绘图区域从一点向左上方拖动,然后松开,可以将放大后的波形还原。
6:按住鼠标右键,在绘图区域上下左右拖动,可以移动波形。
7:显示波形时按F9键,可以打开波形高级设置。

四:DEBUG功能
  1. 在调试过程中可以将某些标志位、寄存器、变量实时发回上位机,并在DEBUG页面显示。
  2. 通讯格式为:0x88 + 0xAD + len + num + DATA + SUM, len为num与DATA的总长度,num表示要改变哪个显示状态,例如num=0x01即是要改变第一个LED,num=0x07即是改变第一个数字输出显示。当要改变LED时,DATA只需一字节,DATA=0x00表示关闭LED,大于0x00表示点亮LED;当要改变数字输出时,DATA需要两字节,表示 一个uint16数字,高字节在前。SUM为从0x88开始到SUM前一字节的和校验,uint8格式。

例如:发送 0x88 + 0xAD + 0x02 + 0x01 + 0x01 + 0x39 表示点亮第一个LED
发送 0x88 + 0xAD + 0x03 + 0x07 + 0x00 + 0x05 + 0x44 表示在第一个数字输出位置显示 5 。

五:键鼠控制
  1. 控制数据发送格式为:0x8A + 0x8A + 0X1C + THROT YAW ROLL PITCH AUX1 AUX2 AUX3 AUX4 AUX5 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + SUM,遥控数据都为int16格式,中值1500,最小最大值为1000、 2000。
  2. 发送频率 50Hz。
  3. 鼠标上下控制油门,左右控制YAW,键盘的WASD控制ROLL/PITCH,键盘12345控制AUX12345。共9通道。
六:飞控参数
  1. 点击3D模型显示右下方的校正按钮,上位机会发送0X8A 0X8B 0X1C 0XAA 0XA3 +无用数据+SUM给下位机,
    其中0X8B表示飞控参数,0XAA表示零偏,0XA3表示ACC GYRO都要校正。
  2. 点击飞控参数界面传感器矫正功能里面的校正按钮,分别表示ACC 和GYRO的校正,不会同时校正两个传感器,上位机校正ACC发送格式为:0X8A 0X8B 0X1C 0XAA 0XA1+无用数据+SUM上位机校正GYRO发送格式为:0X8A 0X8B 0X1C 0XAA 0XA2+无用数据+SUM(送有数据整个长度都为32字节)
  3. 上位机发送微调后的offset数据(仅为ACC的 X 和 Y ),格式为0X8A 0X8B 0X1C 0XAB + offset.x + offset.y +无用数据 +SUM,数据为int16格式。
  4. 上位机发送读offset的命令格式为:0X8A 0X8B 0X1C 0XAC + 无用数据 + SUM
  5. 上位机发送读PID数据的命令为:0X8A 0X8B 0X1C 0XAD + 无用数据 + SUM
  6. 下位机发送offset数据给上位机的格式为:0X88 0XAC 0X1C 0XAC + 传感器零偏数据ACC XYZ GYRO XYZ +无用数据+SUM,共六个int16型数据。
  7. 下位机发送PID数据给上位机的格式为:0X88 0XAC 0X1C 0XAD + PID数据 + 无用数据 + SUM
    PID数据为rol_p,rol_i,rol_d,pit_p…i…d,yaw_p,i,d,共9个uint16型数据。
  8. 上位机发送PID数据给下位机的格式为:0X8A 0X8B 0X1C 0XAE +PID数据+ 无用数据 + SUM
    PID数据格式和下位机发送给上位机的格式一样。
  9. 点击飞控解锁按钮,上位机会发送0X8A 0X8B 0X1C 0XA1+无用数据+SUM给下位机,如果下位机已经解锁,点击此按钮会发送0X8A 0X8B 0X1C 0XA0+无用数据+SUM给下位机,锁定飞控。

在上面的相关参考文章中,前者总结的5个通讯办法如下:

  • 1个自定义数据帧+4个官方数据帧
    自定义数据帧:发送MPU6050的原始数据 和 官方数据帧。
  • 官方数据帧:
    1. 飞控显示帧,实现在上位机上观看到四轴的3D动画和波形
    1. 遥控器数据发送帧:将遥控器的各个数据发送到上位机包括PWM占空比
    1. PID数据发送帧:将STM32中设定的PID参数发送到上位机
    1. 零偏数据发送帧:将STM32中测定的零偏值发送给上位机

⛳上位机配置界面设置介绍(重点内容)

  • 🌿设置串口端口号和波特率(工程默认配置的是115200)具体参数如下:
    在这里插入图片描述

  • 高级收码配置项:
    在这里插入图片描述

  • 🌿波形显示,勾选对应的串口端口号,开启高级收码,飞控波形按钮都要打开。
    在这里插入图片描述

  • 🌿飞控状态,根据个人需求勾选

在这里插入图片描述

  • 🌿飞行控制,不用管,代码工程中没有涉及到此功能,只是观测效果。
    在这里插入图片描述
🔨状态开启和切换

🔰下面一排是功能开启,绿色状态的为开启状态,暗绿的是没有开启。如果要看效果,一定要开启高级收码

  • 波形状态切换到飞控状态,可以直接点击下面的键鼠控制按键即可完成切换,但是要切换到波形状态需要通过点击左侧边上的飞控状态,才可切换回去。
    在这里插入图片描述

📝主程序代码部分

/* USER CODE BEGIN Header */


//相关接线
//stm32			MPU6050
//PB6(SCL)  ----  SCL
//PB7(SDA)  ----  SDA
// VCC 		----  VCC
// GND  	----  GND


/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define u8  uint8_t
#define u16 uint16_t
#define u32 uint32_t
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

void usart1_send_char(u8 c)
{
	HAL_UART_Transmit(&huart1 , &c, 1, 0xFFFF);
}
/**  
  *  功能:发送数据给匿名上位机(V2.6)
  *  入口参数:fun,功能字,0xA0~0xAF
  *			   data,数据缓存区,最多28个字节
  *			   len,data数据长度
  *  返回值:无
  *  注:数据格式:0x88+FUN+LEN+DATA+SUM
  */
void usart1_niming_report(u8 fun,u8 *data,u8 len)
{
	u8 send_buf[32]={0x00};
	u8 i;
	if(len>28) return;//超过28个字节,无效
	send_buf[len+3]=0;//校验位置零
	send_buf[0]=0x88;//帧头0x88
	send_buf[1]=fun;//命令帧FUN
	send_buf[2]=len;//数据长度帧LEN
	for(i=0;i<len;i++)
		send_buf[i+3]=data[i];
	for(i=0;i<len+3;i++)
		send_buf[len+3] += send_buf[i];//计算数据校验位SUM
	for(i=0;i<len+4;i++)
		usart1_send_char(send_buf[i]);//发送数据到串口1
}	
/**  自定义帧0xA1
  *  功能:发送加速度传感器和陀螺仪传感器数据给匿名上位机(V2.6)
  *  入口参数:aacx,aacy,aacz:xyz三个方向的加速度值
  *			   gyrox,gyroy,gyroz:xyz三个方向的陀螺仪值		  
  *  返回值:无
  *  注:数据格式:0x88+FUN+LEN+DATA+SUM
  */
void mpu6050_send_data(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz)
{
	u8 buf[12];
	buf[0]=(aacx>>8)&0xFF;
	buf[1]=aacx&0xFF;
	buf[2]=(aacy>>8)&0xFF;
	buf[3]=aacy&0xFF;
	buf[4]=(aacz>>8)&0xFF;
	buf[5]=aacz&0xFF;
	
	buf[6]=(gyrox>>8)&0xFF;
	buf[7]=gyrox&0xFF;
	buf[8]=(gyroy>>8)&0xFF;
	buf[9]=gyroy&0xFF;
	buf[10]=(gyroz>>8)&0xFF;
	buf[11]=gyroz&0xFF;
	
	usart1_niming_report(0xA1,buf,12);
}

/**  飞控显示帧
  *  功能:上报解算后的姿态数据给上位机
  *  入口参数:aacx,aacy,aacz:xyz三个方向的加速度值
  *			   gyrox,gyroy,gyroz:xyz三个方向的陀螺仪值		
  *			   yaw,偏航角,单位为0.1度 0 -> 3600  对应 0 -> 360.0度
  *			   roll,横滚角,单位0.01度。 -18000 -> 18000 对应 -180.00  ->  180.00度
  *			   pitch,俯仰角,单位 0.01度。-9000 - 9000 对应 -90.00 -> 90.00 度
  *  返回值:无
  *  注:数据格式:0x88+0xAF+0x1C+ ACC DATA + GYRO DATA + MAG DATA + ANGLE DATA(roll/pitch/yaw) +0x00+0x00+0x00+0x00+SUM
  *		 ANGLE的roll和pitch数据为实际值乘以100以后得到的整数值,yaw为乘以10以后得到的整数值
  */
void usart1_report_imu(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz,short roll,short pitch,short yaw)
{
	u8 buf[28]={0x00};
	
	buf[0]=(aacx>>8)&0xFF;
	buf[1]=aacx&0xFF;
	buf[2]=(aacy>>8)&0xFF;
	buf[3]=aacy&0xFF;
	buf[4]=(aacz>>8)&0xFF;
	buf[5]=aacz&0xFF;
	
	buf[6]=(gyrox>>8)&0xFF;
	buf[7]=gyrox&0xFF;
	buf[8]=(gyroy>>8)&0xFF;
	buf[9]=gyroy&0xFF;
	buf[10]=(gyroz>>8)&0xFF;
	buf[11]=gyroz&0xFF;
	
	//12-17为磁力计,MPU6050没有磁力计,发送0x00
	
	buf[18]=(roll>>8)&0xFF;
	buf[19]=roll&0xFF;
	buf[20]=(pitch>>8)&0xFF;
	buf[21]=pitch&0xFF;
	buf[22]=(yaw>>8)&0xFF;
	buf[23]=yaw&0xFF;
	
	//24-27为数据格式中的0x00
	
	usart1_niming_report(0xAF,buf,28);
}

/**  
  *  功能:发送PID数据给上位机
  *  入口参数:rol_p,rol_i,rol_d,pit_p,pit_i,pit_d,yaw_p,yaw_i,yaw_d
  *  返回值:无
  *	 格式为:0X88 0XAC 0X1C 0XAD + PID数据 + 无用数据 + SUM
  */
void usart1_report_pid(u16 rol_p,u16 rol_i,u16 rol_d,u16 pit_p,u16 pit_i,u16 pit_d,u16 yaw_p,u16 yaw_i,u16 yaw_d)
{
	u8 buf[28]={0x00};
	
	buf[0]=0xAD;
	
	buf[1]=(rol_p>>8)&0xFF;
	buf[2]=rol_p&0xFF;
	buf[3]=(rol_i>>8)&0xFF;
	buf[4]=rol_i&0xFF;
	buf[5]=(rol_d>>8)&0xFF;
	buf[6]=rol_d&0xFF;
	
	buf[7]=(pit_p>>8)&0xFF;
	buf[8]=pit_p&0xFF;
	buf[9]=(pit_i>>8)&0xFF;
	buf[10]=pit_i&0xFF;
	buf[11]=(pit_d>>8)&0xFF;
	buf[12]=pit_d&0xFF;
	
	buf[13]=(yaw_p>>8)&0xFF;
	buf[14]=yaw_p&0xFF;
	buf[15]=(yaw_i>>8)&0xFF;
	buf[16]=yaw_i&0xFF;
	buf[17]=(yaw_d>>8)&0xFF;
	buf[18]=yaw_d&0xFF;
	
	usart1_niming_report(0xAC,buf,28);
		
}

/**  
  *  功能:遥控,电机pwm,电压显示
  *  入口参数:throt,yaw,roll,pitch,aux1,aux2,aux3,aux4,aux5,pwm1,pwm2,pwm3,pwm4,vol(电压)
  *  返回值:无
  *  帧格式:0x88+0xAE+0x12+THROT YAW ROLL PITCH AUX1 2 3 4 5 PWM:1 2 3 4 VOLTAGE+SUM
	 遥控数据最小在1000左右,最大在2000左右。数据都为uint16格式,
	 其中pwm范围1-100,voltage为实际值*100。
  */
void usart1_report_rc(short thort,short yaw,short roll,short pitch,
						short aux1,short aux2,short aux3,short aux4,short aux5,
							short pwm1,short pwm2,short pwm3,short pwm4,
								short vol)
{
	u8 buf[28]={0x00};
	
	//THROT YAW ROLL PITCH	
	buf[0]=(thort>>8)&0xFF;//
	buf[1]=thort&0xFF;//
	buf[2]=(yaw>>8)&0xFF;//
	buf[3]=yaw&0xFF;//
	buf[4]=(roll>>8)&0xFF;//
	buf[5]=roll&0xFF;	//
	buf[6]=(pitch>>8)&0xFF;//
	buf[7]=pitch&0xFF;//
	
	//AUX1 2 3 4 5
	buf[8]=(aux1>>8)&0xFF;
	buf[9]=aux1&0xFF;
	buf[10]=(aux2>>8)&0xFF;
	buf[11]=aux2&0xFF;
	buf[12]=(aux3>>8)&0xFF;
	buf[13]=aux3&0xFF;
	buf[14]=(aux4>>8)&0xFF;
	buf[15]=aux4&0xFF;
	buf[16]=(aux5>>8)&0xFF;
	buf[17]=aux5&0xFF;	
	
	//PWM:1 2 3 4 
	buf[18]=(pwm1>>8)&0xFF;
	buf[19]=pwm1&0xFF;
	buf[20]=(pwm2>>8)&0xFF;
	buf[21]=pwm2&0xFF;
	buf[22]=(pwm3>>8)&0xFF;
	buf[23]=pwm3&0xFF;
	buf[24]=(pwm4>>8)&0xFF;
	buf[25]=pwm4&0xFF;
	
	//VOLTAGE
	buf[26]=(vol>>8)&0xFF;
	buf[27]=vol&0xFF;
	
	usart1_niming_report(0xAE,buf,28);
}

/**  
  *  功能:发送offset给上位机
  *  入口参数:acc_x,acc_y,acc_z,gyro_x,gyro_y,gyro_z
  *  返回值:无
  *  格式为:0X88 0XAC 0X1C 0XAC + 传感器零偏数据ACC XYZ GYRO XYZ+无用数据+SUM
  */
void usart1_report_offset(short acc_x,short acc_y,short acc_z,short gyro_x,short gyro_y,short gyro_z)
{
	u8 buf[28]={0x00};
	
	buf[0]=0xAC;
	
	buf[1]=(acc_x>>8)&0xFF;
	buf[2]=acc_x&0xFF;
	buf[3]=(acc_y>>8)&0xFF;
	buf[4]=acc_y&0xFF;
	buf[5]=(acc_z>>8)&0xFF;
	buf[6]=acc_z&0xFF;	
	
	buf[7]=(gyro_x>>8)&0xFF;
	buf[8]=gyro_x&0xFF;
	buf[9]=(gyro_y>>8)&0xFF;
	buf[10]=gyro_y&0xFF;
	buf[11]=(gyro_z>>8)&0xFF;
	buf[12]=gyro_z&0xFF;

	usart1_niming_report(0xAC,buf,28);
}


/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	short aacx,aacy,aacz,gyrox,gyroy,gyroz,yaw,roll,pitch;
	
  /* 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_I2C1_Init();
  MX_TIM1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  mpu_dmp_init();

  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
		dmp_getdata();
//		MPU6050_Read_Temp();
		pitch= (short)My_Mpu6050.pitch;
		yaw =(short)My_Mpu6050.yaw;
		roll =(short)My_Mpu6050.roll;
		aacx = My_Mpu6050.accel[0];//加速度计m/s^2
		aacy = My_Mpu6050.accel[1];
		aacz = My_Mpu6050.accel[2]; 
		gyrox = My_Mpu6050.gyro[0];//加速度rps
		gyroy = My_Mpu6050.gyro[1];
		gyroz = My_Mpu6050.gyro[2];
		mpu6050_send_data(aacx,aacy,aacz,gyrox,gyroy,gyroz);
		usart1_report_imu(aacx,aacy,aacz,gyrox,gyroy,gyroz,(int)(roll*100),(int)(pitch*100),(int)(yaw*10));
		usart1_report_rc(1500,(int)yaw,(int)roll,(int)pitch,1200,1200,1200,1200,1200,90,40,50,100,300);      
		usart1_report_pid(123,123,123,456,456,456,789,789,789);	
		usart1_report_offset(aacx,aacy,aacz,gyrox,gyroy,gyroz);


//		printf("pitch:%.2f\r\n",My_Mpu6050.pitch);
//		printf("roll:%.2f\r\n",My_Mpu6050.roll);
//		printf("yaw:%.2f\r\n",My_Mpu6050.yaw);
//		printf("temperature:%.2f\r\n",My_Mpu6050.temperature);
		HAL_Delay(10);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}



/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

📚工程源码和上位机软件



链接: https://pan.baidu.com/e/1FNFvOJHNg_CJ6juiUEGR1A
提取码: 8vu9

  酒杯太浅,敬不到来日方长;巷子太短,走不到白发苍苍;不是年少守不住旧心而是岁月慌了人心。人生最大的遗憾,不是错过最好的人,而是错过那个想对你好的人--余华《文成》。
  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值