Tengo un problema con STM32L031 Nucleo board comunicación USART.
Estoy intentando enviar datos a PC en USART periódicamente y capturar el carácter específico ('a') con Interrupción de Rx y encender el LED interno cuando el microcontrolador recibe alguno de ellos.
Estos son los problemas que encontré durante la prueba:
-
El microcontrolador envió los datos periódicamente a la PC, pero los datos se corrompieron cuando se trataba de PC. La cadena original era " STM32L031 USART Test " pero cuando la recibió de la PC fue " S⸮M3⸮⸮03⸮⸮USA⸮Ԡ⸮e⸮t ".
-
Cuando envío el carácter 'a' de la PC al microcontrolador; el controlador de interrupciones activó y apagó el LED con éxito. Después de recibir los datos, el microcontrolador se detuvo para enviar datos a la PC, pero continúa recibiendo el carácter y activando el controlador de interrupciones con éxito.
Utilicé los Controladores de bajo nivel (LL) de ST en mi programa, aquí están mis rutinas.
Esta es una función para la configuración del reloj del sistema, utilicé HSI (16MHz - Reloj interno de alta velocidad) como fuente de PLL y usé el reloj de 24 MHz PLL como reloj del sistema.
/**
* @brief This function configurates the system clock as:
* - uses HSI as PLL source
* - uses PLL as system clock at 24 MHz
* @param none
* @retval none
*/
void System_ClockConfiguration(void)
{
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE3); // regulator configuraiton in order to freq
/* high speed internal (HSI - 16MHz) system clock avtivating
* in order to use for PLL source clock */
LL_RCC_HSI_Enable();
LL_RCC_HSI_DisableDivider();
/* PLL configuration */
LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLL_MUL_6, LL_RCC_PLL_DIV_4);
LL_RCC_PLL_Enable();
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); // set system clock source as PLL
/* peripheral clock divide value configuraiton */
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_SYSCLK_DIV_2);
SystemCoreClockUpdate(); // system clock updating
}
Aquí está mi configuración de USART2:
/**
* @brief This function initializes the USART2
* @param none
* @retval none
*/
void USART2_Init(void)
{
LL_USART_InitTypeDef LL_Usart_InitStruct; // USART initialization struct
LL_GPIO_InitTypeDef LL_GPIO_Initstruct; // GPIO initialization struct
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA); // Clock freq activated for GPIOA peripheral
/* GPIO pin configuration */
LL_GPIO_Initstruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Initstruct.Mode = LL_GPIO_MODE_ALTERNATE;
LL_GPIO_Initstruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
LL_GPIO_Initstruct.Pin = LL_GPIO_PIN_9; // Tx Pin
LL_GPIO_Initstruct.Pull = LL_GPIO_PULL_UP;
LL_GPIO_Initstruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
LL_GPIO_Init(GPIOA, &LL_GPIO_Initstruct); // GPIO pin initialize
LL_GPIO_Initstruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Initstruct.Mode = LL_GPIO_MODE_ALTERNATE;
LL_GPIO_Initstruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
LL_GPIO_Initstruct.Pin = LL_GPIO_PIN_10; // Rx Pin
LL_GPIO_Initstruct.Pull = LL_GPIO_PULL_UP;
LL_GPIO_Initstruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
LL_GPIO_Init(GPIOA, &LL_GPIO_Initstruct); // GPIO pin initialize
/* Important: we need to disable related USART first in order to write
* USART segisters properly! */
LL_USART_Disable(USART2);
LL_USART_DeInit(USART2);
LL_RCC_SetUSARTClockSource(LL_RCC_USART2_CLKSOURCE_SYSCLK); // define usart clocksource as system clock
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2); // Clock freq activated for USART2 peripheral
/* USART initialization struct configurations */
LL_Usart_InitStruct.BaudRate = 9600;
LL_Usart_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
LL_Usart_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
LL_Usart_InitStruct.Parity = LL_USART_PARITY_NONE;
LL_Usart_InitStruct.StopBits = LL_USART_STOPBITS_1;
LL_Usart_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
LL_USART_Init(USART2, &LL_Usart_InitStruct); // edit USART registers from related struct
/* NVIC Configuration */
__NVIC_DisableIRQ(USART2_IRQn);
__NVIC_ClearPendingIRQ(USART2_IRQn);
__NVIC_SetPriority(USART2_IRQn, 1);
__NVIC_SetVector(USART2_IRQn, USART2_IRQn);
__NVIC_EnableIRQ(USART2_IRQn);
LL_USART_Enable(USART2); // enable USART
}
Aquí está mi función de controlador de interrupciones:
/**
* @brief USART2 interrupt handler
* @param none
* @retval none
*/
void USART2_IRQHandler(void)
{
if((USART2->ISR & USART_ISR_RXNE) == USART_ISR_RXNE)
{
char t = USART2->RDR;
if(t == 'a')
{
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_3);
}
}
}
La función que utilicé para enviar los datos en USART:
/**
* @brief This function is used for transmit a character array
* through USART communication
* @param USARTx
* @param txArray
* @retval none
*/
void USART_Puts(USART_TypeDef* USARTx, volatile char *txArray)
{
while(*txArray)
{
while(!(USARTx ->ISR & 0x0040)); // wait for the USART until its available again (TC bit)
LL_USART_TransmitData8(USART2, *txArray); // send the data
*txArray++; // jump to next array member (next character)
}
}
Finalmente, aquí está la función principal de mi programa:
char str[50]; // USART buffer string
int32_t i = 0; // general purpose
char t;
/**
* @brief Program entry point
* @param none
* @retval none
*/
int main(void)
{
System_ClockConfiguration(); // system clock configuration
LED3_Init(); // on board LED initialization
USART2_Init(); // USART2 initialization
/* main loop */
while(1)
{
sprintf(str, "STM32L031 USART Test\n");
USART_Puts(USART2, str);
i = 150000;
/* basic delay */
while(i)
{
i--;
}
}
}