文章目录
- 单片机介绍
- 引脚
- DMA—直接存储器访问
- 串口 引脚
- 串口1,初始化,发送与接收
- 串口2,初始化,发送与接收
- 串口3,初始化,发送与接收
- 串口4,初始化,发送与接收
- 串口5,初始化,发送与接收
单片机介绍
STM32F103RCT6是一款主流性能系列的单片机,采用Arm Cortex-M3内核,具有256K字节的Flash存储器,72 MHz的CPU频率,支持电机控制、USB和CAN等功能。
该产品已经批量生产,10kU的单价为4.0035美元,采用LQFP 64封装,尺寸为10x10x1.4mm。
STM32F103xC、STM32F103xD和STM32F103xE性能系列产品采用高性能的ARM Cortex-M3 32位RISC内核,工作频率为72 MHz。它们拥有高速嵌入式存储器(Flash存储器最高达512K字节,SRAM最高达64K字节),以及广泛的增强型I/O口和外围设备,可以连接两个APB总线。所有这些设备都提供了三路12位ADC、四个通用16位定时器和两个PWM定时器,以及标准和高级通信接口:最多两个I2C接口、三个SPI接口、两个I2S接口、一个SDIO接口、五个串行USART接口、一个USB接口和一个CAN接口。
STM32F103xC/D/E高密度性能系列单片机可在-40℃至+105℃的温度范围内工作,电源电压为2.0至3.6V。它们具有一套全面的省电模式,适用于低功耗应用的设计。
这些特性使得STM32F103xC/D/E高密度性能系列单片机非常适合广泛的应用领域,如电机驱动、应用控制、医疗和便携设备、个人电脑和游戏外围设备、GPS平台、工业应用、可编程逻辑控制器(PLC)、变频器、打印机、扫描仪、报警系统、视频对讲系统和暖通空调系统等。
主要特性包括:
72 MHz的最大频率,每MHz可执行1.25 DMIPS(Dhrystone 2.1)指令
单周期乘法和硬件除法
256至512 K字节的Flash存储器
最多64 K字节的SRAM
灵活的静态存储器控制器,支持紧凑型Flash、SRAM、PSRAM、NOR和NAND存储器
LCD并行接口,支持8080和6800模式
2.0至3.6 V的应用供电和I/O口电压
POR(上电复位)、PDR(电源降低复位)和可编程电压检测器(PVD)
4至16 MHz的晶振和内部8 MHz的出厂修裁RC振荡器
带校准的内部40 kHz RC振荡器
带校准的32 kHz时钟用于RTC(实时时钟)
低功耗模式:休眠、停止和待机
VBAT供电用于RTC和备份寄存器
3路12位、1微秒的A/D转换器(最多21个通道),输入范围为0至3.6 V
三路采样和保持功能,温度传感器
2路12位D/A转换器
支持DMA(直接内存访问)的外设包括定时器、ADC、DAC、SDIO、I2S、SPI、I2C和USART
调试模式:串行线调试(SWD)和JTAG接口,Cortex-M3嵌入式追踪宏单元
最多112个快速I/O口,51/80/112个I/O口,可以映射到16个外部中断向量上,几乎所有的I/O都能耐受5V电平
最多11个定时器,包括四路16位定时器,每个定时器可配置为4路输入捕获/输出比较/脉冲宽度调制(PWM)或脉冲计数器及象限(增量)编码器输入;两路带死区生成和紧急停止功能的16位电机控制PWM定时器;两路看门狗定时器(独立和窗口);SysTick定时器,用于倒计时的24位;
最多13个通信接口,包括最多2个I2C接口(支持SMBus/PMBus)、最多5个USART接口(支持ISO 7816接口、LIN、IrDA功能、调制解调器控制)、最多3个SPI接口(18 Mbit/s),其中2个带I2S接口复用,CAN接口(2.0B主动型)、USB 2.0全速接口、SDIO接口
CRC(循环冗余校验)计算单元,96位唯一标识符
ECOPACK®封装形式。
引脚
DMA—直接存储器访问
看看资料:
https://doc.embedfire.com/mcu/stm32/f103mini/std/zh/latest/book/DMA.html
DMA控制器包含了DMA1和DMA2,其中DMA1有7个通道,DMA2有5个通道, 这里的通道可以理解为传输数据的一种管道。要注意的是DMA2只存在于大容量产品和互联型产品中。
STM32F103RCT6 是大容量产品。256K。
小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx、STM32F102xx和 STM32F103xx微控制器。
中容量产品是指闪存存储器容量在64K至128K字节之间的STM32F101xx、STM32F102xx和 STM32F103xx微控制器。
大容量产品是指闪存存储器容量在256K至512K字节之间的STM32F101xx和STM32F103xx微控 制器。
互联型产品是指STM32F105xx和STM32F107xx微控制器。
DMA请求映像表:
发现没UART5_TX,那这里我的串口就不用DMA来配置了。
串口 引脚
串口1,初始化,发送与接收
用的正点原子代码,这个串口1是默认就用的,这里给出代码:
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
懒得定义文件,接下来我将串口2、3、4、5的初始化函数的定义写在usart.c、接收中断写在usart.c、初始化函数的声明写在usart.h、调用写在main.c。调用无非就是类似于uart_init(115200)的定义了。接下来的小节里都直接给出定义来。
串口2,初始化,发送与接收
//串口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);
}
}
串口3,初始化,发送与接收
//串口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);
}
}
串口4,初始化,发送与接收
//串口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);
}
}
串口5,初始化,发送与接收
//串口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);
}
}