13CubeMx+Keil+Proteus仿真STM32
本文例子参考《STM32单片机开发实例——基于Proteus虚拟仿真与HAL/LL库》
源代码:https://github.com/LanLinnet/STM33F103R6
项目要求
单片机将由串口收到的1字节数据存入Flash ROM的指定地址;按下按钮BTN,单片机将存储在Flash ROM指定地址的字节数据通过串口发送。串口通信参数:波特率为19200bit/s,无校验。
硬件设计
在第一节的基础上,在Proteus中添加电路如下图所示。其中我们添加了:串口组件
COMPIM
,用于连接计算机虚拟串口;调试过程也可以添加一个虚拟仪器
VIRTUAL TERMINAL
,用来查看单片机收到的串口数据,具体参考第11节由于要实现串口通信,我们要将其波特率、字长、校验方式、停止位等都设置一下,具体参数如下图所示
COMPIM设置
Flash ROM简介:STM32单片机Flash ROM(程序存储器)的作用是存放用户编写的单片机程序(机器码),但是其除了用来存放单片机的程序外,也可以用来存储一些既可以修改又能断电保存的数据,如设备或模块的设定参数。但是在实际中,由于STM32单片机的Flash ROM擦除次数有限,因此不建议在Flash ROM擦写,可以通过外扩(E^2 PROM)、FRAM、存储卡等方式实现保护产品设定参数的目的。不过为了熟悉Flash ROM操作,本节我们使用Flash ROM来存储数据。
1)STM32F103R6单片机具有32KB的FlashROM,地址为0x0800 0000 ~ 0x0800 7FFF,每KB为一页,共32页。
2)Flash ROM数据写入步骤:Flash ROM解锁 → 擦除扇区 → 向指定地址写入数据 → Flash ROM锁定。
3)Flash ROM数据读取没有繁琐的步骤,直接读取即可。
打开CubeMX,建立工程。
首先,设置PA5为
GPIO_Input
。然后,点击“Connectivity”列表中的“USART”进行串口配置。将Mode设置为
Asynchronous
(异步),波特率设为19200Bits/s
,字长设为8Bits
,校验设为None
,停止位设为1
,数据传送设为Receive and Transmit
(接收与发送)。设置完成后,会看到右侧的PA9和PA10引脚被自动设置为USART1_TX
和USART1_RX
,即USART1的发送端和接收端。随后,再点击“NVIC Settings”,选中
USART global interrupt
,使能Enabled
串口1的中断功能。点击“Generator Code”生成Keil工程。
软件编写
本次我们需要实现串口助手发送单字节数据,单片机收到数据后存入Flash ROM,按键按下后将存储的数据通过串口发回串口助手,需要用到Flash ROM相关函数其API文档如下:
HAL_FLASH_Unlock 解锁Flash ROM函数
HAL_FLASH_Lock 锁定Flash ROM函数
HAL_FLASHEx_Erase 擦除Flash ROM指定部分函数
HAL_FLASH_Program 将数据写入Flash ROM函数
其中,
TypeErase
形参有以下2个宏定义TypeProgram
有以下3个宏定义点击“Open Project”在Keil中打开工程,双击“main.c”文件。
首先我们需要在main.c文件中的最前面设置全局变量、声明自定义函数。
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define _FLASH_ADD 0x08006400 //写入Flash ROM首地址(Page 25)
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t rf = 0; //自定义串口接收完毕标志
uint8_t RcvBuf[1]; //接收缓冲
uint8_t SndBuf[1]; //发送缓冲
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void FlashErase(uint32_t Add); //声明自定义Flash ROM擦除函数
void FlashWrite(uint32_t Add, uint16_t Dat); //声明自定义Flash ROM写函数
uint16_t FlashRead(uint32_t Add); //声明自定义Flash ROM读函数
/* USER CODE END PFP */
然后,在
main
函数中中插入代码如下,定义中间变量,打开串口1接收中断/* USER CODE BEGIN 1 */
uint16_t flash_wdat; //写入Flash数据存储变量
/* USER CODE END 1 */
/* USER CODE BEGIN 2 */
//打开串口1接收中断,接收数据存入RcvBuf数组,数组长度为1
HAL_UART_Receive_IT(&huart1,RcvBuf,1);
/* USER CODE END 2 */
随后,在
/* USER CODE BEGIN 4 */
和/* USER CODE END 4 */
中插入接收完毕回调函数、自定义的Flash页擦除函数、Flash写函数、Flash读函数代码如下/* USER CODE BEGIN 4 */
//串口接收完毕回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart==&huart1) //如果串口1接收完毕
{
rf = 1; //标志位置1
}
}
/*Flash页擦除
*-Add表示待擦除页的首地址
*-Flash必须整页擦除,也就是整页的每个地址单元内容都为FFH才能写入新数据
*/
void FlashErase(uint32_t Add)
{
uint32_t page_error = 0; //错误指针
FLASH_EraseInitTypeDef erase_initstruct =
{
.TypeErase = FLASH_TYPEERASE_PAGES, //擦除方式为页擦除
.NbPages = 1, //页数量为1页
.PageAddress = Add //擦除页起始地址
};
HAL_FLASH_Unlock(); //解锁Flash ROM
HAL_FLASHEx_Erase(&erase_initstruct, &page_error); //擦除
HAL_FLASH_Lock(); //锁定Flash ROM
}
/*Flash写函数
*-写入一个Half Word(16位)型数据
*-Add表示Flash ROM地址
*-Dat表示写入数据(16位)
*-注意:写入时,高字节在高地址
*/
void FlashWrite(uint32_t Add, uint16_t Dat)
{
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Add, Dat); //将数据写入Flash
HAL_FLASH_Lock();
}
/*Flash读函数
*-返回一个Half Word(16位)型数据
*-Add表示Flash ROM地址
*/
uint16_t FlashRead(uint32_t Add)
{
uint16_t dat;
dat = *(uint16_t *)Add;
return dat;
}
/* USER CODE END 4 */
最后,在
while(1)
中插入代码如下,进行Flash和串口相关操作/* USER CODE BEGIN WHILE */
while (1)
{
if(rf == 1) //串口接收完毕
{
rf = 0; //标志位清0
flash_wdat = RcvBuf[0]; //将接收到的数据存入写Flash变量中
FlashErase(_FLASH_ADD); //擦除指定部分
FlashWrite(_FLASH_ADD, flash_wdat); //写入Flash
HAL_UART_Receive_IT(&huart1, RcvBuf, 1); //每次接收前都需要调用一次
}
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET)
{
HAL_Delay(25); //消抖
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET) //如果按键按下
{
SndBuf[0] = (uint8_t)FlashRead(_FLASH_ADD); //读Flash中值并存入发送缓冲
HAL_UART_Transmit(&huart1, SndBuf, 1, 10); //由串口1发送缓冲中的值
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET); //等待按键松开
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
联合调试
点击运行,生成HEX文件。
在Proteus中加载相应HEX文件,点击运行。
打开串口调试助手“XCOM”,选择
COM4
,设置相应的波特率、停止位、数据位、奇偶校验等,勾选“16进制显示”和“16进制发送”,点击“打开串口”。在发送框输入“00”,点击“发送”。在Proteus中我们可以看到“VIRTUAL TERMINAL”接收到数据“00”。按下按键,同时再观察串口调试助手“XCOM”,可以看到接收窗口收到数据“00”。同理,发送“AA”和“BB”也能得到相应的结果。
以上是 13CubeMx+Keil+Proteus仿真STM32 的全部内容, 来源链接: utcz.com/z/520511.html