STM32 F103C8T6
본 예제는 STM32F103C8T6 코어 보드, Windows PC 1대, 점퍼 와이어 여러 개, IMU 자세 센서를 사용합니다.
keil5 소프트웨어로 USART.uvprojx를 열어 STM32F103C8T6 코어 보드에 프로그램을 굽습니다
1. 장치 연결

2. 핵심 코드 해설
구체적인 코드는 자료의 소스 코드를 참조하세요.
c++
//링 버퍼의 데이터를 파싱하여 완전한 프레임 추출 및 캐시 갱신
//Process RX ring buffer, parse frames and update internal cache
void IMU_UART_Process(void)
{
enum {
RX_STATE_EXPECT_HEAD1 = 0,
RX_STATE_EXPECT_HEAD2,
RX_STATE_EXPECT_LENGTH,
RX_STATE_EXPECT_FUNCTION,
RX_STATE_COLLECT_DATA
};
static uint8_t rx_state = RX_STATE_EXPECT_HEAD1;
static uint8_t frame_length = 0;
static uint8_t frame_function = 0;
static uint8_t frame_buffer[64]; /* 数据区 + 校验 / data section + checksum */
static uint16_t frame_index = 0;
uint8_t current_byte = 0;
//링 버퍼의 모든 데이터 처리
while (_rxbuf_pop(¤t_byte) == 0) {
switch (rx_state) {
case RX_STATE_EXPECT_HEAD1:
//프레임 헤더 1 탐색
if (current_byte == FRAME_HEAD1) {
rx_state = RX_STATE_EXPECT_HEAD2;
}
//아니면 현재 상태 유지
break;
case RX_STATE_EXPECT_HEAD2:
//프레임 헤더 2 탐색
if (current_byte == FRAME_HEAD2) {
rx_state = RX_STATE_EXPECT_LENGTH;
} else {
//프레임 헤더 불일치, 처음부터 다시 탐색
rx_state = RX_STATE_EXPECT_HEAD1;
}
break;
case RX_STATE_EXPECT_LENGTH:
//프레임 길이 저장
frame_length = current_byte;
rx_state = RX_STATE_EXPECT_FUNCTION;
break;
case RX_STATE_EXPECT_FUNCTION:
//기능 코드 저장
frame_function = current_byte;
frame_index = 0;
rx_state = RX_STATE_COLLECT_DATA;
break;
case RX_STATE_COLLECT_DATA: {
//데이터 길이 계산(프레임 길이 - 헤더 2바이트 - 길이 1바이트 - 기능 코드 1바이트)
uint16_t data_length = (frame_length >= 4) ? (uint16_t)(frame_length - 4) : 0;
//데이터 길이 유효성 확인
if (data_length == 0 || data_length > sizeof(frame_buffer)) {
rx_state = RX_STATE_EXPECT_HEAD1;
break;
}
//현재 바이트 저장
frame_buffer[frame_index++] = current_byte;
//모든 데이터 수집 완료 여부 확인
if (frame_index >= data_length) {
//체크섬 계산
uint8_t calculated_checksum = (uint8_t)(FRAME_HEAD1 + FRAME_HEAD2 + frame_length + frame_function);
for (uint16_t i = 0; i < data_length - 1; ++i) {
calculated_checksum += frame_buffer[i];
}
//체크섬 검증
uint8_t received_checksum = frame_buffer[data_length - 1];
if (calculated_checksum == received_checksum) {
//검증 통과, 데이터 파싱
_parse_frame_data(frame_function, frame_buffer);
}
//상태 초기화, 다음 프레임 수신 대기
rx_state = RX_STATE_EXPECT_HEAD1;
}
} break;
default:
//알 수 없는 상태, 초기화
rx_state = RX_STATE_EXPECT_HEAD1;
break;
}
}
}
/* ---------- 解析数据帧 / Parse one complete frame ---------- */
static void _parse_frame_data(uint8_t frame_function, const uint8_t *frame_data)
{
switch (frame_function) {
case IMU_FUNC_RAW_ACCEL: {
//상수 스케일 계수 정의
const float ACCEL_RATIO = 16.0f / 32767.0f;
const float DEG2RAD = 3.14159265358979323846f / 180.0f;
const float GYRO_RATIO = (2000.0f / 32767.0f) * DEG2RAD;
const float MAG_RATIO = 800.0f / 32767.0f;
//가속도 데이터 파싱
s_ax = to_int16(&frame_data[0]) * ACCEL_RATIO;
s_ay = to_int16(&frame_data[2]) * ACCEL_RATIO;
s_az = to_int16(&frame_data[4]) * ACCEL_RATIO;
//자이로 데이터 파싱
s_gx = to_int16(&frame_data[6]) * GYRO_RATIO;
s_gy = to_int16(&frame_data[8]) * GYRO_RATIO;
s_gz = to_int16(&frame_data[10]) * GYRO_RATIO;
//자력계 데이터 파싱
s_mx = to_int16(&frame_data[12]) * MAG_RATIO;
s_my = to_int16(&frame_data[14]) * MAG_RATIO;
s_mz = to_int16(&frame_data[16]) * MAG_RATIO;
break;
}
case IMU_FUNC_EULER:
s_roll = to_float(&frame_data[0]);
s_pitch = to_float(&frame_data[4]);
s_yaw = to_float(&frame_data[8]);
break;
case IMU_FUNC_QUAT:
s_q0 = to_float(&frame_data[0]);
s_q1 = to_float(&frame_data[4]);
s_q2 = to_float(&frame_data[8]);
s_q3 = to_float(&frame_data[12]);
break;
case IMU_FUNC_BARO:
s_height = to_float(&frame_data[0]);
s_temperature = to_float(&frame_data[4]);
s_pressure = to_float(&frame_data[8]);
s_pressure_contrast = to_float(&frame_data[12]);
break;
case IMU_FUNC_VERSION:
s_version_high = frame_data[0];
s_version_mid = frame_data[1];
s_version_low = frame_data[2];
break;
case IMU_FUNC_RETURN_STATE:
s_last_rx_function = frame_data[0];
s_last_rx_state = (int16_t)frame_data[1];
break;
default:
//알 수 없는 프레임 유형, 오류 처리 추가 가능
break;
}
}IMU_UART_Process(): 캐시된 데이터를 읽고, 통신 프로토콜에 맞는 데이터를 _parse_frame_data로 파싱합니다.
_parse_frame_data(): 데이터 프레임을 파싱합니다.
3. imu 데이터 읽기
프로그램이 Arduino에 다운로드된 후 시리얼 어시스턴트를 열면(설정 파라미터는 아래 그림 참조) IMU 모듈의 데이터가 계속 출력되는 것을 볼 수 있습니다. IMU 모듈의 자세를 바꾸면 데이터가 변화합니다.

주의: 위는 10축 IMU 데이터 읽기입니다. 6축은 자기력계(Magnetometer)와 기압계(Barometer) 데이터가 없고, 9축은 기압계(Barometer) 데이터가 없습니다.

