温度检测控制仿真系统
软件环境
- proteus8.17 win64
- VSPD
- sscom或Xcom
- keil
- stm32CubeMx
功能要求::
1.MCU通过串行接口组件与上位机PC进行双向通信,PC机用串口调试助 手软件向MCU发送“运行”命令,MCU收到后向PC机发送“OK”。 PC机上 的串口调试助手软件接收窗口显示收到的字符串“OK”。
2. MCU控制驱动直流电 机,当环境温度低于预定的温度(摄氏25°+(学号末3位数的和/3))时,直流 电机停止转动;当环境温度等于或高于预定的温度(摄氏25°+(学号末3位数 的和/3))时,启动直流电机转动。
3.同时,实时环境温度在 LCD 上显示,LCD 第一行显示TEMPRATURE:第二行显示摄氏温度值。
4.MCU 向PC 机发送实时环境温度。PC机上的串口调试助手软件接收窗口显示收到的 实时环境温度。
如:学生学号末3位数为“078”,手动增加温度等于或超过设 定的温度值30°(25+(0+7+8)/3=30)时,驱动直流电机开始顺时针方向转动。 预定的温度值如果有小数部分,按照“四舍五入”取整。
系统框图如下:
备注:在最近的更新中,我将相关的工程文件资源上传并绑定该文。但是由于没有注意,资源仅VIP可见,且我这边似乎没有修改权限,各位同学如果没有会员不必理会,相关代码在文章中已给出。
一、proteus的安装与原理图绘制
(1)proteus的安装
proteus 8.17安装包
链接: https://pan.baidu.com/s/1234ejVVuMXblklUHeuX5Eg 提取码: XDer
解压后获得以下几个文件
选择setup,右键以管理员身份运行
修改安装路径,之后next下一步
一直next,等待安装完成后,点finish退出 ;
在桌面选中proteus 8,右键打开文件所在位置
退到上一级,也就是Proteus 8 Professional目录下
将解压文件夹里的Translations文件夹复制到上图Proteus 8 Professional目录下
替换目标中的文件
打开proteus,如图所示,破解完成;
(2)系统原理图绘制
1. proteus工程文件可在此获取:temp_dect.rar
temp_dect
链接: https://pan.baidu.com/s/1-5Tr6jQj3Kh0p19cN6jI-g 提取码: XDer
提示:最近有同学反应使用上面的工程后最后仿真没有反应,一般都是原理图问题。proteus在绘制原理图时尽量不要复制粘贴,有条件可以自己尝试跟着画一下。
新版经测试,理论上可以正常使用:temp_csdndemo.zip
https://pan.baidu.com/s/1NiaD9GfxGUjv5QApQX836w
提取码:XDER
完整原理图如下:
2. 创建工程文件和原理图绘制过程
2.1 打开proteus,点击“新建工程”,修改工程名称和路径(自测一般中文名称和路径不会有影响)
2.2 next
2.3 选择创建固件项目,选择芯片,一直next后点finish创建完成
刚创建好的工程原理图如下:
完整系统的原理图绘制见下一篇文章
二、虚拟串口软件与串口调试助手
虚拟串口软件:VSPD,
串口调试助手:XCOM或sscom (本文以sscom为例)
安装包以下获取:
链接: https://pan.baidu.com/s/1CRrg1uou8ebfhKms-I05rg 提取码: XDer
(1)虚拟串口软件VSPD的安装,破解,使用
1. 下载安装包后,解压;运行vspd进行安装
2.点击OK
3.点击next后,同意协议再点击next
4.更改为自己的路径后,一直next,直至安装(install)
5.安装完成后,先不运行,将 解压文件中的vspdctl.dll 文件复制到安装的工程目录中,覆盖原有文件,即完成破解
6.破解后,打开vspd
7.点击add pair,创建虚拟串口对(我这里已经创建过,即COM1和COM2,可在左侧栏看出)
8. 可以在设备管理器中查看创建的虚拟串口:按下win+X,点击设备管理器,即可在端口项中看到虚拟串口COM1和2。
(2)串口调试助手的使用
1.解压后直接打开即可(其实不解压也能使用)(该软件打开后稍卡,但是博主懒得换😂)
2.可以在左下角直接选择端口和设置波特率,也可以在左上方串口设置处选择端口并设置波特率等;
3. 发送数据时,先设置好串口,打开串口后输入数据并发送即可
4.如果有中文,可以在上方点击显示,字体,设置字体和字符集,如:中文GB2312
5.为了保证proteus仿真时串口之间的正确的数据传输,proteus原理图中的虚拟串口也需要设置端口和波特率等,端口选择与sscom中成对的虚拟串口,波特率等设置一致。
proteus中,选中COMPIM,右键,选择编辑属性;设置端口和波特率等。
三、Keil的安装
相关安装包:
Keil.rar
链接: https://pan.baidu.com/s/1NaqXRzFadHUkIu_ancpsNw 提取码: XDer
1. 下载解压后得到以下文件,详细安装过程参考PDF:Keil集成开发环境的安装
2.注意:由于已经提供相关软件包,PDF安装教程中的从官网获取可以跳过,直接从以下开始
四、stm32cubeMX 安装
相关安装包:cubemx
链接: https://pan.baidu.com/s/1CdUxKKWcG-dWRm8b8XjU5g 提取码: XDer
下载并解压后,可以得到以下文件:
(1)安装Java环境
选择安装环境文件夹,根据自己情况选择64位或32位
以64位为例,打开两个任意一个安装包,勾选更改目标文件夹,点击安装;
选择合适的安装目录,点击 下一步;
等待自动安装;安装完毕后,点击 关闭;
在开始菜单中搜Java,看到下图即代表安装成功。
安装成功后,配置环境变量:右键此电脑,点击“属性”,点击高级系统设置
新建系统变量,点击新建,变量名为JAVA_HOME,路径改为自己的路径
步骤同上,新建一个CLASSPATH,变量值为:
.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar
然后找到path环境变量,双击进去
%JAVA_HOME\bin
%JAVA_HOME\jre\bin
注意下面的改为自己的路径
C:\Program Files\Java\jdk-1.8\bin
接下来检验:按下win+R,输入cmd,打开命令行
分别输入java -version,java,javac,回车
输出以上信息,没有“不是内部或外部命令”的输出就是配置成功
(2) CubeMX 安装
在以下路径中,找到cubemx安装包
解压任意一个后,打开 SetupSTM32CubeMX-6.x.x.exe 文件,如果未安装 Java 环境或没有配置环境变量,将会出现以下报错:
安装 Java 并配置环境变量后,重新打开 SetupSTM32CubeMX-6.x.x.exe 文件,点击 Next;
勾选 I accpt,点击 Next;
勾选第一个,点击 Next;
选择合适的安装路径,点击 Next;(若路径未创建,会提示路径将被创建)
根据需求勾选,点击 Next;
程序自动安装,安装完成后,一直点击 Next,点击 Done结束;
打开 STM32CubeMX 软件,软件界面如下。
五、CubeMx新建工程并进行芯片配置
(1)修改默认配置
新建工程之前,建议先修改PACK安装地址。pack是需要额外下载的对芯片的支持包,默认的安装位置是C盘,会非常占用C盘空间,在此将其改到其他内存盘。
点击最上方一栏的HELP按钮,并打开update setting选项,如图:
修改Repository Folder里面的文件夹路径即可将PACK安装路径修改到其他磁盘。
(2)新建工程
1. 选中菜单栏File,点击New Project新建工程
2.在左上方搜索框中搜索要使用的MCU(或在左侧选择栏逐步筛选找到),本项目使用STM32F411RE芯片;找到后双击芯片即可直接建立工程(或选中芯片后,点击右上角START PROJECT)
4.STM32CUBEMX工程配置修改
点击上侧菜单栏的Project Manager,打开后如下,然后设置工程名称;修改工程路径,注意不要有中文路径。在TOOLCHAIN出修改编译工具,我们使用的Keil,因此选择 MDK ARM。
点击最左边的Code Generate,进入代码生成的配置界面,推荐勾选下面的选项(这个选项默认是不勾选的),勾选之后代码会更加清晰明了。
5.生成代码
基本配置完成后,可以开始生成代码,(到这里我们没有进行有关芯片的配置,等下再进行,先了解生成代码的步骤),点击GENERATE CODE 按钮
如果点击后提示以下界面,即缺少依赖包,是否自动下载,点击yes即可
生成成功后,点击“Open porject”直接打开项目。如果提示生成失败请检查是否存在中文路径。
工程自动调用keil5打开,如图所示
注:可以关闭browse information以提示编译速度,步骤如下:
先点击这个按钮;然后在最上面一行选择output;把browse information选项取消勾选,然后点击确定,完成修改。此时按下F7进行编译,可以极大提升编译速度。
六、CubeMx配置芯片
根据原理图:以下引脚均需配置
1. LCD相关引脚:
RS,RW,E,D0~D7与LCD连接,进行以下配置:点击pinout进行引脚配置,点击右图芯片对应引脚,配置为GPIO_Output,选择左侧system Core下的GPIO,在中间栏对每个引脚进行详细配置,GPIO_output level 改为high。“User Label”可以设置为原理图中的label
2.LM温度传感器相关:
ADC连接PA7。在右侧点击芯片对应的PA7,配置为ADC_IN7。ADC相关属性可以在左侧Analog栏下选择ADC1,点击中间栏的“parameter Settings”查看。
3.电机有关管脚:
IN1,IN2,ENA;对应PA11,12,13。与1同方法,点击右图芯片对应引脚,配置为GPIO_Output,选择左侧system Core下的GPIO,在中间栏对对应引脚进行详细配置,如图所示“User Label”可以设置为原理图中的label。
4.串口配置
串口有关引脚:TXD,RXD,对应PA2,PA3。首先选择connectivity下的USART2,将Mode改为“Asynchronous”,在“parameter Settings”下将波特率改为9600;再点击NVIC settings,勾选enable
至此,我们用到的所有管脚均配置完成,点击右上角的“GENERATE CODE”,再次生成代码。
接下来,就需要根据我们的功能要求,写出对应的代码了。
七、在Keil中写入相关代码
1.LCD相关:(.c和.h文件)
LCD1602.c
#include "LCD1602.h"
//D0-D7设定方向:I-输入;O-输出
void DataDir(char dir)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_GPIO_WritePin(GPIOC, D0_Pin|D1_Pin|D2_Pin|D3_Pin|D4_Pin|D5_Pin|D6_Pin|D7_Pin, GPIO_PIN_SET);
GPIO_InitStruct.Pin = D0_Pin|D1_Pin|D2_Pin|D3_Pin|D4_Pin|D5_Pin|D6_Pin|D7_Pin;
GPIO_InitStruct.Pull = GPIO_PULLUP;
if(dir == 'I')
{
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
}
else if(dir == 'O')
{
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
}
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
//D0-D7读数据
uint8_t ReadData()
{
uint8_t dat=0;
//DataDir('I');
if(HAL_GPIO_ReadPin(GPIOC, D0_Pin)==GPIO_PIN_SET) dat|=0x01;
if(HAL_GPIO_ReadPin(GPIOC, D1_Pin)==GPIO_PIN_SET) dat|=0x02;
if(HAL_GPIO_ReadPin(GPIOC, D2_Pin)==GPIO_PIN_SET) dat|=0x04;
if(HAL_GPIO_ReadPin(GPIOC, D3_Pin)==GPIO_PIN_SET) dat|=0x08;
if(HAL_GPIO_ReadPin(GPIOC, D4_Pin)==GPIO_PIN_SET) dat|=0x10;
if(HAL_GPIO_ReadPin(GPIOC, D5_Pin)==GPIO_PIN_SET) dat|=0x20;
if(HAL_GPIO_ReadPin(GPIOC, D6_Pin)==GPIO_PIN_SET) dat|=0x40;
if(HAL_GPIO_ReadPin(GPIOC, D7_Pin)==GPIO_PIN_SET) dat|=0x80;
return dat;
}
//D0-D7写数据
void WriteData(uint8_t dat)
{
uint16_t Set_Pins = 0, Rst_Pins = 0;
//DataDir('O');
if(dat & 0x01) Set_Pins |= D0_Pin;
else Rst_Pins |= D0_Pin;
if(dat & 0x02) Set_Pins |= D1_Pin;
else Rst_Pins |= D1_Pin;
if(dat & 0x04) Set_Pins |= D2_Pin;
else Rst_Pins |= D2_Pin;
if(dat & 0x08) Set_Pins |= D3_Pin;
else Rst_Pins |= D3_Pin;
if(dat & 0x10) Set_Pins |= D4_Pin;
else Rst_Pins |= D4_Pin;
if(dat & 0x20) Set_Pins |= D5_Pin;
else Rst_Pins |= D5_Pin;
if(dat & 0x40) Set_Pins |= D6_Pin;
else Rst_Pins |= D6_Pin;
if(dat & 0x80) Set_Pins |= D7_Pin;
else Rst_Pins |= D7_Pin;
HAL_GPIO_WritePin(GPIOC, Set_Pins, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, Rst_Pins, GPIO_PIN_RESET);
}
//LCD忙等待
void LCD_Busy_Wait()
{
uint8_t status;
DataDir('I');
RS_InstructionR();
RW_Read();
do
{
E_Set();
__NOP();
status = ReadData();
E_Rst();
}
while(status & 0x80);
}
//写LCD指令
void LCD_Write_Cmd(uint8_t cmd)
{
DataDir('O');
WriteData(cmd);
RS_InstructionR();
RW_Write();
E_Rst();
RS_InstructionR();
RW_Write();
E_Set();
__NOP();
E_Rst();
LCD_Busy_Wait();
}
//写LCD数据寄存器
void LCD_Write_Data(uint8_t dat)
{
DataDir('O');
WriteData(dat);
RS_DataR();
RW_Write();
E_Set();
__NOP();
E_Rst();
LCD_Busy_Wait();
}
//LCD初始化
void LCD_Init()
{
LCD_Write_Cmd(0x38);
HAL_Delay(2);
LCD_Write_Cmd(0x01);
HAL_Delay(2);
LCD_Write_Cmd(0x06);
HAL_Delay(2);
LCD_Write_Cmd(0x0c);
HAL_Delay(2);
}
//在x行(0-1),y列(0-15)显示字符串
void LCD_ShowString(uint8_t x, uint8_t y, char *str)
{
uint8_t i=0;
//设置显示起始位置
if(x == 0)
LCD_Write_Cmd(0x80|y);
else if(x == 1)
LCD_Write_Cmd(0xc0|y);
//输出字符串
for(i=0; i<16 && str[i]!='\0'; i++)
{
LCD_Write_Data(str[i]);
HAL_Delay(2);
}
}
LCD1602.h
#ifndef INC_LCD1602_H_
#define INC_LCD1602_H_
#include "main.h"
//选择数据寄存器
#define RS_DataR() HAL_GPIO_WritePin(GPIOA, RS_Pin, GPIO_PIN_SET)
#define RS_InstructionR() HAL_GPIO_WritePin(GPIOA, RS_Pin, GPIO_PIN_RESET)
//选择指令寄存器
//读操作
#define RW_Read() HAL_GPIO_WritePin(GPIOA, RW_Pin, GPIO_PIN_SET)
//写操作
#define RW_Write() HAL_GPIO_WritePin(GPIOA, RW_Pin, GPIO_PIN_RESET)
//Enable操作:高电平-读取信息;下降沿-执行指令
#define E_Set() HAL_GPIO_WritePin(GPIOA, E_Pin, GPIO_PIN_SET)
#define E_Rst() HAL_GPIO_WritePin(GPIOA, E_Pin, GPIO_PIN_RESET)
void LCD_Init(void);
void LCD_ShowString(uint8_t x, uint8_t y, char *str);
#endif //INC_LCD1602_H_
步骤:在此处右键,选择新建文件
分别选择.c文件和.h文件,命名后add,将以上代码分别粘贴到对应文件中
2.motor的c和h文件
motor.c
#include "motor.h"
#include "main.h"
void SZhun()
{
HAL_GPIO_WritePin(IN1_GPIO_Port,IN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(IN2_GPIO_Port,IN2_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(ENA_GPIO_Port,ENA_Pin,GPIO_PIN_SET);
}
void NZhun()
{
HAL_GPIO_WritePin(IN1_GPIO_Port,IN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(IN2_GPIO_Port,IN2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(ENA_GPIO_Port,ENA_Pin,GPIO_PIN_SET);
}
void Stop()
{
HAL_GPIO_WritePin(IN1_GPIO_Port,IN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(IN2_GPIO_Port,IN2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(ENA_GPIO_Port,ENA_Pin,GPIO_PIN_SET);
}
motor.h
#ifndef __motor_H_
#define __motor_H_
void SZhun(void);//顺时针转动
void NZhun(void);//逆时针转动
void Stop(void);//停止转动
#endif
与1同理,在Keil中新建对应的motor.c和motor.h
3.main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2025 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "LCD1602.h"
#include <stdio.h>
#include "motor.h"
#include <stdlib.h>
#include <string.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* 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 */
uint32_t AD_value;
int temp;
int last_temp=0;
char str[20];
uint8_t Rx_data = 0;
int Flag=0;
char str1[]="TEMPRATURE:";
uint8_t str2[] = "OK!\r\n";
char str3[] = "";
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2)
{
static uint8_t buffer[4];
static uint8_t index = 0;
buffer[index++] = Rx_data;
if (index >= 4)
{
if (buffer[0] == 0xD4 && buffer[1] == 0xCB && buffer[2] == 0xD0 && buffer[3] == 0xD0)
{
uint8_t response[] = "OK\r\n";
HAL_UART_Transmit(&huart2, response, sizeof(response) - 1, 1000);
Flag = 1;
}
index = 0;
}
HAL_UART_Receive_IT(&huart2, &Rx_data, 1);
}
}
void LCD_ShowTemperature(int temp)
{
char tempStr[16];
sprintf(tempStr, "%d", temp);
LCD_ShowString(1, 0, tempStr);
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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_ADC1_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
LCD_ShowString(0,0,str1);
HAL_UART_Receive_IT(&huart2,&Rx_data,1);
//HAL_ADCEx_Calibration_Start(&hadc1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,50);
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1),HAL_ADC_STATE_REG_EOC))
{
AD_value=HAL_ADC_GetValue(&hadc1);
temp=(int)AD_value*500/4095.0;
}
if(Flag == 1)
{
// 温度低于25℃时,停止电机(请在此处根据个人学号修改)
if (temp < 25)
{
Stop(); // 停止电机
}
// 温度高于或等于25℃时,启动电机
else if (temp >= 25)
{
SZhun(); // 启动电机
}
if (temp != last_temp)
{
LCD_ShowTemperature(temp);
sprintf(str3, "%d℃\r\n", temp);
HAL_UART_Transmit(&huart2, (uint8_t *)str3, strlen(str3), HAL_MAX_DELAY);
last_temp = temp;
}
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
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_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* 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****/
可以将以上代码直接复制到你的main.c中,代码解释有时间另外写一篇进行讲解。
4.可能存在的问题:
解决方法:
-
点击魔法棒
-
在弹出的窗口中,选择 C/C++ 选项卡。
-
在 Include Paths 部分,点击右侧的
...
按钮。 -
添加
LCD1602.h
文件所在的目录路径(将鼠标放在左侧对应文件处就能看到路径啦!)。
另外,经反馈与排查,也有同学单纯是因为相关头文件命名与本文章不一致,但main.c文件的头文件名称没有改为一致😁。
(2)此处感谢某位同学的补充
对于最后仿真没有现象的问题,请检查此处"Use MicroLIB"是否勾选
5. 编译生成.hex文件
点击魔法棒,选择output,勾选创建hex文件,点击编译
八、在proteus中仿真
1. 打开proteus,选中芯片,右键选择编辑属性
2. 找到自己的HEX文件(就在cubemx的工程目录下)并导入,确定
3. 点击左下角绿色三角开始仿真(对于仿真后没反应的现象,优先考虑原理图问题;其次考虑cubemx配置问题)
4.打开串口调试工具sscom,打开串口,发送“运行”,可以看到收到“OK”
5.手动调节温度,可以看到LCD显示和串口接收,以及电机转动。
注意每个人的学号不同,设定温度不同,记得修改哦!(修改位置已经在main.c中标出)
学习过程中出现的问题可以私信我或在评论区留言,有时间便会回复,也感谢大家为文章的完善贡献力量。
到此,个人项目仿真部分已经完成。有关个人项目硬件演示部分,由于较为简单,不出详细教程,可以参考我的对应文章(但是由于考虑各种情况,对应代码比个人会麻烦一些)。