Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6
Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

A, Giới thiệu

UART – Universal asynchronous receiver transmitter bộ truyền nhận nối tiếp không đồng bộ là một ngoại vi cơ bản sử dụng hai đường TxD và RxD để truyền và nhận dữ liệu và thường được dùng để giao tiếp với các module như Zigbee, Bluetooth, Wifi…

Ưu điểm:  vi điều khiển có khả năng truyền-nhận nhiều dữ liệu, tiết kiệm đường đường IO, dễ kết nối nó phù hợp nhất khi chỉ cần duy nhất 2 thiết bị giao tiếp với nhau.

Nhược điểm: Vì là truyền thông nối tiếp nên tốc độ là chậm hơn so với so với các phương thức truyền song song.

Các thiết bị yêu cầu khi làm: FT232 USB to serial ,PL2303, CP2012 or CH340 …

Sơ đồ Kết nối:

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

1, UART trong stm32f103C8T6

a, Khung dữ liệu:

Ngoài việc giống nhau của tốc độ baud 2 thiết bị truyền nhận thì khung truyền của bên cũng được cấu hình giống nhau. Khung truyền quy định số bit trong mỗi lần truyền,Start bit, Stop bit, Parity bit, ngoài ra số bit quy định trong một gói dữ liệu cũng được quy định bởi khung truyền.

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

khung truyền dữ liệu của bộ USART gồm 1 Start bit, data (8 hoặc 9 bits tùy người dùng cấu hình), 0.5/1/1.5/2 stops bits. Độ dài của data được lập trình bằng cách ghi mức logic 1 hoặc 0 vào M bit của thanh ghi USART_CR1.

Một số thuận ngữ:

  • Start bit: Là bit đầu tiên của frame nó báo hiệu rằng dòng dữ liệu đã rời khỏi trạng thái idle ( UART luôn ở trạng thái cao mức HIGH cho đến khi chip muốn truyền dữ liệu đi thì nó gởi bit start bằng cách kéo xuống mức LOW) Data sẽ được truyền từ thời điểm này.
  • Stop bit: Là bit cuối cùng của frame nó báo hiệu rằng Data đã được gửu xong. Stop bits có thể là 1bit, 1.5bit, 2bit, 0.5bit

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

  • Baudrate: Số bit truyền được trong 1s, ở truyền nhận không đồng bộ thì ở các bên truyền và nhận phải thống nhất Baudrate.

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

  • Parity bit: Dùng để kiếm tra tính đúng đắn của dữ liệu. Có 2 loại Parity đó là Parity chẵn (even parity) và parity lẽ (odd parity), bit này không bắt buộc.
  • Data: Data hay dữ liệu là thông tin mà chúng ta nhận được trong quá trình truyền và nhận. Data trong STM32 có quy định khung truyền là 8bit hoặc 9bit. Trong quá trình truyền UART, bit có trọng số thấp nhất (LSB – least significant bit – bên phải) sẽ được truyền trước và cuối cùng là bit có ảnh hưởng cao nhất (MSB – most significant bit – bên trái)

b, Quá trình truyền data

Data từ đường bus sẽ được lưu trong bộ đệm TDR. Khi bit cho phép truyền (TE) được set, dữ liệu sẽ được đưa xuống thanh ghi Transmit Shift Register và bit có trọng số thấp nhất (LSB) sẽ được gửi đi đầu tiên trên chân TX MCU. Sau khi truyền đi một byte, thanh ghi TDR sẽ được làm trống và byte tiếp theo có thể được truyền đi. Ở chế độ này dữ liệu của thanh ghi USART_DR chính là dữ liệu của bộ đệm TDR.

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

c, Quá trình nhận data

Khi có dữ liệu được truyền từ thiết bị bên ngoài, bit có trọng số thấp nhất của frame data đầu tiên được truyền qua chân RX của MCU và lưu vào thanh ghi Receive Shift Register. Khi một byte đã nhận xong, bit RXNE (Read data register not empty) set lên 1, dữ liệu chứa trong thanh ghi Receive Shift Register được đưa đến bộ đệm RDR, dữ liệu lúc này đã sẵn sàng để đọc. Nếu bit RXNE và bitRXNEIE (RXNE interrupt enable) cùng set lên 1 thì một tín hiệu ngắt sẽ được sinh ra. Bit RXNE được reset khi có hoạt động đọc dữ liệu trên thanh ghi USART_DR hoặc khi ghi bit ‘0’ vào nó. Tuy nhiên nếu quá trình nhận dữ liệu xảy ra các vấn đề sau thì các error flags tương ứng sẽ được set lên 1:

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

Overrun error: Lỗi này xảy ra khi một byte dữ liệu được nhận trong lúc bit RXNE (Rx not empty) chưa được reset dẫn đến dữ liệu không được chuyển từ thanh ghi Shift Register qua bộ đệm RDR. Bất cứ dữ liệu nào được nhận trong quá trình overrun sẽ bị mất.

Frame error: Lỗi này xảy ra khi stop bit không được nhận ra tại thời điểm dự kiến vì xảy ra nhiễu hay bị mất đồng bộ. Thông thường một frame data chứa 1 Stop bit và được lấy mẫu ở các thời điểm mẫu thứ 8, 9, 10.

2, Một số tính năng chính

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

  • Đầy đủ các tính năng của bộ giao tiếp không đồng bộ.
  • Điều chỉnh baud rate bằng lập trình và tốc độ tối đa lên đến 4.5Mb/s.
  • Độ dài được lập trình là 8 hoặc 9 bit.
  • Cấu hình bit stop hỗ trợ là 1 hoặc 2.
  • Có chân clock nếu muốn chuyển giao tiếp thành đồng bộ.
  • Cấu hình sử dụng 1 dây hoặc 2 dây.
  • Có bộ DMA nếu muốn đẩy cao thời gian truyền nhận.
  • Bit cho phép truyền nhận riêng biệt.
  • Các cờ báo lỗi : Overrun error, Noise error, Frame error, Parity error.
  • Kiểm tra dữ liệu thông qua các bit chẵn, lẻ.

3, một số thanh ghi quan trọng

1. USART_DR – Data register.

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

Thanh ghi này chứa Data nhận và Data truyền gồm 9bit. Và nó phụ thuộc vào trạng thái truyền hoặc nhận sẽ quyết định đó là data truyền hoặc data nhận. MSB bit là bit parity được dùng để kiểm tra dữ liệu, bit này có thể có hoặc không.

2. USART_SR – Status register.Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

  • TXE : bit báo có data đã truyền hay không

+ TXE = 1 :  Dữ liệu đã truyền tới thanh ghi TDR, thanh ghi USART_DR rỗng.

+ TXE = 0 : Dữ liệu chưa truyền tới thanh ghi TDR, thanh ghi USART_DR vẫn chứa kí tự gửu.

  • RXNE: bit báo data đã nhận hay chưa =1: đã nhận, =0 chưa nhận hoặc nhận chưa xong.

+ RXE = 1 : Đã nhận được dữ liệu, thanh ghi USART_DR not empty

+ RXE = 0 : Chưa nhận hoặc nhận chưa xong, thanh ghi USART_DR empty

  • TC : cờ báo đã nhận data hoặc data vừa mới truyền xong.

3. USART_BRR – Baud rate register.

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

Thanh ghi này chứa giá trị tốc độ baund được cài đặt. DIV_Mantissa[11:0] là thành phần trước dấu “,” và DIV_Freaction[3:0] là thành phần sau dấu phẩy của tốc độ baud được quy đổi theo bảng sau:

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

Công thức tính tốc độ baud:

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

4. USART_CR1 – Control register.Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

  • UE: bit cho phép UART hoạt động.
  • M: độ dài của data là 8 hay 9 bit.
  • WAKE: phương pháp đánh thức UART là Idle line hoặc Address Mask.
  • PCE : cho phép hoặc k cho phép parity.
  • PS: chọn loại Parity chẵn hoặc lẻ.
  • PEIE: cho phép ngắt PE hay k ngắt.
  • TXEIE: cho phép ngắt truyền hay k.
  • TCIE: cho phép ngắt khi truyền/nhận xong hay k.
  • RXNEIE: cho phép ngắt nhận hay k.
  • TE: cho phép truyền hay k.
  • RE: cho phép nhận hay k.
  • RWU : cho phép thức tỉnh hay không khi nhận dc data từ bên ngoài.

5. USART_GTPR – Guard time and prescaler register.

Hướng dẫn lập trình UART trong vi điều khiển STM32F103C8T6

PSC[7:0] (Prescaler value) :  Bộ chia clock cho USART

GT[7:0] (Guard time value) : sử dụng trong chế độ Smartcard, Cờ TC sẽ được set sau Guard time value

B, DEV CODE

VD: Viết chương trình VĐK nhận được kí tự nào từ máy tính thì gửi lại kí tự đó lên lại máy tính. Sử dụng phần mềm hercules để gửi và quan sát kí tự nhận được.

link tải phần mềm hesrcules: tại đây

Phải để đúng tốc độ baund thì mới hiển thị đúng kí tự. Cài đặt đúng cổng COM, datasize, parity. Để đúng mode hex, text… Cho phép CR/LF hay không.

Cấu hình chân GPIO

void GPIO_Config(void)
{
     GPIO_InitTypeDef GPIO_InitStructure;
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); /*enable clock*/
     /* 
        USART1_Rx : PA10  input floating 
        USART1_Tx : PA9  alternate function push-pull
     */
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
     GPIO_Init( GPIOA, &GPIO_InitStructure );

     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
     GPIO_Init( GPIOA, &GPIO_InitStructure );
}

Cấu hình UART

void UART_Config(void)
{
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef	NVIC_InitStructure;
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE );
        /* configuration UART */
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	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);
	/* configuration NVIC*/
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

        USART_ClearFlag(USART1, USART_IT_RXNE);
        USART_ITConfig( USART1, USART_IT_RXNE, ENABLE ); //Enable RX interrupt 
        USART_Cmd( USART1, ENABLE );
}

Hàm phục vụ ngắt

void USART1_IRQHandler()
{
	uint16_t data;
	if(USART_GetITStatus(USART1, USART_FLAG_RXNE)==SET){ 
		data = USART_ReceiveData(USART1);
		if(USART_GetITStatus(USART1, USART_FLAG_TXE) == RESET){
			USART_SendData(USART1, data);
		}
	}
}

Một số hàm khác

+ hàm gửu string:

uint32_t SendChar(char ch)
{
  USART_SendData(USART1, (unsigned char) ch);
  while (!(USART1->SR & USART_FLAG_TXE));
}

void SendString( const char *pcString )
{
  while(*pcString != '\0')
  {
    USART_SendData(USART1, *pcString);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    pcString++;
  }
}

 

Link Source code: tại đây