![[ARM] STM32_Serial Communication(UART), Queue](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbajLO0%2FbtsG0S1mHVh%2F1NvYsDMUMqvbHivFwKUlak%2Fimg.png)
[ARM] STM32_Serial Communication(UART), QueueARM/2_Study2024. 4. 29. 23:43
Table of Contents
1. Serial Communication
동기/비동기 | 통신 방식 | 핀 | 다중 통신 여부 |
Slave 구분 방법 |
속도 | |
UART | 비동기 | 전이중 (Full Duplex) |
TxD, Rxd | 1:1 통신 | X | CLK이 없어 속도의 제한이 있음 |
I2C | 동기 | 반이중 (Half Duplex) |
SCL, SDA | 1:n 통신 | Address | SPI보다 느림 |
SPI | 동기 | 전이중 (Full Duplex) |
CLOCK, MOSI, MISO, CS | 1:n 통신 | CS(Chip Select) | 제일 빠름 |
특징
- I2C
- 반이중 통신으로 송수신 동시 불가
- 데이터 전송에 Address 송신, ACK bit 수신 프로토콜이 추가되어 속도가 SPI에 비해 느림(100kHz, 400kHz)
- 핀 개수 적음
- Pull-up 저항 필요
- SPI
- 속도 가장 빠름 (Mbps)
- 각 Slave별로 CS핀이 필요하여 핀 개수 많음
2. UART Communication
UART Communication Protocol
- baudrate 115200bps : 초당 115200 bit 전송 ← 1클럭에 1bit 전송
⇒ 수신 기기에서 baudrate 다르면 데이터를 제대로 읽을 수 없음
⇒ 송수신 기기 2개의 baudrate 같아야함
- IDLE 상태(데이터 전송하고 있지 않는 상태) : High
- IDLE → Falling edge : Start signal (Trigger signal)
- 8bit 데이터 전송 후 → Rising edge : Stop signal
- Parity bit : 데이터 각 bit의 총합이 짝수/홀수
- 짝수로 설정하면 데이터 총합이 짝수일 때 Parity bit 1
⇒ 송수신 2개 기기 설정이 같아야함
UART 테스트
int _write(int file, char *ptr, int len)
{
HAL_UART_Transmit(&huart2, (uint8_t *)ptr, len, 1000);
return len;
}
...
printf("Hello World\\n");
⇒ `printf()` 사용하기 위한 `_write()` 함수 수정
Polling 방식 & Interrupt 방식
Polling 방식
uint8_t rcvData;
while (1)
{
HAL_UART_Receive(&huart2, &rcvData, 1, 0xfffffff);
if (rcvData == '1')
{
printf("ON!\\n");
}
else if (rcvData == '2')
{
printf("OFF!\\n");
}
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(300);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
Interrupt 방식
uint8_t rcvData;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2)
{
HAL_UART_Transmit(&huart2, &rcvData, 1, 1000);
HAL_UART_Receive_IT(&huart2, &rcvData, 1);
}
}
HAL_UART_Receive_IT(&huart2, &rcvData, 1);
while (1)
{
if (rcvData == '1')
{
printf("ON!\\n");
}
else if (rcvData == '2')
{
printf("OFF!\\n");
}
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(300);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
- Polling 방식
- 데이터 한번 수신 → LED ON → 데이터 한번 수신 → LED OFF …
- 데이터가 수신 되야 Toggle 함수가 실행됨 (300ms마다 LED Toggle 되지 않음) → 오류
- `HAL_UART_Receive()` 함수에서 데이터를 수신할 때 까지 LED Toggle이 실행되지 않음
- Interrupt 방식
- 데이터가 수신되지 않아도 300ms마다 LED Toggle
- 데이터 수신될 때 Intterupt 발생 → 데이터가 수신되지 않을 때는 다른 동작 수행 가능
- `HAL_UART_RxCpltCallback()` : 수신 완료되면 호출되는 함수
- `HAL_UART_Receive_IT()` 호출 → 데이터 수신 → Interrupt 발생 → `HAL_UART_RxCpltCallback(*UART_HandleTypeDef* *huart)` 실행 (Interrupt 완료 후 `HAL_UART_Receive_IT()` 를 다시 호출해야 다음 Interrupt 발생)
3. Queue 자료구조 (FIFO)
: First-In First-Out ↔ Stack(LIFO)
enQue & deQue
int queBuff[4];
int tail = 0;
int head = 0;
void enQue(int data) // push(write)
{
queBuff[tail] = data;
tail = (tail+1) % 4; // tail : 0~3
}
int deQue() // pop(read)
{
int temp = queBuff[head];
head = (head+1) % 4; // head : 0~3
return temp;
}
Queue의 Full & Empty 상태 구분
int queFull()
{
if(head == ((tail+1) % 4))
return 1;
else
return 0;
}
int queEmpty()
{
if(head == tail)
return 1;
else
return 0;
}
⇒ 단점 : 버퍼의 슬롯 1개 사용 불가
보완
int queBuff[4];
int tail = 0;
int head = 0;
int queFull()
{
//if(head == ((tail+1) % 4))
if(queCounter == 4)
return 1;
else
return 0;
}
int queEmpty()
{
//if(head == tail)
if(queCounter == 0)
return 1;
else
return 0;
}
void enQue(int data) // push(write)
{
if(queFull()) return;
queBuff[tail] = data;
tail = (tail+1) % 4; // tail : 0~3
queCOunter++;
}
int deQue() // pop(read)
{
if(queEmpty()) return -1;
int temp = queBuff[head];
head = (head+1) % 4; // head : 0~3
queCOunter--;
return temp;
}
⇒ write하면서 Counter를 하나씩 증가시키고, read하면서 Counter를 하나씩 감소시킴
== Ring Buffer (빨간색 화살표 : tail / 파란색 화살표 : head )
Queue 사용해보기
Queue 사용 X) 12를 전송했을 떄 1은 무시되고 2만 실행됨
Queue 사용 O) 12를 전송했을 떄 무시되지 않고 모두 출력
더보기
main.c
int _write(int file, char *ptr, int len)
{
HAL_UART_Transmit(&huart2, (uint8_t *)ptr, len, 1000);
return len;
}
uint8_t rcvData;
Que_t uart2RxQue;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2)
{
enQue(&uart2RxQue, rcvData);
HAL_UART_Transmit(&huart2, &rcvData, 1, 1000);
HAL_UART_Receive_IT(&huart2, &rcvData, 1);
}
}
int main(void)
{
/* USER CODE BEGIN 2 */
Que_init(&uart2RxQue);
printf("Hello World\n");
HAL_UART_Receive_IT(&huart2, &rcvData, 1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
uint8_t rxData;
while (1)
{
rxData = deQue(&uart2RxQue);
if (rxData == '1')
{
printf("ON!\n");
//rcvData = 0;
}
else if (rxData == '2')
{
printf("OFF!\n");
//rcvData = 0;
}
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(300);
}
/* USER CODE END 3 */
}
Queue 파일
// 헤더 파일
/*
* Queue.h
*
* Created on: Apr 26, 2024
* Author: k1min
*/
#ifndef COMMON_QUEUE_QUEUE_H_
#define COMMON_QUEUE_QUEUE_H_
#include "stm32f4xx_hal.h"
#include "stdint.h"
#define BUF_SIZE 100
typedef struct{
uint8_t QueBuff[BUF_SIZE];
int tail;
int head;
int QueCounter;
}Que_t;
void Que_init(Que_t *Que);
int QueFull(Que_t *Que);
int QueEmpty(Que_t *Que);
void enQue(Que_t *Que, uint8_t data);
int deQue(Que_t *Que);
#endif /* COMMON_QUEUE_QUEUE_H_ */
// 소스 파일
/*
* Queue.c
*
* Created on: Apr 26, 2024
* Author: k1min
*/
#include "Queue.h"
void Que_init(Que_t *Que)
{
Que->head = 0;
Que->tail = 0;
Que->QueCounter = 0;
}
int QueFull(Que_t *Que)
{
//if(head == ((tail+1) % BUF_SIZE))
if(Que->QueCounter == BUF_SIZE)
return 1;
else
return 0;
}
int QueEmpty(Que_t *Que)
{
//if(head == tail)
if(Que->QueCounter == 0)
return 1;
else
return 0;
}
void enQue(Que_t *Que, uint8_t data) // push(write)
{
if(QueFull(Que)) return;
Que->QueBuff[Que->tail] = data;
Que->tail = (Que->tail+1) % BUF_SIZE; // tail : 0~3
Que->QueCounter++;
}
int deQue(Que_t *Que) // pop(read)
{
if(QueEmpty(Que)) return -1;
int temp = Que->QueBuff[Que->head];
Que->head = (Que->head+1) % BUF_SIZE; // head : 0~3
Que->QueCounter--;
return temp;
}
Made By Minseok KIM
'ARM > 2_Study' 카테고리의 다른 글
[ARM] STM32_FreeRTOS, Shared Memory (0) | 2024.04.30 |
---|---|
[ARM] STM32_PWM, Driver(Motor) (0) | 2024.04.29 |
[ARM] STM32_Driver(CLCD I2C, Ultrasonic) (0) | 2024.04.26 |
[ARM] STM32_메모리 저장&실행 과정, Driver(Button, LED) (0) | 2024.04.26 |
[ARM] STM32_Low level Programming (0) | 2024.04.24 |
@민바Minba :: Minba's blog
Let's Be Happy!
도움이 되었으면 좋겠어요 :)