Introducción popular y uso de STM32 y puerto serie (Usart) (ejemplo: luces pequeñas de control de puerto serie)
1. Descripción
El propósito de escribir este artículo es ayudar a esos amigos a comprender y dominar la configuración y el uso de los puertos serie desde la perspectiva de amigos que no tienen un conocimiento claro de los puertos serie o que son nuevos en ellos.
La configuración específica de los tres grupos de puertos seriales se presenta arriba, y se da un ejemplo al final del artículo: el puerto serial controla una pequeña luz.
2. Una breve introducción al puerto serie
¿Qué es un puerto serie?
En pocas palabras, es implementar printf(""), getchar() y otras funciones, es decir, realizar la recepción y el envío de caracteres o cadenas, para realizar la comunicación.
Entre ellos, el puerto serie se divide en: USART (transceptor asíncrono síncrono) - intercambio de datos full-duplex y UART (transceptor asíncrono) - solo función de transmisión asíncrona, este artículo solo presenta la configuración y el uso de tres USART.
3. El diagrama de flujo de la función de interrupción en serie (de derecha a izquierda)
4. Introducción al diagrama esquemático del circuito de los pines.
Como se muestra en la figura anterior: la placa tiene tres conjuntos de puertos serie (TX es el pin de envío, RX es el pin de recepción), correspondientes a:
RX1/TX1 ——> PA10/PA9 ——> USART1
RX2/TX2 —— > PA3/PA2 ——> USART2
RX3/TX3 ——> PB11/PB10 ——> USART3
alfiler | USART1 | USART2 | USART3 |
---|---|---|---|
Texas | PA9 | PA2 | PB10 |
RX | PA10 | PA3 | PB11 |
línea de reloj | APB2 | APB1 | APB1 |
Nombre de la función de interrupción | USART1_IRQHandler (vacío) | USART2_IRQHandler (vacío) | USART3_IRQHandler (vacío) |
Cinco, configuración de código
1.USART1
(1) enviar, recibir configuración de pin y configuración de puerto serie
void USART1_Config(void)
{
GPIO_InitTypeDef x;
USART_InitTypeDef y;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启管脚PA9,PA10对应的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //开启串口USART1的时钟,注意:**APB2**
x.GPIO_Pin=GPIO_Pin_9;
x.GPIO_Mode=GPIO_Mode_AF_PP;
x.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&x); //配置发送引脚——选择管脚9,模式为复用推挽输出(因为是发送引脚),频率为50MHz,初始化到GPIOA
x.GPIO_Pin=GPIO_Pin_10;
x.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&x); //配置接收引脚——选择管脚10,模式为浮空输入(因为是接收引脚),输入模式不用配置频率,初始化到GPIOA
y.USART_BaudRate=9600; //配置波特率9600/115200等,具体看你的硬件配置要求
y.USART_WordLength=USART_WordLength_8b; //配置数据位8位
y.USART_StopBits=USART_StopBits_1; //配置停止位为1
y.USART_Parity=USART_Parity_No; //奇偶校验位为无校验
y.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //配置硬件控制流选择为无
y.USART_Mode=USART_Mode_Rx|USART_Mode_Tx; //配置串口模式为接收和发送
USART_Init(USART1,&y); //初始化到USART1
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //开启窗口接收中断(即当发生接收数据或发送数据时将触发对应的中断处理函数)
USART_Cmd(USART1,ENABLE); //使能USART1,也就是打开USART1功能
NVIC_Configuration(); //中断优先级配置
}
(2) Configurar prioridad de interrupción
agrupación prioritaria | prioridad maestra | sub-prioridad |
---|---|---|
NVIC_PriorityGroup0 (0 bits para prioridad de prioridad 4 bits para subprioridad) | 0 | 0~15 |
NVIC_PriorityGroup1 (1 bit para prioridad de preferencia 3 bits para subprioridad) | 0~1 | 0~7 |
NVIC_PriorityGroup2 (2 bits para prioridad de preferencia y 2 bits para subprioridad) | 0~3 | 0~3 |
NVIC_PriorityGroup3 (3 bits para prioridad de preferencia 1 bit para subprioridad) | 0~7 | 0~1 |
NVIC_PriorityGroup4 (4 bits para prioridad de preferencia 0 bits para subprioridad) | 0~15 | 0 |
void NVIC_Configuration()
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置分组为组2
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; //配置中断源为USART1
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //配置主优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //配置子优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //中断使能
NVIC_Init(&NVIC_InitStruct); //初始化NVIC
}
(3) Función de procesamiento de interrupciones
void USART1_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //若当前USART1的状态为接收
{
res= USART_ReceiveData(USART1); //读取此时接收的数据
USART_SendData(USART1,res); //将数据重新发回去,用于告诉它接收成功
}
}
(4) Redirección de funciones de envío y recepción (en las funciones estándar C de Keil, funciones como printf no han implementado su capa inferior, y los desarrolladores de programas necesitan redirigir las funciones fgets y fputs para usar funciones estándar como printf, scanf, gets, puts, etc., recuerde agregar #include " stdio.h " oh)
#include "stdio.h"
int fputc(int ch,FILE *f)
{
USART_SendData(USART1,(uint8_t)ch); //发送一个字符
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); //直到发送完毕
return (ch);
}
int fgetc(FILE *f)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET); //直到接收完毕
return (int)USART_ReceiveData(USART1);
}
(5) Finalmente la función principal
int main(void)
{
USART1_Config();
while(1);
}
¡Se realiza una configuración de puerto serie tan completa! ! !
A continuación, siga los mismos pasos para utilizar los otros dos puertos serie para realizar esta función.
2.USART2
(1) enviar, recibir configuración de pin y configuración de puerto serie
void USART2_Config(void)
{
GPIO_InitTypeDef x;
USART_InitTypeDef y;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //注意**APB1**,**USART2**
x.GPIO_Pin=GPIO_Pin_2;
x.GPIO_Mode=GPIO_Mode_AF_PP;
x.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&x);
x.GPIO_Pin=GPIO_Pin_3;
x.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&x);
y.USART_BaudRate=9600;
y.USART_WordLength=USART_WordLength_8b;
y.USART_StopBits=USART_StopBits_1;
y.USART_Parity=USART_Parity_No;
y.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
y.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART2,&y);
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
USART_Cmd(USART2,ENABLE);
NVIC_Configuration();
}
(2) Configurar prioridad de interrupción
void NVIC_Configuration()
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn; //注意:**USART2_IRQn**
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
(3) Función de procesamiento de interrupciones
void USART2_IRQHandler(void) //注意:**USART2_IRQHandler**
{
u8 res;
if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)
{
res= USART_ReceiveData(USART2);
USART_SendData(USART2,res);
}
}
(4) Redirigir la función de envío y recepción (recuerde agregar #include " stdio.h ")
#include "stdio.h"
int fputc(int ch,FILE *f)
{
USART_SendData(USART2,(uint8_t)ch);
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
return (ch);
}
int fgetc(FILE *f)
{
while(USART_GetFlagStatus(USART2,USART_FLAG_RXNE)==RESET);
return (int)USART_ReceiveData(USART2);
}
(5) Finalmente la función principal
int main(void)
{
USART2_Config();
while(1);
}
2.USART3
(1) enviar, recibir configuración de pin y configuración de puerto serie
void USART3_Config(void)
{
GPIO_InitTypeDef x;
USART_InitTypeDef y;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //注意:**GPIOB**
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //注意:**APB1**,**USART3**
x.GPIO_Pin=GPIO_Pin_10;
x.GPIO_Mode=GPIO_Mode_AF_PP;
x.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&x); //注意:**GPIOB**
x.GPIO_Pin=GPIO_Pin_11;
x.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB,&x); //注意:**GPIOB**
y.USART_BaudRate=9600;
y.USART_WordLength=USART_WordLength_8b;
y.USART_StopBits=USART_StopBits_1;
y.USART_Parity=USART_Parity_No;
y.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
y.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART3,&y);
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
USART_Cmd(USART3,ENABLE);
NVIC_Configuration();
}
(2) Configurar prioridad de interrupción
void NVIC_Configuration()
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn; //注意:**USART3_IRQn**
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
}
(3) Función de procesamiento de interrupciones
void USART3_IRQHandler(void) //注意:**USART3_IRQHandler**
{
u8 res;
if(USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET)
{
res= USART_ReceiveData(USART3);
USART_SendData(USART3,res);
}
}
(4) Redirigir la función de envío y recepción (recuerde agregar #include " stdio.h ")
#include "stdio.h"
int fputc(int ch,FILE *f)
{
USART_SendData(USART3,(uint8_t)ch);
while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET);
return (ch);
}
int fgetc(FILE *f)
{
while(USART_GetFlagStatus(USART3,USART_FLAG_RXNE)==RESET);
return (int)USART_ReceiveData(USART3);
}
(5) Finalmente la función principal
int main(void)
{
USART3_Config();
while(1);
}
6. Finalmente, un ejemplo de control de una pequeña luz a través de un puerto serie
(1) Configure el puerto serie (seleccione uno de los tres grupos anteriores al azar, aquí tomamos el grupo 1-PA9, PA10 como ejemplo) (2) Inicialice
la luz pequeña (el pin de mi STM32 para controlar la luz LED es PC13 )
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
}
(3) función de control de luz pequeña
void LED_G(uint8_t n) //LED_G(0): 灯亮 LED_G(1):灯灭
{
if(n)
GPIO_SetBits(GPIOC, GPIO_Pin_13);
else
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
}
(4) Modificar la función principal
#include "stm32f10x.h"
int main(void)
{
USART_Config();
LED_GPIO_Config();
while(1);
}
(5) Modificar la función de interrupción en serie
void USART1_IRQHandler(void) //如果串口发送‘0’则灯亮,(若其他数据)否则灯灭
{
u8 res;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
{
res= USART_ReceiveData(USART1);
USART_SendData(USART1,res);
if(res=='0')
{
LED_G(0);
}
else
{
LED_G(1);
}
}
}
7. Intercambio completo de recursos del proyecto
Enlace: https://pan.baidu.com/s/1UvxMlFSzKVpQfpDA3zxnBA
Código de extracción: o8c7