#include "uart.h" #include "delay.h" #include "r_cg_adc.h" #include "r_cg_port.h" #include #define RS485_EN_PORT P4 #define RS485_EN_PM PM4 #define RS485_EN_MASK (0x20U) // P4.5 volatile uint8_t g_uart0_tx_done = 1; volatile uint8_t g_uart1_tx_done = 1; extern volatile uint16_t g_uart1_tx_count; extern volatile uint8_t rs485_rx_done; extern volatile uint8_t rs485_rx_index; extern volatile uint16_t rs485_rx_length; extern volatile uint8_t rs485_rx_buffer[]; extern volatile uint8_t g_rs485_bridge_active; extern volatile uint8_t g_rs485_bridge_done; volatile uint8_t g_rs485_need_recover = 0; void rs485_recover(void) { DI(); // ISR 경쟁 줄이기 (권장) rs485_set_tx(0); // RX 모드 고정 // UART0 재시작 R_UART0_Stop(); delay_us(200); R_UART0_Create(); delay_us(200); R_UART0_Start(); delay_us(200); // 에러 플래그/카운터 정리 g_uart0_err_fef = 0; g_uart0_err_ovf = 0; g_uart0_err_pef = 0; // RX 다시 arm rs485_rx_done = 0; rs485_rx_index = 0; rs485_rx_length = 0; R_UART0_Receive((uint8_t*)&rs485_rx_buffer[0], 1); g_rs485_need_recover = 0; // recover 완료 처리 (여기서 내려도 OK) EI(); } /* UART1 송신용 내부 버퍼(스택 포인터 안전) */ static uint8_t s_uart1_txbuf[1024]; // 너 출력 단위가 "72 " / "7272 " 정도라 64면 충분 // (더 길게 보내면 키워도 됨) static void UART1_WaitTxIdle(void) { unsigned long guard = 0; while (g_uart1_tx_count != 0U) { if (guard++ > 3000000UL) break; // 무한루프 방지 } } void rs485_set_tx(uint8_t on) { if (on) RS485_EN_PORT |= RS485_EN_MASK; // EN=1 (TX) else RS485_EN_PORT &= (uint8_t)~RS485_EN_MASK; // EN=0 (RX) } void rs485_init(void) { RS485_EN_PM &= (uint8_t)~RS485_EN_MASK; // 출력 rs485_set_tx(0); // 기본 RX 모드 } void UART0_WaitTxDone_Us(uint32_t timeout_us) { while (!g_uart0_tx_done && timeout_us >= 10U) { delay_us(10); timeout_us -= 10U; } } void RS485_Send(const uint8_t* data, uint16_t len) { if (!data || len == 0) return; /* 송신 시작을 명확히 */ g_uart0_tx_done = 0; rs485_set_tx(1); R_UART0_Send((uint8_t*)data, len); } void RS485_SendString(const char* s) { uint16_t len = 0; while (s[len] != '\0') len++; RS485_Send((const uint8_t*)s, len); } static void UART1_WaitTxDone_Us(uint32_t timeout_us) { while (!g_uart1_tx_done && timeout_us >= 10U) { delay_us(10); timeout_us -= 10U; } } /** * 함수명: uart_send_string * 목적: null 종료된 문자열을 UART0로 전송 * * 매개변수: * - str : 전송할 문자열 (C 문자열, '\0'로 종료) * * 반환값: 없음 (void) * * 동작 방식: * 1) 문자열 길이 계산 * - 문자열 끝을 나타내는 '\0'이 나올 때까지 len 증가 * * 2) UART 전송 * - R_UART0_Send() 함수를 사용하여 계산한 길이만큼 문자열 전송 * - (uint8_t *)로 캐스팅하여 바이트 배열 형식 전달 * * 참고: * - null 문자('\0')는 전송되지 않음 * - UART0 초기화와 전송 준비는 별도로 되어 있어야 함 */ // UART0(RS485) void uart_send_string(const char *str) { uint16_t len = 0; while (str[len] != '\0') len++; RS485_Send((const uint8_t*)str, len); } // UART1(PC) void uart1_send_string(const char *str) { uint16_t len = 0; if (str == 0) return; while (str[len] != '\0') len++; /* ✅ 이전 전송 끝날 때까지 대기 */ UART1_WaitTxIdle(); g_uart1_tx_done = 0; /* ✅ 스택 포인터/버퍼 수명 문제 방지: 내부 버퍼로 복사 */ if (len >= (uint16_t)sizeof(s_uart1_txbuf)) len = (uint16_t)(sizeof(s_uart1_txbuf) - 1); memcpy(s_uart1_txbuf, str, len); /* ✅ 비동기 송신 시작 */ R_UART1_Send(s_uart1_txbuf, len); /* ❌ 여기서 또 기다리지 마(속도 저하). 다음 호출이 알아서 대기함 */ } /** * 함수명: uart_send_hex * 목적: 8비트 값(uint8_t)을 16진수 문자열로 변환 후 UART0로 전송 * * 매개변수: * - val : 전송할 8비트 값 * * 반환값: 없음 (void) * * 동작 방식: * 1) 상위/하위 4비트 분리 * - high = val >> 4, 상위 4비트 * - low = val & 0x0F, 하위 4비트 * * 2) 16진수 문자로 변환 * - 0~9 → '0'~'9' * - 10~15 → 'A'~'F' * - hex[0] = 상위 4비트 문자 * - hex[1] = 하위 4비트 문자 * * 3) UART 전송 * - R_UART0_Send()를 사용해 2바이트 전송 * * 4) 전송 후 지연 * - delay(10000)으로 약간의 전송 간격 확보 * * 참고: * - 이 함수는 1바이트 값을 항상 2자리 16진수로 표현 * - 예: val = 0xAF → "AF" 전송 */ void uart_send_hex(uint8_t val) { uint8_t hex[2]; uint8_t high = (val >> 4) & 0x0F; uint8_t low = val & 0x0F; hex[0] = (high < 10) ? ('0' + high) : ('A' + (high - 10)); hex[1] = (low < 10) ? ('0' + low) : ('A' + (low - 10)); RS485_Send(hex, 2); } void uart1_send_hex(uint8_t val) { static uint8_t hex[2]; uint8_t high = (val >> 4) & 0x0F; uint8_t low = val & 0x0F; hex[0] = (high < 10) ? ('0' + high) : ('A' + (high - 10)); hex[1] = (low < 10) ? ('0' + low ) : ('A' + (low - 10)); UART1_WaitTxIdle(); g_uart1_tx_done = 0; R_UART1_Send(hex, 2); }