La USART es un módulo de comunicación serial asíncrona. Implementa la comunicación full-Duplex (Puede transmitir y Recibir información al mismo tiempo). Por lo tanto, usan dos canales, uno de transmisión Tx y uno de recepción Rx.
NOTA: Los pines deben ser configurados en modo Alterno
La comunicación USART tiene un bit de inicio, 8 bits máximos de comunicación y 1, 1.5 o 2 bits de parada (stop). La STM32401 posee USART1, USART2, y USART6 Pines de USART para la STM32F401RE
| USART | Tx | Rx |
|---|---|---|
| USART1 | PA9 , PB6 | PA10 |
| USART2 | PA2 | PA3 |
| USART6 | PA11, PC6 | PA12 |
Reloj: RCC → APB: Habilitar el reloj de la USART
Baud Rate Register: USARTx_BRR: Configura la velocidad de comunicación del módulo. Se usa la siguiente fórmula:
$$ BRR = \frac{FCLK_{UART}}{Vel.Deseada} \rightarrow \frac{16MHz}{9600bps} = 1666.66 = 1666 \rightarrow 0X682 $$
| Velocidad | Valor Decimal | Código Hexadecimal |
|---|---|---|
| 1200 | 13333.33 | 0X3415 |
| 4800 | 3333.33 | 0XD05 |
| 9600 | 1666.66 | 0X682 |
| 19200 | 833.33 | 0X341 |
| 38400 | 416.66 | 0X1A0 |
| 57600 | 277.77 | 0X115 |
| 115200 | 138.88 | 0X8A |
USARTx_CR1 → Se Habilitan los bits 2 (RE) para habilitar recepción, bit 3 (TE) para habilitar Transmisión, bit 5 (RXENEIE) para habilitar interrupción de Recepción y bit 13 (UE) para habilitar el funcionamiento general del puerto USART. En la configuración, se deben habilitar los bits 2, 3 y 5. En el while(1) se habilita el bit 13.
FUNCIONES ALTERNAS A UTILIZAR Se usan AFR[3:0] → 0111 → USART1/2 AF7 1000 → USART6 AF8
Para USART1 en PA9 y PA10 → GPIOA→ AFR[1] |= 0X770;
****Para USART1 en PB6 y PA10 → GPIOA → AFR[1] |= 0X700; ****GPIOB → AFR[0] |= 0X7000000;
****Para USART2 en PA2 y PA3 → GPIOA → AFR[0] |=0X7700;
****Para USART6 en PA11 y PA12 → GPIOA → AFR[1] |= 0X88000;
****Para USART6 en PC6 y PA12 → GPIOC → AFR[0] |= 0X8000000; ****GPIOA → AFR[1] |= 0X80000;
**NOTA: Si se quieren transmitir datos desde la tarjeta hacia el computador usando USART se deberá usar la USART2 sin necesidad de usar los pines PA2 y PA3, solo requiere del cable de datos.
LOS EJEMPLOS A CONTINUACIÓN ENVIAN EL MISMO DATO QUE RECIBEN**
Esta librería proporciona funciones para enviar a monitores seriales como el de arduino IDE o CoolTerm, Las funciones tienen un uso similar al del entorno de Arduino.
//Nombre de la ibrería Serial.h
#include "stm32f4xx.h"
#include <stdio.h>
#include <string>
/*Función de configuración para USART con PC
Pines PA2 y PA3*/
void confi_usart2_PA2_PA3(unsigned int velocidad){ //USART2 PA2 y PA3
GPIOA->MODER |= 0XA0; //1010 0000 ALTERNATIVO PA2 PA3
GPIOA->AFR[0] |= 0X7700; //Función Alternativa
RCC ->APB1ENR |= (1UL<<17); //Habilitar reloj USART2
USART2->BRR = (unsigned int)(16000000/velocidad); //Puerto a 9600bps
USART2->CR1 |=0X2C; //0000 0000 0010 1100 Habilita TX, RX e Interrup RX
USART2->CR2 = 0;
USART2->CR3 = 0;
NVIC_EnableIRQ(USART2_IRQn); // Activa vector interrupción
USART2->CR1 |= (1UL<<13); //Activa el USART bit UE
}
/*Función para enviar caracteres tipo ASCII
Sin salto de linea*/
void Serial_print_siu(const char* cmd) {
while (*cmd) {
USART2->DR = *cmd++;
while (!(USART2->SR & USART_SR_TXE));
}
}
// Sobrecarga para enteros
void Serial_print(int cmd) {
char dist[50] = {};
sprintf(dist, "%d", cmd); // Convierte el entero a cadena y concatena con `val`
Serial_print_siu(dist);
}
// Sobrecarga para double
void Serial_print(double cmd) {
char dist[50] = {};
sprintf(dist, "%.*f", 9, cmd); // Convierte el double a cadena y concatena con `val`
Serial_print_siu(dist);
}
// Sobrecarga para flotantes
void Serial_print(float cmd) {
char dist[50] = {};
sprintf(dist, "%.4f", cmd); // Convierte el flotante a cadena y concatena con `val`
Serial_print_siu(dist);
}
// Versión original para cadenas
void Serial_print(const char* cmd) {
char dist[50] = {};
sprintf(dist, "%s", cmd); // Concatenación con cadena y carácter
Serial_print_siu(dist);
}
/*Función para enviar caracteres tipo ASCII
Con salto de linea*/
void Serial_println_siu(const char* cmd) {
while (*cmd) {
USART2->DR = *cmd++;
while (!(USART2->SR & USART_SR_TXE));
}
USART2->DR = '\n';
while (!(USART2->SR & USART_SR_TXE));
}
/*Función para enviar caracteres tipo Byte
Tiene un argumento:
1. Valores a enviar puede ser un vector de n valores*/
/*void Serial_write(const uint8_t* data) {
uint16_t length = sizeof(data);
for (uint16_t i = 0; i < length; i++) {
USART2->DR = data[i]; // Enviar un byte
while (!(USART2->SR & USART_SR_TXE)); // Esperar a que el registro de datos esté vacío
}
}*/
void Serial_write(uint8_t data) {
USART2->DR = data; // Enviar un byte
while (!(USART2->SR & USART_SR_TXE)); // Esperar a que el registro de datos esté vacío
}
// Sobrecarga para enteros
void Serial_println(int cmd) {
char dist[50] = {};
sprintf(dist, "%d", cmd); // Convierte el entero a cadena y concatena con `val`
Serial_println_siu(dist);
}
// Sobrecarga para double
void Serial_println(double cmd) {
char dist[50] = {};
sprintf(dist, "%.*f", 9, cmd); // Convierte el double a cadena y concatena con `val`
Serial_println_siu(dist);
}
// Sobrecarga para flotantes
void Serial_println(float cmd) {
char dist[50] = {};
sprintf(dist, "%.4f", cmd); // Convierte el flotante a cadena y concatena con `val`
Serial_println_siu(dist);
}
// Versión original para cadenas
void Serial_println(const char* cmd) {
char dist[50] = {};
sprintf(dist, "%s", cmd); // Concatenación con cadena y carácter
Serial_println_siu(dist);
}
char Dato;
extern "C"{
void USART2_IRQHandler(void){
Dato=USART2->SR; // Limpiar banderas
Dato=USART2->DR; // Lee dato
while(!(USART2->SR&USART_SR_TXE)); // Espera puerto disponible
}
}
#include "stm32f4xx.h"
#include "Serial.h"
#include <stdio.h>
#include <string>
void Delay_ms(int x){
for(volatile int i=0;i<x*940; i++){ //Cambiar el 940 por un valor para que de cerca en ms
asm("nop");
}
}
int main(void){
RCC->AHB1ENR |= 0X7; //Activa relojes
confi_usart2_PA2_PA3(115200);
float siu = 22.34;
while(1){
uint8_t byte[] = {0x41,0x42,0x43}; //Valores: 'A' 'B' 'C'
Delay_ms(1000);
Serial_print("Imprimo un entero: "); Serial_println(77);
Delay_ms(1000);
Serial_print("Imprimo un double: "); Serial_println(45.1234567890);
Delay_ms(1000);
Serial_print("Imprimo un float: "); Serial_println(siu);
Delay_ms(1000);
Serial_print("Imprimo un String: "); Serial_println("Siu");
Delay_ms(1000);
Serial_print("Imprimo un byte: ");
for(int i = 0; i<3;i++){
Serial_write(byte[i]);}
Serial_println("");Serial_println("");
}
return 0;
}

#include "stm32f4xx.h"
extern "C"{
void USART1_IRQHandler(void){
unsigned char Dato;
Dato=USART1->SR; // Limpiar banderas
Dato=USART1->DR; // Lee dato
while(!(USART1->SR&USART_SR_TXE)); // Espera puerto disponible
USART1->DR=Dato; // Transmite dato
}
}
void confi_usart1_PA9_PA10(unsigned int velocidad){
//USART1 PA9 y PA10
GPIOA->MODER |= 0X280000; //0010 1000 0000 0000 0000 0000 ALTERNATIVO PA9 PA10
GPIOA->AFR[1] |= 0X770; //Función Alternativa
RCC ->APB2ENR |= (1UL<<4); //Habilitar reloj USART1
USART1->BRR = (unsigned int)(16000000/velocidad); //Puerto a 9600bps
USART1->CR1 |=0X2C; //0000 0000 0010 1100 Habilita TX, RX e Interrup RX
USART1->CR2 = 0;
USART1->CR3 = 0;
NVIC_EnableIRQ(USART1_IRQn); // Activa vector interrupción
USART1->CR1 |= (1UL<<13); //Activa el USART bit UE
}
int main(void){
RCC->AHB1ENR |= 0X7; //Activa relojes
confi_usart1_PA9_PA10(9600);
while(1){}
return 0;
}
