[STM32 MCU] STM32F103RCT6 serial port 1 serial port 2 serial port 3 serial port 4 serial port 5 initialization, standard library, support printf

Microcontroller Introduction

STM32F103RCT6 is a mainstream performance single-chip microcomputer, which adopts Arm Cortex-M3 core, has 256K bytes of Flash memory, 72 MHz CPU frequency, and supports functions such as motor control, USB and CAN.

The product has been mass-produced, and the unit price of 10kU is 4.0035 US dollars. It adopts LQFP 64 package and the size is 10x10x1.4mm.

The STM32F103xC, STM32F103xD and STM32F103xE Performance Line products feature the high-performance ARM Cortex-M3 32-bit RISC core operating at 72 MHz. They have high-speed embedded memory (Flash memory up to 512K bytes, SRAM up to 64K bytes), and a wide range of enhanced I/O ports and peripherals, which can be connected to two APB buses. All of these devices provide three 12-bit ADCs, four general-purpose 16-bit timers, and two PWM timers, as well as standard and advanced communication interfaces: up to two I2C interfaces, three SPI interfaces, two I2S interfaces, one SDIO interface, five serial USART interfaces, one USB interface and one CAN interface.

The STM32F103xC/D/E high-density performance line of microcontrollers can operate over a temperature range of -40°C to +105°C with a supply voltage of 2.0 to 3.6V. They feature a comprehensive set of power-saving modes for designs in low-power applications.

These features make the STM32F103xC/D/E high-density performance series microcontrollers ideal for a wide range of applications such as motor drives, application control, medical and portable equipment, PC and gaming peripherals, GPS platforms, industrial applications, programmable logic controllers (PLC), frequency converter, printer, scanner, alarm system, video intercom system and HVAC system, etc.

Key features include:

72 MHz maximum frequency, capable of executing 1.25 DMIPS (Dhrystone 2.1) instructions per MHz
Single-cycle multiplication and hardware division
256 to 512 Kbytes of Flash memory
Up to 64 Kbytes of SRAM
Flexible static memory controller that supports compact Flash , SRAM, PSRAM, NOR and NAND memory
LCD parallel interface, supports 8080 and 6800 mode
2.0 to 3.6 V application power supply and I/O port voltage
POR (power-on reset), PDR (power-down reset) and programmable voltage detector (PVD)
4 to 16 MHz crystal and internal 8 MHz factory trimmed RC oscillator
Internal 40 kHz RC oscillator
with calibration 32 kHz clock with calibration for RTC (Real Time Clock)
Low power modes: sleep, stop And standby
VBAT power supply for RTC and backup registers
3-way 12-bit, 1 microsecond A/D converter (up to 21 channels), input range is 0 to 3.6 V
3-way sample and hold function, temperature sensor
2-way 12 Bit D/A converter
DMA (Direct Memory Access) capable peripherals including timers, ADC, DAC, SDIO, I2S, SPI, I2C and USART
Debug mode: Serial Wire Debug (SWD) and JTAG interface, Cortex-M3 Embedded trace macrocell
Up to 112 fast I/O ports, 51/80/112 I/O ports, can be mapped to 16 external interrupt vectors, almost all I/Os can withstand 5V level
Up to 11 timers, including four 16-bit timers, each configurable as four input capture/output compare/pulse width modulation (PWM) or pulse counter and quadrant (incremental) encoder inputs; two 16-bit motor control PWM timer with dead-band generation and emergency stop; two watchdog timers (independent and window); SysTick timer, 24-bit for countdown; up to 13 communication interfaces, including up to
2 1 I2C interface (supports SMBus/PMBus), up to 5 USART interfaces (supports ISO 7816 interface, LIN, IrDA function, modem control), up to 3 SPI interfaces (18 Mbit/s), 2 of which are multiplexed with I2S interface , CAN interface (2.0B active type), USB 2.0 full-speed interface, SDIO interface
CRC (cyclic redundancy check) calculation unit, 96-bit unique identifier
ECOPACK® package.

pin

insert image description here
insert image description here
insert image description here
insert image description here
insert image description here

insert image description here

DMA - direct memory access

Look at the information:
https://doc.embedfire.com/mcu/stm32/f103mini/std/zh/latest/book/DMA.html

The DMA controller includes DMA1 and DMA2. DMA1 has 7 channels, and DMA2 has 5 channels . The channels here can be understood as a kind of pipeline for transmitting data. It should be noted that DMA2 only exists in high-capacity products and interconnected products.

The STM32F103RCT6 is a high-capacity product. 256K.

Small-capacity products refer to STM32F101xx, STM32F102xx and STM32F103xx microcontrollers with a flash memory capacity between 16K and 32K bytes.
Medium-density products refer to STM32F101xx, STM32F102xx and STM32F103xx microcontrollers with a flash memory capacity between 64K and 128K bytes.
High-capacity products refer to STM32F101xx and STM32F103xx microcontrollers with a flash memory capacity between 256K and 512K bytes.
Connected products refer to STM32F105xx and STM32F107xx microcontrollers.

DMA request map table:

insert image description here
insert image description here
It is found that there is no UART5_TX, so my serial port does not need DMA to configure here.

serial pin

insert image description here
insert image description here

Serial port 1, initialization, sending and receiving

The punctual atomic code used, this serial port 1 is used by default, here is the code:

usart.c

#include "sys.h"
#include "usart.h"

//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"					//ucos 使用	  
#endif


//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数                 
struct __FILE {
    
    
    int handle;

};

FILE __stdout;

//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) {
    
    
    x = x;
}

//重定义fputc函数 
int fputc(int ch, FILE *f) {
    
    
    while ((USART1->SR & 0X40) == 0);//循环发送,直到发送完毕
    USART1->DR = (u8) ch;
    return ch;
}

#endif


void uart_init(u32 bound) {
    
    
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);    //使能USART1,GPIOA时钟

    //USART1_TX   GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9

    //USART1_RX	  GPIOA.10初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10

    //Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器

    //USART 初始化设置

    USART_InitStructure.USART_BaudRate = bound;//串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式

    USART_Init(USART1, &USART_InitStructure); //初始化串口1
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
    USART_Cmd(USART1, ENABLE);                    //使能串口1

}

void USART1_IRQHandler(void)                    //串口1中断服务程序
{
    
    
    u8 Res;
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    
    
        Res = USART_ReceiveData(USART1);    //读取接收到的数据
        printf("收到了一个字符: %c\r\n", Res);
    }

}




usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" 


//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);

#endif



I am too lazy to define the file. Next, I write the definition of the initialization function of the serial port 2, 3, 4, and 5 in usart.c, write the receiving interrupt in usart.c, write the declaration of the initialization function in usart.h, and write the call in main. c. The call is nothing more than a definition similar to uart_init(115200). Definitions are given directly in the following subsections.

insert image description here

Serial port 2, initialization, sending and receiving



//串口2 PA2 PA3 ,APB1时钟
void uart2_init(u32 bound){
    
    
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);    //使能USART2,GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    //使能USART2,GPIOA时钟

    //USART2_TX   GPIOA.2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2

    //USART2_RX	  GPIOA.3初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3

    //Usart2 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器

    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式

    USART_Init(USART2, &USART_InitStructure); //初始化串口2
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
    USART_Cmd(USART2, ENABLE);                    //使能串口2
}

void u2_printf(char* fmt, ...)
{
    
    
	  int i;
	  int len;
    char buffer[50]; //足够容纳才可以,可以搞大点
    va_list args;
    va_start(args, fmt);
    vsprintf(buffer, fmt, args);
    va_end(args);

    len = strlen(buffer);

    for( i=0; i<len; i++)
    {
    
    
        while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); //等待发送完毕
        USART_SendData(USART2, buffer[i]); //发送一个字符
    }
}

void USART2_IRQHandler(void)                    //串口2中断服务程序
{
    
    
    u8 Res;
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    
    
        Res = USART_ReceiveData(USART2);    //读取接收到的数据
			
        u2_printf("收到了一个字符: %c\r\n", Res);
    }

}


Serial port 3, initialization, sending and receiving


//串口3 PB10 PB11 ,APB1时钟
void uart3_init(u32 bound) {
    
    
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);    //使能USART3,GPIOB时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);    //使能USART3,GPIOB时钟

    //USART3_TX   GPIOB.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB.10
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.10

    //USART3_RX	  GPIOB.11初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.11

    //Usart3 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器

    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式

    USART_Init(USART3, &USART_InitStructure); //初始化串口3
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启串口接受中断
    USART_Cmd(USART3, ENABLE);                    //使能串口3
}

void u3_printf(char *fmt, ...) {
    
    
    int i;
    int len;
    char buffer[50]; //足够容纳才可以,可以搞大点
    va_list args;
    va_start(args, fmt);
    vsprintf(buffer, fmt, args);
    va_end(args);

    len = strlen(buffer);

    for (i = 0; i < len; i++) {
    
    
        while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET); //等待发送完毕
        USART_SendData(USART3, buffer[i]); //发送一个字符
    }
}

void USART3_IRQHandler(void)                    //串口3中断服务程序
{
    
    
    u8 Res;
    if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    
    
        Res = USART_ReceiveData(USART3);    //读取接收到的数据

        u3_printf("收到了一个字符: %c\r\n", Res);
    }

}

Serial port 4, initialization, sending and receiving


//串口4 PC10 PC11 ,APB1时钟
void uart4_init(u32 bound) {
    
    
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);    //使能UART4,GPIOC时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);    //使能UART4,GPIOC时钟

    //UART4_TX   GPIOC.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PC.10
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
    GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.10

    //UART4_RX	  GPIOC.11初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PC11
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.11

    //Usart4 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器

    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式

    USART_Init(UART4, &USART_InitStructure); //初始化串口4
    USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);//开启串口接受中断
    USART_Cmd(UART4, ENABLE);                    //使能串口4
}

void u4_printf(char *fmt, ...) {
    
    
    int i;
    int len;
    char buffer[50]; //足够容纳才可以,可以搞大点
    va_list args;
    va_start(args, fmt);
    vsprintf(buffer, fmt, args);
    va_end(args);

    len = strlen(buffer);

    for (i = 0; i < len; i++) {
    
    
        while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET); //等待发送完毕
        USART_SendData(UART4, buffer[i]); //发送一个字符
    }
}

void UART4_IRQHandler(void)                    //串口4中断服务程序
{
    
    
    u8 Res;
    if (USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    
    
        Res = USART_ReceiveData(UART4);    //读取接收到的数据

        u4_printf("收到了一个字符: %c\r\n", Res);
    }

}

Serial port 5, initialization, sending and receiving


//串口5 PC12 PD2 ,APB1时钟
void uart5_init(u32 bound) {
    
    
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);    //使能UART5,GPIOC时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);    //使能UART5,GPIOC时钟

    //UART5_TX   GPIOD.12
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //PD.12
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
    GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化GPIOD.12

    //UART5_RX	  GPIOD.2初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//PD2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化GPIOD.2

    //Usart5 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器

    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    //收发模式

    USART_Init(UART5, &USART_InitStructure); //初始化串口5
    USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);//开启串口接受中断
    USART_Cmd(UART5, ENABLE);                    //使能串口5
}

void u5_printf(char *fmt, ...) {
    
    
    int i;
    int len;
    char buffer[50]; //足够容纳才可以,可以搞大点
    va_list args;
    va_start(args, fmt);
    vsprintf(buffer, fmt, args);
    va_end(args);

    len = strlen(buffer);

    for (i = 0; i < len; i++) {
    
    
        while (USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET); //等待发送完毕
        USART_SendData(UART5, buffer[i]); //发送一个字符
    }
}

void UART5_IRQHandler(void)                    //串口5中断服务程序
{
    
    
    u8 Res;
    if (USART_GetITStatus(UART5, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    
    
        Res = USART_ReceiveData(UART5);    //读取接收到的数据

        u5_printf("收到了一个字符: %c\r\n", Res);
    }

}

Guess you like

Origin blog.csdn.net/x1131230123/article/details/132612923