|
|
|
|
#include "uart.h"
|
|
|
|
|
#include "delay.h"
|
|
|
|
|
#include "r_cg_adc.h"
|
|
|
|
|
#include "r_cg_port.h"
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#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 uint16_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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|