Serial port transceiver in STM32 bare board development (with / without development board)

  • Background: I learned about the serial port transceiver experiment in the development of STM32 bare board. I suffer from having no money to buy the development board. Now there are few computers with their own serial port, so I wonder whether I can cover the White Wolf empty handed and directly use KEIL5 to complete the Simulation online. I didn't expect there was a way!
  • Required software:
    • 1 KEIL5
    • Virtual serial port: VSPD
    • Virtual serial debugger SSCOM
  • Experimental purpose: complete the programming based on STM32F103 development board in KEIL5, so as to achieve the purpose that the PC sends the string to the development board through the serial port, and the development board receives the data through the serial port, and then sends it back to the PC intact.

1. Download and install VSPD (Virtual Serial Port Driver) standby

  • Download link:
  • Software interface: complete the installation and cracking according to the requirements of downloading compressed package files (it is recommended to install the version before 7.2. The cracking of the newer version circulated on the Internet is not perfect. After using it for a few days, it will prompt that can not pair port can not be used). After installation, it is shown in the figure below:


  • usage method:

    • 1 select the serial port group pairs that appear in the list (only those that have not been used are displayed)
    • 2 click Add pair to create a serial port group pair
    • 3 the newly created group pair appears under Virtual ports
    • 4 in the serial port list, there are no more pairs of them (the above figure shows the created COM1 and COM2 serial port pairs)
    • 5 you can verify the newly created virtual serial port group in control panel - Device Manager

After successful creation, you can use them like a physical serial port. One end uses your program to open the virtual serial port COM1, and the other end uses the serial port assistant to open the virtual serial port COM2. Because the virtual serial ports COM2 and COM1 are a pair of interrelated ports, COM1 will receive the data sent from COM2, while COM2 will receive the data sent from COM1, so it is convenient to debug your program.

The created virtual serial ports will always exist. If they are no longer used, they can be deleted. (first select the serial port pairs to be deleted on the left, and then click the Delete pair button on the right to delete them. After deleting the serial port pairs, they will not be available in the device manager.

2. Programming

  • Create the project folder Usart, and create three folders CMSIS, FWLib and User:

    • Copy the core_cm3.c and core_cm3.h files in Libraries\CMSIS\CM3\CoreSupport \ in the STM32Fx standard peripheral Library (STM32F10x_StdPeriph_Lib_V3.5.0) to Usart\CMSIS \;
    • Copy stm32f10x.h, system_stm32f10x.c and system_stm32f10x.h3 files in Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x \ in STM32Fx standard peripheral Library (STM32F10x_StdPeriph_Lib_V3.5.0) to Usart\CMSIS \;
    • Copy the arm folder in Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup \ in the STM32Fx standard peripheral Library (STM32F10x_StdPeriph_Lib_V3.5.0) to Usart\CMSIS\StartUp \;
    • Copy the inc and src folders in Libraries\STM32F10x_StdPeriph_Driver \ in the STM32Fx standard peripheral Library (STM32F10x_StdPeriph_Lib_V3.5.0) to Usart\FWLib \;
    • Copy stm32f10x_conf.h, stm32f10x_it.c, stm32f10x_main.c, system_stm32f10x.c in Libraries\Project\STM32F10x_StdPeriph_Template \ in STM32Fx standard peripheral Library (stm32f10x_stdperiph_v3.5.0) to Usart\User \;
  • Open KEIL5, click Project - new uVision Project, select the Usart folder just created, create the project name Usart for the project, and click Save to create the project (select STM32F103RB development board).

  • In the left project tree, right-click Target 1 and select Manerge Project Items

  • Establish FWLIB, STARTUP, CMSIS and USER groups for Target1, and add the following files respectively:
    • Add all files in Usart\FWLib\src \ to FWLIB;
    • Add STARTUP files of three types of boards in STARTUP: startup_stm32f10x_hd.s, startup_stm32f10x_md.s, startup_stm32f10x_ld.s;
    • Add core_cm3.c file in CMSIS;
    • Add all files in Usart\User to USER.

  • Configure target project 1: right click Target1 under the left structure tree, select Option for Target, select the C\C + + tab, and define two preprocessing symbols as shown in the figure: use_stdprotocol_driver, stm32f10x_md

  • Configure target project 2: set the header file search path. Select the C\C + + tab and define three search paths as shown in the figure:. \ CMSIS;.\FWlib\inc;.\User:

  • Edit the main.c function to build the USART transceiver main function:

  • /*
      * @file    main.c 
      * @author  Leon
      * @version V1.0
      * @date    2021-9-28
      * @brief   PC send data to STM32 with USART, then STM32 send the data back to PC
    /* Includes ------------------------------------------------------------------*/
    #include "stm32f10x.h"
    #include <stdio.h>
    /* Private typedef -----------------------------------------------------------*/
    /* Private define ------------------------------------------------------------*/
    /* Private macro -------------------------------------------------------------*/
    /* Private variables ---------------------------------------------------------*/
    /* Private function prototypes -----------------------------------------------*/
    void RCC_Configuration(void);
    void GPIO_Configuration(void);
    void USART_Configuration(void);
    /* Private functions ---------------------------------------------------------*/
      * @brief  Main program.
      * @param  None
      * @retval None
    int main(void)
    	vu16 i = 0;
    		/*Wait for USART1 to receive over*/
    		if(USART_GetFlagStatus(USART1, USART_IT_RXNE) == SET){
    			/* Send data received to USART1 */
    			USART_SendData(USART1, USART_ReceiveData(USART1));
    			/* Short delay */
    			for(i = 0; i<500; i++);
    			//while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);							
      * @brief  RCC configuration program, enable USART and GPIOA.
      * @param  None
      * @retval None
    void RCC_Configuration(void)
    	ErrorStatus HSEStartUpStatus;
    	HSEStartUpStatus = RCC_WaitForHSEStartUp();
    	if(HSEStartUpStatus == SUCCESS)
    		/* PLL CLK Source is HSE, Mull 9, PLL = 8M * 9 = 72M */
    		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    		while(RCC_GetSYSCLKSource() != 0x8);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
      * @brief  Config USATR1 Pin which Tx(GPIOA.9), Rx(GPIOA.10).
      * @param  None
      * @retval None
    void GPIO_Configuration(void)
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
      * @brief  Config USART1(Baund=9600, DataLen=8,StopBit=1, No ECC,)
                Disable USART CLK, CLK Polar low, Catch data at second edage
    			LastBit clk not from SCLK.
      * @param  None
      * @retval None
    void USART_Configuration(void)
    	USART_InitTypeDef USART_InitStructure;
    	USART_ClockInitTypeDef USART_ClockInitStructure;
    	USART_InitStructure.USART_BaudRate = 9600;
    	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    	USART_InitStructure.USART_Parity = USART_Parity_No;
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    	USART_Init(USART1, &USART_InitStructure);
    	USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
    	USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
    	USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
    	USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
    	USART_ClockInit(USART1, &USART_ClockInitStructure);
    /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
  • Edit the configuration file stm32f10x_conf.h to enable the GPIO, RCC, USART and FLASH modules used in the project:

  • /**
      * @file    stm32f10x_conf.h 
      * @author  leon
      * @version V1.0
      * @date    2021/9/18
      * @brief   Library configuration file.
      * @attention
      * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
    /* Define to prevent recursive inclusion -------------------------------------*/
    #ifndef __STM32F10x_CONF_H
    #define __STM32F10x_CONF_H
    /* Includes ------------------------------------------------------------------*/
    /* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */
    //#include "stm32f10x_adc.h"
    //#include "stm32f10x_bkp.h"
    //#include "stm32f10x_can.h"
    //#include "stm32f10x_cec.h"
    //#include "stm32f10x_crc.h"
    //#include "stm32f10x_dac.h"
    //#include "stm32f10x_dbgmcu.h"
    //#include "stm32f10x_dma.h"
    //#include "stm32f10x_exti.h"
    #include "stm32f10x_flash.h"
    //#include "stm32f10x_fsmc.h"
    #include "stm32f10x_gpio.h"
    //#include "stm32f10x_i2c.h"
    //#include "stm32f10x_iwdg.h"
    //#include "stm32f10x_pwr.h"
    #include "stm32f10x_rcc.h"
    //#include "stm32f10x_rtc.h"
    //#include "stm32f10x_sdio.h"
    //#include "stm32f10x_spi.h"
    //#include "stm32f10x_tim.h"
    #include "stm32f10x_usart.h"
    //#include "stm32f10x_wwdg.h"
    //#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
    /* Exported types ------------------------------------------------------------*/
    /* Exported constants --------------------------------------------------------*/
    /* Uncomment the line below to expanse the "assert_param" macro in the 
       Standard Peripheral Library drivers code */
    /* #define USE_FULL_ASSERT    1 */
    /* Exported macro ------------------------------------------------------------*/
    #ifdef  USE_FULL_ASSERT
      * @brief  The assert_param macro is used for function's parameters check.
      * @param  expr: If expr is false, it calls assert_failed function which reports 
      *         the name of the source file and the source line number of the call 
      *         that failed. If expr is true, it returns no value.
      * @retval None
      #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
    /* Exported functions ------------------------------------------------------- */
      void assert_failed(uint8_t* file, uint32_t line);
      #define assert_param(expr) ((void)0)
    #endif /* USE_FULL_ASSERT */
    #endif /* __STM32F10x_CONF_H */
    /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
  • The interrupt processing function file stm32f10x_it.c does not need to be modified because interrupts are not used in this program.

  • Click the compile button (rebuild: compile all files under the project; Build: compile the current file) to achieve the compilation results of error 0 and warning 0.

3. Serial port settings in KEIL

  • 1. Create the ini file for debugging initialization

In the folder D:\Keil_v5 of Keil uvisin5 development tool, create a new configuration file map_com.ini (change the suffix to ini after creating a txt document), the content is:

MODE COM1 9600,0,8,1

It means: set COM1 to 9600 baud rate, no parity, 8 data bits and 1 stop bit (consistent with the setting in the program of KEIL project) . this is for the ARM series. However, if it is a C51 development board, there is no need to add numbers to < sin > and SOUT in the second line of the above configuration file, because C51 generally has only one serial port, and it is not necessary to use numbers to distinguish which serial port is on the development board.

  • Map the serial port of KEIL software emulator to COM1 (load configuration file)

    • 1) In Keil software, click Project – Options for Target(Alt+F7) in the menu or the [configuration and selection] icon in the toolbar

      2) Click the Debug option page, and click Use simulator on the upper left

      3) Click the... Button after the Initialization File box and select the Initialization File map_com.ini, click open – OK to return.

4. Start debugging

  • First click the menu Debug – Start/Stop Debug Session(Ctrl+F5), then click Debug – Run(F5) or Debug on the toolbar to enter the debugging interface, and then click Run at full speed on the toolbar to start debugging.

  • Open the serial port debugging assistant and select COM2 (because the serial port used on the development board set in KEIL is COM1, the connection between COM1 and COM2 has been established through the virtual serial port driving VSPD, so the serial ports can send data to each other)

  • Select COM2 in "port number" in the menu bar (Note: the baud rate must be 9600, which is consistent with COM1 mapped by the program), and then click to open the serial port. It will be displayed as shown in the above figure

  • In the text input box in the lower right corner, enter character A and click send to see the received character A in the output window

  • ]

  • You can open the USART1 serial port observation window in KEIL to view the data sent by PC to STM32

  • ]

  • View port information:

    • Menu Peripherals – General Purpose I/O – GPIO
    • On the right side of GPIO ODR, you can see whether the specific bit is checked according to the actual level.


  • Graphical display of logic analyzer viewing port

    • Click the start debugging – Logic Analyzer – Logic Analyzer – Setup... – add new icon in the toolbar
    • Enter port. 6 and select Bit to view its level change and obtain the time difference
  • ]

5. Physical Download

When you have the actual development board and debugging line (USB to serial driver), how to download and debug the program?

  • Debugging line with * * ST link**
    • After installing the driver, connect the device to the computer and click Project – Options for Target in the menu
    • 1) On the Debug options page
      • (1) Check the use st link debugger on the right
      • (2) Click the Setting button
      • (3) On the Debug option page, select p ort: SW Max: 1.8MHz
      • (4) On the Flash Download options page
        • Check Program, Verify, Reset and Run
        • Select stm32f10x high density... 512k
    • 2) On the Utilities options page
      • Check Use Debug Driver
      • Check Update Target before Debugging
    • 3) Click the load icon on the toolbar to download


  • Using USB to serial port cable
    • 1) Download and install CH340 driver (USB serial driver)_ XP_WIN7 shared driver
    • 2) Connect the device with USB cable and start FlyMcu download tool
    • 3) Click the search serial port on the menu to find COMx: idle USB-SERIAL CH340 (own cable)
    • 4) Click the button... To find the generated. hex file
    • 5) Click start programming until it is finished.


  • The above is all the programming and debugging methods with and without physical objects that use KEIL5 to complete STM programming, debugging and downloading. It should be noted that the results of our online simulation debugging program may be different from that of the program downloaded to the actual board for operation. The reason is that the simulation speed is relatively slow and the actual operation speed is relatively fast. Therefore, if necessary, we can add a delay function after the appropriate statement to solve the speed matching problem.

reference material: Keil software simulation without physical object and on-line debugging of serial port assistant_ Wu Chao_ Sina blog (

Tags: stm32

Posted on Thu, 30 Sep 2021 22:51:59 -0400 by zulx