init refactoring
This commit is contained in:
@@ -19,12 +19,6 @@
|
||||
#define RX_STATE_BINDING 1
|
||||
#define RX_STATE_CONNECTED 2
|
||||
|
||||
/* 输出模式 */
|
||||
#define OUT_MODE_PWM 0
|
||||
#define OUT_MODE_SBUS 1
|
||||
#define OUT_MODE_UART 2
|
||||
#define OUT_MODE_CRFS 3
|
||||
|
||||
/* EEPROM 地址 (IAP) */
|
||||
#define EEPROM_ADDR_BIND_FLAG 0x0000
|
||||
#define EEPROM_ADDR_TX_ADDR 0x0001 /* 5字节 */
|
||||
@@ -87,3 +81,6 @@ static volatile uint8_t uart_cmd_ready = 0;
|
||||
|
||||
/* 定时器计数 (用于LED闪烁) */
|
||||
static volatile uint16_t sys_tick = 0;
|
||||
|
||||
void (*code runModel)(void) = PwmModel;
|
||||
void (*code outputFun)(void) = PwmUpdate;
|
||||
@@ -17,60 +17,57 @@
|
||||
*/
|
||||
# ifndef CONFIG
|
||||
# define CONFIG
|
||||
# include "CONFIG.h"
|
||||
# include "config.h"
|
||||
# endif
|
||||
|
||||
#include "NRF24.h"
|
||||
#include "UART.h"
|
||||
#include "nrf24.h"
|
||||
#include "uart.h"
|
||||
|
||||
/* ========================================================================
|
||||
* 函数声明
|
||||
* ======================================================================== */
|
||||
void EEPROM_LoadConfig();
|
||||
void Init();
|
||||
|
||||
static void System_Init(void);
|
||||
static void GPIO_Init(void);
|
||||
static void Timer0_Init(void);
|
||||
static void UART1_Init(void);
|
||||
static void ADC_Init(void);
|
||||
static void IAP_Init(void);
|
||||
void main(void) {
|
||||
/* 系统初始化 */
|
||||
System_Init();
|
||||
GPIO_Init();
|
||||
Timer0_Init();
|
||||
UART1_Init();
|
||||
ADC_Init();
|
||||
IAP_Init();
|
||||
|
||||
static uint8_t IAP_ReadByte(uint16_t addr);
|
||||
static void IAP_WriteByte(uint16_t addr, uint8_t dat);
|
||||
static void IAP_EraseSector(uint16_t addr);
|
||||
/* 初始化NRF24L01 */
|
||||
NRF24L01_Init();
|
||||
|
||||
static void EEPROM_LoadConfig(void);
|
||||
static void EEPROM_SaveConfig(void);
|
||||
static uint8_t EEPROM_IsBound(void);
|
||||
/* 初始PWM: 中位 */
|
||||
PWM_SetAllFailsafe();
|
||||
|
||||
static void LED_SetMode(uint8_t mode);
|
||||
static void LED_Update(void);
|
||||
// 从EEPROM加载配置 */
|
||||
EEPROM_LoadConfig();
|
||||
|
||||
static void PWM_SetChannel(uint8_t ch, uint16_t pulse_us);
|
||||
static void PWM_SetAllFailsafe(void);
|
||||
/* 检测NRF模块 */
|
||||
if (!NRF24L01_Check()) {
|
||||
/* NRF模块未检测到, 设置硬件错误标志, LED双闪 */
|
||||
nrf_hw_error = 1;
|
||||
}
|
||||
|
||||
static void UART1_SendByte(uint8_t dat);
|
||||
static void UART1_SendString(const char *s);
|
||||
static void UART1_SendStringLen(const char *s, uint8_t len);
|
||||
while (1) {
|
||||
/* 处理串口命令 */
|
||||
UART1_ProcessCmd();
|
||||
|
||||
static void SBUS_SendFrame(void);
|
||||
static void SBUS_Init(void);
|
||||
if (NRF_IRQ == 1) {
|
||||
// 处理NRF24L01接收数据
|
||||
NRF24L01_ProcessRX();
|
||||
// 更新输出数据
|
||||
outputFun();
|
||||
}
|
||||
|
||||
static void CRFS_SendFrame(void);
|
||||
static void CRFS_Init(void);
|
||||
/* LED状态指示 */
|
||||
LED_Update();
|
||||
}
|
||||
}
|
||||
|
||||
static void Cmd_Parse(void);
|
||||
static void Cmd_Respond(const char *resp);
|
||||
|
||||
static void NRF_ProcessPacket(void);
|
||||
static void NRF_EnterBindMode(void);
|
||||
static uint8_t NRF_DoBindScan(void);
|
||||
static void NRF_SendTelemetry(void);
|
||||
|
||||
/* ========================================================================
|
||||
* 系统初始化
|
||||
* ======================================================================== */
|
||||
|
||||
static void System_Init(void) {
|
||||
void Init() {
|
||||
// System_Init()
|
||||
/* 切换到内部24MHz IRC */
|
||||
P_SW2 |= EAXFR; /* 使能访问扩展SFR */
|
||||
CLKDIV = 0x00; /* 主时钟不分频 */
|
||||
@@ -80,9 +77,8 @@ static void System_Init(void) {
|
||||
/* 设置内部IRC为24MHz */
|
||||
IRC24MCR = 0x80; /* 使能内部24MHz IRC */
|
||||
while (!(IRC24MCR & 0x01)); /* 等待IRC稳定 */
|
||||
}
|
||||
|
||||
static void GPIO_Init(void) {
|
||||
// GPIO_Init()
|
||||
/* P3.4-P3.7: 推挽输出 (PWM通道) */
|
||||
P3M0 |= 0xF0;
|
||||
P3M1 &= ~0xF0;
|
||||
@@ -128,13 +124,8 @@ static void GPIO_Init(void) {
|
||||
NRF_CSN = 1;
|
||||
NRF_SCK = 0;
|
||||
NRF_MOSI = 0;
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* 定时器0 - PWM 时基 (4us 中断)
|
||||
* ======================================================================== */
|
||||
|
||||
static void Timer0_Init(void) {
|
||||
// Timer_Init()
|
||||
/* 16位自动重载模式, 1T */
|
||||
TMOD &= ~0x0F;
|
||||
TMOD |= 0x01; /* T0: 16位定时器 */
|
||||
@@ -147,862 +138,3 @@ static void Timer0_Init(void) {
|
||||
ET0 = 1; /* 使能T0中断 */
|
||||
TR0 = 1; /* 启动T0 */
|
||||
}
|
||||
|
||||
/* T0 中断服务 - 4us一次, 生成4路PWM */
|
||||
void tm0_isr(void) __interrupt(1) {
|
||||
static uint16_t pwm_cnt = 0;
|
||||
|
||||
pwm_cnt++;
|
||||
if (pwm_cnt >= PWM_PERIOD) {
|
||||
pwm_cnt = 0;
|
||||
}
|
||||
|
||||
/* 4路舵机PWM (P3.4-P3.7) */
|
||||
if (pwm_cnt < pwm_ch[0]) P37 = 1; else P37 = 0;
|
||||
if (pwm_cnt < pwm_ch[1]) P36 = 1; else P36 = 0;
|
||||
if (pwm_cnt < pwm_ch[2]) P35 = 1; else P35 = 0;
|
||||
if (pwm_cnt < pwm_ch[3]) P34 = 1; else P34 = 0;
|
||||
|
||||
/* 系统滴答 (每10ms) */
|
||||
if (pwm_cnt == 0) {
|
||||
sys_tick++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* UART1 - 串口通信 (使用Timer2做波特率发生器)
|
||||
* ======================================================================== */
|
||||
|
||||
static void UART1_Init(void) {
|
||||
/* 使用 Timer2 做波特率发生器 */
|
||||
/* 115200 @ 24MHz: T2 reload = 65536 - 52 = 0xFFCC */
|
||||
T2H = 0xFF;
|
||||
T2L = 0xCC;
|
||||
AUXR |= T2x12; /* T2: 1T模式 */
|
||||
AUXR |= T2R; /* 启动T2 */
|
||||
|
||||
/* UART1 配置: 8位可变波特率, 模式1 */
|
||||
SCON = 0x50; /* 模式1, REN=1 */
|
||||
AUXR |= S1ST2; /* UART1使用T2做波特率 */
|
||||
PCON &= ~SMOD0; /* SMOD0=0, 帧格式8位数据 */
|
||||
|
||||
/* 使能接收中断 */
|
||||
ES = 1;
|
||||
RI = 0;
|
||||
}
|
||||
|
||||
/* UART1 中断服务 */
|
||||
void uart1_isr(void) __interrupt(4) {
|
||||
if (RI) {
|
||||
RI = 0;
|
||||
uint8_t dat = SBUF;
|
||||
|
||||
if (out_mode == OUT_MODE_CRFS) {
|
||||
/* CRFS 模式: 接收飞控发来的 CRSF 帧并缓存转发 */
|
||||
if (dat == 0xEE) {
|
||||
/* CRSF 帧起始 */
|
||||
crfs_forward_len = 0;
|
||||
crfs_forward_buf[crfs_forward_len++] = dat;
|
||||
} else if (crfs_forward_len > 0 && crfs_forward_len < sizeof(crfs_forward_buf)) {
|
||||
crfs_forward_buf[crfs_forward_len++] = dat;
|
||||
/* 如果收到完整帧 (根据长度字段), 标记为待转发 */
|
||||
if (crfs_forward_len >= 3) {
|
||||
uint8_t frame_len = crfs_forward_buf[1] + 2; /* type+payload+crc = length field */
|
||||
if (crfs_forward_len >= frame_len) {
|
||||
/* 完整帧已收到, 保持缓存, 主循环会处理转发 */
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* 命令接收: 回车/换行结束 */
|
||||
if (dat == '\r' || dat == '\n') {
|
||||
if (uart_rx_idx > 0) {
|
||||
uart_rx_buf[uart_rx_idx] = '\0';
|
||||
uart_cmd_ready = 1;
|
||||
}
|
||||
uart_rx_idx = 0;
|
||||
} else {
|
||||
if (uart_rx_idx < UART_BUF_SIZE - 1) {
|
||||
uart_rx_buf[uart_rx_idx++] = dat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TI) {
|
||||
TI = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void UART1_SendByte(uint8_t dat) {
|
||||
SBUF = dat;
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
|
||||
static void UART1_SendString(const char *s) {
|
||||
while (*s) {
|
||||
UART1_SendByte((uint8_t)(*s++));
|
||||
}
|
||||
}
|
||||
|
||||
static void UART1_SendStringLen(const char *s, uint8_t len) {
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
UART1_SendByte((uint8_t)s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* SBUS 输出 (100kbps 8E2, 与UART1共用TX)
|
||||
* ======================================================================== */
|
||||
|
||||
static void SBUS_Init(void) {
|
||||
/* 切换到 SBUS 波特率 100kbps */
|
||||
/* 100000 @ 24MHz: T2 reload = 65536 - 60 = 0xFFC4 */
|
||||
T2H = 0xFF;
|
||||
T2L = 0xC4;
|
||||
AUXR |= T2x12;
|
||||
AUXR |= T2R;
|
||||
|
||||
/* 8E2: 8数据位, 偶校验, 2停止位 */
|
||||
PCON |= SMOD0; /* SMOD0=1, 帧格式由SM2控制 */
|
||||
SCON &= ~0x0E; /* 清除SM2, TB8 */
|
||||
/* 注意: 对于SBUS, 标准是8E2, 但这里通过三极管反相,
|
||||
* 所以实际发送的是反相SBUS信号 */
|
||||
}
|
||||
|
||||
static void SBUS_SendFrame(void) {
|
||||
static uint8_t __xdata frame[25];
|
||||
static uint16_t __xdata sbus_ch[16];
|
||||
uint8_t i;
|
||||
|
||||
/* SBUS 帧结构 */
|
||||
frame[0] = 0x0F; /* 起始字节 */
|
||||
|
||||
/* 16通道 11-bit 编码 (这里只填充前4个通道, 其余为中间值) */
|
||||
/* 将pwm值(250-500)映射到SBUS范围(172-1811) */
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint16_t val = pwm_ch[i];
|
||||
/* pwm_ch: 250~500 → SBUS: 172~1811 */
|
||||
if (val < PWM_MIN) val = PWM_MIN;
|
||||
if (val > PWM_MAX) val = PWM_MAX;
|
||||
sbus_ch[i] = (uint16_t)((uint32_t)(val - PWM_MIN) * (1811 - 172) / (PWM_MAX - PWM_MIN) + 172);
|
||||
}
|
||||
for (i = 4; i < 16; i++) {
|
||||
sbus_ch[i] = 992; /* 中间值 */
|
||||
}
|
||||
|
||||
/* 11-bit 打包 */
|
||||
frame[1] = (uint8_t)(sbus_ch[0] & 0xFF);
|
||||
frame[2] = (uint8_t)((sbus_ch[0] >> 8) | ((sbus_ch[1] & 0x07) << 3));
|
||||
frame[3] = (uint8_t)((sbus_ch[1] >> 3) | ((sbus_ch[2] & 0x3F) << 5));
|
||||
frame[4] = (uint8_t)((sbus_ch[2] >> 6) | ((sbus_ch[3] & 0x01) << 2) | ((sbus_ch[3] & 0x01) << 2));
|
||||
/* 简化: 只打包前4通道, 其余保持中间值 */
|
||||
|
||||
/* 简化处理 - 完整16通道打包太复杂, 用中间值填充 */
|
||||
for (i = 5; i < 23; i++) {
|
||||
frame[i] = 0x00;
|
||||
}
|
||||
|
||||
frame[23] = 0x00; /* 标志字节 */
|
||||
frame[24] = 0x00; /* 结束字节 */
|
||||
|
||||
/* 通过UART1发送 */
|
||||
for (i = 0; i < 25; i++) {
|
||||
SBUF = frame[i];
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* CRFS (CRSF/Crossfire) 输出 (420kbps 8N1, 与UART1共用TX)
|
||||
* 帧格式: 0xEE + len + type + payload + crc8
|
||||
* RC通道帧: type=0x16, payload=22字节 (16ch × 11bit)
|
||||
* ======================================================================== */
|
||||
|
||||
/* CRC8 查表 (多项式 0xD5, CRSF 标准, 放在 CODE 区) */
|
||||
static const uint8_t __code crsf_crc8_tab[256] = {
|
||||
0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54,
|
||||
0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
|
||||
0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06,
|
||||
0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
|
||||
0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0,
|
||||
0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
|
||||
0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2,
|
||||
0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
|
||||
0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9,
|
||||
0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
|
||||
0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B,
|
||||
0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
|
||||
0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D,
|
||||
0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
|
||||
0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F,
|
||||
0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
|
||||
0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB,
|
||||
0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
|
||||
0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9,
|
||||
0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
|
||||
0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F,
|
||||
0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
|
||||
0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D,
|
||||
0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
|
||||
0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26,
|
||||
0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
|
||||
0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74,
|
||||
0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
|
||||
0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82,
|
||||
0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
|
||||
0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0,
|
||||
0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
|
||||
};
|
||||
|
||||
static uint8_t CRSF_CalcCRC(uint8_t *data, uint8_t len) {
|
||||
uint8_t crc = 0;
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
crc = crsf_crc8_tab[crc ^ data[i]];
|
||||
return crc;
|
||||
}
|
||||
|
||||
static void CRFS_Init(void) {
|
||||
/* 切换到 CRSF 波特率 420000 */
|
||||
/* 420000 @ 24MHz: T2 reload = 65536 - 14 = 0xFFF2 */
|
||||
T2H = 0xFF;
|
||||
T2L = 0xF2;
|
||||
AUXR |= T2x12;
|
||||
AUXR |= T2R;
|
||||
|
||||
/* 8N1: 8数据位, 无校验, 1停止位 */
|
||||
PCON &= ~SMOD0; /* SMOD0=0, 标准帧格式 */
|
||||
SCON = 0x50; /* 模式1, REN=1, 8N1 */
|
||||
}
|
||||
|
||||
static void CRFS_SendFrame(void) {
|
||||
static uint8_t __xdata frame[28]; /* 0xEE + len + type + 22payload + crc */
|
||||
static uint16_t __xdata crsf_ch[16];
|
||||
uint8_t i;
|
||||
|
||||
/* CRSF RC通道帧: type=0x16 */
|
||||
frame[0] = 0xEE; /* sync */
|
||||
frame[1] = 24; /* length (type + payload + crc = 1+22+1) */
|
||||
frame[2] = 0x16; /* RC channels type */
|
||||
|
||||
/* 将4路pwm值(250-500)映射到CRSF范围(0-1984, 中位992) */
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint16_t val = pwm_ch[i];
|
||||
if (val < PWM_MIN) val = PWM_MIN;
|
||||
if (val > PWM_MAX) val = PWM_MAX;
|
||||
/* pwm_ch: 250~500 → CRSF: 0~1984 (中位992) */
|
||||
crsf_ch[i] = (uint16_t)((uint32_t)(val - PWM_MIN) * 1984 / (PWM_MAX - PWM_MIN));
|
||||
}
|
||||
for (i = 4; i < 16; i++) {
|
||||
crsf_ch[i] = 992; /* 中位 */
|
||||
}
|
||||
|
||||
/* 11-bit 打包到 payload (22字节) */
|
||||
uint8_t *pl = frame + 3;
|
||||
pl[0] = (uint8_t)(crsf_ch[0] & 0xFF);
|
||||
pl[1] = (uint8_t)((crsf_ch[0] >> 8) | ((crsf_ch[1] & 0x07) << 3));
|
||||
pl[2] = (uint8_t)((crsf_ch[1] >> 3) | ((crsf_ch[2] & 0x3F) << 5));
|
||||
pl[3] = (uint8_t)((crsf_ch[2] >> 6) | ((crsf_ch[3] & 0x01) << 2) | ((crsf_ch[3] & 0x01) << 2));
|
||||
/* 剩余通道用中间值填充 */
|
||||
for (i = 4; i < 22; i++)
|
||||
pl[i] = 0x00;
|
||||
|
||||
/* CRC8 (从 type 开始到 payload 结束) */
|
||||
frame[25] = CRSF_CalcCRC(frame + 2, 23); /* type(1) + payload(22) */
|
||||
|
||||
/* 通过UART1发送 */
|
||||
for (i = 0; i < 26; i++) {
|
||||
SBUF = frame[i];
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* ADC - 电池电压检测 (P3.3/ADC11)
|
||||
* ======================================================================== */
|
||||
|
||||
static void ADC_Init(void) {
|
||||
ADCCFG = ADC_RESFMT; /* 右对齐, 12位结果 */
|
||||
ADC_CONTR = ADC_POWER; /* 开启ADC电源 */
|
||||
/* 选择通道11 (P3.3) */
|
||||
ADC_CONTR = (ADC_CONTR & 0xF0) | 0x0B;
|
||||
}
|
||||
|
||||
/* 读取指定ADC通道 */
|
||||
static uint16_t ADC_ReadChannel(uint8_t ch) {
|
||||
ADC_CONTR = (ADC_CONTR & 0xF0) | ch; /* 切换通道 */
|
||||
__asm nop __endasm; /* 等待通道切换稳定 */
|
||||
__asm nop __endasm;
|
||||
ADC_CONTR |= ADC_START; /* 启动转换 */
|
||||
while (!(ADC_CONTR & ADC_FLAG)); /* 等待完成 */
|
||||
ADC_CONTR &= ~ADC_FLAG; /* 清除标志 */
|
||||
return ((uint16_t)ADC_RES << 8) | ADC_RESL;
|
||||
}
|
||||
|
||||
static uint16_t ADC_Read(void) {
|
||||
return ADC_ReadChannel(0x0B); /* P3.3/ADC11 */
|
||||
}
|
||||
|
||||
/* 读取内部带隙基准电压 (通道14), 用于反算VCC */
|
||||
/* VCC(mV) = 1190 * 4096 / bandgap_adc */
|
||||
static uint16_t ADC_ReadBandgap(void) {
|
||||
return ADC_ReadChannel(0x0E); /* 内部带隙基准 */
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* IAP/EEPROM 操作
|
||||
* ======================================================================== */
|
||||
|
||||
static void IAP_Init(void) {
|
||||
/* IAP 默认已就绪, 无需额外初始化 */
|
||||
}
|
||||
|
||||
static uint8_t IAP_ReadByte(uint16_t addr) {
|
||||
uint8_t dat;
|
||||
IAP_CONTR = IAPEN; /* 使能IAP */
|
||||
IAP_CMD = IAP_READ;
|
||||
IAP_ADDRH = (uint8_t)(addr >> 8);
|
||||
IAP_ADDRL = (uint8_t)(addr & 0xFF);
|
||||
/* 触发 */
|
||||
TA = 0x5A;
|
||||
TA = 0xA5;
|
||||
IAP_TRIG = 0x5A;
|
||||
IAP_TRIG = 0xA5;
|
||||
/* NOP 等待 */
|
||||
__asm nop __endasm;
|
||||
__asm nop __endasm;
|
||||
dat = IAP_DATA;
|
||||
IAP_CONTR = 0x00; /* 关闭IAP */
|
||||
return dat;
|
||||
}
|
||||
|
||||
static void IAP_WriteByte(uint16_t addr, uint8_t dat) {
|
||||
IAP_CONTR = IAPEN; /* 使能IAP */
|
||||
IAP_CMD = IAP_WRITE;
|
||||
IAP_ADDRH = (uint8_t)(addr >> 8);
|
||||
IAP_ADDRL = (uint8_t)(addr & 0xFF);
|
||||
IAP_DATA = dat;
|
||||
/* 触发 */
|
||||
TA = 0x5A;
|
||||
TA = 0xA5;
|
||||
IAP_TRIG = 0x5A;
|
||||
IAP_TRIG = 0xA5;
|
||||
__asm nop __endasm;
|
||||
__asm nop __endasm;
|
||||
IAP_CONTR = 0x00; /* 关闭IAP */
|
||||
}
|
||||
|
||||
static void IAP_EraseSector(uint16_t addr) {
|
||||
IAP_CONTR = IAPEN; /* 使能IAP */
|
||||
IAP_CMD = IAP_ERASE;
|
||||
IAP_ADDRH = (uint8_t)(addr >> 8);
|
||||
IAP_ADDRL = (uint8_t)(addr & 0xFF);
|
||||
/* 触发 */
|
||||
TA = 0x5A;
|
||||
TA = 0xA5;
|
||||
IAP_TRIG = 0x5A;
|
||||
IAP_TRIG = 0xA5;
|
||||
__asm nop __endasm;
|
||||
__asm nop __endasm;
|
||||
IAP_CONTR = 0x00; /* 关闭IAP */
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* EEPROM 配置存储
|
||||
* ======================================================================== */
|
||||
|
||||
static uint8_t EEPROM_IsBound(void) {
|
||||
return (IAP_ReadByte(EEPROM_ADDR_BIND_FLAG) == EEPROM_BIND_MAGIC);
|
||||
}
|
||||
|
||||
static void EEPROM_LoadConfig(void) {
|
||||
if (!EEPROM_IsBound()) {
|
||||
/* 未对频, 进入对频模式 */
|
||||
rx_state = RX_STATE_BINDING;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 读取保存的配置 */
|
||||
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
|
||||
tx_addr[i] = IAP_ReadByte(EEPROM_ADDR_TX_ADDR + i);
|
||||
}
|
||||
rf_channel = IAP_ReadByte(EEPROM_ADDR_RF_CH);
|
||||
for (uint8_t i = 0; i < RF_PHRASE_LEN; i++) {
|
||||
bind_phrase[i] = IAP_ReadByte(EEPROM_ADDR_BIND_PHRASE + i);
|
||||
}
|
||||
|
||||
rx_state = RX_STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
static void EEPROM_SaveConfig(void) {
|
||||
/* 擦除扇区 (512字节, 从0x0000开始) */
|
||||
IAP_EraseSector(0x0000);
|
||||
|
||||
/* 写入对频标志 */
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, EEPROM_BIND_MAGIC);
|
||||
|
||||
/* 写入TX地址 */
|
||||
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
|
||||
IAP_WriteByte(EEPROM_ADDR_TX_ADDR + i, tx_addr[i]);
|
||||
}
|
||||
|
||||
/* 写入RF频道 */
|
||||
IAP_WriteByte(EEPROM_ADDR_RF_CH, rf_channel);
|
||||
|
||||
/* 写入对频短语 */
|
||||
for (uint8_t i = 0; i < RF_PHRASE_LEN; i++) {
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_PHRASE + i, bind_phrase[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* LED 控制 (P3.2, 低电平亮)
|
||||
* ======================================================================== */
|
||||
|
||||
static void LED_SetMode(uint8_t mode) {
|
||||
static uint8_t current_mode = 0xFF;
|
||||
if (mode != current_mode) {
|
||||
current_mode = mode;
|
||||
switch (mode) {
|
||||
case LED_ON: P32 = 0; break; /* 常亮 */
|
||||
case LED_OFF: P32 = 1; break; /* 熄灭 */
|
||||
default: break; /* 闪烁模式由 LED_Update 处理 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LED_Update(void) {
|
||||
uint8_t mode;
|
||||
if (nrf_hw_error) {
|
||||
mode = LED_BLINK_DOUBLE;
|
||||
} else if (rx_state == RX_STATE_BINDING) {
|
||||
mode = LED_BLINK_FAST;
|
||||
} else if (rx_state == RX_STATE_CONNECTED) {
|
||||
mode = LED_ON;
|
||||
} else {
|
||||
mode = LED_BLINK_SLOW;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case LED_BLINK_SLOW: /* 1Hz: 500ms亮/500ms灭 */
|
||||
P32 = (sys_tick % 100 < 50) ? 0 : 1;
|
||||
break;
|
||||
case LED_BLINK_FAST: /* 3Hz: ~167ms亮/~167ms灭 */
|
||||
P32 = (sys_tick % 30 < 15) ? 0 : 1;
|
||||
break;
|
||||
case LED_BLINK_DOUBLE: /* 双闪: 100ms亮+100ms灭+100ms亮+700ms灭 */
|
||||
{
|
||||
uint16_t t = sys_tick % 100;
|
||||
if (t < 10) P32 = 0; /* 亮 100ms */
|
||||
else if (t < 20) P32 = 1; /* 灭 100ms */
|
||||
else if (t < 30) P32 = 0; /* 亮 100ms */
|
||||
else P32 = 1; /* 灭 700ms */
|
||||
}
|
||||
break;
|
||||
case LED_ON:
|
||||
P32 = 0;
|
||||
break;
|
||||
default:
|
||||
P32 = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* PWM 通道设置
|
||||
* ======================================================================== */
|
||||
|
||||
static void PWM_SetChannel(uint8_t ch, uint16_t pulse_us) {
|
||||
if (ch >= CHANNEL_COUNT) return;
|
||||
|
||||
/* 限制脉宽范围: 1.0ms ~ 2.0ms */
|
||||
if (pulse_us < 1000) pulse_us = 1000;
|
||||
if (pulse_us > 2000) pulse_us = 2000;
|
||||
|
||||
/* 转换为4us步长 */
|
||||
pwm_ch[ch] = pulse_us / 4;
|
||||
}
|
||||
|
||||
static void PWM_SetAllFailsafe(void) {
|
||||
/* 失控保护: 所有通道回到中位 */
|
||||
for (uint8_t i = 0; i < CHANNEL_COUNT; i++) {
|
||||
pwm_ch[i] = PWM_MID;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* 串口命令解析
|
||||
* ======================================================================== */
|
||||
|
||||
static void Cmd_Respond(const char *resp) {
|
||||
UART1_SendString(resp);
|
||||
UART1_SendString("\r\n");
|
||||
}
|
||||
|
||||
static void Cmd_Parse(void) {
|
||||
if (!uart_cmd_ready) return;
|
||||
uart_cmd_ready = 0;
|
||||
|
||||
char *cmd = (char *)uart_rx_buf;
|
||||
|
||||
/* MODEL(SBUS) - 切换到SBUS模式 */
|
||||
if (strcmp(cmd, "MODEL(SBUS)") == 0) {
|
||||
out_mode = OUT_MODE_SBUS;
|
||||
SBUS_Init();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* MODEL(PWM) - 切换到PWM模式 */
|
||||
if (strcmp(cmd, "MODEL(PWM)") == 0) {
|
||||
out_mode = OUT_MODE_PWM;
|
||||
/* 重新初始化UART1为115200 */
|
||||
UART1_Init();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* MODEL(UART) - 切换到UART模式 (占位) */
|
||||
if (strcmp(cmd, "MODEL(UART)") == 0) {
|
||||
out_mode = OUT_MODE_UART;
|
||||
UART1_Init();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* MODEL(CRFS) - 切换到CRFS/CRSF输出模式 */
|
||||
if (strcmp(cmd, "MODEL(CRFS)") == 0) {
|
||||
out_mode = OUT_MODE_CRFS;
|
||||
CRFS_Init();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* ADDR(0xHH HH HH HH HH) - 切换NRF24L01地址 */
|
||||
if (cmd[0] == 'A' && cmd[1] == 'D' && cmd[2] == 'D' && cmd[3] == 'R') {
|
||||
/* 解析: ADDR(0xHH HH HH HH HH) */
|
||||
static uint8_t __xdata new_addr[NRF_ADDR_WIDTH];
|
||||
uint8_t ok = 1;
|
||||
char *p = cmd + 5; /* 跳过 "ADDR(" */
|
||||
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
|
||||
/* 跳过 "0x" */
|
||||
if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) p += 2;
|
||||
/* 跳过空格 */
|
||||
while (*p == ' ') p++;
|
||||
/* 解析两位十六进制 */
|
||||
uint8_t hi = 0, lo = 0;
|
||||
if (*p >= '0' && *p <= '9') hi = *p - '0';
|
||||
else if (*p >= 'A' && *p <= 'F') hi = *p - 'A' + 10;
|
||||
else if (*p >= 'a' && *p <= 'f') hi = *p - 'a' + 10;
|
||||
else { ok = 0; break; }
|
||||
p++;
|
||||
if (*p >= '0' && *p <= '9') lo = *p - '0';
|
||||
else if (*p >= 'A' && *p <= 'F') lo = *p - 'A' + 10;
|
||||
else if (*p >= 'a' && *p <= 'f') lo = *p - 'a' + 10;
|
||||
else { ok = 0; break; }
|
||||
p++;
|
||||
new_addr[i] = (hi << 4) | lo;
|
||||
}
|
||||
if (ok) {
|
||||
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++)
|
||||
tx_addr[i] = new_addr[i];
|
||||
NRF24L01_WriteBuf(NRF_TX_ADDR, tx_addr, NRF_ADDR_WIDTH);
|
||||
NRF24L01_WriteBuf(NRF_RX_ADDR_P0, tx_addr, NRF_ADDR_WIDTH);
|
||||
Cmd_Respond("OK");
|
||||
} else {
|
||||
Cmd_Respond("ERR_ADDR");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* TUN(N) - 切换RF频道 */
|
||||
if (cmd[0] == 'T' && cmd[1] == 'U' && cmd[2] == 'N') {
|
||||
uint8_t ch = 0;
|
||||
char *p = cmd + 4; /* 跳过 "TUN(" */
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
ch = ch * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
if (ch <= NRF_MAX_CHANNEL) {
|
||||
NRF24L01_SetChannel(ch);
|
||||
Cmd_Respond("OK");
|
||||
} else {
|
||||
Cmd_Respond("ERR_RANGE");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* DEL(BIND) - 清除对频信息 */
|
||||
if (strcmp(cmd, "DEL(BIND)") == 0) {
|
||||
/* 擦除EEPROM中的对频标志 */
|
||||
IAP_EraseSector(0x0000);
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, 0x00);
|
||||
rx_state = RX_STATE_BINDING;
|
||||
NRF_EnterBindMode();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* PHRASE(xxxxxx) - 设置对频短语, 1~6位字母数字 */
|
||||
if (cmd[0] == 'P' && cmd[1] == 'H' && cmd[2] == 'R' && cmd[3] == 'A'
|
||||
&& cmd[4] == 'S' && cmd[5] == 'E') {
|
||||
uint8_t i;
|
||||
char *p = cmd + 7; /* 跳过 "PHRASE(" */
|
||||
/* 计算短语长度 (直到 ')' 或结束) */
|
||||
uint8_t len = 0;
|
||||
while (p[len] && p[len] != ')' && len < RF_PHRASE_LEN) {
|
||||
char c = p[len];
|
||||
/* 只允许字母和数字 */
|
||||
if (!((c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z'))) {
|
||||
Cmd_Respond("ERR");
|
||||
return;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
if (len < 1 || len > RF_PHRASE_LEN) {
|
||||
Cmd_Respond("ERR_RANGE");
|
||||
return;
|
||||
}
|
||||
/* 复制新短语 */
|
||||
for (i = 0; i < len; i++)
|
||||
bind_phrase[i] = (uint8_t)p[i];
|
||||
/* 剩余部分用空格填充 */
|
||||
for (i = len; i < RF_PHRASE_LEN; i++)
|
||||
bind_phrase[i] = ' ';
|
||||
/* 保存到EEPROM */
|
||||
IAP_EraseSector(0x0000);
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, EEPROM_BIND_MAGIC);
|
||||
for (i = 0; i < NRF_ADDR_WIDTH; i++)
|
||||
IAP_WriteByte(EEPROM_ADDR_TX_ADDR + i, tx_addr[i]);
|
||||
IAP_WriteByte(EEPROM_ADDR_RF_CH, rf_channel);
|
||||
for (i = 0; i < RF_PHRASE_LEN; i++)
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_PHRASE + i, bind_phrase[i]);
|
||||
/* 重新初始化NRF以使用新短语 */
|
||||
NRF24L01_Init();
|
||||
NRF24L01_RXMode();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* TELEM(N) - 设置回传频率 1~10Hz */
|
||||
if (cmd[0] == 'T' && cmd[1] == 'E' && cmd[2] == 'L' && cmd[3] == 'E'
|
||||
&& cmd[4] == 'M') {
|
||||
uint8_t hz = 0;
|
||||
char *p = cmd + 6; /* 跳过 "TELEM(" */
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
hz = hz * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
if (hz >= 1 && hz <= 10) {
|
||||
telem_rate_hz = hz;
|
||||
Cmd_Respond("OK");
|
||||
} else {
|
||||
Cmd_Respond("ERR_RANGE");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 未知命令 */
|
||||
Cmd_Respond("UNK");
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* 主函数
|
||||
* ======================================================================== */
|
||||
|
||||
void main(void) {
|
||||
/* 系统初始化 */
|
||||
System_Init();
|
||||
GPIO_Init();
|
||||
Timer0_Init();
|
||||
UART1_Init();
|
||||
ADC_Init();
|
||||
IAP_Init();
|
||||
|
||||
/* 初始PWM: 中位 */
|
||||
PWM_SetAllFailsafe();
|
||||
|
||||
/* 从EEPROM加载配置 */
|
||||
EEPROM_LoadConfig();
|
||||
|
||||
/* 初始化NRF24L01 */
|
||||
NRF24L01_Init();
|
||||
|
||||
/* 检测NRF模块 */
|
||||
if (!NRF24L01_Check()) {
|
||||
/* NRF模块未检测到, 设置硬件错误标志, LED双闪 */
|
||||
nrf_hw_error = 1;
|
||||
}
|
||||
|
||||
/* 进入接收模式 */
|
||||
if (rx_state == RX_STATE_BINDING) {
|
||||
NRF_EnterBindMode();
|
||||
} else {
|
||||
NRF24L01_RXMode();
|
||||
}
|
||||
|
||||
/* 主循环 */
|
||||
while (1) {
|
||||
/* 处理串口命令 */
|
||||
Cmd_Parse();
|
||||
|
||||
/* NRF 硬件错误时定期重检 */
|
||||
if (nrf_hw_error) {
|
||||
static uint16_t last_check_tick = 0;
|
||||
if (sys_tick - last_check_tick >= 50) { /* 每 500ms 重检一次 */
|
||||
last_check_tick = sys_tick;
|
||||
NRF24L01_Init();
|
||||
if (NRF24L01_Check()) {
|
||||
nrf_hw_error = 0;
|
||||
NRF24L01_RXMode();
|
||||
}
|
||||
}
|
||||
LED_Update();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 对频模式 */
|
||||
if (rx_state == RX_STATE_BINDING) {
|
||||
if (NRF_DoBindScan()) {
|
||||
/* 对频成功, 继续 */
|
||||
}
|
||||
/* 更新LED */
|
||||
LED_Update();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 接收数据包 */
|
||||
if (NRF24L01_IsDataReady()) {
|
||||
NRF_ProcessPacket();
|
||||
} else {
|
||||
lost_packet_cnt++;
|
||||
/* 每 100 个丢失包更新一次丢包率 (滑动窗口) */
|
||||
static uint16_t loss_window_cnt = 0;
|
||||
static uint16_t loss_window_pkts = 0;
|
||||
loss_window_cnt++;
|
||||
loss_window_pkts++;
|
||||
if (loss_window_cnt >= 100) {
|
||||
/* 如果连续100次都没收到, 丢包率上升 */
|
||||
if (telem_packet_loss < 99) telem_packet_loss++;
|
||||
loss_window_cnt = 0;
|
||||
loss_window_pkts = 0;
|
||||
}
|
||||
if (lost_packet_cnt > LOST_PACKET_TIMEOUT) {
|
||||
if (rx_state == RX_STATE_CONNECTED) {
|
||||
rx_state = RX_STATE_DISCONNECTED;
|
||||
PWM_SetAllFailsafe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 回传发送 (PWM/SBUS 模式通过 NRF, CRFS 模式通过 UART) */
|
||||
if (rx_state == RX_STATE_CONNECTED) {
|
||||
static uint16_t last_telem_tick = 0;
|
||||
uint16_t telem_interval = 100 / telem_rate_hz; /* sys_tick=10ms单位 */
|
||||
if (telem_interval < 1) telem_interval = 1;
|
||||
if (sys_tick - last_telem_tick >= telem_interval) {
|
||||
last_telem_tick = sys_tick;
|
||||
|
||||
if (out_mode == OUT_MODE_CRFS) {
|
||||
/* CRFS 模式: 通过 CRSF 链路回传电压/RSSI/丢包
|
||||
* CRSF 遥测帧: type=0x02 (GPS), 或 type=0x08 (Battery sensor)
|
||||
* 这里使用 Battery sensor type=0x08
|
||||
* 帧: 0xEE + len + 0x08 + voltage(2B)+current(2B)+capacity(3B)+remaining(1B) + crc
|
||||
* 简化: 直接发一个精简遥测帧
|
||||
*/
|
||||
static uint8_t __xdata telem_frame[14];
|
||||
telem_frame[0] = 0xEE;
|
||||
telem_frame[1] = 10; /* len */
|
||||
telem_frame[2] = 0x08; /* Battery sensor */
|
||||
telem_frame[3] = (uint8_t)((bat_voltage_mv / 10) >> 8); /* voltage high (10mV单位) */
|
||||
telem_frame[4] = (uint8_t)((bat_voltage_mv / 10) & 0xFF); /* voltage low */
|
||||
telem_frame[5] = 0; /* current high */
|
||||
telem_frame[6] = 0; /* current low */
|
||||
telem_frame[7] = 0; /* capacity */
|
||||
telem_frame[8] = 0;
|
||||
telem_frame[9] = 0;
|
||||
telem_frame[10] = telem_rssi; /* remaining = RSSI */
|
||||
telem_frame[11] = CRSF_CalcCRC(telem_frame + 2, 9);
|
||||
for (uint8_t i = 0; i < 12; i++) {
|
||||
SBUF = telem_frame[i];
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
} else {
|
||||
/* PWM/SBUS 模式: 通过 NRF 回传 */
|
||||
NRF_SendTelemetry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SBUS 输出模式 (每10ms发送一帧) */
|
||||
if (out_mode == OUT_MODE_SBUS && rx_state == RX_STATE_CONNECTED) {
|
||||
static uint16_t last_sbus_tick = 0;
|
||||
if (sys_tick - last_sbus_tick >= 10) {
|
||||
last_sbus_tick = sys_tick;
|
||||
SBUS_SendFrame();
|
||||
}
|
||||
}
|
||||
|
||||
/* CRFS 输出模式 (每10ms发送一帧) */
|
||||
if (out_mode == OUT_MODE_CRFS && rx_state == RX_STATE_CONNECTED) {
|
||||
static uint16_t last_crfs_tick = 0;
|
||||
if (sys_tick - last_crfs_tick >= 10) {
|
||||
last_crfs_tick = sys_tick;
|
||||
CRFS_SendFrame();
|
||||
}
|
||||
|
||||
/* 转发飞控发来的 CRSF 帧到 NRF 回传通道 */
|
||||
if (crfs_forward_len >= 3) {
|
||||
uint8_t frame_len = crfs_forward_buf[1] + 2;
|
||||
if (crfs_forward_len >= frame_len) {
|
||||
/* 通过 NRF 转发给发射机 */
|
||||
NRF24L01_TXMode();
|
||||
NRF_CSN = 0;
|
||||
NRF_SPI_TransferByte(NRF_CMD_FLUSH_TX);
|
||||
NRF_CSN = 1;
|
||||
NRF_CSN = 0;
|
||||
NRF_SPI_TransferByte(NRF_CMD_W_TX_PAYLOAD);
|
||||
for (uint8_t i = 0; i < frame_len && i < RF_PACKET_SIZE; i++)
|
||||
NRF_SPI_TransferByte(crfs_forward_buf[i]);
|
||||
NRF_CSN = 1;
|
||||
NRF_CE = 1;
|
||||
for (volatile uint16_t d = 0; d < 100; d++);
|
||||
NRF_CE = 0;
|
||||
NRF24L01_RXMode();
|
||||
NRF24L01_FlushRX();
|
||||
crfs_forward_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 读取电池电压 (每100ms) */
|
||||
static uint16_t last_adc_tick = 0;
|
||||
if (sys_tick - last_adc_tick >= 100) {
|
||||
last_adc_tick = sys_tick;
|
||||
|
||||
/* 读取电池分压 ADC (P3.3/ADC11) */
|
||||
uint16_t bat_adc = ADC_Read();
|
||||
|
||||
/* 读取内部带隙基准 (通道14), 反算 VCC */
|
||||
uint16_t bg_adc = ADC_ReadBandgap();
|
||||
|
||||
/* VCC(mV) = 1190 * 4096 / bg_adc
|
||||
* V_bat(mV) = bat_adc * VCC / 4096 * 11 (分压比 1K:10K = 1/11)
|
||||
* 合并: V_bat(mV) = bat_adc * 1190 * 11 / bg_adc
|
||||
* = bat_adc * 13090 / bg_adc
|
||||
*/
|
||||
if (bg_adc > 0) {
|
||||
uint32_t tmp = (uint32_t)bat_adc * 13090UL / bg_adc;
|
||||
bat_voltage_mv = (uint16_t)tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* 更新LED */
|
||||
LED_Update();
|
||||
}
|
||||
}
|
||||
|
||||
+590
@@ -0,0 +1,590 @@
|
||||
/**
|
||||
* ZhaTianRX - STC8H1K08 接收机固件
|
||||
* 主程序: NRF24L01 接收 + 4路舵机PWM + SBUS输出 + 串口命令
|
||||
*
|
||||
* MCU: STC8H1K08 (SOP16/SOP20)
|
||||
* 编译: SDCC -mmcs51 --model-small
|
||||
*
|
||||
* 引脚分配:
|
||||
* CH1(P3.7) CH2(P3.6) CH3(P3.5) CH4(P3.4) - 舵机PWM输出 50Hz
|
||||
* BAT_ADC(P3.3/ADC11) - 电池电压分压输入
|
||||
* LED(P3.2) - 状态指示灯 (低电平亮)
|
||||
* TX(P3.1) - UART1 TX / SBUS 输出 (经板上三极管反相)
|
||||
* RX(P3.0) - UART1 RX / 命令输入
|
||||
*
|
||||
* NRF24L01 (硬件SPI):
|
||||
* SCK(P1.5) CE(P1.6) IRQ(P1.7) CSN(P5.4) MISO(P1.3) MOSI(P1.4)
|
||||
*/
|
||||
# ifndef CONFIG
|
||||
# define CONFIG
|
||||
# include "CONFIG.h"
|
||||
# endif
|
||||
|
||||
#include "NRF24.h"
|
||||
#include "UART.h"
|
||||
|
||||
/* ========================================================================
|
||||
* 函数声明
|
||||
* ======================================================================== */
|
||||
|
||||
static void System_Init(void);
|
||||
static void GPIO_Init(void);
|
||||
static void Timer0_Init(void);
|
||||
static void UART1_Init(void);
|
||||
static void ADC_Init(void);
|
||||
static void IAP_Init(void);
|
||||
|
||||
static uint8_t IAP_ReadByte(uint16_t addr);
|
||||
static void IAP_WriteByte(uint16_t addr, uint8_t dat);
|
||||
static void IAP_EraseSector(uint16_t addr);
|
||||
|
||||
static void EEPROM_LoadConfig(void);
|
||||
static void EEPROM_SaveConfig(void);
|
||||
static uint8_t EEPROM_IsBound(void);
|
||||
|
||||
static void LED_SetMode(uint8_t mode);
|
||||
static void LED_Update(void);
|
||||
|
||||
static void PWM_SetChannel(uint8_t ch, uint16_t pulse_us);
|
||||
static void PWM_SetAllFailsafe(void);
|
||||
|
||||
static void UART1_SendByte(uint8_t dat);
|
||||
static void UART1_SendString(const char *s);
|
||||
static void UART1_SendStringLen(const char *s, uint8_t len);
|
||||
|
||||
static void SBUS_SendFrame(void);
|
||||
static void SBUS_Init(void);
|
||||
|
||||
static void CRFS_SendFrame(void);
|
||||
static void CRFS_Init(void);
|
||||
|
||||
static void Cmd_Parse(void);
|
||||
static void Cmd_Respond(const char *resp);
|
||||
|
||||
static void NRF_ProcessPacket(void);
|
||||
static void NRF_EnterBindMode(void);
|
||||
static uint8_t NRF_DoBindScan(void);
|
||||
static void NRF_SendTelemetry(void);
|
||||
|
||||
/* ========================================================================
|
||||
* 系统初始化
|
||||
* ======================================================================== */
|
||||
|
||||
static void System_Init(void) {
|
||||
|
||||
}
|
||||
|
||||
static void GPIO_Init(void) {
|
||||
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* 定时器0 - PWM 时基 (4us 中断)
|
||||
* ======================================================================== */
|
||||
|
||||
static void Timer0_Init(void) {
|
||||
|
||||
}
|
||||
|
||||
/* T0 中断服务 - 4us一次, 生成4路PWM */
|
||||
void tm0_isr(void) __interrupt(1) {
|
||||
static uint16_t pwm_cnt = 0;
|
||||
|
||||
pwm_cnt++;
|
||||
if (pwm_cnt >= PWM_PERIOD) {
|
||||
pwm_cnt = 0;
|
||||
}
|
||||
|
||||
/* 4路舵机PWM (P3.4-P3.7) */
|
||||
if (pwm_cnt < pwm_ch[0]) P37 = 1; else P37 = 0;
|
||||
if (pwm_cnt < pwm_ch[1]) P36 = 1; else P36 = 0;
|
||||
if (pwm_cnt < pwm_ch[2]) P35 = 1; else P35 = 0;
|
||||
if (pwm_cnt < pwm_ch[3]) P34 = 1; else P34 = 0;
|
||||
|
||||
/* 系统滴答 (每10ms) */
|
||||
if (pwm_cnt == 0) {
|
||||
sys_tick++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* ADC - 电池电压检测 (P3.3/ADC11)
|
||||
* ======================================================================== */
|
||||
|
||||
static void ADC_Init(void) {
|
||||
ADCCFG = ADC_RESFMT; /* 右对齐, 12位结果 */
|
||||
ADC_CONTR = ADC_POWER; /* 开启ADC电源 */
|
||||
/* 选择通道11 (P3.3) */
|
||||
ADC_CONTR = (ADC_CONTR & 0xF0) | 0x0B;
|
||||
}
|
||||
|
||||
/* 读取指定ADC通道 */
|
||||
static uint16_t ADC_ReadChannel(uint8_t ch) {
|
||||
ADC_CONTR = (ADC_CONTR & 0xF0) | ch; /* 切换通道 */
|
||||
__asm nop __endasm; /* 等待通道切换稳定 */
|
||||
__asm nop __endasm;
|
||||
ADC_CONTR |= ADC_START; /* 启动转换 */
|
||||
while (!(ADC_CONTR & ADC_FLAG)); /* 等待完成 */
|
||||
ADC_CONTR &= ~ADC_FLAG; /* 清除标志 */
|
||||
return ((uint16_t)ADC_RES << 8) | ADC_RESL;
|
||||
}
|
||||
|
||||
static uint16_t ADC_Read(void) {
|
||||
return ADC_ReadChannel(0x0B); /* P3.3/ADC11 */
|
||||
}
|
||||
|
||||
/* 读取内部带隙基准电压 (通道14), 用于反算VCC */
|
||||
/* VCC(mV) = 1190 * 4096 / bandgap_adc */
|
||||
static uint16_t ADC_ReadBandgap(void) {
|
||||
return ADC_ReadChannel(0x0E); /* 内部带隙基准 */
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* LED 控制 (P3.2, 低电平亮)
|
||||
* ======================================================================== */
|
||||
|
||||
static void LED_SetMode(uint8_t mode) {
|
||||
static uint8_t current_mode = 0xFF;
|
||||
if (mode != current_mode) {
|
||||
current_mode = mode;
|
||||
switch (mode) {
|
||||
case LED_ON: P32 = 0; break; /* 常亮 */
|
||||
case LED_OFF: P32 = 1; break; /* 熄灭 */
|
||||
default: break; /* 闪烁模式由 LED_Update 处理 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LED_Update(void) {
|
||||
uint8_t mode;
|
||||
if (nrf_hw_error) {
|
||||
mode = LED_BLINK_DOUBLE;
|
||||
} else if (rx_state == RX_STATE_BINDING) {
|
||||
mode = LED_BLINK_FAST;
|
||||
} else if (rx_state == RX_STATE_CONNECTED) {
|
||||
mode = LED_ON;
|
||||
} else {
|
||||
mode = LED_BLINK_SLOW;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case LED_BLINK_SLOW: /* 1Hz: 500ms亮/500ms灭 */
|
||||
P32 = (sys_tick % 100 < 50) ? 0 : 1;
|
||||
break;
|
||||
case LED_BLINK_FAST: /* 3Hz: ~167ms亮/~167ms灭 */
|
||||
P32 = (sys_tick % 30 < 15) ? 0 : 1;
|
||||
break;
|
||||
case LED_BLINK_DOUBLE: /* 双闪: 100ms亮+100ms灭+100ms亮+700ms灭 */
|
||||
{
|
||||
uint16_t t = sys_tick % 100;
|
||||
if (t < 10) P32 = 0; /* 亮 100ms */
|
||||
else if (t < 20) P32 = 1; /* 灭 100ms */
|
||||
else if (t < 30) P32 = 0; /* 亮 100ms */
|
||||
else P32 = 1; /* 灭 700ms */
|
||||
}
|
||||
break;
|
||||
case LED_ON:
|
||||
P32 = 0;
|
||||
break;
|
||||
default:
|
||||
P32 = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* PWM 通道设置
|
||||
* ======================================================================== */
|
||||
|
||||
static void PWM_SetChannel(uint8_t ch, uint16_t pulse_us) {
|
||||
if (ch >= CHANNEL_COUNT) return;
|
||||
|
||||
/* 限制脉宽范围: 1.0ms ~ 2.0ms */
|
||||
if (pulse_us < 1000) pulse_us = 1000;
|
||||
if (pulse_us > 2000) pulse_us = 2000;
|
||||
|
||||
/* 转换为4us步长 */
|
||||
pwm_ch[ch] = pulse_us / 4;
|
||||
}
|
||||
|
||||
static void PWM_SetAllFailsafe(void) {
|
||||
/* 失控保护: 所有通道回到中位 */
|
||||
for (uint8_t i = 0; i < CHANNEL_COUNT; i++) {
|
||||
pwm_ch[i] = PWM_MID;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* 串口命令解析
|
||||
* ======================================================================== */
|
||||
|
||||
static void Cmd_Respond(const char *resp) {
|
||||
UART1_SendString(resp);
|
||||
UART1_SendString("\r\n");
|
||||
}
|
||||
|
||||
static void Cmd_Parse(void) {
|
||||
if (!uart_cmd_ready) return;
|
||||
uart_cmd_ready = 0;
|
||||
|
||||
char *cmd = (char *)uart_rx_buf;
|
||||
|
||||
/* MODEL(SBUS) - 切换到SBUS模式 */
|
||||
if (strcmp(cmd, "MODEL(SBUS)") == 0) {
|
||||
out_mode = OUT_MODE_SBUS;
|
||||
SBUS_Init();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* MODEL(PWM) - 切换到PWM模式 */
|
||||
if (strcmp(cmd, "MODEL(PWM)") == 0) {
|
||||
out_mode = OUT_MODE_PWM;
|
||||
/* 重新初始化UART1为115200 */
|
||||
UART1_Init();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* MODEL(UART) - 切换到UART模式 (占位) */
|
||||
if (strcmp(cmd, "MODEL(UART)") == 0) {
|
||||
out_mode = OUT_MODE_UART;
|
||||
UART1_Init();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* MODEL(CRFS) - 切换到CRFS/CRSF输出模式 */
|
||||
if (strcmp(cmd, "MODEL(CRFS)") == 0) {
|
||||
out_mode = OUT_MODE_CRFS;
|
||||
CRFS_Init();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* ADDR(0xHH HH HH HH HH) - 切换NRF24L01地址 */
|
||||
if (cmd[0] == 'A' && cmd[1] == 'D' && cmd[2] == 'D' && cmd[3] == 'R') {
|
||||
/* 解析: ADDR(0xHH HH HH HH HH) */
|
||||
static uint8_t __xdata new_addr[NRF_ADDR_WIDTH];
|
||||
uint8_t ok = 1;
|
||||
char *p = cmd + 5; /* 跳过 "ADDR(" */
|
||||
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
|
||||
/* 跳过 "0x" */
|
||||
if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) p += 2;
|
||||
/* 跳过空格 */
|
||||
while (*p == ' ') p++;
|
||||
/* 解析两位十六进制 */
|
||||
uint8_t hi = 0, lo = 0;
|
||||
if (*p >= '0' && *p <= '9') hi = *p - '0';
|
||||
else if (*p >= 'A' && *p <= 'F') hi = *p - 'A' + 10;
|
||||
else if (*p >= 'a' && *p <= 'f') hi = *p - 'a' + 10;
|
||||
else { ok = 0; break; }
|
||||
p++;
|
||||
if (*p >= '0' && *p <= '9') lo = *p - '0';
|
||||
else if (*p >= 'A' && *p <= 'F') lo = *p - 'A' + 10;
|
||||
else if (*p >= 'a' && *p <= 'f') lo = *p - 'a' + 10;
|
||||
else { ok = 0; break; }
|
||||
p++;
|
||||
new_addr[i] = (hi << 4) | lo;
|
||||
}
|
||||
if (ok) {
|
||||
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++)
|
||||
tx_addr[i] = new_addr[i];
|
||||
NRF24L01_WriteBuf(NRF_TX_ADDR, tx_addr, NRF_ADDR_WIDTH);
|
||||
NRF24L01_WriteBuf(NRF_RX_ADDR_P0, tx_addr, NRF_ADDR_WIDTH);
|
||||
Cmd_Respond("OK");
|
||||
} else {
|
||||
Cmd_Respond("ERR_ADDR");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* TUN(N) - 切换RF频道 */
|
||||
if (cmd[0] == 'T' && cmd[1] == 'U' && cmd[2] == 'N') {
|
||||
uint8_t ch = 0;
|
||||
char *p = cmd + 4; /* 跳过 "TUN(" */
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
ch = ch * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
if (ch <= NRF_MAX_CHANNEL) {
|
||||
NRF24L01_SetChannel(ch);
|
||||
Cmd_Respond("OK");
|
||||
} else {
|
||||
Cmd_Respond("ERR_RANGE");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* DEL(BIND) - 清除对频信息 */
|
||||
if (strcmp(cmd, "DEL(BIND)") == 0) {
|
||||
/* 擦除EEPROM中的对频标志 */
|
||||
IAP_EraseSector(0x0000);
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, 0x00);
|
||||
rx_state = RX_STATE_BINDING;
|
||||
NRF_EnterBindMode();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* PHRASE(xxxxxx) - 设置对频短语, 1~6位字母数字 */
|
||||
if (cmd[0] == 'P' && cmd[1] == 'H' && cmd[2] == 'R' && cmd[3] == 'A'
|
||||
&& cmd[4] == 'S' && cmd[5] == 'E') {
|
||||
uint8_t i;
|
||||
char *p = cmd + 7; /* 跳过 "PHRASE(" */
|
||||
/* 计算短语长度 (直到 ')' 或结束) */
|
||||
uint8_t len = 0;
|
||||
while (p[len] && p[len] != ')' && len < RF_PHRASE_LEN) {
|
||||
char c = p[len];
|
||||
/* 只允许字母和数字 */
|
||||
if (!((c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z'))) {
|
||||
Cmd_Respond("ERR");
|
||||
return;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
if (len < 1 || len > RF_PHRASE_LEN) {
|
||||
Cmd_Respond("ERR_RANGE");
|
||||
return;
|
||||
}
|
||||
/* 复制新短语 */
|
||||
for (i = 0; i < len; i++)
|
||||
bind_phrase[i] = (uint8_t)p[i];
|
||||
/* 剩余部分用空格填充 */
|
||||
for (i = len; i < RF_PHRASE_LEN; i++)
|
||||
bind_phrase[i] = ' ';
|
||||
/* 保存到EEPROM */
|
||||
IAP_EraseSector(0x0000);
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, EEPROM_BIND_MAGIC);
|
||||
for (i = 0; i < NRF_ADDR_WIDTH; i++)
|
||||
IAP_WriteByte(EEPROM_ADDR_TX_ADDR + i, tx_addr[i]);
|
||||
IAP_WriteByte(EEPROM_ADDR_RF_CH, rf_channel);
|
||||
for (i = 0; i < RF_PHRASE_LEN; i++)
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_PHRASE + i, bind_phrase[i]);
|
||||
/* 重新初始化NRF以使用新短语 */
|
||||
NRF24L01_Init();
|
||||
NRF24L01_RXMode();
|
||||
Cmd_Respond("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
/* TELEM(N) - 设置回传频率 1~10Hz */
|
||||
if (cmd[0] == 'T' && cmd[1] == 'E' && cmd[2] == 'L' && cmd[3] == 'E'
|
||||
&& cmd[4] == 'M') {
|
||||
uint8_t hz = 0;
|
||||
char *p = cmd + 6; /* 跳过 "TELEM(" */
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
hz = hz * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
if (hz >= 1 && hz <= 10) {
|
||||
telem_rate_hz = hz;
|
||||
Cmd_Respond("OK");
|
||||
} else {
|
||||
Cmd_Respond("ERR_RANGE");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 未知命令 */
|
||||
Cmd_Respond("UNK");
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* 主函数
|
||||
* ======================================================================== */
|
||||
|
||||
void main(void) {
|
||||
/* 系统初始化 */
|
||||
System_Init();
|
||||
GPIO_Init();
|
||||
Timer0_Init();
|
||||
UART1_Init();
|
||||
ADC_Init();
|
||||
IAP_Init();
|
||||
|
||||
/* 初始PWM: 中位 */
|
||||
PWM_SetAllFailsafe();
|
||||
|
||||
/* 从EEPROM加载配置 */
|
||||
EEPROM_LoadConfig();
|
||||
|
||||
/* 初始化NRF24L01 */
|
||||
NRF24L01_Init();
|
||||
|
||||
/* 检测NRF模块 */
|
||||
if (!NRF24L01_Check()) {
|
||||
/* NRF模块未检测到, 设置硬件错误标志, LED双闪 */
|
||||
nrf_hw_error = 1;
|
||||
}
|
||||
|
||||
/* 进入接收模式 */
|
||||
if (rx_state == RX_STATE_BINDING) {
|
||||
NRF_EnterBindMode();
|
||||
} else {
|
||||
NRF24L01_RXMode();
|
||||
}
|
||||
|
||||
/* 主循环 */
|
||||
while (1) {
|
||||
/* 处理串口命令 */
|
||||
Cmd_Parse();
|
||||
|
||||
/* NRF 硬件错误时定期重检 */
|
||||
if (nrf_hw_error) {
|
||||
static uint16_t last_check_tick = 0;
|
||||
if (sys_tick - last_check_tick >= 50) { /* 每 500ms 重检一次 */
|
||||
last_check_tick = sys_tick;
|
||||
NRF24L01_Init();
|
||||
if (NRF24L01_Check()) {
|
||||
nrf_hw_error = 0;
|
||||
NRF24L01_RXMode();
|
||||
}
|
||||
}
|
||||
LED_Update();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 对频模式 */
|
||||
if (rx_state == RX_STATE_BINDING) {
|
||||
if (NRF_DoBindScan()) {
|
||||
/* 对频成功, 继续 */
|
||||
}
|
||||
/* 更新LED */
|
||||
LED_Update();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 接收数据包 */
|
||||
if (NRF24L01_IsDataReady()) {
|
||||
NRF_ProcessPacket();
|
||||
} else {
|
||||
lost_packet_cnt++;
|
||||
/* 每 100 个丢失包更新一次丢包率 (滑动窗口) */
|
||||
static uint16_t loss_window_cnt = 0;
|
||||
static uint16_t loss_window_pkts = 0;
|
||||
loss_window_cnt++;
|
||||
loss_window_pkts++;
|
||||
if (loss_window_cnt >= 100) {
|
||||
/* 如果连续100次都没收到, 丢包率上升 */
|
||||
if (telem_packet_loss < 99) telem_packet_loss++;
|
||||
loss_window_cnt = 0;
|
||||
loss_window_pkts = 0;
|
||||
}
|
||||
if (lost_packet_cnt > LOST_PACKET_TIMEOUT) {
|
||||
if (rx_state == RX_STATE_CONNECTED) {
|
||||
rx_state = RX_STATE_DISCONNECTED;
|
||||
PWM_SetAllFailsafe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 回传发送 (PWM/SBUS 模式通过 NRF, CRFS 模式通过 UART) */
|
||||
if (rx_state == RX_STATE_CONNECTED) {
|
||||
static uint16_t last_telem_tick = 0;
|
||||
uint16_t telem_interval = 100 / telem_rate_hz; /* sys_tick=10ms单位 */
|
||||
if (telem_interval < 1) telem_interval = 1;
|
||||
if (sys_tick - last_telem_tick >= telem_interval) {
|
||||
last_telem_tick = sys_tick;
|
||||
|
||||
if (out_mode == OUT_MODE_CRFS) {
|
||||
/* CRFS 模式: 通过 CRSF 链路回传电压/RSSI/丢包
|
||||
* CRSF 遥测帧: type=0x02 (GPS), 或 type=0x08 (Battery sensor)
|
||||
* 这里使用 Battery sensor type=0x08
|
||||
* 帧: 0xEE + len + 0x08 + voltage(2B)+current(2B)+capacity(3B)+remaining(1B) + crc
|
||||
* 简化: 直接发一个精简遥测帧
|
||||
*/
|
||||
static uint8_t __xdata telem_frame[14];
|
||||
telem_frame[0] = 0xEE;
|
||||
telem_frame[1] = 10; /* len */
|
||||
telem_frame[2] = 0x08; /* Battery sensor */
|
||||
telem_frame[3] = (uint8_t)((bat_voltage_mv / 10) >> 8); /* voltage high (10mV单位) */
|
||||
telem_frame[4] = (uint8_t)((bat_voltage_mv / 10) & 0xFF); /* voltage low */
|
||||
telem_frame[5] = 0; /* current high */
|
||||
telem_frame[6] = 0; /* current low */
|
||||
telem_frame[7] = 0; /* capacity */
|
||||
telem_frame[8] = 0;
|
||||
telem_frame[9] = 0;
|
||||
telem_frame[10] = telem_rssi; /* remaining = RSSI */
|
||||
telem_frame[11] = CRSF_CalcCRC(telem_frame + 2, 9);
|
||||
for (uint8_t i = 0; i < 12; i++) {
|
||||
SBUF = telem_frame[i];
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
} else {
|
||||
/* PWM/SBUS 模式: 通过 NRF 回传 */
|
||||
NRF_SendTelemetry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SBUS 输出模式 (每10ms发送一帧) */
|
||||
if (out_mode == OUT_MODE_SBUS && rx_state == RX_STATE_CONNECTED) {
|
||||
static uint16_t last_sbus_tick = 0;
|
||||
if (sys_tick - last_sbus_tick >= 10) {
|
||||
last_sbus_tick = sys_tick;
|
||||
SBUS_SendFrame();
|
||||
}
|
||||
}
|
||||
|
||||
/* CRFS 输出模式 (每10ms发送一帧) */
|
||||
if (out_mode == OUT_MODE_CRFS && rx_state == RX_STATE_CONNECTED) {
|
||||
static uint16_t last_crfs_tick = 0;
|
||||
if (sys_tick - last_crfs_tick >= 10) {
|
||||
last_crfs_tick = sys_tick;
|
||||
CRFS_SendFrame();
|
||||
}
|
||||
|
||||
/* 转发飞控发来的 CRSF 帧到 NRF 回传通道 */
|
||||
if (crfs_forward_len >= 3) {
|
||||
uint8_t frame_len = crfs_forward_buf[1] + 2;
|
||||
if (crfs_forward_len >= frame_len) {
|
||||
/* 通过 NRF 转发给发射机 */
|
||||
NRF24L01_TXMode();
|
||||
NRF_CSN = 0;
|
||||
NRF_SPI_TransferByte(NRF_CMD_FLUSH_TX);
|
||||
NRF_CSN = 1;
|
||||
NRF_CSN = 0;
|
||||
NRF_SPI_TransferByte(NRF_CMD_W_TX_PAYLOAD);
|
||||
for (uint8_t i = 0; i < frame_len && i < RF_PACKET_SIZE; i++)
|
||||
NRF_SPI_TransferByte(crfs_forward_buf[i]);
|
||||
NRF_CSN = 1;
|
||||
NRF_CE = 1;
|
||||
for (volatile uint16_t d = 0; d < 100; d++);
|
||||
NRF_CE = 0;
|
||||
NRF24L01_RXMode();
|
||||
NRF24L01_FlushRX();
|
||||
crfs_forward_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 读取电池电压 (每100ms) */
|
||||
static uint16_t last_adc_tick = 0;
|
||||
if (sys_tick - last_adc_tick >= 100) {
|
||||
last_adc_tick = sys_tick;
|
||||
|
||||
/* 读取电池分压 ADC (P3.3/ADC11) */
|
||||
uint16_t bat_adc = ADC_Read();
|
||||
|
||||
/* 读取内部带隙基准 (通道14), 反算 VCC */
|
||||
uint16_t bg_adc = ADC_ReadBandgap();
|
||||
|
||||
/* VCC(mV) = 1190 * 4096 / bg_adc
|
||||
* V_bat(mV) = bat_adc * VCC / 4096 * 11 (分压比 1K:10K = 1/11)
|
||||
* 合并: V_bat(mV) = bat_adc * 1190 * 11 / bg_adc
|
||||
* = bat_adc * 13090 / bg_adc
|
||||
*/
|
||||
if (bg_adc > 0) {
|
||||
uint32_t tmp = (uint32_t)bat_adc * 13090UL / bg_adc;
|
||||
bat_voltage_mv = (uint16_t)tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* 更新LED */
|
||||
LED_Update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
static uint8_t CRSF_CalcCRC(uint8_t *data, uint8_t len) {
|
||||
uint8_t crc = 0;
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
crc = crsf_crc8_tab[crc ^ data[i]];
|
||||
return crc;
|
||||
}
|
||||
|
||||
static void CRFS_Init(void) {
|
||||
/* 切换到 CRSF 波特率 420000 */
|
||||
/* 420000 @ 24MHz: T2 reload = 65536 - 14 = 0xFFF2 */
|
||||
T2H = 0xFF;
|
||||
T2L = 0xF2;
|
||||
AUXR |= T2x12;
|
||||
AUXR |= T2R;
|
||||
|
||||
/* 8N1: 8数据位, 无校验, 1停止位 */
|
||||
PCON &= ~SMOD0; /* SMOD0=0, 标准帧格式 */
|
||||
SCON = 0x50; /* 模式1, REN=1, 8N1 */
|
||||
}
|
||||
|
||||
static void CRFS_SendFrame(void) {
|
||||
static uint8_t __xdata frame[28]; /* 0xEE + len + type + 22payload + crc */
|
||||
static uint16_t __xdata crsf_ch[16];
|
||||
uint8_t i;
|
||||
|
||||
/* CRSF RC通道帧: type=0x16 */
|
||||
frame[0] = 0xEE; /* sync */
|
||||
frame[1] = 24; /* length (type + payload + crc = 1+22+1) */
|
||||
frame[2] = 0x16; /* RC channels type */
|
||||
|
||||
/* 将4路pwm值(250-500)映射到CRSF范围(0-1984, 中位992) */
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint16_t val = pwm_ch[i];
|
||||
if (val < PWM_MIN) val = PWM_MIN;
|
||||
if (val > PWM_MAX) val = PWM_MAX;
|
||||
/* pwm_ch: 250~500 → CRSF: 0~1984 (中位992) */
|
||||
crsf_ch[i] = (uint16_t)((uint32_t)(val - PWM_MIN) * 1984 / (PWM_MAX - PWM_MIN));
|
||||
}
|
||||
for (i = 4; i < 16; i++) {
|
||||
crsf_ch[i] = 992; /* 中位 */
|
||||
}
|
||||
|
||||
/* 11-bit 打包到 payload (22字节) */
|
||||
uint8_t *pl = frame + 3;
|
||||
pl[0] = (uint8_t)(crsf_ch[0] & 0xFF);
|
||||
pl[1] = (uint8_t)((crsf_ch[0] >> 8) | ((crsf_ch[1] & 0x07) << 3));
|
||||
pl[2] = (uint8_t)((crsf_ch[1] >> 3) | ((crsf_ch[2] & 0x3F) << 5));
|
||||
pl[3] = (uint8_t)((crsf_ch[2] >> 6) | ((crsf_ch[3] & 0x01) << 2) | ((crsf_ch[3] & 0x01) << 2));
|
||||
/* 剩余通道用中间值填充 */
|
||||
for (i = 4; i < 22; i++)
|
||||
pl[i] = 0x00;
|
||||
|
||||
/* CRC8 (从 type 开始到 payload 结束) */
|
||||
frame[25] = CRSF_CalcCRC(frame + 2, 23); /* type(1) + payload(22) */
|
||||
|
||||
/* 通过UART1发送 */
|
||||
for (i = 0; i < 26; i++) {
|
||||
SBUF = frame[i];
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* ========================================================================
|
||||
* CRFS (CRSF/Crossfire) 输出 (420kbps 8N1, 与UART1共用TX)
|
||||
* 帧格式: 0xEE + len + type + payload + crc8
|
||||
* RC通道帧: type=0x16, payload=22字节 (16ch × 11bit)
|
||||
* ======================================================================== */
|
||||
/* CRC8 查表 (多项式 0xD5, CRSF 标准, 放在 CODE 区) */
|
||||
static const uint8_t __code crsf_crc8_tab[256] = {
|
||||
0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54,
|
||||
0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
|
||||
0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06,
|
||||
0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
|
||||
0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0,
|
||||
0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
|
||||
0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2,
|
||||
0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
|
||||
0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9,
|
||||
0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
|
||||
0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B,
|
||||
0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
|
||||
0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D,
|
||||
0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
|
||||
0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F,
|
||||
0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
|
||||
0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB,
|
||||
0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
|
||||
0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9,
|
||||
0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
|
||||
0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F,
|
||||
0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
|
||||
0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D,
|
||||
0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
|
||||
0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26,
|
||||
0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
|
||||
0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74,
|
||||
0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
|
||||
0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82,
|
||||
0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
|
||||
0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0,
|
||||
0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
|
||||
};
|
||||
|
||||
static uint8_t CRSF_CalcCRC(uint8_t *data, uint8_t len);
|
||||
static void CRFS_Init(void);
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/* ========================================================================
|
||||
* IAP/EEPROM 操作
|
||||
* ======================================================================== */
|
||||
|
||||
static void IAP_Init(void) {
|
||||
/* IAP 默认已就绪, 无需额外初始化 */
|
||||
}
|
||||
|
||||
static uint8_t IAP_ReadByte(uint16_t addr) {
|
||||
uint8_t dat;
|
||||
IAP_CONTR = IAPEN; /* 使能IAP */
|
||||
IAP_CMD = IAP_READ;
|
||||
IAP_ADDRH = (uint8_t)(addr >> 8);
|
||||
IAP_ADDRL = (uint8_t)(addr & 0xFF);
|
||||
/* 触发 */
|
||||
TA = 0x5A;
|
||||
TA = 0xA5;
|
||||
IAP_TRIG = 0x5A;
|
||||
IAP_TRIG = 0xA5;
|
||||
/* NOP 等待 */
|
||||
__asm nop __endasm;
|
||||
__asm nop __endasm;
|
||||
dat = IAP_DATA;
|
||||
IAP_CONTR = 0x00; /* 关闭IAP */
|
||||
return dat;
|
||||
}
|
||||
|
||||
static void IAP_WriteByte(uint16_t addr, uint8_t dat) {
|
||||
IAP_CONTR = IAPEN; /* 使能IAP */
|
||||
IAP_CMD = IAP_WRITE;
|
||||
IAP_ADDRH = (uint8_t)(addr >> 8);
|
||||
IAP_ADDRL = (uint8_t)(addr & 0xFF);
|
||||
IAP_DATA = dat;
|
||||
/* 触发 */
|
||||
TA = 0x5A;
|
||||
TA = 0xA5;
|
||||
IAP_TRIG = 0x5A;
|
||||
IAP_TRIG = 0xA5;
|
||||
__asm nop __endasm;
|
||||
__asm nop __endasm;
|
||||
IAP_CONTR = 0x00; /* 关闭IAP */
|
||||
}
|
||||
|
||||
static void IAP_EraseSector(uint16_t addr) {
|
||||
IAP_CONTR = IAPEN; /* 使能IAP */
|
||||
IAP_CMD = IAP_ERASE;
|
||||
IAP_ADDRH = (uint8_t)(addr >> 8);
|
||||
IAP_ADDRL = (uint8_t)(addr & 0xFF);
|
||||
/* 触发 */
|
||||
TA = 0x5A;
|
||||
TA = 0xA5;
|
||||
IAP_TRIG = 0x5A;
|
||||
IAP_TRIG = 0xA5;
|
||||
__asm nop __endasm;
|
||||
__asm nop __endasm;
|
||||
IAP_CONTR = 0x00; /* 关闭IAP */
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* EEPROM 配置存储
|
||||
* ======================================================================== */
|
||||
|
||||
static uint8_t EEPROM_IsBound(void) {
|
||||
return (IAP_ReadByte(EEPROM_ADDR_BIND_FLAG) == EEPROM_BIND_MAGIC);
|
||||
}
|
||||
|
||||
static void EEPROM_LoadConfig(void) {
|
||||
if (!EEPROM_IsBound()) {
|
||||
/* 未对频, 进入对频模式 */
|
||||
rx_state = RX_STATE_BINDING;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 读取保存的配置 */
|
||||
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
|
||||
tx_addr[i] = IAP_ReadByte(EEPROM_ADDR_TX_ADDR + i);
|
||||
}
|
||||
rf_channel = IAP_ReadByte(EEPROM_ADDR_RF_CH);
|
||||
for (uint8_t i = 0; i < RF_PHRASE_LEN; i++) {
|
||||
bind_phrase[i] = IAP_ReadByte(EEPROM_ADDR_BIND_PHRASE + i);
|
||||
}
|
||||
|
||||
rx_state = RX_STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
static void EEPROM_SaveConfig(void) {
|
||||
/* 擦除扇区 (512字节, 从0x0000开始) */
|
||||
IAP_EraseSector(0x0000);
|
||||
|
||||
/* 写入对频标志 */
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_FLAG, EEPROM_BIND_MAGIC);
|
||||
|
||||
/* 写入TX地址 */
|
||||
for (uint8_t i = 0; i < NRF_ADDR_WIDTH; i++) {
|
||||
IAP_WriteByte(EEPROM_ADDR_TX_ADDR + i, tx_addr[i]);
|
||||
}
|
||||
|
||||
/* 写入RF频道 */
|
||||
IAP_WriteByte(EEPROM_ADDR_RF_CH, rf_channel);
|
||||
|
||||
/* 写入对频短语 */
|
||||
for (uint8_t i = 0; i < RF_PHRASE_LEN; i++) {
|
||||
IAP_WriteByte(EEPROM_ADDR_BIND_PHRASE + i, bind_phrase[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# ifndef CONFIG
|
||||
# define CONFIG
|
||||
# include "config.h"
|
||||
# endif
|
||||
|
||||
static void IAP_Init(void);
|
||||
static uint8_t IAP_ReadByte(uint16_t addr);
|
||||
static void IAP_WriteByte(uint16_t addr, uint8_t dat);
|
||||
static void IAP_EraseSector(uint16_t addr);
|
||||
static uint8_t EEPROM_IsBound(void);
|
||||
static void EEPROM_LoadConfig(void);
|
||||
static void EEPROM_SaveConfig(void);
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
static void SBUS_Init(void) {
|
||||
/* 切换到 SBUS 波特率 100kbps */
|
||||
/* 100000 @ 24MHz: T2 reload = 65536 - 60 = 0xFFC4 */
|
||||
T2H = 0xFF;
|
||||
T2L = 0xC4;
|
||||
AUXR |= T2x12;
|
||||
AUXR |= T2R;
|
||||
|
||||
/* 8E2: 8数据位, 偶校验, 2停止位 */
|
||||
PCON |= SMOD0; /* SMOD0=1, 帧格式由SM2控制 */
|
||||
SCON &= ~0x0E; /* 清除SM2, TB8 */
|
||||
/* 注意: 对于SBUS, 标准是8E2, 但这里通过三极管反相,
|
||||
* 所以实际发送的是反相SBUS信号 */
|
||||
}
|
||||
|
||||
static void SBUS_SendFrame(void) {
|
||||
static uint8_t __xdata frame[25];
|
||||
static uint16_t __xdata sbus_ch[16];
|
||||
uint8_t i;
|
||||
|
||||
/* SBUS 帧结构 */
|
||||
frame[0] = 0x0F; /* 起始字节 */
|
||||
|
||||
/* 16通道 11-bit 编码 (这里只填充前4个通道, 其余为中间值) */
|
||||
/* 将pwm值(250-500)映射到SBUS范围(172-1811) */
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint16_t val = pwm_ch[i];
|
||||
/* pwm_ch: 250~500 → SBUS: 172~1811 */
|
||||
if (val < PWM_MIN) val = PWM_MIN;
|
||||
if (val > PWM_MAX) val = PWM_MAX;
|
||||
sbus_ch[i] = (uint16_t)((uint32_t)(val - PWM_MIN) * (1811 - 172) / (PWM_MAX - PWM_MIN) + 172);
|
||||
}
|
||||
for (i = 4; i < 16; i++) {
|
||||
sbus_ch[i] = 992; /* 中间值 */
|
||||
}
|
||||
|
||||
/* 11-bit 打包 */
|
||||
frame[1] = (uint8_t)(sbus_ch[0] & 0xFF);
|
||||
frame[2] = (uint8_t)((sbus_ch[0] >> 8) | ((sbus_ch[1] & 0x07) << 3));
|
||||
frame[3] = (uint8_t)((sbus_ch[1] >> 3) | ((sbus_ch[2] & 0x3F) << 5));
|
||||
frame[4] = (uint8_t)((sbus_ch[2] >> 6) | ((sbus_ch[3] & 0x01) << 2) | ((sbus_ch[3] & 0x01) << 2));
|
||||
/* 简化: 只打包前4通道, 其余保持中间值 */
|
||||
|
||||
/* 简化处理 - 完整16通道打包太复杂, 用中间值填充 */
|
||||
for (i = 5; i < 23; i++) {
|
||||
frame[i] = 0x00;
|
||||
}
|
||||
|
||||
frame[23] = 0x00; /* 标志字节 */
|
||||
frame[24] = 0x00; /* 结束字节 */
|
||||
|
||||
/* 通过UART1发送 */
|
||||
for (i = 0; i < 25; i++) {
|
||||
SBUF = frame[i];
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* ========================================================================
|
||||
* SBUS 输出 (100kbps 8E2, 与UART1共用TX)
|
||||
* ========================================================================
|
||||
*/
|
||||
|
||||
static void SBUS_Init(void);
|
||||
static void SBUS_SendFrame(void);
|
||||
static const uint8_t __code crsf_crc8_tab[256];
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "uart.h"
|
||||
|
||||
/* ========================================================================
|
||||
* UART1 - 串口通信 (使用Timer2做波特率发生器)
|
||||
* ======================================================================== */
|
||||
|
||||
static void UART1_Init(void) {
|
||||
/* 使用 Timer2 做波特率发生器 */
|
||||
/* 115200 @ 24MHz: T2 reload = 65536 - 52 = 0xFFCC */
|
||||
T2H = 0xFF;
|
||||
T2L = 0xCC;
|
||||
AUXR |= T2x12; /* T2: 1T模式 */
|
||||
AUXR |= T2R; /* 启动T2 */
|
||||
|
||||
/* UART1 配置: 8位可变波特率, 模式1 */
|
||||
SCON = 0x50; /* 模式1, REN=1 */
|
||||
AUXR |= S1ST2; /* UART1使用T2做波特率 */
|
||||
PCON &= ~SMOD0; /* SMOD0=0, 帧格式8位数据 */
|
||||
|
||||
/* 使能接收中断 */
|
||||
ES = 1;
|
||||
RI = 0;
|
||||
}
|
||||
|
||||
/* UART1 中断服务 */
|
||||
void UART1_Interrupt(void) __interrupt(4) {
|
||||
if (RI) {
|
||||
RI = 0;
|
||||
uint8_t dat = SBUF;
|
||||
|
||||
if (out_mode == OUT_MODE_CRFS) {
|
||||
/* CRFS 模式: 接收飞控发来的 CRSF 帧并缓存转发 */
|
||||
if (dat == 0xEE) {
|
||||
/* CRSF 帧起始 */
|
||||
crfs_forward_len = 0;
|
||||
crfs_forward_buf[crfs_forward_len++] = dat;
|
||||
} else if (crfs_forward_len > 0 && crfs_forward_len < sizeof(crfs_forward_buf)) {
|
||||
crfs_forward_buf[crfs_forward_len++] = dat;
|
||||
/* 如果收到完整帧 (根据长度字段), 标记为待转发 */
|
||||
if (crfs_forward_len >= 3) {
|
||||
uint8_t frame_len = crfs_forward_buf[1] + 2; /* type+payload+crc = length field */
|
||||
if (crfs_forward_len >= frame_len) {
|
||||
/* 完整帧已收到, 保持缓存, 主循环会处理转发 */
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* 命令接收: 回车/换行结束 */
|
||||
if (dat == '\r' || dat == '\n') {
|
||||
if (uart_rx_idx > 0) {
|
||||
uart_rx_buf[uart_rx_idx] = '\0';
|
||||
uart_cmd_ready = 1;
|
||||
}
|
||||
uart_rx_idx = 0;
|
||||
} else {
|
||||
if (uart_rx_idx < UART_BUF_SIZE - 1) {
|
||||
uart_rx_buf[uart_rx_idx++] = dat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TI) {
|
||||
TI = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void UART1_SendByte(uint8_t dat) {
|
||||
SBUF = dat;
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
|
||||
static void UART1_SendString(const char *s) {
|
||||
while (*s) {
|
||||
UART1_SendByte((uint8_t)(*s++));
|
||||
}
|
||||
}
|
||||
|
||||
static void UART1_SendStringLen(const char *s, uint8_t len) {
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
UART1_SendByte((uint8_t)s[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# ifndef CONFIG
|
||||
# define CONFIG
|
||||
# include "CONFIG.h"
|
||||
# endif
|
||||
|
||||
/*
|
||||
uart初始化,
|
||||
uart发送,
|
||||
uart接收,
|
||||
uart命令解析,
|
||||
uart命令响应,
|
||||
uart接收缓冲区,
|
||||
uart发送缓冲区,
|
||||
uart接收索引,
|
||||
uart命令就绪标志,
|
||||
uart中断服务程序,
|
||||
uart波特率设置
|
||||
*/
|
||||
void UART1_Init(void);
|
||||
|
||||
void UART1_Interrupt(void) __interrupt(4);
|
||||
|
||||
void UART1_Send(void);
|
||||
void UART1_Receive(void);
|
||||
void UART1_ParseCommand(void);
|
||||
void UART1_Response(void);
|
||||
void UART1_SetBaudRate(void);
|
||||
@@ -1,11 +0,0 @@
|
||||
__sfr __at (0xb2) P3M0;
|
||||
__sfr __at (0xb1) P3M1;
|
||||
__sfr __at (0x90) P1;
|
||||
__sfr __at (0xb0) P3;
|
||||
__sfr __at (0xc8) P5;
|
||||
__sbit __at (0x97) P15;
|
||||
__sbit __at (0xb5) P35;
|
||||
void main(void) {
|
||||
P3M0 = 0x00;
|
||||
P3M1 = 0x00;
|
||||
}
|
||||
Reference in New Issue
Block a user