![[ARM] STM32_UART 기초](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlDyce%2FbtsFUBFde2e%2FoKY5RjtwMVpH1K2JyhhzfK%2Fimg.png)
UART 사용 프로그램
1. Coolterm(간단하게 사용하기 좋음)
https://freeware.the-meiers.org/
Roger Meier's Freeware
THE SOFTWARE TITLES ON THIS WEBSITE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EV
freeware.the-meiers.org
2. Serial plot(데이터를 파형으로 보고싶을 때 사용하기 좋음)
https://hackaday.io/project/5334-serialplot-realtime-plotting-software
SerialPlot - Realtime Plotting Software
This is a Qt based software for plotting data from serial port in real time. IMPORTANT: instead of commenting please consider creating a ticket at issue tracker (https://todo.sr.ht/~hyozd/serialplot or https://github.com/hyOzd/serialplot/issues) Hackaday's
hackaday.io
UART 문장 출력



⦁ printf
는 _write
를 호출 → _write
함수 재설정하여 UART 출력으로 사용
⦁ value
의 주소값과 포인터 변수 pt
에 저장된 값이 동일한 것을 알 수 있다.
1. UART sin그래프 출력

⦁ 각도를 라디안으로 바꾸어 5ms에 한번씩 파형 출력
2. 데이터를 한번에 많이 보내기

while (1)
{
static int angle = 0;
int32_t data[10];
angle++;
angle %= 360;
for(int i = 0; i<10; i++)
{
data[i] = sin((angle + i * 36) * 3.14 / 180) * 10000;
}
uint8_t txBuffer[42];
// data copy to txBuffer
txBuffer[0] = 0xaa; // start point 1
txBuffer[1] = 0xbb; // start point 2
memcpy(&txBuffer[2], data, 40);
HAL_UART_Transmit(&huart2, txBuffer, 42, 10);
HAL_Delay(5);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
2-1. 코드리뷰
txBuffer[0] = 0xaa; // start point 1
txBuffer[1] = 0xbb; // start point 2
→ 데이터의 시작점을 알리는 포인트
for(int i = 0; i<10; i++)
{
data[i] = sin((angle + i * 36) * 3.14 / 180) * 10000;
}
→ 10개짜리 배열에 36도씩 위상차이가 나는 데이터 10개 저장(각 배열의 크기는 32bit)
+ sin 범위는 -1 ~ +1 이기에 확대해서 보기위해 *10000
memcpy(&txBuffer[2], data, 40);
⦁ memcpy(&a, &b, n)
= b의 주소에 저장된 값을 a에 주소에 1byte씩 n번 복사
txBuffer[2] ~ [5] : data[0] 저장
txBuffer[6] ~ [9] : data[1] 저장
…
txBuffer[39] ~ [42] : data[9] 저장
→ data배열 index하나의 크기는 32bit(4byte)이기 때문에 40번 복사(40byte)
⇒ txBuffer에 data를 쭉 저장
3. Interrupt 사용하여 제어

⦁ UART Receive Interrupt 동작 순서
① HAL_UART_Receive_IT(&huart2, rxBuffer, 3);
함수 호출하면 2번 과정 실행
- &huart2
: UART 채널 2번에 대한 configure 값을 가지고 있는 구조체 변수 주소
- rxBuffer
: UART로부터 수신받은 data를 저장할 배열(주소)
- 3
: 몇 글자를 수신받을 것인지 size
② UART 통신을 통해 MCU에 1byte data 수신될 때마다 UART2_IRQHandler()
함수 호출되어 rxBuffer
에 1byte data 저장
③ 2번 과정이 3번 반복(size 크기만큼)되면 UART2 Rx Enable bit clear → 이후 UART Recevie Interrupt 발동 X
④ HAL_UART_RxCpltCallback()
함수 호출
⑤ 다음 UART Receive Interrupt 발동위해 HAL_UART_Receive_IT(&huart2, rxBuffer, 3);
함수 호출
... (과정 반복)
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <stdbool.h>
/* USER CODE END Includes */
/* USER CODE BEGIN 0 */
int _write(int file, char *p, int len)
{
HAL_UART_Transmit(&huart2, p, len, 10);
return len;
}
uint8_t rxBuffer[3];
bool flagState = false; // Boolean type -> 1bit(0 or 1)
// ㅡㅡㅡInterrupt 실행 함수ㅡㅡㅡ
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(rxBuffer[0] == 0x01 && rxBuffer[1] == 0x02 &&
rxBuffer[2] == 0x03)
{
flagState = true;
}
else if(rxBuffer[0] == 0x01 && rxBuffer[1] == 0x02 &&
rxBuffer[2] == 0x04)
{
flagState = false;
}
HAL_UART_Receive_IT(&huart2, rxBuffer, 3);
// Interrupt 한번 실행하고 다음 Interrupt 실행하기 다시 Interrupt 사용 세팅
}
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 2 */
// setup interrupt for uart Rx
// ㅡㅡㅡInterrupt 사용 세팅ㅡㅡㅡ
HAL_UART_Receive_IT(&huart2, rxBuffer, 3);
/* 만약 수신받은 data가 3개이면 실행 -> rxBuffer에 저장 + Interrupt 실행 */
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
static int angle = 0;
int32_t data[10];
angle++;
angle %= 360;
for(int i = 0; i<10; i++)
{
data[i] = sin((angle + i * 36) * 3.14 / 180) * 10000;
}
uint8_t txBuffer[42];
// data copy to txBuffer
txBuffer[0] = 0xaa; // start point 1
txBuffer[1] = 0xbb; // start point 2
memcpy(&txBuffer[2], data, 40);
if (flagState)
{
// flagState 있을 때에만 UART 송신
HAL_UART_Transmit(&huart2, txBuffer, 42, 10);
}
HAL_Delay(1);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

3-1. UART.c 파일 만들기
/*
* UART.h
*
* Created on: Mar 11, 2024
* Author: minseok
*/
#ifndef SRC_UART_H_
#define SRC_UART_H_
#include "main.h"
void initUart(UART_HandleTypeDef inHuart);
uint8_t getChar();
#endif /* SRC_UART_H_ */
/*
* UART.c
*
* Created on: Mar 11, 2024
* Author: minseok
*/
#include "UART.h"
#include <stdio.h>
UART_HandleTypeDef *myHuart;
#define rxBufferMax 255
int rxBufferGp; // get pointer (read)
int rxBufferPp; // put pointer (write)
uint8_t rxBuffer[rxBufferMax];
uint8_t rxChar;
// Device init
// Inetrrupt 사용 세팅(init)
void initUart(UART_HandleTypeDef *inHuart) // Interrupt setting
{
myHuart = inHuart;
HAL_UART_Receive_IT(myHuart, &rxChar, 1);
}
// process received character
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
rxBuffer[rxBufferPp++] = rxChar;
rxBufferPp %= rxBufferMax; // 값이 최대치(rxBufferMax)에 도달하면 0으로 초기화
HAL_UART_Receive_IT(myHuart, &rxChar, 1);
}
// get character form buffer
uint8_t getChar() // data가 있는지 없는지 확인, 있으면 result에 저장
{
uint8_t result;
if(rxBufferGp == rxBufferPp) return 0; // 같다 -> data 없다는 뜻
result = rxBuffer[rxBufferGp++];
rxBufferGp %= rxBufferMax; // 값이 최대치(rxBufferMax)에 도달하면 0으로 초기화
return result;
}
int _write(int file, char *p, int len)
{
HAL_UART_Transmit(myHuart, p, len, 10);
return len;
}

⦁ Ring Buffer
: abc 입력 받으면 void HAL_UART_RxCpltCallback()
함수에서
1. rxBuffer[0] = a, BufferPp = 1
2. rxBuffer[1] = b, BufferPp = 2
3. rxBuffer[2] = c, BufferPp = 3
이후,
uint8_t getChar()
함수에서
1. result = rxBuffer[0] = a, BufferGp = 1, result 반환
2. result = rxBuffer[1] = b, BufferGp = 2, result 반환
3. result = rxBuffer[2] = c, BufferGp = 3 , result 반환
4. BufferGp(3) == BufferPp(3) 이므로 함수 실행 X
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdbool.h>
#include "UART.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
// setup interrupt for uart Rx
initUart(&huart2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
static int angle = 0;
static bool flagState = false;
uint8_t ch;
ch = getChar();
if(ch == 's') flagState = true;
else if(ch == 'p') flagState = false;
int32_t data[10];
angle++;
angle %= 360;
for(int i = 0; i<10; i++)
{
data[i] = sin((angle + i * 36) * 3.14 / 180) * 10000;
}
uint8_t txBuffer[42];
// data copy to txBuffer
txBuffer[0] = 0xaa; // start point 1
txBuffer[1] = 0xbb; // start point 2
memcpy(&txBuffer[2], data, 40);
if (flagState)
{
HAL_UART_Transmit(&huart2, txBuffer, 42, 10);
}
HAL_Delay(1);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
Made By Minseok KIM
'ARM > 1_Study' 카테고리의 다른 글
[ARM] STM32_RTC, Switch (0) | 2024.04.02 |
---|---|
[ARM] STM32_LCD I2C, ADC(polling 방식, DMA 방식), CDS (0) | 2024.03.29 |
[ARM] STM32_Radar (0) | 2024.03.24 |
[ARM] STM32_Buzzer, Ulatrasonic, 필터링, ServoMotor (0) | 2024.03.19 |
[ARM] STM32_TIMER정리, data 전송 flow 구상, PWM(LED, Buzzer) (0) | 2024.03.18 |
Let's Be Happy!
도움이 되었으면 좋겠어요 :)