Gặp vấn đề với STM32 UART

Dạ em chào các anh các chị ạ. Hiện tại em đang viết 1 chương trình đơn giản để test UART của stm32f10c8t6 . Em có sử dụng ngắt nhận RX của UART. Chương trình của em là khi nhận được dữ liệu từ UART thì sẽ xảy ra ngắt RX và chương trình trong ngắt là toggle led và gửi lại dữ liệu đã nhận được qua UART về máy tính. Nhưng mà hiện tại khi chương trình được upload lên stm32, khi gửi dữ liệu thì ngắt UART vẫn nhận được, đèn led vẫn được toggle bình thường nhưng stm32 không gửi lại dữ liệu qua UART cho máy tính. Gửi dữ liệu bình thường từ STM32 sang máy tính cũng không được ạ. Có ai biết về vấn đề này không ạ, chỉ em với ạ. Em cảm ơn ạ !
Đây là code trong main.c.

#include "main.h"
#include "stm32f10x.h"

#define USART_IT_Rx

GPIO_InitTypeDef 		GPIO_InitStructure;
USART_InitTypeDef 		USART_InitStructure;
USART_ClockInitTypeDef 	USART_ClockInitStructure;
NVIC_InitTypeDef		NVIC_InitStructure;

void Delay(int time);
void GPIO_Conf(void);
void RCC_Conf(void);
void USART_Conf(void);

int main(void)
{
	RCC_Conf();
	GPIO_Conf();
	USART_Conf();

	USART_PutString("START \n");
	USART_PutString("START \n");
	USART_PutString("START \n");
	USART_PutString("START \n");
	USART_PutString("START \n");


	while(1);

}

void GPIO_Conf(void)
{
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOC, &GPIO_InitStructure);

	// Config USART 1: Tx(PA9); Rx(PA10)
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

	GPIO_Init(GPIOA, &GPIO_InitStructure);

//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//
//	GPIO_Init(GPIOA, &GPIO_InitStructure);


}

void RCC_Conf(void)
{
	// RCC enable USART1
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

}


void USART_Conf(void)
{
	USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;

	USART_Init(USART1, &USART_InitStructure);

	USART_ClockInitStructure.USART_CPHA =	USART_CPHA_2Edge;
	USART_ClockInitStructure.USART_CPOL =	USART_CPOL_Low;
	USART_ClockInitStructure.USART_Clock =	USART_Clock_Disable;
	USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;

	USART_ClockInit(USART1, &USART_ClockInitStructure);
	USART_Cmd(USART1, ENABLE);

#ifdef	USART_IT_Rx
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  // Init Rx receive interrupt

	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

	NVIC_Init(&NVIC_InitStructure);

#endif



}

char USART_PutChar(char ch)
{
	USART_SendData(USART2,ch);
	while (!(USART1->SR & USART_FLAG_TXE));
	return ch;
}

void USART_PutString(char *pString)
{
    while(*pString){
    	      USART_SendData(USART2,*pString);
    	      while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) != SET);
    	      pString++;
    }
}

void Led_Status(int led_number, int Status)
{
	if(Status)
	{
		switch(led_number)
		{
		case 1:
			GPIO_ResetBits(GPIOA,GPIO_Pin_4);
			break;
		case 2:
			GPIO_ResetBits(GPIOA,GPIO_Pin_5);
			break;
		case 3:
			GPIO_ResetBits(GPIOA,GPIO_Pin_6);
			break;
		default:
			break;
		}
	}else
	{
		switch(led_number)
		{
		case 1:
			GPIO_SetBits(GPIOA,GPIO_Pin_4);
			break;
		case 2:
			GPIO_SetBits(GPIOA,GPIO_Pin_5);
			break;
		case 3:
			GPIO_SetBits(GPIOA,GPIO_Pin_6);
			break;
		default:
			break;
		}
	}
}

void Delay(int time)
{
	while(time--);
}

Đây là code trong stm32f10x_it.c

void USART1_IRQHandler(void)
{
	uint16_t data;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
		GPIO_WriteBit(GPIOC, GPIO_Pin_13, (BitAction)(1^GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13)));
		data = USART_ReceiveData(USART1);
		if (USART_GetITStatus(USART1, USART_IT_TXE) == RESET)
		{
			USART_SendData(USART1, data);
		}
	}
}

Coi lại 2 thằng này xem. Không set interrupt TX thì làm gì có USART_IT_TXE mà check.
Nối dây RX và TX của board STM32 làm thành cái loop, tự gửi tự nhận xem.
Mà sao để PA10 là FLOATING vậy? Thường là GPIO_Mode_AF_PP chứ nhỉ.

Copy code mẫu trên mạng về chạy thử simple uart trước, rồi modify sau.

3 Likes

Dạ anh!
Chân PA10 là chân Rx của UART, nên khi em chạy chương trình trên board thì ngắt Rx vẫn xảy ra bình thường nên em nghĩ để Input FLOATING vẫn được. Em có sửa lại thành GPIO_Mode_AF_PP thì board vẫn nhận dữ liệu bình thường nên em nghĩ lỗi không nằm ở đấy.
Còn về USART_IT_TXE thì e có bỏ 2 câu lệnh while đấy đi rồi.
Nhưng vẫn không sửa được. USART trên board chỉ nhận được dữ liệu chứ không thể gửi dữ liệu được. Nối 2 chân Tx với Rx với nhau thì ngắt cũng không xảy ra do board không gửi dữ liệu được ạ.
Việc nhận dữ liệu thì vẫn nhân bth, nhưng không thể gửi được ạ !

Init UART1 mà send UART2 thì sao chạy đc :smiley:
Copy code không thèm nhìn.

2 Likes

Chỗ đấy em nhầm thật. Nhưng trong trình phục vụ ngắt của USART e có sử dụng hàm USART_SendData đúng nhưng nó không gửi. Em sửa lại thành USART1 vẫn không gửi được ạ !

  1. Debug bằng IDE hoặc bằng LED đi. Xem thử nó có bị dừng ở mấy chỗ như:

… không.
Nếu nó chạy qua được thì chứng tỏ config sai. Còn nếu nó lặp vô tận ở đó chứng tỏ … config sai luôn. :smiley:

Trường hợp 1 là config output sai. Ví dụ thiếu internal Pull Up. Bạn có thể dùng đồng hồ đo điện để xem điện áp output có ở mức cao không. Nếu không có đồng hồ thì dùng 1 con LED nối trở rồi nối đất chân đó.
Trường hợp 2 là config init sai hoặc bạn sử dụng cờ đó sai mục đích.

  1. Bạn thử lấy code mẫu của nó chạy coi TX xài được không đã. Mình đã nói ngay từ post đầu rồi. Phải chắn chắn là setup phần cứng không sai, demo mẫu chạy được rồi mới làm tiếp được. Sau khi xác nhận code mẫu chạy thì dùng 1 tool compare (ví dụ Beyond compare) để xem code của bạn và code mẫu khác nhau cái gì.

Cái này chưa chắc đúng nhé, bỏ phần IT đi thôi. Tốt nhất là tham khảo code mẫu. Vì một số phần cứng phải có while đó để chờ output send xong mới send next character được. Do đó đừng assume nó chạy thế nào mà nên tham khảo example.

  1. Bạn phải chắc chắn là phía PC nhận TX RX bình thường (bằng cách thiết lập loop).

Đây là debug phần cứng, mình không có phần cứng để debug giúp bạn. Bạn phải sử dụng mọi thứ bạn có thể để debug.

Debug chuyên sâu hơn thì đọc datasheet, dùng oscilloscope để đo tín hiệu, vân vân. Nhưng chắc bạn không cần làm tới mức này.

Đây là một lĩnh vực thú vị và cũng rất cực vì khó ai giúp được mình trong 1 vấn đề cụ thể như các bộ môn phần mềm khác. Hi vọng bạn tiếp tục kiên trì. Hãy post các update mới lên theo các hướng dẫn ở trên, mình sẽ giúp bạn tiếp.

2 Likes

Dạ vâng anh ạ. Em sẽ thử hết các trường hợp. Em cảm ơn anh nhiều ạ. Em sẽ update lên nếu em vướng mắc hoặc có vấn đề gì anh ạ !

Nếu giải quyết được rồi thì update solution lên cho cộng đồng nhé bạn.

2 Likes

Em chưa giải quyết được ạ. Tại cuối tuần em về quê nên chưa thực hiện được ạ. Nay em có thử thì khi em nối dây Tx với Rx và sử dụng LED thì em thấy là tín hiệu vẫn được gửi đi từ Tx bình thường, không có vấn đề gì ạ. Em đã thử mô phỏng bằng proteus thì khi đo tín hiệu từ chân Tx vẫn thu được xung ạ ( Em để mặc định gửi chuỗi “START \n” vài lần ), nhưng khi sử dụng Terminal Monitor hay sử dụng PL2303 thì đều không nhận được dữ liệu ạ. Dù Tx vẫn gửi dữ liệu. Nay em mới thử được nên em mới update lên ạ

1 Like

Con chip bạn sử dụng là dòng chip STM32F100, do đó, điện áp chân ra là 3.3V.

The STM32F100xx low- and medium-density devices operate in the – 40 to + 85 °C and – 40 to + 105 °C temperature ranges, from a 2.0 to 3.6 V power supply.

Trong trường hợp này, module PL2303 là module nhận UART ở mức điện áp 5v nên không thể bắt được tín hiệu từ STM32.

Bạn cần sử dụng 1 module UART khác có thể đọc UART ở mức 3V-3.3V, hoặc sử dụng một module trung gian để chuyển đổi mức điện áp 3.3V-5V.
Nếu bạn thích vọc phá thì tự chế ra cầu điện trở để convert.

Protues chỉ là mô phỏng nên có thể bỏ qua điện áp convert.

2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?