13CubeMx+Keil+Proteus仿真STM32

编程

本文例子参考《STM32单片机开发实例——基于Proteus虚拟仿真与HAL/LL库》

源代码:https://github.com/LanLinnet/STM33F103R6

项目要求

单片机将由串口收到的1字节数据存入Flash ROM的指定地址;按下按钮BTN,单片机将存储在Flash ROM指定地址的字节数据通过串口发送。串口通信参数:波特率为19200bit/s,无校验。

硬件设计

  1. 在第一节的基础上,在Proteus中添加电路如下图所示。其中我们添加了:串口组件COMPIM,用于连接计算机虚拟串口;


    调试过程也可以添加一个虚拟仪器VIRTUAL TERMINAL,用来查看单片机收到的串口数据,具体参考第11节

    由于要实现串口通信,我们要将其波特率、字长、校验方式、停止位等都设置一下,具体参数如下图所示

    COMPIM设置

  2. 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数据读取没有繁琐的步骤,直接读取即可。

  3. 打开CubeMX,建立工程。

    首先,设置PA5为GPIO_Input

    然后,点击“Connectivity”列表中的“USART”进行串口配置。将Mode设置为Asynchronous(异步),波特率设为19200Bits/s,字长设为8Bits,校验设为None,停止位设为1,数据传送设为Receive and Transmit(接收与发送)。设置完成后,会看到右侧的PA9和PA10引脚被自动设置为USART1_TXUSART1_RX,即USART1的发送端和接收端。


    随后,再点击“NVIC Settings”,选中USART global interrupt,使能Enabled串口1的中断功能。

  4. 点击“Generator Code”生成Keil工程。

软件编写

  1. 本次我们需要实现串口助手发送单字节数据,单片机收到数据后存入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个宏定义

  2. 点击“Open Project”在Keil中打开工程,双击“main.c”文件。

  3. 首先我们需要在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 */

联合调试

  1. 点击运行,生成HEX文件。

  2. 在Proteus中加载相应HEX文件,点击运行。

  3. 打开串口调试助手“XCOM”,选择COM4,设置相应的波特率、停止位、数据位、奇偶校验等,勾选“16进制显示”和“16进制发送”,点击“打开串口”。在发送框输入“00”,点击“发送”。在Proteus中我们可以看到“VIRTUAL TERMINAL”接收到数据“00”。按下按键,同时再观察串口调试助手“XCOM”,可以看到接收窗口收到数据“00”。同理,发送“AA”和“BB”也能得到相应的结果。

以上是 13CubeMx+Keil+Proteus仿真STM32 的全部内容, 来源链接: utcz.com/z/520511.html

回到顶部