이번 과정은 STM32 보드와 추가로 제작된 확장보드 및 RC카 구동체를 이용해서 자동차를 제어하기 위한 간단한 프로그램을 만드는 과정의 두 번째로 확장보드의 LED와 BUZZER를 제어하는 과정입니다.
아래 과정은 이전 과정을 완료 후 진행하시길 추천드립니다.
1. 통신규격 정의하기
- 우선 STM32 보드를 제어하기 위한 프로토콜을 아래와 같이 정의하였습니다.
◦ START FLAG: 명령의 시작을 의미하는 flag (0xFF 고정 값)
◦ LENGTH: START FLAG와 LENGTH를 제외한 나머지 데이터의 길이
◦ SEQUENE NO: 1 ~ 0xFE 사이의 명령 일련번호, 0xFF에 도달하면 다시 1부터 시작
◦ COMMAND: 수행할 명령어 (bsp_uart.h 파일에 정의)
◦ RESULT: 명령어 수행 결과 (0: REQUEST, 1: RESULT OK, 기타 오류는 필요에 따라 정의)
◦ DATA: 명령어 수행에 필요한 데이터 (명령어에 따라서 길이가 입력)
◦ CHECK SUM: 명령어 데이터의 유효성 검증을 위한 값
- 우선 아래 코드와 같이 bsp_uart.h 에 COMMAND 및 RESULT를 정의합니다.
/* BSP UART command */
#define CMD_LED 0x01
#define CMD_BUZZER 0x02
/* BSP UART error */
#define REQUEST 0x00
#define RES_OK 0x01
- python의 Car_driver.py에도 아래와 같이 COMMAND 및 RESULT를 정의합니다.
# BSP UART command
CMD_LED = 0x01
CMD_BUZZER = 0x02
CMD_MOTOR = 0x03
# BSP UART error
REQUEST = 0x00
RES_OK = 0x01
- 확장보드의 LED 제어를 위해서는 아래와 같이 STM32 보드에 보내면 됩니다.
◦ COMMAND: 0x01
◦ RESULT: 0x00
◦ DATA: [state (off: 0x00, on: 0x01) ]
- 확장보드의 BUZZER를 제어를 위해서는 아래와 같이 STM32 보드에 보내면 됩니다.
◦ COMMAND: 0x02
◦ RESULT: 0x00
◦ DATA: [state (off: 0x00, on: 0x01) ]
2. STM32 - 메시지 수신 및 제어 기능 구현 (LED, BUZZER)
- 아래 그림과 같이 PC13핀을 GPIO_Output으로 설정합니다.
- 다음은 아래 그림과 같이 PC5핀을 GPIO_Output으로 설정합니다.
- 다음은 'System Core' >> 'GPIO' >> 'PC13'의 'User Label'을 'LED2'로 지정합니다.
- 다음은 'System Core' >> 'GPIO' >> 'PC5'의 'User Label'을 'BUZZER'로 지정합니다.
- 툴바의 'Device Configuration Tool Code Generation' 버튼을 눌러서 코드를 생성합니다.
- 아래와 같이 'bsp_uart.h' 파일을 수정합니다.
#ifndef BSP_UART_H_
#define BSP_UART_H_
/* BSP UART command */
#define CMD_LED 0x01
#define CMD_BUZZER 0x02
/* BSP UART error */
#define REQUEST 0x00
#define RES_OK 0x01
/* BSP UART function */
void USART2_Init(void);
#endif /* BSP_UART_H_ */
- 다음은 아래와 같이 'bsp_uart.c' 파일을 수정합니다.
#include <string.h>
#include "main.h"
#include "bsp_uart.h"
extern UART_HandleTypeDef huart2;
uint8_t rx_flag;
uint8_t rx_data[256];
uint8_t rx_csum;
uint8_t tx_data[256];
uint8_t tx_csum;
void USART2_Init(void)
{
HAL_UART_Receive_IT(&huart2, &rx_flag, 1);
}
int Check_RxCheckSum() {
int len = rx_data[1] + 2;
int sum = 0;
for(int i = 0; i < len; i++) {
sum += rx_data[i];
}
sum &= 0xFF;
return rx_csum == sum;
}
void Make_TxCheckSum() {
int len = tx_data[1] + 2;
int sum = 0;
for(int i = 0; i < len; i++) {
sum += tx_data[i];
}
tx_csum = sum & 0xFF;
}
void Send_Data() {
Make_TxCheckSum();
HAL_UART_Transmit(&huart2, tx_data, tx_data[1] + 2, 10);
HAL_UART_Transmit(&huart2, &tx_csum, 1, 10);
}
void Set_Led() {
if (rx_data[3] == CMD_LED) {
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, rx_data[5]);
// response
memset(tx_data, 0x00, sizeof(tx_data));
memcpy(tx_data, rx_data, rx_data[1] + 2);
tx_data[4] = RES_OK; // result
Send_Data(); // send result
}
}
void Set_Buzzer() {
if (rx_data[3] == CMD_BUZZER) {
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, rx_data[5]);
// response
memset(tx_data, 0x00, sizeof(tx_data));
memcpy(tx_data, rx_data, rx_data[1] + 2);
tx_data[4] = RES_OK; // result
Send_Data(); // send result
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2) {
if (rx_flag == 0xFF) {
memset(rx_data, 0x00, sizeof(rx_data));
rx_data[0] = rx_flag;
HAL_StatusTypeDef uartState = HAL_UART_Receive(&huart2, &rx_data[1], 1, 10); // recv len
if (uartState == HAL_OK) {
uartState = HAL_UART_Receive(&huart2, &rx_data[2], rx_data[1], 10); // recv data
}
if (uartState == HAL_OK) {
uartState = HAL_UART_Receive(&huart2, &rx_csum, 1, 10); // recv crc
}
if (uartState == HAL_OK && Check_RxCheckSum() > 0) {
switch (rx_data[3]) {
case CMD_LED:
Set_Led();
break;
case CMD_BUZZER:
Set_Buzzer();
break;
}
}
}
HAL_UART_Receive_IT(&huart2, &rx_flag, 1);
}
}
- 다음은 아래 그림과 같이 툴바의 'Build Debug' 버튼을 눌러 컴파일을 진행합니다.
- 다음은 아래 그림과 같이 툴바의 'Debug' 버튼을 눌러서 프로그램을 보드에 다운로드합니다.
3. Python - STM32 보드 제어기능 구현 (LED, BUZZER)
- 아래와 같이 보드를 제어하기 위한 'Car_driver.py' 코드를 작성합니다.
import itertools
import threading
import serial
# BSP UART command
CMD_LED = 0x01
CMD_BUZZER = 0x02
# BSP UART error
REQUEST = 0x00
RES_OK = 0x01
class CarDriver:
def __init__(self, baudrate=115200, port="COM1"):
# unique seq counter
self.seq = itertools.count()
# serial communication driver
self.ser = serial.Serial()
self.ser.baudrate = baudrate
self.ser.port = port
self.ser.open()
# serial recive thread run
self.run_receive_thread()
def run_receive_thread(self):
task_receive = threading.Thread(target=self.__recv_data, name="serial_recv_task")
task_receive.setDaemon(True)
task_receive.start()
def __recv_data(self):
while True:
data = bytearray(self.ser.read())[0]
print(data)
def set_led(self, state):
self.__send_data(CMD_LED, [1 if state else 0])
def set_buzzer(self, state):
self.__send_data(CMD_BUZZER, [1 if state else 0])
def __send_data(self, command, data):
seq = next(self.seq) % 0xFE + 1
cmd = [0xFF, 0, seq, command, REQUEST]
cmd.extend(data)
cmd[1] = len(cmd) - 2
checksum = sum(cmd) & 0xFF
cmd.append(checksum)
print(cmd)
self.ser.write(cmd)
- 다음은 보드를 제어하기 위한 'Car_driver_test.ipynb' 파일의 내용을 아래와 같이 바꿉니다.
from Car_driver import CarDriver
driver = CarDriver(baudrate=115200, port="COM5")
driver.set_led(True)
driver.set_led(False)
driver.set_buzzer(True)
driver.set_buzzer(False)
- 명령이 실행됨에 따라 LED 또는 Buzzer가 켜지거나 꺼지는 것을 확인할 수 있습니다.
'로봇 > STM32' 카테고리의 다른 글
STM32 자동차 제어하기(3) - 모터 제어하기 (0) | 2023.03.20 |
---|---|
STM32 자동차 제어하기(1) - 기본환경 설정 (0) | 2023.03.19 |
STM32 UART로 보드 제어하기 (1) | 2023.03.01 |
STM32 Button을 누르면 UART로 메시지 출력하기 (2) | 2023.02.28 |
STM32 Button Interrupt를 이용한 LED 제어 (0) | 2023.02.28 |