Compare commits
6
Commits
a93acbc140
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb44ccc19e | ||
|
|
ef3601f9e8 | ||
|
|
2d25f6bb06 | ||
|
|
af9563b90f | ||
|
|
877973c0d5 | ||
|
|
8aa637be48 |
+39
-19
@@ -1,17 +1,8 @@
|
||||
#include "STC8_SDCC.H"
|
||||
#include <string.h>
|
||||
|
||||
/* ========================================================================
|
||||
* 系统常量
|
||||
* ======================================================================== */
|
||||
|
||||
#define FOSC 24000000UL /* 系统主频 24MHz */
|
||||
#define PWM_PERIOD 5000 /* 20ms / 4us = 5000 步 */
|
||||
#define PWM_MIN 250 /* 1.0ms 脉宽 (4us/步) */
|
||||
#define PWM_MAX 500 /* 2.0ms 脉宽 */
|
||||
#define PWM_MID 375 /* 1.5ms 脉宽 */
|
||||
#define CHANNEL_COUNT 4 /* 4路PWM输出 */
|
||||
|
||||
#define UART_BUF_SIZE 32
|
||||
|
||||
/* 接收状态 */
|
||||
@@ -33,16 +24,50 @@
|
||||
#define RF_PHRASE_LEN 6
|
||||
|
||||
/* LED 闪烁模式 */
|
||||
#define LED_BLINK_SLOW 0 /* 1Hz - 未连接 */
|
||||
#define LED_BLINK_FAST 1 /* 3Hz - 对频中 */
|
||||
#define LED_ON 2 /* 常亮 - 已连接 */
|
||||
#define LED_OFF 3 /* 熄灭 */
|
||||
#define LED_BLINK_DOUBLE 4 /* 双闪 - NRF硬件错误 */
|
||||
#define UNCONNECTED 0 /* 1Hz - 未连接 */
|
||||
#define NRF_BINDING 1 /* 3Hz - 对频中 */
|
||||
#define CONNECTED 2 /* 常亮 - 已连接 */
|
||||
#define NRF_ERROR 4 /* 双闪 - NRF硬件错误 */
|
||||
/* UART运行模式 */
|
||||
#define UART_CMD 0
|
||||
#define UART_SBUS 1
|
||||
#define UART_CRSF 2
|
||||
|
||||
/* ========================================================================
|
||||
* 全局变量
|
||||
* ======================================================================== */
|
||||
|
||||
// 配置信息
|
||||
struct CONFIG
|
||||
{
|
||||
// 运行模式
|
||||
uint8 RunMode;
|
||||
// nrf24使用的通道
|
||||
uint8 NrfCH;
|
||||
// nrf24使用的对频短语
|
||||
uint8 BindPhr[6];
|
||||
// nrf24地址,40位
|
||||
uint8 RxAddr[5];
|
||||
// 对频标志
|
||||
uint8 BindMagic;
|
||||
// 记录的发射机地址
|
||||
uint8 TxAddr[5];
|
||||
// 回传频率
|
||||
uint8 TelemRate;
|
||||
} Config;
|
||||
|
||||
// nrf24l01接收的数据
|
||||
struct RFDATA
|
||||
{
|
||||
// nrf24l01一次性接收32byte数据
|
||||
uint8 RefreshRate;
|
||||
uint16 CH[15];
|
||||
uint8 end;
|
||||
} RF_Data;
|
||||
|
||||
// 系统滴答定时器计数 (用于LED闪烁)
|
||||
static uint8 sys_tick = 0;
|
||||
|
||||
/* PWM 通道脉宽值 (4us单位, 放在 xdata) */
|
||||
static volatile uint16_t __xdata pwm_ch[CHANNEL_COUNT];
|
||||
|
||||
@@ -74,11 +99,6 @@ static uint8_t telem_rate_hz = 2; /* 回传频率 1-10Hz, 默认2Hz */
|
||||
static uint8_t __xdata crfs_forward_buf[24];
|
||||
static uint8_t crfs_forward_len = 0;
|
||||
|
||||
/* UART 接收缓冲 (放在 xdata) */
|
||||
static uint8_t __xdata uart_rx_buf[UART_BUF_SIZE];
|
||||
static uint8_t uart_rx_idx = 0;
|
||||
static volatile uint8_t uart_cmd_ready = 0;
|
||||
|
||||
/* 定时器计数 (用于LED闪烁) */
|
||||
static volatile uint16_t sys_tick = 0;
|
||||
|
||||
|
||||
-942
@@ -1,942 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ZhaTianRX 接收机操作指南 PDF 生成脚本 - 完整版"""
|
||||
|
||||
from fpdf import FPDF
|
||||
import os
|
||||
|
||||
# 中文字体路径
|
||||
CN_FONT = '/root/SourceHanSansCN-VF.ttf'
|
||||
CN_FONT_BOLD = '/root/SourceHanSansCN-VF.ttf'
|
||||
|
||||
|
||||
class ZhaTianPDF(FPDF):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_auto_page_break(auto=True, margin=15)
|
||||
self.add_font('CN', '', CN_FONT)
|
||||
self.add_font('CN', 'B', CN_FONT_BOLD)
|
||||
|
||||
def header(self):
|
||||
if self.page_no() > 1:
|
||||
self.set_font('CN', '', 8)
|
||||
self.set_text_color(0x7F, 0x8C, 0x8D)
|
||||
self.cell(0, 8, 'ZhaTianRX 接收机操作指南', new_x="LMARGIN", new_y="NEXT", align='L')
|
||||
self.cell(0, 8, f'第 {self.page_no()} 页', new_x="LMARGIN", new_y="NEXT", align='R')
|
||||
self.set_draw_color(0xDD, 0xDD, 0xDD)
|
||||
self.line(10, 14, 200, 14)
|
||||
self.ln(4)
|
||||
|
||||
def footer(self):
|
||||
self.set_y(-15)
|
||||
self.set_font('CN', '', 7)
|
||||
self.set_text_color(0xBB, 0xBB, 0xBB)
|
||||
self.cell(0, 10, 'ZhaTianRC 项目 | STC8H1K08 + NRF24L01+ | SDCC', align='C')
|
||||
|
||||
def chapter_title(self, title, level=1):
|
||||
if level == 1:
|
||||
self.set_font('CN', 'B', 16)
|
||||
self.set_text_color(0x1A, 0x1A, 0x2E)
|
||||
self.cell(0, 12, title, new_x="LMARGIN", new_y="NEXT")
|
||||
self.set_draw_color(0xC0, 0x39, 0x2B)
|
||||
self.line(10, self.get_y(), 200, self.get_y())
|
||||
self.ln(4)
|
||||
elif level == 2:
|
||||
self.set_font('CN', 'B', 13)
|
||||
self.set_text_color(0x2C, 0x3E, 0x50)
|
||||
self.cell(0, 10, title, new_x="LMARGIN", new_y="NEXT")
|
||||
self.ln(2)
|
||||
elif level == 3:
|
||||
self.set_font('CN', 'B', 11)
|
||||
self.set_text_color(0x34, 0x49, 0x5E)
|
||||
self.cell(0, 8, title, new_x="LMARGIN", new_y="NEXT")
|
||||
self.ln(1)
|
||||
|
||||
def body_text(self, text):
|
||||
self.set_font('CN', '', 10)
|
||||
self.set_text_color(0x33, 0x33, 0x33)
|
||||
self.multi_cell(0, 5.5, text)
|
||||
self.ln(2)
|
||||
|
||||
def bullet(self, text, indent=10):
|
||||
self.set_font('CN', '', 10)
|
||||
self.set_text_color(0x33, 0x33, 0x33)
|
||||
x = self.get_x()
|
||||
self.cell(indent, 5.5, '')
|
||||
self.set_font('CN', '', 10)
|
||||
self.cell(5, 5.5, '• ')
|
||||
self.multi_cell(0, 5.5, text)
|
||||
self.ln(1)
|
||||
|
||||
def code_block(self, text):
|
||||
self.set_fill_color(0xF5, 0xF5, 0xF5)
|
||||
self.set_text_color(0x1A, 0x1A, 0x2E)
|
||||
self.set_font('Courier', '', 9)
|
||||
self.ln(1)
|
||||
for line in text.split('\n'):
|
||||
self.cell(0, 5, ' ' + line, new_x="LMARGIN", new_y="NEXT", fill=True)
|
||||
self.ln(2)
|
||||
|
||||
def step_block(self, num, title, desc, code=None):
|
||||
"""操作步骤"""
|
||||
self.set_font('CN', 'B', 10)
|
||||
self.set_text_color(0xC0, 0x39, 0x2B)
|
||||
self.cell(0, 6, f'步骤 {num}: {title}', new_x="LMARGIN", new_y="NEXT")
|
||||
self.set_font('CN', '', 10)
|
||||
self.set_text_color(0x33, 0x33, 0x33)
|
||||
self.multi_cell(0, 5.5, desc)
|
||||
if code:
|
||||
self.code_block(code)
|
||||
self.ln(2)
|
||||
|
||||
def table_header(self, cols, widths):
|
||||
self.set_font('CN', 'B', 9)
|
||||
self.set_fill_color(0x2C, 0x3E, 0x50)
|
||||
self.set_text_color(0xFF, 0xFF, 0xFF)
|
||||
for i, col in enumerate(cols):
|
||||
self.cell(widths[i], 7, col, border=1, align='C', fill=True)
|
||||
self.ln()
|
||||
|
||||
def table_row(self, cols, widths, fill=False):
|
||||
self.set_font('CN', '', 9)
|
||||
self.set_text_color(0x33, 0x33, 0x33)
|
||||
if fill:
|
||||
self.set_fill_color(0xF0, 0xF0, 0xF0)
|
||||
else:
|
||||
self.set_fill_color(0xFF, 0xFF, 0xFF)
|
||||
for i, col in enumerate(cols):
|
||||
self.cell(widths[i], 6, col, border=1, align='C', fill=True)
|
||||
self.ln()
|
||||
|
||||
|
||||
def build_pdf():
|
||||
pdf = ZhaTianPDF()
|
||||
pdf.set_title('ZhaTianRX 接收机操作指南')
|
||||
pdf.set_author('ZhaTianRC Project')
|
||||
|
||||
# ==================== 封面 ====================
|
||||
pdf.add_page()
|
||||
pdf.ln(40)
|
||||
pdf.set_font('CN', 'B', 28)
|
||||
pdf.set_text_color(0x1A, 0x1A, 0x2E)
|
||||
pdf.cell(0, 15, 'ZhaTianRX', new_x="LMARGIN", new_y="NEXT", align='C')
|
||||
pdf.set_font('CN', '', 16)
|
||||
pdf.set_text_color(0x7F, 0x8C, 0x8D)
|
||||
pdf.cell(0, 10, '接收机操作指南', new_x="LMARGIN", new_y="NEXT", align='C')
|
||||
pdf.ln(10)
|
||||
pdf.set_draw_color(0xC0, 0x39, 0x2B)
|
||||
pdf.line(60, pdf.get_y(), 150, pdf.get_y())
|
||||
pdf.ln(10)
|
||||
pdf.set_font('CN', '', 11)
|
||||
pdf.set_text_color(0x55, 0x55, 0x55)
|
||||
pdf.cell(0, 7, 'MCU: STC8H1K08 | 射频: NRF24L01+ | 编译器: SDCC', new_x="LMARGIN", new_y="NEXT", align='C')
|
||||
pdf.cell(0, 7, '固件版本: 1.0 | 项目: ZhaTianRC', new_x="LMARGIN", new_y="NEXT", align='C')
|
||||
pdf.ln(20)
|
||||
pdf.set_font('CN', '', 9)
|
||||
pdf.set_text_color(0x99, 0x99, 0x99)
|
||||
pdf.cell(0, 7, '本文档涵盖接收机的所有功能、操作步骤及串口命令参考', new_x="LMARGIN", new_y="NEXT", align='C')
|
||||
|
||||
# ==================== 目录 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('目录')
|
||||
pdf.set_font('CN', '', 11)
|
||||
toc = [
|
||||
'1. 概述',
|
||||
'2. 硬件引脚分配',
|
||||
'3. 首次使用 - 对频操作',
|
||||
'4. 输出模式切换',
|
||||
'5. 串口命令详解',
|
||||
'6. 回传遥测功能',
|
||||
'7. LED 状态指示',
|
||||
'8. 固件烧录方法',
|
||||
'9. 附录 - 技术规格',
|
||||
'10. 完整功能清单(38 项)',
|
||||
]
|
||||
for item in toc:
|
||||
pdf.set_text_color(0x2C, 0x3E, 0x50)
|
||||
pdf.cell(0, 8, item, new_x="LMARGIN", new_y="NEXT")
|
||||
pdf.ln(1)
|
||||
|
||||
# ==================== 1. 概述 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('1. 概述')
|
||||
pdf.body_text(
|
||||
'ZhaTianRX 是 ZhaTianRC 遥控器项目的接收机子项目。采用 STC8H1K08 系列单片机作为主控芯片,'
|
||||
'NRF24L01+ 作为 2.4GHz 射频收发芯片。接收机从发射机接收遥控通道数据,转换为多种输出格式,'
|
||||
'驱动舵机、飞控等设备。'
|
||||
)
|
||||
pdf.chapter_title('主要特性', 2)
|
||||
features = [
|
||||
'4 路 50Hz 舵机 PWM 输出 (P3.4-P3.7)',
|
||||
'SBUS 输出 (100kbps 8E2, 经三极管反相)',
|
||||
'CRSF/Crossfire 输出 (420kbps 8N1)',
|
||||
'UART 直通输出 (115200 8N1)',
|
||||
'电池电压检测 (12位ADC)',
|
||||
'NRF24L01 遥测回传 (电压/RSSI/丢包率)',
|
||||
'EEPROM 存储对频信息',
|
||||
'串口命令配置 (115200 8N1)',
|
||||
'信号丢失保护 (失控回中位)',
|
||||
'NRF 模块硬件检测与自动恢复',
|
||||
]
|
||||
for f in features:
|
||||
pdf.bullet(f)
|
||||
|
||||
# ==================== 2. 硬件引脚分配 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('2. 硬件引脚分配')
|
||||
pdf.chapter_title('2.1 功能引脚', 2)
|
||||
|
||||
cols = ['功能', '引脚', '说明']
|
||||
widths = [35, 50, 95]
|
||||
pdf.table_header(cols, widths)
|
||||
rows = [
|
||||
['CH1', 'P3.7', '舵机 PWM 输出 1 (50Hz)'],
|
||||
['CH2', 'P3.6', '舵机 PWM 输出 2'],
|
||||
['CH3', 'P3.5', '舵机 PWM 输出 3'],
|
||||
['CH4', 'P3.4', '舵机 PWM 输出 4'],
|
||||
['BAT_ADC', 'P3.3/ADC11', '电池电压分压输入'],
|
||||
['LED', 'P3.2', '状态指示灯 (低电平亮)'],
|
||||
['TX', 'P3.1', 'UART1 TX / SBUS 输出 (经三极管反相)'],
|
||||
['RX', 'P3.0', 'UART1 RX / 命令输入'],
|
||||
]
|
||||
for i, row in enumerate(rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(4)
|
||||
pdf.chapter_title('2.2 NRF24L01 连接引脚', 2)
|
||||
pdf.body_text('NRF24L01 通过 STC8H 硬件 SPI 连接,IRQ 连接到了不具备中断功能的引脚,通过主循环轮询检测。')
|
||||
|
||||
cols = ['信号', '引脚']
|
||||
widths = [40, 40]
|
||||
pdf.table_header(cols, widths)
|
||||
rows = [
|
||||
['SCK', 'P1.5'],
|
||||
['CE', 'P1.6'],
|
||||
['IRQ', 'P1.7'],
|
||||
['CSN', 'P5.4'],
|
||||
['MISO', 'P1.3'],
|
||||
['MOSI', 'P1.4'],
|
||||
]
|
||||
for i, row in enumerate(rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
# ==================== 3. 首次使用 - 对频操作 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('3. 首次使用 - 对频操作')
|
||||
pdf.body_text(
|
||||
'接收机上电后自动检测 EEPROM 中是否存有对频信息。如果没有对频数据,'
|
||||
'自动进入对频模式(LED 快闪 3Hz),等待与发射机配对。'
|
||||
)
|
||||
|
||||
pdf.chapter_title('3.1 首次对频', 2)
|
||||
pdf.step_block(1, '给接收机上电',
|
||||
'连接接收机电源(3.3V-5V),观察 LED 状态。'
|
||||
'如果 EEPROM 无数据,LED 会以 3Hz 快闪表示进入对频模式。'
|
||||
'如果 LED 双闪,说明 NRF24L01 模块未检测到,请检查硬件连接。')
|
||||
pdf.step_block(2, '打开发射机并进入对频',
|
||||
'在发射机上操作进入对频模式。发射机会在 0~125 频道上广播对频包,'
|
||||
'包含同步头 (0xAA 0x55)、对频短语和地址信息。')
|
||||
pdf.step_block(3, '等待自动配对',
|
||||
'接收机会自动扫描所有频道,匹配对频短语(默认 "LOVE")。'
|
||||
'匹配成功后自动保存地址到 EEPROM,LED 变为常亮。')
|
||||
|
||||
pdf.chapter_title('3.2 重新对频', 2)
|
||||
pdf.step_block(1, '清除对频信息',
|
||||
'通过串口发送命令清除 EEPROM 中的对频数据:',
|
||||
'DEL(BIND)')
|
||||
pdf.step_block(2, '确认接收机进入对频模式',
|
||||
'发送 DEL(BIND) 后,接收机会自动擦除 EEPROM 并进入对频模式,'
|
||||
'LED 变为 3Hz 快闪。')
|
||||
pdf.step_block(3, '重复首次对频步骤',
|
||||
'在发射机上进入对频模式,等待自动配对。')
|
||||
|
||||
pdf.chapter_title('3.3 修改对频短语', 2)
|
||||
pdf.step_block(1, '发送 PHRASE 命令',
|
||||
'通过串口发送新的对频短语,1~6 位字母数字:',
|
||||
'PHRASE(Abc123)')
|
||||
pdf.step_block(2, '确认成功',
|
||||
'接收机返回 "OK" 表示设置成功,短语已保存到 EEPROM。')
|
||||
pdf.step_block(3, '重新对频',
|
||||
'修改短语后需要重新对频。发送 DEL(BIND) 清除旧绑定,'
|
||||
'然后确保发射机也使用相同的短语进行对频。')
|
||||
|
||||
# ==================== 4. 输出模式切换 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('4. 输出模式切换')
|
||||
pdf.body_text(
|
||||
'接收机支持 4 种输出模式,默认为 PWM 模式。切换模式通过串口发送 MODEL 命令实现。'
|
||||
'注意:所有输出模式共用 UART1 TX 引脚 (P3.1),切换模式时会自动调整波特率和帧格式。'
|
||||
)
|
||||
|
||||
pdf.chapter_title('4.1 PWM 模式(默认)', 2)
|
||||
pdf.body_text(
|
||||
'4 路 50Hz 舵机 PWM 信号,通过定时器0 4us 中断生成。'
|
||||
'脉宽范围 1.0ms ~ 2.0ms,中位 1.5ms。'
|
||||
)
|
||||
pdf.step_block(1, '切换到 PWM 模式', '通过串口发送:', 'MODEL(PWM)')
|
||||
pdf.step_block(2, '确认切换成功', '接收机返回 "OK",UART1 恢复 115200 8N1 命令模式。')
|
||||
pdf.step_block(3, '连接舵机',
|
||||
'将舵机信号线连接到对应的 PWM 输出引脚:\n'
|
||||
' CH1 -> P3.7\n CH2 -> P3.6\n CH3 -> P3.5\n CH4 -> P3.4\n'
|
||||
'注意舵机电源需独立供电,不要从 MCU 引脚取电。')
|
||||
|
||||
pdf.chapter_title('4.2 SBUS 模式', 2)
|
||||
pdf.body_text(
|
||||
'SBUS 是 Futaba 制定的串行舵机总线协议,100kbps 8E2 帧格式。'
|
||||
'16 通道 11-bit 编码。接收机输出经板上三极管反相,可直接连接支持 SBUS 的飞控。'
|
||||
)
|
||||
pdf.step_block(1, '切换到 SBUS 模式', '通过串口发送:', 'MODEL(SBUS)')
|
||||
pdf.step_block(2, '确认切换成功', '接收机返回 "OK",UART1 切换为 100kbps 8E2。')
|
||||
pdf.step_block(3, '连接飞控',
|
||||
'将接收机 TX (P3.1) 连接到飞控的 SBUS RX 引脚。\n'
|
||||
'注意:SBUS 信号已经过三极管反相,可直接连接。')
|
||||
|
||||
pdf.chapter_title('4.3 CRFS/CRSF 模式', 2)
|
||||
pdf.body_text(
|
||||
'CRSF (Crossfire) 是 ExpressLRS/TBS 等使用的协议,420kbps 8N1。'
|
||||
'帧格式: 0xEE + length + type + payload + CRC8。'
|
||||
'RC 通道帧 type=0x16,遥测帧 type=0x08。'
|
||||
)
|
||||
pdf.step_block(1, '切换到 CRFS 模式', '通过串口发送:', 'MODEL(CRFS)')
|
||||
pdf.step_block(2, '确认切换成功', '接收机返回 "OK",UART1 切换为 420kbps 8N1。')
|
||||
pdf.step_block(3, '连接飞控',
|
||||
'将接收机 TX (P3.1) 连接到飞控的 CRSF RX 引脚。\n'
|
||||
'接收机会发送 RC 通道帧,同时接收飞控发来的 CRSF 遥测帧并转发给发射机。')
|
||||
|
||||
pdf.chapter_title('4.4 UART 模式', 2)
|
||||
pdf.body_text('UART 直通模式,115200 8N1,预留扩展用途。')
|
||||
pdf.step_block(1, '切换到 UART 模式', '通过串口发送:', 'MODEL(UART)')
|
||||
pdf.step_block(2, '确认切换成功', '接收机返回 "OK",UART1 为 115200 8N1 直通模式。')
|
||||
|
||||
# ==================== 5. 串口命令详解 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('5. 串口命令详解')
|
||||
pdf.body_text(
|
||||
'通过 P3.0 (RX) 输入命令,115200 8N1,回车或换行结束命令。'
|
||||
'接收机在 PWM 和 UART 模式下持续监听串口命令,不影响正常输出。'
|
||||
'SBUS 和 CRFS 模式下串口用于协议输出,命令解析暂停。'
|
||||
)
|
||||
|
||||
pdf.chapter_title('5.1 命令速查表', 2)
|
||||
cols = ['命令', '参数', '说明']
|
||||
widths = [48, 48, 84]
|
||||
pdf.table_header(cols, widths)
|
||||
cmd_rows = [
|
||||
['MODEL(PWM)', '无', '切换到 PWM 输出模式'],
|
||||
['MODEL(SBUS)', '无', '切换到 SBUS 输出模式'],
|
||||
['MODEL(UART)', '无', '切换到 UART 直通模式'],
|
||||
['MODEL(CRFS)', '无', '切换到 CRSF 输出模式'],
|
||||
['ADDR(0x...)', '5字节十六进制', '设置 NRF24L01 地址'],
|
||||
['PHRASE(...)', '1~6位字母数字', '设置对频短语'],
|
||||
['TUN(N)', '0~125', '设置 RF 频道'],
|
||||
['DEL(BIND)', '无', '清除对频信息,进入对频'],
|
||||
['TELEM(N)', '1~10', '设置回传频率 (Hz)'],
|
||||
]
|
||||
for i, row in enumerate(cmd_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(4)
|
||||
pdf.chapter_title('5.2 应答格式', 2)
|
||||
cols = ['应答', '含义']
|
||||
widths = [40, 140]
|
||||
pdf.table_header(cols, widths)
|
||||
resp_rows = [
|
||||
['OK', '命令执行成功'],
|
||||
['ERR', '命令格式错误'],
|
||||
['ERR_ADDR', '地址参数错误'],
|
||||
['ERR_RANGE', '参数超出范围'],
|
||||
['UNK', '未知命令'],
|
||||
]
|
||||
for i, row in enumerate(resp_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(4)
|
||||
pdf.chapter_title('5.3 命令详解', 2)
|
||||
|
||||
# MODEL 命令
|
||||
pdf.chapter_title('MODEL() - 切换输出模式', 3)
|
||||
pdf.body_text('功能:切换接收机的输出模式。每次切换成功后,UART1 自动调整为对应协议的波特率和帧格式。')
|
||||
pdf.step_block(1, '连接串口', '将 USB-TTL 转换器的 TX 接接收机 P3.0(RX),GND 接 GND。')
|
||||
pdf.step_block(2, '打开串口终端', '设置 115200 8N1,打开串口。')
|
||||
pdf.step_block(3, '发送命令', '输入 MODEL(PWM) 或 MODEL(SBUS) 等,回车发送。')
|
||||
pdf.step_block(4, '确认应答', '接收机返回 "OK" 表示切换成功。')
|
||||
|
||||
# ADDR 命令
|
||||
pdf.chapter_title('ADDR() - 设置 NRF24L01 地址', 3)
|
||||
pdf.body_text('功能:修改 NRF24L01 的 5 字节通信地址。地址需与发射机一致才能通信。')
|
||||
pdf.step_block(1, '准备新地址', '准备 5 个字节的十六进制值,例如 E7 E7 E7 E7 E7。')
|
||||
pdf.step_block(2, '发送命令', '格式:ADDR(0xHH HH HH HH HH),例如:', 'ADDR(0xE7 E7 E7 E7 E7)')
|
||||
pdf.step_block(3, '确认应答', '返回 "OK" 表示地址修改成功,NRF 已重新初始化。')
|
||||
|
||||
# PHRASE 命令
|
||||
pdf.chapter_title('PHRASE() - 设置对频短语', 3)
|
||||
pdf.body_text('功能:设置对频短语,1~6 位字母数字。发射机和接收机必须使用相同的短语才能对频。')
|
||||
pdf.step_block(1, '确定短语', '准备 1~6 位字母数字组合,例如 "LOVE"、"Abc123"。')
|
||||
pdf.step_block(2, '发送命令', '例如:', 'PHRASE(LOVE)')
|
||||
pdf.step_block(3, '确认应答', '返回 "OK" 表示设置成功,已保存到 EEPROM。')
|
||||
|
||||
# TUN 命令
|
||||
pdf.chapter_title('TUN() - 切换 RF 频道', 3)
|
||||
pdf.body_text('功能:切换 NRF24L01 的 RF 频道 (0~125)。频道需与发射机一致。')
|
||||
pdf.step_block(1, '发送命令', '例如切换到频道 40:', 'TUN(40)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示频道切换成功。')
|
||||
|
||||
# DEL 命令
|
||||
pdf.chapter_title('DEL(BIND) - 清除对频信息', 3)
|
||||
pdf.body_text('功能:擦除 EEPROM 中的对频数据,使接收机重新进入对频模式。')
|
||||
pdf.step_block(1, '发送命令', '', 'DEL(BIND)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK",LED 变为 3Hz 快闪表示进入对频模式。')
|
||||
pdf.step_block(3, '重新对频', '在发射机上进入对频模式,等待自动配对。')
|
||||
|
||||
# TELEM 命令
|
||||
pdf.chapter_title('TELEM() - 设置回传频率', 3)
|
||||
pdf.body_text('功能:设置遥测回传频率,范围 1~10Hz,默认 2Hz。')
|
||||
pdf.step_block(1, '发送命令', '例如设置为 5Hz:', 'TELEM(5)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示设置成功。')
|
||||
|
||||
# ==================== 6. 回传遥测功能 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('6. 回传遥测功能')
|
||||
pdf.body_text(
|
||||
'接收机支持通过 NRF24L01 向发射机回传遥测数据。'
|
||||
'不同输出模式下回传路径不同,PWM 和 SBUS 模式通过 NRF 直接回传,'
|
||||
'CRFS 模式通过 CRSF 遥测帧回传并转发飞控数据。'
|
||||
)
|
||||
|
||||
pdf.chapter_title('6.1 回传数据内容', 2)
|
||||
cols = ['数据项', '来源', '范围']
|
||||
widths = [40, 70, 70]
|
||||
pdf.table_header(cols, widths)
|
||||
telem_rows = [
|
||||
['电池电压', 'P3.3/ADC11 12位采样', 'ADC 原始值 0~4095'],
|
||||
['RSSI', 'NRF RPD 载波检测', '0~100'],
|
||||
['丢包率', '滑动窗口估算', '0~100%'],
|
||||
]
|
||||
for i, row in enumerate(telem_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(4)
|
||||
pdf.chapter_title('6.2 各模式回传路径', 2)
|
||||
cols = ['模式', '回传通道', '数据']
|
||||
widths = [30, 55, 95]
|
||||
pdf.table_header(cols, widths)
|
||||
path_rows = [
|
||||
['PWM', 'NRF24L01 TX', '0xBB 0x44 + 电压(2B) + RSSI(1B) + 丢包(1B) + 温度(2B)'],
|
||||
['SBUS', 'NRF24L01 TX', '同上'],
|
||||
['CRFS', 'CRSF 遥测帧', 'CRSF Battery sensor (type=0x08) + 飞控数据转发'],
|
||||
]
|
||||
for i, row in enumerate(path_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(4)
|
||||
pdf.chapter_title('6.3 设置回传频率', 2)
|
||||
pdf.body_text('回传频率默认 2Hz,可通过 TELEM 命令调整。频率越高,NRF 切换 TX/RX 越频繁。')
|
||||
pdf.step_block(1, '查看当前频率', '回传频率默认 2Hz,无需查看命令。')
|
||||
pdf.step_block(2, '修改频率', '例如设置为 5Hz:', 'TELEM(5)')
|
||||
pdf.step_block(3, '确认应答', '返回 "OK" 表示设置成功。频率范围 1~10Hz。')
|
||||
|
||||
pdf.chapter_title('6.4 CRFS 模式下的飞控数据转发', 2)
|
||||
pdf.body_text(
|
||||
'在 CRFS 模式下,接收机不仅发送 CRSF RC 通道帧到飞控,'
|
||||
'还接收飞控发来的 CRSF 遥测帧(如 GPS、姿态、电池等信息),'
|
||||
'通过 NRF24L01 转发给发射机,实现完整的双向通信。'
|
||||
)
|
||||
pdf.step_block(1, '切换到 CRFS 模式', '', 'MODEL(CRFS)')
|
||||
pdf.step_block(2, '连接飞控',
|
||||
'将接收机 TX 接飞控 RX,接收机 RX 接飞控 TX。\n'
|
||||
'飞控会收到 RC 通道帧,同时发送遥测帧给接收机。')
|
||||
pdf.step_block(3, '自动转发',
|
||||
'接收机自动将飞控发来的 CRSF 帧通过 NRF 转发给发射机,'
|
||||
'无需额外配置。')
|
||||
|
||||
# ==================== 7. LED 状态指示 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('7. LED 状态指示')
|
||||
pdf.body_text(
|
||||
'接收机使用 P3.2 驱动一个 LED(低电平亮),通过不同的闪烁模式指示当前工作状态。'
|
||||
)
|
||||
|
||||
cols = ['LED 模式', '效果', '含义']
|
||||
widths = [35, 50, 95]
|
||||
pdf.table_header(cols, widths)
|
||||
led_rows = [
|
||||
['慢闪', '1Hz: 亮500ms 灭500ms', '未连接,等待发射机信号'],
|
||||
['快闪', '3Hz: 亮167ms 灭167ms', '对频模式,正在搜索发射机'],
|
||||
['常亮', '持续点亮', '已连接,通信正常'],
|
||||
['双闪', '1Hz: 亮100ms 灭100ms 亮100ms 灭700ms', 'NRF24L01 模块硬件错误'],
|
||||
]
|
||||
for i, row in enumerate(led_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(4)
|
||||
pdf.chapter_title('LED 状态诊断', 2)
|
||||
pdf.step_block(1, 'LED 双闪',
|
||||
'NRF24L01 模块未检测到或通信失败。\n'
|
||||
'检查:\n'
|
||||
' 1. NRF24L01 模块是否正确插入\n'
|
||||
' 2. 供电电压是否正常 (3.3V)\n'
|
||||
' 3. SPI 引脚连接是否正确 (P1.3-P1.5, P5.4)\n'
|
||||
'接收机会每 500ms 自动重试检测,模块正常后自动恢复。')
|
||||
pdf.step_block(2, 'LED 慢闪',
|
||||
'接收机已初始化完成,但未收到发射机信号。\n'
|
||||
'检查:\n'
|
||||
' 1. 发射机是否开机\n'
|
||||
' 2. 对频短语和频道是否匹配\n'
|
||||
' 3. 距离是否在有效范围内')
|
||||
pdf.step_block(3, 'LED 快闪',
|
||||
'接收机处于对频模式,正在扫描频道寻找发射机。\n'
|
||||
'请在发射机上进入对频模式。')
|
||||
pdf.step_block(4, 'LED 常亮',
|
||||
'接收机已成功连接发射机,通信正常。\n'
|
||||
'此时可以正常使用遥控器控制设备。')
|
||||
|
||||
# ==================== 8. 固件烧录方法 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('8. 固件烧录方法')
|
||||
|
||||
pdf.chapter_title('8.1 使用 stcgal (Linux/命令行)', 2)
|
||||
pdf.body_text('stcgal 是一个开源的 STC 单片机烧录工具,支持命令行操作。')
|
||||
pdf.step_block(1, '安装 stcgal', '通过 pip 安装:', 'pip3 install stcgal')
|
||||
pdf.step_block(2, '连接硬件',
|
||||
'将 USB-TTL 转换器连接到接收机:\n'
|
||||
' USB-TTL TX -> 接收机 P3.0 (RX)\n'
|
||||
' USB-TTL RX -> 接收机 P3.1 (TX)\n'
|
||||
' USB-TTL GND -> 接收机 GND\n'
|
||||
'给接收机上电 (3.3V-5V)。')
|
||||
pdf.step_block(3, '烧录固件',
|
||||
'确认串口设备后执行:', 'stcgal -p /dev/ttyUSB0 -b 115200 build/ZhaTianRX.hex')
|
||||
pdf.step_block(4, '等待烧录完成',
|
||||
'stcgal 会自动握手并烧录,完成后会显示成功信息。'
|
||||
'烧录完成后接收机会自动重启运行新固件。')
|
||||
|
||||
pdf.chapter_title('8.2 使用 STC-ISP (Windows)', 2)
|
||||
pdf.body_text('STC-ISP 是 STC 官方提供的 Windows 烧录工具。')
|
||||
pdf.step_block(1, '下载 STC-ISP',
|
||||
'从 STC 官方网站下载最新版 STC-ISP 工具。')
|
||||
pdf.step_block(2, '连接硬件',
|
||||
'使用 USB-TTL 转换器连接接收机(同上)。')
|
||||
pdf.step_block(3, '选择芯片型号',
|
||||
'在 STC-ISP 中选择芯片型号:STC8H1K08。')
|
||||
pdf.step_block(4, '选择固件文件',
|
||||
'点击"打开程序文件",选择 build/ZhaTianRX.hex。')
|
||||
pdf.step_block(5, '下载烧录',
|
||||
'点击"下载/编程"按钮,然后给接收机重新上电,'
|
||||
'STC-ISP 会自动检测并烧录。')
|
||||
|
||||
pdf.chapter_title('8.3 编译固件', 2)
|
||||
pdf.body_text('如果修改了源代码,需要重新编译生成固件。')
|
||||
pdf.step_block(1, '安装 SDCC', '确保已安装 SDCC 编译器:', 'sudo apt install sdcc')
|
||||
pdf.step_block(2, '编译固件', '在项目目录下执行:', 'cd rx && make clean && make')
|
||||
pdf.step_block(3, '查看输出',
|
||||
'编译成功后,在 build/ 目录下生成:\n'
|
||||
' ZhaTianRX.hex - Intel HEX 格式固件\n'
|
||||
' ZhaTianRX.bin - 二进制格式固件\n'
|
||||
' ZhaTianRX.map - 内存映射文件')
|
||||
|
||||
# ==================== 9. 附录 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('9. 附录 - 技术规格')
|
||||
|
||||
pdf.chapter_title('9.1 硬件规格', 2)
|
||||
cols = ['项目', '规格']
|
||||
widths = [60, 120]
|
||||
pdf.table_header(cols, widths)
|
||||
spec_rows = [
|
||||
['主控芯片', 'STC8H1K08 (8051 内核)'],
|
||||
['主频', '24MHz 内部 IRC'],
|
||||
['Flash', '8KB (固件占用 ~6.8KB)'],
|
||||
['内部 RAM', '256 字节'],
|
||||
['外部 RAM (XDATA)', '256 字节'],
|
||||
['射频芯片', 'NRF24L01+ 2.4GHz'],
|
||||
['SPI 速率', '6MHz (硬件 SPI)'],
|
||||
['RF 频道', '0~125 (默认 40)'],
|
||||
['通信速率', '1Mbps'],
|
||||
['PWM 输出', '4 路, 50Hz, 1.0~2.0ms'],
|
||||
['SBUS', '100kbps 8E2'],
|
||||
['CRSF', '420kbps 8N1'],
|
||||
['UART 命令', '115200 8N1'],
|
||||
['ADC', '12位, P3.3/ADC11'],
|
||||
['工作电压', '3.3V ~ 5V'],
|
||||
]
|
||||
for i, row in enumerate(spec_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(4)
|
||||
pdf.chapter_title('9.2 固件信息', 2)
|
||||
cols = ['项目', '数值']
|
||||
widths = [60, 120]
|
||||
pdf.table_header(cols, widths)
|
||||
fw_rows = [
|
||||
['编译器', 'SDCC 4.2.0'],
|
||||
['编译参数', '-mmcs51 --model-small --no-xinit-opt'],
|
||||
['固件大小', '6,756 字节 (HEX)'],
|
||||
['Flash 占用', '82% (剩余 ~1.4KB)'],
|
||||
['栈空间', '153 字节空闲'],
|
||||
['XDATA 占用', '283 字节'],
|
||||
['源码行数', '~1,350 行'],
|
||||
]
|
||||
for i, row in enumerate(fw_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(4)
|
||||
pdf.chapter_title('9.3 数据包格式', 2)
|
||||
|
||||
pdf.chapter_title('NRF24L01 下行 (发射机 -> 接收机)', 3)
|
||||
cols = ['偏移', '大小', '内容']
|
||||
widths = [30, 30, 120]
|
||||
pdf.table_header(cols, widths)
|
||||
pkt_rows = [
|
||||
['0', '1', '同步头 0xAA'],
|
||||
['1', '1', '同步头 0x55'],
|
||||
['2', '6', '对频短语 (如 "LOVE")'],
|
||||
['8', '16', '8 通道数据, 每通道 2 字节大端 (0~2000)'],
|
||||
['24', '7', '保留/扩展'],
|
||||
['31', '1', 'XOR 校验和'],
|
||||
]
|
||||
for i, row in enumerate(pkt_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(2)
|
||||
pdf.chapter_title('NRF24L01 上行 (接收机 -> 发射机, 回传)', 3)
|
||||
cols = ['偏移', '大小', '内容']
|
||||
widths = [30, 30, 120]
|
||||
pdf.table_header(cols, widths)
|
||||
telem_pkt_rows = [
|
||||
['0', '1', '同步头 0xBB'],
|
||||
['1', '1', '同步头 0x44'],
|
||||
['2', '2', '电池电压 (大端)'],
|
||||
['4', '1', 'RSSI (0~100)'],
|
||||
['5', '1', '丢包率 (0~100%)'],
|
||||
['6', '2', '温度 (保留)'],
|
||||
]
|
||||
for i, row in enumerate(telem_pkt_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
pdf.ln(2)
|
||||
pdf.chapter_title('CRSF 帧格式', 3)
|
||||
cols = ['偏移', '大小', '内容']
|
||||
widths = [30, 30, 120]
|
||||
pdf.table_header(cols, widths)
|
||||
crsf_rows = [
|
||||
['0', '1', '同步头 0xEE'],
|
||||
['1', '1', '长度 (type+payload+crc)'],
|
||||
['2', '1', '类型 (0x16=RC通道, 0x08=电池遥测)'],
|
||||
['3', '可变', 'Payload'],
|
||||
['末尾', '1', 'CRC8 (多项式 0xD5)'],
|
||||
]
|
||||
for i, row in enumerate(crsf_rows):
|
||||
pdf.table_row(row, widths, fill=(i % 2 == 0))
|
||||
|
||||
# ==================== 10. 完整功能清单 ====================
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('10. 完整功能清单(38 项)')
|
||||
pdf.body_text(
|
||||
'以下列出 ZhaTianRX 接收机固件的全部功能,每项附带详细操作步骤。'
|
||||
)
|
||||
|
||||
# --- 一、无线通信 ---
|
||||
pdf.chapter_title('一、无线通信 (功能 1~8)', 2)
|
||||
|
||||
# 功能1
|
||||
pdf.chapter_title('功能 1: NRF24L01 接收', 3)
|
||||
pdf.body_text('通过 STC8H 硬件 SPI 接收发射机 32 字节数据包。')
|
||||
pdf.step_block(1, '确认硬件连接',
|
||||
'确保 NRF24L01 模块正确连接:\n'
|
||||
' SCK -> P1.5, CE -> P1.6, IRQ -> P1.7\n'
|
||||
' CSN -> P5.4, MISO -> P1.3, MOSI -> P1.4\n'
|
||||
' 供电 3.3V, GND 共地。')
|
||||
pdf.step_block(2, '上电自动初始化',
|
||||
'接收机上电后自动初始化 NRF24L01 模块,设置 SPI 速率 6MHz。'
|
||||
'如果模块检测失败,LED 双闪报警。')
|
||||
pdf.step_block(3, '接收数据',
|
||||
'NRF24L01 收到有效数据包后,接收机解析 8 通道数据(每通道 2 字节大端 0~2000),'
|
||||
'更新输出 PWM/SBUS/CRSF。')
|
||||
|
||||
# 功能2
|
||||
pdf.chapter_title('功能 2: 对频绑定', 3)
|
||||
pdf.body_text('上电 EEPROM 无数据自动进入对频模式,扫描 0~125 频道匹配短语。')
|
||||
pdf.step_block(1, '进入对频模式',
|
||||
'接收机上电后检测 EEPROM。无对频数据则自动进入对频模式(LED 快闪 3Hz)。')
|
||||
pdf.step_block(2, '扫描频道',
|
||||
'接收机在 0~125 频道上逐频道监听,等待接收包含匹配短语的对频包。')
|
||||
pdf.step_block(3, '保存绑定信息',
|
||||
'匹配成功后,将发射机地址、频道写入 EEPROM,LED 变为常亮。')
|
||||
|
||||
# 功能3
|
||||
pdf.chapter_title('功能 3: 对频短语', 3)
|
||||
pdf.body_text('默认短语 "LOVE",支持 1~6 位字母数字,通过 PHRASE() 命令修改。')
|
||||
pdf.step_block(1, '查看当前短语', '短语保存在 EEPROM 中,可通过串口读取(需在代码中扩展读取命令)。')
|
||||
pdf.step_block(2, '修改短语', '发送命令修改:', 'PHRASE(Abc123)')
|
||||
pdf.step_block(3, '重新对频', '修改短语后需发送 DEL(BIND) 重新对频。')
|
||||
|
||||
# 功能4
|
||||
pdf.chapter_title('功能 4: 地址管理', 3)
|
||||
pdf.body_text('5 字节 NRF24L01 地址,通过 ADDR() 命令修改。')
|
||||
pdf.step_block(1, '发送新地址', '格式:', 'ADDR(0xE7 E7 E7 E7 E7)')
|
||||
pdf.step_block(2, '确认修改', '返回 "OK" 表示成功,NRF 重新初始化。')
|
||||
pdf.step_block(3, '重新对频', '修改地址后需重新对频。')
|
||||
|
||||
# 功能5
|
||||
pdf.chapter_title('功能 5: 频道切换', 3)
|
||||
pdf.body_text('0~125 频道,通过 TUN(N) 命令切换。')
|
||||
pdf.step_block(1, '发送频道命令', '例如切到频道 40:', 'TUN(40)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示切换成功。')
|
||||
|
||||
# 功能6
|
||||
pdf.chapter_title('功能 6: 数据包校验', 3)
|
||||
pdf.body_text('XOR 校验和验证。')
|
||||
pdf.step_block(1, '自动校验',
|
||||
'接收机收到 32 字节数据包后,自动计算前 31 字节的 XOR 校验和,'
|
||||
'与第 32 字节对比。不一致则丢弃该包。')
|
||||
|
||||
# 功能7
|
||||
pdf.chapter_title('功能 7: 信号丢失保护', 3)
|
||||
pdf.body_text('连续 ~5 秒无数据自动判丢失,PWM 回中位。')
|
||||
pdf.step_block(1, '信号丢失自动处理',
|
||||
'接收机内部维护一个丢失计数器。每次收到有效数据包清零,'
|
||||
'主循环每 10ms 递增一次。计数超过 500(约 5 秒)判定为信号丢失。')
|
||||
pdf.step_block(2, '丢失后行为',
|
||||
'PWM 模式下所有通道输出回中位(1.5ms 脉宽),LED 变为慢闪。'
|
||||
'信号恢复后自动回到正常状态。')
|
||||
|
||||
# 功能8
|
||||
pdf.chapter_title('功能 8: NRF 硬件检测', 3)
|
||||
pdf.body_text('上电检测 NRF 模块是否存在,失败 LED 双闪并定期重试。')
|
||||
pdf.step_block(1, '上电检测',
|
||||
'接收机初始化时读取 NRF24L01 寄存器验证通信。失败则 LED 双闪。')
|
||||
pdf.step_block(2, '自动恢复',
|
||||
'接收机每 500ms 重试检测 NRF 模块。模块正常后自动恢复运行。')
|
||||
|
||||
# --- 二、输出模式 ---
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('二、输出模式 (功能 9~12)', 2)
|
||||
|
||||
# 功能9
|
||||
pdf.chapter_title('功能 9: PWM 输出(默认)', 3)
|
||||
pdf.body_text('4 路 50Hz 舵机 PWM,P3.4-P3.7,1.0~2.0ms 脉宽,定时器0 4us 中断生成。')
|
||||
pdf.step_block(1, '切换到 PWM 模式', '', 'MODEL(PWM)')
|
||||
pdf.step_block(2, '连接舵机',
|
||||
'CH1(P3.7) CH2(P3.6) CH3(P3.5) CH4(P3.4) 接舵机信号线。'
|
||||
'舵机电源需独立供电。')
|
||||
pdf.step_block(3, '确认输出',
|
||||
'用示波器或舵机测试 PWM 信号。中位 1.5ms,范围 1.0~2.0ms。')
|
||||
|
||||
# 功能10
|
||||
pdf.chapter_title('功能 10: SBUS 输出', 3)
|
||||
pdf.body_text('100kbps 8E2,16 通道 11-bit 编码,经三极管反相输出。')
|
||||
pdf.step_block(1, '切换到 SBUS 模式', '', 'MODEL(SBUS)')
|
||||
pdf.step_block(2, '连接飞控',
|
||||
'接收机 TX(P3.1) 接飞控 SBUS RX。信号已反相,可直接连接。')
|
||||
pdf.step_block(3, '验证输出',
|
||||
'用逻辑分析仪或飞控调参软件查看 16 通道数据。')
|
||||
|
||||
# 功能11
|
||||
pdf.chapter_title('功能 11: UART 输出', 3)
|
||||
pdf.body_text('115200 8N1 直通,预留扩展。')
|
||||
pdf.step_block(1, '切换到 UART 模式', '', 'MODEL(UART)')
|
||||
pdf.step_block(2, '连接设备', 'TX(P3.1) 接目标设备 RX。波特率 115200 8N1。')
|
||||
|
||||
# 功能12
|
||||
pdf.chapter_title('功能 12: CRFS/CRSF 输出', 3)
|
||||
pdf.body_text('420kbps 8N1,CRSF RC 通道帧 (type=0x16),CRC8 校验。')
|
||||
pdf.step_block(1, '切换到 CRFS 模式', '', 'MODEL(CRFS)')
|
||||
pdf.step_block(2, '连接飞控',
|
||||
'TX(P3.1) 接飞控 CRSF RX,RX(P3.0) 接飞控 CRSF TX(双向通信)。')
|
||||
pdf.step_block(3, '验证双向通信',
|
||||
'飞控应收到 RC 通道帧,同时接收机转发飞控遥测数据给发射机。')
|
||||
|
||||
# --- 三、回传遥测 ---
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('三、回传遥测 (功能 13~19)', 2)
|
||||
|
||||
# 功能13
|
||||
pdf.chapter_title('功能 13: 电池电压回传', 3)
|
||||
pdf.body_text('BAT_ADC(P3.3) 12 位 ADC 采样,所有模式均可回传。')
|
||||
pdf.step_block(1, '连接电池分压电路',
|
||||
'电池电压经分压电阻接入 P3.3。分压比需确保最高电压不超过 3.3V。')
|
||||
pdf.step_block(2, '读取电压',
|
||||
'接收机自动 12 位 ADC 采样,通过回传通道发送给发射机。'
|
||||
'发射机端显示电压值。')
|
||||
|
||||
# 功能14
|
||||
pdf.chapter_title('功能 14: RSSI 回传', 3)
|
||||
pdf.body_text('基于 NRF RPD 载波检测寄存器估算 (0-100)。')
|
||||
pdf.step_block(1, '自动采集',
|
||||
'接收机在每个接收周期读取 NRF RPD 寄存器,估算信号强度。')
|
||||
pdf.step_block(2, '查看 RSSI', 'RSSI 值通过回传通道发送给发射机,在发射机端显示。')
|
||||
|
||||
# 功能15
|
||||
pdf.chapter_title('功能 15: 丢包率回传', 3)
|
||||
pdf.body_text('滑动窗口估算 (0-100%)。')
|
||||
pdf.step_block(1, '自动计算',
|
||||
'接收机维护滑动窗口,统计最近 N 个数据包中丢失的比例。')
|
||||
pdf.step_block(2, '查看丢包率', '丢包率通过回传通道发送给发射机。')
|
||||
|
||||
# 功能16
|
||||
pdf.chapter_title('功能 16: NRF 回传(PWM/SBUS)', 3)
|
||||
pdf.body_text('PWM/SBUS 模式下通过 NRF TX 发 0xBB 0x44 回传包。')
|
||||
pdf.step_block(1, '自动回传',
|
||||
'在 PWM 或 SBUS 模式下,接收机自动在接收间隙切换 NRF 为 TX 模式发送回传包。')
|
||||
pdf.step_block(2, '配置回传频率', '默认 2Hz,可通过 TELEM 命令调整。', 'TELEM(5)')
|
||||
|
||||
# 功能17
|
||||
pdf.chapter_title('功能 17: CRSF 遥测回传', 3)
|
||||
pdf.body_text('CRFS 模式下通过 CRSF Battery sensor 帧 (type=0x08) 回传。')
|
||||
pdf.step_block(1, '自动发送',
|
||||
'在 CRFS 模式下,接收机自动构造 CRSF Battery sensor 遥测帧,'
|
||||
'通过 UART 发送给飞控(飞控再转发给遥控器)。')
|
||||
|
||||
# 功能18
|
||||
pdf.chapter_title('功能 18: 飞控数据转发', 3)
|
||||
pdf.body_text('CRFS 模式下接收飞控 UART 发来的 CRSF 帧,通过 NRF 转发给发射机。')
|
||||
pdf.step_block(1, '自动转发',
|
||||
'接收机在 CRFS 模式下持续监听 UART RX,收到飞控发来的 CRSF 帧后,'
|
||||
'通过 NRF 转发给发射机。无需额外配置。')
|
||||
|
||||
# 功能19
|
||||
pdf.chapter_title('功能 19: 回传频率可调', 3)
|
||||
pdf.body_text('1~10Hz,默认 2Hz,通过 TELEM(N) 命令设置。')
|
||||
pdf.step_block(1, '设置频率', '例如设置为 5Hz:', 'TELEM(5)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示设置成功。')
|
||||
|
||||
# --- 四、串口命令系统 ---
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('四、串口命令系统 (功能 20~28)', 2)
|
||||
|
||||
# 功能20-23
|
||||
for cmd_name, cmd_code, desc in [
|
||||
('功能 20: MODEL(PWM)', 'MODEL(PWM)', '切 PWM 模式'),
|
||||
('功能 21: MODEL(SBUS)', 'MODEL(SBUS)', '切 SBUS 模式'),
|
||||
('功能 22: MODEL(UART)', 'MODEL(UART)', '切 UART 模式'),
|
||||
('功能 23: MODEL(CRFS)', 'MODEL(CRFS)', '切 CRSF 模式'),
|
||||
]:
|
||||
pdf.chapter_title(cmd_name, 3)
|
||||
pdf.body_text(desc)
|
||||
pdf.step_block(1, '发送命令', '', cmd_code)
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示切换成功。')
|
||||
|
||||
# 功能24
|
||||
pdf.chapter_title('功能 24: ADDR() - 设置 NRF 地址', 3)
|
||||
pdf.body_text('设置 5 字节 NRF 地址。')
|
||||
pdf.step_block(1, '发送命令', '格式:ADDR(0xHH HH HH HH HH)', 'ADDR(0xE7 E7 E7 E7 E7)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示成功。')
|
||||
|
||||
# 功能25
|
||||
pdf.chapter_title('功能 25: PHRASE() - 设置对频短语', 3)
|
||||
pdf.body_text('设置对频短语 (1-6位字母数字)。')
|
||||
pdf.step_block(1, '发送命令', '', 'PHRASE(LOVE)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示成功。')
|
||||
|
||||
# 功能26
|
||||
pdf.chapter_title('功能 26: TUN() - 设置 RF 频道', 3)
|
||||
pdf.body_text('设置 RF 频道 (0-125)。')
|
||||
pdf.step_block(1, '发送命令', '', 'TUN(40)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示成功。')
|
||||
|
||||
# 功能27
|
||||
pdf.chapter_title('功能 27: DEL(BIND) - 清除对频信息', 3)
|
||||
pdf.body_text('清除 EEPROM 对频信息,重新对频。')
|
||||
pdf.step_block(1, '发送命令', '', 'DEL(BIND)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK",LED 快闪进入对频模式。')
|
||||
|
||||
# 功能28
|
||||
pdf.chapter_title('功能 28: TELEM() - 设置回传频率', 3)
|
||||
pdf.body_text('设置回传频率 (1-10Hz)。')
|
||||
pdf.step_block(1, '发送命令', '', 'TELEM(5)')
|
||||
pdf.step_block(2, '确认应答', '返回 "OK" 表示成功。')
|
||||
|
||||
# --- 五、LED 状态指示 ---
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('五、LED 状态指示 (功能 29~32)', 2)
|
||||
|
||||
# 功能29
|
||||
pdf.chapter_title('功能 29: 慢闪 (1Hz)', 3)
|
||||
pdf.body_text('未连接(等待发射机)。')
|
||||
pdf.step_block(1, '观察 LED', 'LED 以 1Hz 慢闪(亮 500ms 灭 500ms),表示接收机已初始化但未收到发射机信号。')
|
||||
pdf.step_block(2, '排查原因',
|
||||
'检查发射机是否开机、对频短语和频道是否匹配、距离是否在有效范围内。')
|
||||
|
||||
# 功能30
|
||||
pdf.chapter_title('功能 30: 快闪 (3Hz)', 3)
|
||||
pdf.body_text('对频中。')
|
||||
pdf.step_block(1, '观察 LED', 'LED 以 3Hz 快闪(亮 167ms 灭 167ms),表示接收机正在对频模式。')
|
||||
pdf.step_block(2, '操作', '在发射机上进入对频模式,等待自动配对。')
|
||||
|
||||
# 功能31
|
||||
pdf.chapter_title('功能 31: 常亮', 3)
|
||||
pdf.body_text('已连接正常。')
|
||||
pdf.step_block(1, '观察 LED', 'LED 持续点亮,表示接收机已成功连接发射机,通信正常。')
|
||||
pdf.step_block(2, '正常使用', '此时可以正常使用遥控器控制设备。')
|
||||
|
||||
# 功能32
|
||||
pdf.chapter_title('功能 32: 双闪 (1Hz)', 3)
|
||||
pdf.body_text('NRF 模块硬件错误。')
|
||||
pdf.step_block(1, '观察 LED', 'LED 以双闪模式(亮100ms 灭100ms 亮100ms 灭700ms)报警。')
|
||||
pdf.step_block(2, '排查原因',
|
||||
'检查 NRF24L01 模块是否插好、供电 3.3V 是否正常、SPI 引脚连接是否正确。'
|
||||
'接收机会自动重试,模块正常后恢复。')
|
||||
|
||||
# --- 六、存储与配置 ---
|
||||
pdf.add_page()
|
||||
pdf.chapter_title('六、存储与配置 (功能 33~34)', 2)
|
||||
|
||||
# 功能33
|
||||
pdf.chapter_title('功能 33: EEPROM 存储', 3)
|
||||
pdf.body_text('通过 IAP 读写,保存对频标志、地址、频道、短语。')
|
||||
pdf.step_block(1, '自动保存',
|
||||
'对频成功后,接收机自动将地址、频道、短语写入 EEPROM。'
|
||||
'下次上电直接读取使用。')
|
||||
pdf.step_block(2, '清除数据',
|
||||
'发送 DEL(BIND) 命令擦除 EEPROM 对频数据。')
|
||||
|
||||
# 功能34
|
||||
pdf.chapter_title('功能 34: 上电自动恢复', 3)
|
||||
pdf.body_text('检测 EEPROM 对频标志,有数据直接进入接收模式。')
|
||||
pdf.step_block(1, '上电流程',
|
||||
'接收机上电后读取 EEPROM 对频标志。\n'
|
||||
' 有数据 -> 直接进入接收模式,LED 慢闪等待信号\n'
|
||||
' 无数据 -> 进入对频模式,LED 快闪')
|
||||
|
||||
# --- 七、硬件外设 ---
|
||||
pdf.chapter_title('七、硬件外设 (功能 35~38)', 2)
|
||||
|
||||
# 功能35
|
||||
pdf.chapter_title('功能 35: 硬件 SPI', 3)
|
||||
pdf.body_text('STC8H 内置 SPI 主模式,6MHz,驱动 NRF24L01。')
|
||||
pdf.step_block(1, '自动初始化',
|
||||
'接收机上电后自动配置 STC8H 硬件 SPI 为主模式,速率 6MHz。')
|
||||
pdf.step_block(2, '无需用户操作',
|
||||
'SPI 通信完全由固件自动管理,用户无需干预。')
|
||||
|
||||
# 功能36
|
||||
pdf.chapter_title('功能 36: 定时器0', 3)
|
||||
pdf.body_text('4us 中断,生成 4 路 PWM + 系统滴答 (10ms)。')
|
||||
pdf.step_block(1, '自动配置',
|
||||
'定时器0 配置为 4us 中断,用于生成 PWM 信号和系统滴答时钟。')
|
||||
pdf.step_block(2, '无需用户操作', '定时器由固件自动管理。')
|
||||
|
||||
# 功能37
|
||||
pdf.chapter_title('功能 37: UART1', 3)
|
||||
pdf.body_text('使用 Timer2 做波特率发生器,支持 115200/100k/420k 切换。')
|
||||
pdf.step_block(1, '自动切换',
|
||||
'切换输出模式时,UART1 自动调整波特率和帧格式。\n'
|
||||
' PWM/UART: 115200 8N1\n'
|
||||
' SBUS: 100kbps 8E2\n'
|
||||
' CRFS: 420kbps 8N1')
|
||||
|
||||
# 功能38
|
||||
pdf.chapter_title('功能 38: ADC', 3)
|
||||
pdf.body_text('12 位,P3.3/ADC11,电池电压采样。')
|
||||
pdf.step_block(1, '连接分压电路',
|
||||
'将电池电压经分压电阻接入 P3.3。确保最高电压不超过 3.3V。')
|
||||
pdf.step_block(2, '自动采样',
|
||||
'接收机自动进行 12 位 ADC 采样,结果通过回传通道发送给发射机。')
|
||||
|
||||
# ==================== 保存 ====================
|
||||
output_path = '/root/ZhaTianRC/rx/操作指南.pdf'
|
||||
pdf.output(output_path)
|
||||
print(f'PDF 已生成: {output_path}')
|
||||
print(f'共 {pdf.page_no()} 页')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
build_pdf()
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert Intel HEX to binary"""
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: hex2bin.py <input.hex> <output.bin>")
|
||||
sys.exit(1)
|
||||
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
data = bytearray()
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line or line[0] != ':':
|
||||
continue
|
||||
count = int(line[1:3], 16)
|
||||
rtype = int(line[7:9], 16)
|
||||
if rtype == 0: # Data record
|
||||
for i in range(count):
|
||||
byte_val = int(line[9+i*2:11+i*2], 16)
|
||||
data.append(byte_val)
|
||||
elif rtype == 1: # EOF
|
||||
break
|
||||
|
||||
with open(sys.argv[2], 'wb') as f:
|
||||
f.write(data)
|
||||
|
||||
print(f"Binary: {len(data)} bytes")
|
||||
@@ -23,61 +23,48 @@
|
||||
#include "nrf24.h"
|
||||
#include "uart.h"
|
||||
|
||||
void EEPROM_LoadConfig();
|
||||
void Init();
|
||||
// EEPROM操作
|
||||
static CONFIG IAP_Read();
|
||||
static void IAP_Write(uint8 addr, CONFIG dat);
|
||||
static void IAP_Erase(uint8 addr);
|
||||
|
||||
void main(void) {
|
||||
static void LoadConfig();
|
||||
static void SystemInit();
|
||||
static void PWMBInit();
|
||||
static void UpdatePWMB();
|
||||
|
||||
static void main(void) {
|
||||
/* 系统初始化 */
|
||||
System_Init();
|
||||
GPIO_Init();
|
||||
Timer0_Init();
|
||||
UART1_Init();
|
||||
ADC_Init();
|
||||
IAP_Init();
|
||||
SystemInit();
|
||||
PWMBInit();
|
||||
|
||||
/* 初始化NRF24L01 */
|
||||
NRF24L01_Init();
|
||||
|
||||
/* 初始PWM: 中位 */
|
||||
PWM_SetAllFailsafe();
|
||||
|
||||
// 从EEPROM加载配置 */
|
||||
EEPROM_LoadConfig();
|
||||
// 从EEPROM加载配置并应用 */
|
||||
InitSet(LoadConfig());
|
||||
|
||||
/* 检测NRF模块 */
|
||||
if (!NRF24L01_Check()) {
|
||||
/* NRF模块未检测到, 设置硬件错误标志, LED双闪 */
|
||||
nrf_hw_error = 1;
|
||||
SysStatus = NRF_ERROR;
|
||||
while (1) LED_Update();
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/* 处理串口命令 */
|
||||
UART1_ProcessCmd();
|
||||
|
||||
if (NRF_IRQ == 1) {
|
||||
// 处理NRF24L01接收数据
|
||||
NRF24L01_ProcessRX();
|
||||
// 更新输出数据
|
||||
outputFun();
|
||||
}
|
||||
|
||||
/* LED状态指示 */
|
||||
LED_Update();
|
||||
}
|
||||
}
|
||||
|
||||
void Init() {
|
||||
void SystemInit() {
|
||||
// System_Init()
|
||||
/* 切换到内部24MHz IRC */
|
||||
P_SW2 |= EAXFR; /* 使能访问扩展SFR */
|
||||
CLKDIV = 0x00; /* 主时钟不分频 */
|
||||
CKSEL = 0x00; /* 选择内部高速IRC */
|
||||
P_SW2 &= ~EAXFR;
|
||||
// 使用stc-isp下载时, 系统时钟已设置为内部IRC 40MHz, 可省略
|
||||
P_SW2 |= 0x80; // 使能访问扩展SFR(XFR)
|
||||
// 选择内部高速IRC作为主时钟源(复位后默认即为内部IRC,可省略)
|
||||
CLKSEL = 0x00; // MCKSEL[1:0]=00 选择内部IRC
|
||||
// 主时钟不分频
|
||||
CLKDIV = 0x00; // 系统时钟 = 主时钟 / 1 = 40MHz
|
||||
|
||||
/* 设置内部IRC为24MHz */
|
||||
IRC24MCR = 0x80; /* 使能内部24MHz IRC */
|
||||
while (!(IRC24MCR & 0x01)); /* 等待IRC稳定 */
|
||||
|
||||
// GPIO_Init()
|
||||
/* P3.4-P3.7: 推挽输出 (PWM通道) */
|
||||
P3M0 |= 0xF0;
|
||||
@@ -127,14 +114,149 @@ void Init() {
|
||||
|
||||
// Timer_Init()
|
||||
/* 16位自动重载模式, 1T */
|
||||
TMOD &= ~0x0F;
|
||||
TMOD |= 0x01; /* T0: 16位定时器 */
|
||||
AUXR |= T0x12; /* T0: 1T模式 */
|
||||
|
||||
/* 4us @ 24MHz: 96 ticks */
|
||||
TH0 = 0xFF;
|
||||
TL0 = 0xA0; /* 65536 - 96 = 0xFFA0 */
|
||||
|
||||
TMOD &= 0xF0; /* 清除T0模式低4位 */
|
||||
TMOD |= 0x00; /* T0: 16位定时器 */
|
||||
AUXR |= 0x80; /* 不分频,T0x12=1,定时器0时钟 = SYSCLK */
|
||||
/* 50us @ 40MHz */
|
||||
TH0 = 0xFE;
|
||||
TL0 = 0x70;
|
||||
ET0 = 1; /* 使能T0中断 */
|
||||
EA = 1;
|
||||
TR0 = 1; /* 启动T0 */
|
||||
}
|
||||
|
||||
// UART_Init()
|
||||
/* 使用 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;
|
||||
|
||||
/* SPI 初始化: 主模式, 模式0, 5MHz @ 40MHz */
|
||||
// 1. 配置 SPI 时钟频率 (SPR[1:0] = 01)
|
||||
// 同时设置其他控制位:
|
||||
// SSIG = 1 (忽略SS引脚,由MSTR控制主从)[reference:7]
|
||||
// SPEN = 1 (使能SPI)[reference:8]
|
||||
// DORD = 0 (MSB先发)[reference:9]
|
||||
// MSTR = 1 (主机模式)[reference:10]
|
||||
// CPOL = 0 (时钟空闲时为低电平)[reference:11]
|
||||
// CPHA = 0 (第一个时钟沿采样)[reference:12]
|
||||
// 组合得到 SPCTL = 0b11010001 = 0xD1
|
||||
SPCTL = 0xD1;
|
||||
// 2. 清空中断标志
|
||||
SPSTAT = 0xC0;
|
||||
// 3. (可选) 使能SPI中断
|
||||
// IE2 |= ESPI;
|
||||
|
||||
// ADC_Init()
|
||||
ADCCFG = ADC_RESFMT; /* 右对齐, 12位结果 */
|
||||
ADC_CONTR = ADC_POWER; /* 开启ADC电源 */
|
||||
/* 选择通道11 (P3.3) */
|
||||
ADC_CONTR = (ADC_CONTR & 0xF0) | 0x0B;
|
||||
}
|
||||
void PWMBInit() {
|
||||
// 1. 使能访问扩展特殊功能寄存器 (XFR)
|
||||
P_SW2 |= 0x80;
|
||||
|
||||
// 2. 配置时基:1MHz 计数时钟,20ms 周期, 基于40MHz系统
|
||||
PWMB_PSCR = 39; // 预分频器
|
||||
PWMB_ARR = 19999; // 自动重装载值
|
||||
|
||||
// 3. 配置四个通道为 PWM 模式1 (PWM1),使能预装载
|
||||
PWMB_CCMR1 = 0x68; // 通道5: PWM模式1, 预装载使能
|
||||
PWMB_CCMR2 = 0x68; // 通道6
|
||||
PWMB_CCMR3 = 0x68; // 通道7
|
||||
PWMB_CCMR4 = 0x68; // 通道8
|
||||
|
||||
// 4. 设置初始占空比(例如 1.5ms,对应 90°)
|
||||
PWMB_CCR5 = 1500;
|
||||
PWMB_CCR6 = 1500;
|
||||
PWMB_CCR7 = 1500;
|
||||
PWMB_CCR8 = 1500;
|
||||
|
||||
// 5. 配置 GPIO 为推挽输出
|
||||
// P1.7
|
||||
P1M0 |= 0x80; // P1M0.7 = 1
|
||||
P1M1 &= ~0x80; // P1M1.7 = 0
|
||||
// P5.4
|
||||
P5M0 |= 0x10; // P5M0.4 = 1
|
||||
P5M1 &= ~0x10; // P5M1.4 = 0
|
||||
// P3.3, P3.4
|
||||
P3M0 |= 0x18; // bit3 and bit4
|
||||
P3M1 &= ~0x18;
|
||||
|
||||
// 6. 引脚功能映射 (选择第二组引脚)
|
||||
PWMB_PS = PWMB_PS_VALUE; // 0x55
|
||||
|
||||
// 7. 使能输出
|
||||
PWMB_ENO = 0x55; // bit0: ENO5P, bit2: ENO6P, bit4: ENO7P, bit6: ENO8P
|
||||
PWMB_CCER1 = 0x11; // CC5E=1, CC6E=1
|
||||
PWMB_CCER2 = 0x11; // CC7E=1, CC8E=1
|
||||
|
||||
// 8. 主输出使能
|
||||
PWMB_BKR |= 0x80; // MOE=1
|
||||
|
||||
// 9. 启动计数器
|
||||
PWMB_CR1 |= 0x01; // CEN=1
|
||||
}
|
||||
void LED_Update(void) {
|
||||
switch (led_mode) {
|
||||
case UNCONNECTED:
|
||||
// 未连接状态,1Hz闪烁
|
||||
if (sys_tick < 500) P32 = 1; else P32 = 0;
|
||||
break;
|
||||
case NRF_BINDING:
|
||||
// 对频状态,2Hz闪烁
|
||||
if (sys_tick % 500 < 250) P32 = 1; else P32 = 0;
|
||||
break;
|
||||
case NRF_ERROR:
|
||||
// NRF硬件错误状态,双闪
|
||||
if (sys_tick < 100) P32 = 0; /* 亮 100ms */
|
||||
else if (sys_tick < 200) P32 = 1; /* 灭 100ms */
|
||||
else if (sys_tick < 300) P32 = 0; /* 亮 100ms */
|
||||
else P32 = 1; /* 灭 700ms */
|
||||
break;
|
||||
case CONNECTED:
|
||||
// 已连接状态,常亮
|
||||
P32 = 1;
|
||||
break;
|
||||
default:
|
||||
P32 = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void Servo_SetAngle(uint16 CH_Value[4]) {
|
||||
// 角度范围 0 ~ 180,对应脉宽 0.5ms ~ 2.5ms,即500~2500
|
||||
// CH_Value范围1000~2000,值为1500时中点
|
||||
PWMB_CCR5 = CH_Value[0]*2-1500;
|
||||
PWMB_CCR6 = CH_Value[1]*2-1500;
|
||||
PWMB_CCR7 = CH_Value[2]*2-1500;
|
||||
PWMB_CCR8 = CH_Value[3]*2-1500;
|
||||
}
|
||||
// 中断
|
||||
void tm0_isr(void) __interrupt(1) {
|
||||
// 40MHz系统下10us中断, 用于系统滴答
|
||||
static idata uint8 sys_tick_cnt = 0;
|
||||
/* 系统滴答 (1ms) */
|
||||
if (sys_tick_cnt++ >= 100) {
|
||||
sys_tick_cnt = 0;
|
||||
if (sys_tick++ >= 1000) sys_tick = 0; // 1秒清零
|
||||
}
|
||||
}
|
||||
|
||||
static CONFIG IAP_Read(){
|
||||
static __xdata CONFIG dat;
|
||||
|
||||
return dat;
|
||||
}
|
||||
static void IAP_Write(uint8 addr, CONFIG dat);
|
||||
static void IAP_Erase(uint8 addr);
|
||||
@@ -1,16 +1,10 @@
|
||||
|
||||
/* ========================================================================
|
||||
* NRF24L01 硬件 SPI 实现 (STC8H 内置 SPI)
|
||||
* P1.3=MISO, P1.4=MOSI, P1.5=SCLK, P5.4=CSN(GPIO)
|
||||
* P1.7=IRQ, P1.6=CE,
|
||||
* ======================================================================== */
|
||||
|
||||
/* SPI 初始化: 主模式, 模式0, 6MHz @ 24MHz */
|
||||
static void NRF_SPI_Init(void) {
|
||||
SPCTL = SSIG | SPEN | MSTR; /* 0xD0: SSIG=1, SPEN=1, MSTR=1, CPOL=0, CPHA=0, fosc/4 */
|
||||
SPSTAT = SPIF | WCOL; /* 清除标志 */
|
||||
}
|
||||
|
||||
uint8_t NRF_SPI_TransferByte(uint8_t dat) {
|
||||
uint8_t SPI_ReadWrite(uint8_t dat) {
|
||||
SPDAT = dat;
|
||||
/* 等待传输完成 */
|
||||
while (!(SPSTAT & SPIF));
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
# ifndef CONFIG
|
||||
# define CONFIG
|
||||
# include "CONFIG.h"
|
||||
# endif
|
||||
/**
|
||||
* NRF24L01+ 驱动头文件 (STC8H1K08 移植版, SDCC 兼容)
|
||||
* SPI 引脚: SCK=P1.5, CE=P1.6, IRQ=P1.7, CSN=P5.4, MISO=P1.3, MOSI=P1.4
|
||||
* 使用 STC8H 硬件 SPI (SPI 默认引脚)
|
||||
*/
|
||||
|
||||
/* ========== 引脚定义 (SDCC 语法) ========== */
|
||||
__sbit __at(0x95) NRF_SCK; /* P1^5 */
|
||||
__sbit __at(0x96) NRF_CE; /* P1^6 */
|
||||
__sbit __at(0x97) NRF_IRQ; /* P1^7 */
|
||||
__sbit __at(0xCC) NRF_CSN; /* P5^4 */
|
||||
__sbit __at(0x93) NRF_MISO; /* P1^3 */
|
||||
__sbit __at(0x94) NRF_MOSI; /* P1^4 */
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//NRF24L01寄存器操作命令
|
||||
#define NRF_READ_REG 0x00 //读配置寄存器,低5位为寄存器地址
|
||||
#define NRF_WRITE_REG 0x20 //写配置寄存器,低5位为寄存器地址
|
||||
#define RD_RX_PLOAD 0x61 //读RX有效数据,1~32字节
|
||||
#define WR_TX_PLOAD 0xA0 //写TX有效数据,1~32字节
|
||||
#define FLUSH_TX 0xE1 //清除TX FIFO寄存器.发射模式下用
|
||||
#define FLUSH_RX 0xE2 //清除RX FIFO寄存器.接收模式下用
|
||||
#define REUSE_TX_PL 0xE3 //重新使用上一包数据,CE为高,数据包被不断发送.
|
||||
#define NOP 0xFF //空操作,可以用来读状态寄存器
|
||||
//SPI(NRF24L01)寄存器地址
|
||||
#define CONFIG 0x00 //配置寄存器地址;bit0:1接收模式,0发射模式;bit1:电选择;bit2:CRC模式;bit3:CRC使能;
|
||||
//bit4:中断MAX_RT(达到最大重发次数中断)使能;bit5:中断TX_DS使能;bit6:中断RX_DR使能
|
||||
#define EN_AA 0x01 //使能自动应答功能 bit0~5,对应通道0~5
|
||||
#define EN_RXADDR 0x02 //接收地址允许,bit0~5,对应通道0~5
|
||||
#define SETUP_AW 0x03 //设置地址宽度(所有数据通道):bit1,0:00,3字节;01,4字节;02,5字节;
|
||||
#define SETUP_RETR 0x04 //建立自动重发;bit3:0,自动重发计数器;bit7:4,自动重发延时 250*x+86us
|
||||
#define RF_CH 0x05 //RF通道,bit6:0,工作通道频率;
|
||||
#define RF_SETUP 0x06 //RF寄存器;bit3:传输速率(0:1Mbps,1:2Mbps);bit2:1,发射功率;bit0:低噪声放大器增益
|
||||
#define STATUS 0x07 //状态寄存器;bit0:TX FIFO满标志;bit3:1,接收数据通道号(最大:6);bit4,达到最多次重发
|
||||
//bit5:数据发送完成中断;bit6:接收数据中断;
|
||||
#define MAX_TX 0x10 //达到最大发送次数中断
|
||||
#define TX_OK 0x20 //TX发送完成中断
|
||||
#define RX_OK 0x40 //接收到数据中断
|
||||
|
||||
#define OBSERVE_TX 0x08 //发送检测寄存器,bit7:4,数据包丢失计数器;bit3:0,重发计数器
|
||||
#define CD 0x09 //载波检测寄存器,bit0,载波检测;
|
||||
#define RX_ADDR_P0 0x0A //数据通道0接收地址,最大长度5个字节,低字节在前
|
||||
#define RX_ADDR_P1 0x0B //数据通道1接收地址,最大长度5个字节,低字节在前
|
||||
#define RX_ADDR_P2 0x0C //数据通道2接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
|
||||
#define RX_ADDR_P3 0x0D //数据通道3接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
|
||||
#define RX_ADDR_P4 0x0E //数据通道4接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
|
||||
#define RX_ADDR_P5 0x0F //数据通道5接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
|
||||
#define TX_ADDR 0x10 //发送地址(低字节在前),ShockBurstTM模式下,RX_ADDR_P0与此地址相等
|
||||
#define RX_PW_P0 0x11 //接收数据通道0有效数据宽度(1~32字节),设置为0则非法
|
||||
#define RX_PW_P1 0x12 //接收数据通道1有效数据宽度(1~32字节),设置为0则非法
|
||||
#define RX_PW_P2 0x13 //接收数据通道2有效数据宽度(1~32字节),设置为0则非法
|
||||
#define RX_PW_P3 0x14 //接收数据通道3有效数据宽度(1~32字节),设置为0则非法
|
||||
#define RX_PW_P4 0x15 //接收数据通道4有效数据宽度(1~32字节),设置为0则非法
|
||||
#define RX_PW_P5 0x16 //接收数据通道5有效数据宽度(1~32字节),设置为0则非法
|
||||
#define NRF_FIFO_STATUS 0x17 //FIFO状态寄存器;bit0,RX FIFO寄存器空标志;bit1,RX FIFO满标志;bit2,3,保留
|
||||
//bit4,TX FIFO空标志;bit5,TX FIFO满标志;bit6,1,循环发送上一数据包.0,不循环;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* ========== 函数声明 ========== */
|
||||
|
||||
/* 底层 SPI */
|
||||
uint8 SPI_ReadWrite(uint8 dat);
|
||||
|
||||
/* 寄存器操作 */
|
||||
uint8 NRF24_ReadReg(uint8 reg);
|
||||
void NRF24_WriteReg(uint8 reg, uint8 value);
|
||||
void NRF24_ReadBuf(uint8 reg, uint8 *buf, uint8 len);
|
||||
void NRF24_WriteBuf(uint8 reg, const uint8 *buf, uint8 len);
|
||||
|
||||
/* 初始化与检测 */
|
||||
void NRF24_Init(void);
|
||||
bool NRF24_Check(void);
|
||||
|
||||
/* 配置 */
|
||||
void NRF24_SetConfig(uint8 ch);
|
||||
void NRF24_SetRXAddr(uint8 pipe, const uint8 *addr);
|
||||
|
||||
/* 模式切换 */
|
||||
void NRF24L01_RXMode(void);
|
||||
void NRF24L01_TXMode(void);
|
||||
|
||||
/* 数据收发 */
|
||||
uint8 NRF24L01_RxPacket(uint8 *data);
|
||||
uint8 NRF24L01_IsDataReady(void);
|
||||
void NRF24L01_FlushRX(void);
|
||||
|
||||
#endif /* __NRF24_H__ */
|
||||
-590
@@ -1,590 +0,0 @@
|
||||
#ifndef __STC8F_H_
|
||||
#define __STC8F_H_
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
//包含本头文件后,不用另外再包含"REG51.H"
|
||||
|
||||
//内核特殊功能寄存器
|
||||
sfr ACC = 0xe0;
|
||||
sfr B = 0xf0;
|
||||
sfr PSW = 0xd0;
|
||||
sbit CY = PSW^7;
|
||||
sbit AC = PSW^6;
|
||||
sbit F0 = PSW^5;
|
||||
sbit RS1 = PSW^4;
|
||||
sbit RS0 = PSW^3;
|
||||
sbit OV = PSW^2;
|
||||
sbit P = PSW^0;
|
||||
sfr SP = 0x81;
|
||||
sfr DPL = 0x82;
|
||||
sfr DPH = 0x83;
|
||||
sfr TA = 0xae;
|
||||
sfr DPS = 0xe3;
|
||||
sfr DPL1 = 0xe4;
|
||||
sfr DPH1 = 0xe5;
|
||||
|
||||
|
||||
//I/O 口特殊功能寄存器
|
||||
sfr P0 = 0x80;
|
||||
sfr P1 = 0x90;
|
||||
sfr P2 = 0xa0;
|
||||
sfr P3 = 0xb0;
|
||||
sfr P4 = 0xc0;
|
||||
sfr P5 = 0xc8;
|
||||
sfr P6 = 0xe8;
|
||||
sfr P7 = 0xf8;
|
||||
sfr P0M0 = 0x94;
|
||||
sfr P0M1 = 0x93;
|
||||
sfr P1M0 = 0x92;
|
||||
sfr P1M1 = 0x91;
|
||||
sfr P2M0 = 0x96;
|
||||
sfr P2M1 = 0x95;
|
||||
sfr P3M0 = 0xb2;
|
||||
sfr P3M1 = 0xb1;
|
||||
sfr P4M0 = 0xb4;
|
||||
sfr P4M1 = 0xb3;
|
||||
sfr P5M0 = 0xca;
|
||||
sfr P5M1 = 0xc9;
|
||||
sfr P6M0 = 0xcc;
|
||||
sfr P6M1 = 0xcb;
|
||||
sfr P7M0 = 0xe2;
|
||||
sfr P7M1 = 0xe1;
|
||||
|
||||
sbit P00 = P0^0;
|
||||
sbit P01 = P0^1;
|
||||
sbit P02 = P0^2;
|
||||
sbit P03 = P0^3;
|
||||
sbit P04 = P0^4;
|
||||
sbit P05 = P0^5;
|
||||
sbit P06 = P0^6;
|
||||
sbit P07 = P0^7;
|
||||
sbit P10 = P1^0;
|
||||
sbit P11 = P1^1;
|
||||
sbit P12 = P1^2;
|
||||
sbit P13 = P1^3;
|
||||
sbit P14 = P1^4;
|
||||
sbit P15 = P1^5;
|
||||
sbit P16 = P1^6;
|
||||
sbit P17 = P1^7;
|
||||
sbit P20 = P2^0;
|
||||
sbit P21 = P2^1;
|
||||
sbit P22 = P2^2;
|
||||
sbit P23 = P2^3;
|
||||
sbit P24 = P2^4;
|
||||
sbit P25 = P2^5;
|
||||
sbit P26 = P2^6;
|
||||
sbit P27 = P2^7;
|
||||
sbit P30 = P3^0;
|
||||
sbit P31 = P3^1;
|
||||
sbit P32 = P3^2;
|
||||
sbit P33 = P3^3;
|
||||
sbit P34 = P3^4;
|
||||
sbit P35 = P3^5;
|
||||
sbit P36 = P3^6;
|
||||
sbit P37 = P3^7;
|
||||
sbit P40 = P4^0;
|
||||
sbit P41 = P4^1;
|
||||
sbit P42 = P4^2;
|
||||
sbit P43 = P4^3;
|
||||
sbit P44 = P4^4;
|
||||
sbit P45 = P4^5;
|
||||
sbit P46 = P4^6;
|
||||
sbit P47 = P4^7;
|
||||
sbit P50 = P5^0;
|
||||
sbit P51 = P5^1;
|
||||
sbit P52 = P5^2;
|
||||
sbit P53 = P5^3;
|
||||
sbit P54 = P5^4;
|
||||
sbit P55 = P5^5;
|
||||
sbit P56 = P5^6;
|
||||
sbit P57 = P5^7;
|
||||
sbit P60 = P6^0;
|
||||
sbit P61 = P6^1;
|
||||
sbit P62 = P6^2;
|
||||
sbit P63 = P6^3;
|
||||
sbit P64 = P6^4;
|
||||
sbit P65 = P6^5;
|
||||
sbit P66 = P6^6;
|
||||
sbit P67 = P6^7;
|
||||
sbit P70 = P7^0;
|
||||
sbit P71 = P7^1;
|
||||
sbit P72 = P7^2;
|
||||
sbit P73 = P7^3;
|
||||
sbit P74 = P7^4;
|
||||
sbit P75 = P7^5;
|
||||
sbit P76 = P7^6;
|
||||
sbit P77 = P7^7;
|
||||
|
||||
//如下特殊功能寄存器位于扩展RAM区域
|
||||
//访问这些寄存器,需先将P_SW2的BIT7设置为1,才可正常读写
|
||||
#define P0PU (*(unsigned char volatile xdata *)0xfe10)
|
||||
#define P1PU (*(unsigned char volatile xdata *)0xfe11)
|
||||
#define P2PU (*(unsigned char volatile xdata *)0xfe12)
|
||||
#define P3PU (*(unsigned char volatile xdata *)0xfe13)
|
||||
#define P4PU (*(unsigned char volatile xdata *)0xfe14)
|
||||
#define P5PU (*(unsigned char volatile xdata *)0xfe15)
|
||||
#define P6PU (*(unsigned char volatile xdata *)0xfe16)
|
||||
#define P7PU (*(unsigned char volatile xdata *)0xfe17)
|
||||
#define P0NCS (*(unsigned char volatile xdata *)0xfe18)
|
||||
#define P1NCS (*(unsigned char volatile xdata *)0xfe19)
|
||||
#define P2NCS (*(unsigned char volatile xdata *)0xfe1a)
|
||||
#define P3NCS (*(unsigned char volatile xdata *)0xfe1b)
|
||||
#define P4NCS (*(unsigned char volatile xdata *)0xfe1c)
|
||||
#define P5NCS (*(unsigned char volatile xdata *)0xfe1d)
|
||||
#define P6NCS (*(unsigned char volatile xdata *)0xfe1e)
|
||||
#define P7NCS (*(unsigned char volatile xdata *)0xfe1f)
|
||||
|
||||
//系统管理特殊功能寄存器
|
||||
sfr PCON = 0x87;
|
||||
#define SMOD 0x80
|
||||
#define SMOD0 0x40
|
||||
#define LVDF 0x20
|
||||
#define POF 0x10
|
||||
#define GF1 0x08
|
||||
#define GF0 0x04
|
||||
#define PD 0x02
|
||||
#define IDL 0x01
|
||||
sfr AUXR = 0x8e;
|
||||
#define T0x12 0x80
|
||||
#define T1x12 0x40
|
||||
#define UART_M0x6 0x20
|
||||
#define T2R 0x10
|
||||
#define T2_CT 0x08
|
||||
#define T2x12 0x04
|
||||
#define EXTRAM 0x02
|
||||
#define S1ST2 0x01
|
||||
sfr AUXR2 = 0x97;
|
||||
#define TXLNRX 0x10
|
||||
sfr BUS_SPEED = 0xa1;
|
||||
sfr P_SW1 = 0xa2;
|
||||
sfr P_SW2 = 0xba;
|
||||
#define EAXFR 0x80
|
||||
sfr VOCTRL = 0xbb;
|
||||
sfr RSTCFG = 0xff;
|
||||
|
||||
//如下特殊功能寄存器位于扩展RAM区域
|
||||
//访问这些寄存器,需先将P_SW2的BIT7设置为1,才可正常读写
|
||||
#define CKSEL (*(unsigned char volatile xdata *)0xfe00)
|
||||
#define CLKDIV (*(unsigned char volatile xdata *)0xfe01)
|
||||
#define IRC24MCR (*(unsigned char volatile xdata *)0xfe02)
|
||||
#define XOSCCR (*(unsigned char volatile xdata *)0xfe03)
|
||||
#define IRC32KCR (*(unsigned char volatile xdata *)0xfe04)
|
||||
|
||||
//中断特殊功能寄存器
|
||||
sfr IE = 0xa8;
|
||||
sbit EA = IE^7;
|
||||
sbit ELVD = IE^6;
|
||||
sbit EADC = IE^5;
|
||||
sbit ES = IE^4;
|
||||
sbit ET1 = IE^3;
|
||||
sbit EX1 = IE^2;
|
||||
sbit ET0 = IE^1;
|
||||
sbit EX0 = IE^0;
|
||||
sfr IE2 = 0xaf;
|
||||
#define ET4 0x40
|
||||
#define ET3 0x20
|
||||
#define ES4 0x10
|
||||
#define ES3 0x08
|
||||
#define ET2 0x04
|
||||
#define ESPI 0x02
|
||||
#define ES2 0x01
|
||||
sfr IP = 0xb8;
|
||||
sbit PPCA = IP^7;
|
||||
sbit PLVD = IP^6;
|
||||
sbit PADC = IP^5;
|
||||
sbit PS = IP^4;
|
||||
sbit PT1 = IP^3;
|
||||
sbit PX1 = IP^2;
|
||||
sbit PT0 = IP^1;
|
||||
sbit PX0 = IP^0;
|
||||
sfr IP2 = 0xb5;
|
||||
#define PI2C 0x40
|
||||
#define PCMP 0x20
|
||||
#define PX4 0x10
|
||||
#define PPWMFD 0x08
|
||||
#define PPWM 0x04
|
||||
#define PSPI 0x02
|
||||
#define PS2 0x01
|
||||
sfr IPH = 0xb7;
|
||||
#define PPCAH 0x80
|
||||
#define PLVDH 0x40
|
||||
#define PADCH 0x20
|
||||
#define PSH 0x10
|
||||
#define PT1H 0x08
|
||||
#define PX1H 0x04
|
||||
#define PT0H 0x02
|
||||
#define PX0H 0x01
|
||||
sfr IP2H = 0xb6;
|
||||
#define PI2CH 0x40
|
||||
#define PCMPH 0x20
|
||||
#define PX4H 0x10
|
||||
#define PPWMFDH 0x08
|
||||
#define PPWMH 0x04
|
||||
#define PSPIH 0x02
|
||||
#define PS2H 0x01
|
||||
sfr INTCLKO = 0x8f;
|
||||
#define EX4 0x40
|
||||
#define EX3 0x20
|
||||
#define EX2 0x10
|
||||
#define T2CLKO 0x04
|
||||
#define T1CLKO 0x02
|
||||
#define T0CLKO 0x01
|
||||
sfr AUXINTIF = 0xef;
|
||||
#define INT4IF 0x40
|
||||
#define INT3IF 0x20
|
||||
#define INT2IF 0x10
|
||||
#define T4IF 0x04
|
||||
#define T3IF 0x02
|
||||
#define T2IF 0x01
|
||||
|
||||
//定时器特殊功能寄存器
|
||||
sfr TCON = 0x88;
|
||||
sbit TF1 = TCON^7;
|
||||
sbit TR1 = TCON^6;
|
||||
sbit TF0 = TCON^5;
|
||||
sbit TR0 = TCON^4;
|
||||
sbit IE1 = TCON^3;
|
||||
sbit IT1 = TCON^2;
|
||||
sbit IE0 = TCON^1;
|
||||
sbit IT0 = TCON^0;
|
||||
sfr TMOD = 0x89;
|
||||
#define T1_GATE 0x80
|
||||
#define T1_CT 0x40
|
||||
#define T1_M1 0x20
|
||||
#define T1_M0 0x10
|
||||
#define T0_GATE 0x08
|
||||
#define T0_CT 0x04
|
||||
#define T0_M1 0x02
|
||||
#define T0_M0 0x01
|
||||
sfr TL0 = 0x8a;
|
||||
sfr TL1 = 0x8b;
|
||||
sfr TH0 = 0x8c;
|
||||
sfr TH1 = 0x8d;
|
||||
sfr T4T3M = 0xd1;
|
||||
#define T4R 0x80
|
||||
#define T4_CT 0x40
|
||||
#define T4x12 0x20
|
||||
#define T4CLKO 0x10
|
||||
#define T3R 0x08
|
||||
#define T3_CT 0x04
|
||||
#define T3x12 0x02
|
||||
#define T3CLKO 0x01
|
||||
sfr T4H = 0xd2;
|
||||
sfr T4L = 0xd3;
|
||||
sfr T3H = 0xd4;
|
||||
sfr T3L = 0xd5;
|
||||
sfr T2H = 0xd6;
|
||||
sfr T2L = 0xd7;
|
||||
sfr TH4 = 0xd2;
|
||||
sfr TL4 = 0xd3;
|
||||
sfr TH3 = 0xd4;
|
||||
sfr TL3 = 0xd5;
|
||||
sfr TH2 = 0xd6;
|
||||
sfr TL2 = 0xd7;
|
||||
sfr WKTCL = 0xaa;
|
||||
sfr WKTCH = 0xab;
|
||||
#define WKTEN 0x80
|
||||
sfr WDT_CONTR = 0xc1;
|
||||
#define WDT_FLAG 0x80
|
||||
#define EN_WDT 0x20
|
||||
#define CLR_WDT 0x10
|
||||
#define IDL_WDT 0x08
|
||||
|
||||
//串行口特殊功能寄存器
|
||||
sfr SCON = 0x98;
|
||||
sbit SM0 = SCON^7;
|
||||
sbit SM1 = SCON^6;
|
||||
sbit SM2 = SCON^5;
|
||||
sbit REN = SCON^4;
|
||||
sbit TB8 = SCON^3;
|
||||
sbit RB8 = SCON^2;
|
||||
sbit TI = SCON^1;
|
||||
sbit RI = SCON^0;
|
||||
sfr SBUF = 0x99;
|
||||
sfr S2CON = 0x9a;
|
||||
#define S2SM0 0x80
|
||||
#define S2ST4 0x40
|
||||
#define S2SM2 0x20
|
||||
#define S2REN 0x10
|
||||
#define S2TB8 0x08
|
||||
#define S2RB8 0x04
|
||||
#define S2TI 0x02
|
||||
#define S2RI 0x01
|
||||
sfr S2BUF = 0x9b;
|
||||
sfr S3CON = 0xac;
|
||||
#define S3SM0 0x80
|
||||
#define S3ST4 0x40
|
||||
#define S3SM2 0x20
|
||||
#define S3REN 0x10
|
||||
#define S3TB8 0x08
|
||||
#define S3RB8 0x04
|
||||
#define S3TI 0x02
|
||||
#define S3RI 0x01
|
||||
sfr S3BUF = 0xad;
|
||||
sfr S4CON = 0x84;
|
||||
#define S4SM0 0x80
|
||||
#define S4ST4 0x40
|
||||
#define S4SM2 0x20
|
||||
#define S4REN 0x10
|
||||
#define S4TB8 0x08
|
||||
#define S4RB8 0x04
|
||||
#define S4TI 0x02
|
||||
#define S4RI 0x01
|
||||
sfr S4BUF = 0x85;
|
||||
sfr SADDR = 0xa9;
|
||||
sfr SADEN = 0xb9;
|
||||
|
||||
//ADC 特殊功能寄存器
|
||||
sfr ADC_CONTR = 0xbc;
|
||||
#define ADC_POWER 0x80
|
||||
#define ADC_START 0x40
|
||||
#define ADC_FLAG 0x20
|
||||
sfr ADC_RES = 0xbd;
|
||||
sfr ADC_RESL = 0xbe;
|
||||
sfr ADCCFG = 0xde;
|
||||
#define ADC_RESFMT 0x20
|
||||
|
||||
//SPI 特殊功能寄存器
|
||||
sfr SPSTAT = 0xcd;
|
||||
#define SPIF 0x80
|
||||
#define WCOL 0x40
|
||||
sfr SPCTL = 0xce;
|
||||
#define SSIG 0x80
|
||||
#define SPEN 0x40
|
||||
#define DORD 0x20
|
||||
#define MSTR 0x10
|
||||
#define CPOL 0x08
|
||||
#define CPHA 0x04
|
||||
sfr SPDAT = 0xcf;
|
||||
|
||||
//IAP/ISP 特殊功能寄存器
|
||||
sfr IAP_DATA = 0xc2;
|
||||
sfr IAP_ADDRH = 0xc3;
|
||||
sfr IAP_ADDRL = 0xc4;
|
||||
sfr IAP_CMD = 0xc5;
|
||||
#define IAP_IDL 0x00
|
||||
#define IAP_READ 0x01
|
||||
#define IAP_WRITE 0x02
|
||||
#define IAP_ERASE 0x03
|
||||
sfr IAP_TRIG = 0xc6;
|
||||
sfr IAP_CONTR = 0xc7;
|
||||
#define IAPEN 0x80
|
||||
#define SWBS 0x40
|
||||
#define SWRST 0x20
|
||||
#define CMD_FAIL 0x10
|
||||
sfr ISP_DATA = 0xc2;
|
||||
sfr ISP_ADDRH = 0xc3;
|
||||
sfr ISP_ADDRL = 0xc4;
|
||||
sfr ISP_CMD = 0xc5;
|
||||
sfr ISP_TRIG = 0xc6;
|
||||
sfr ISP_CONTR = 0xc7;
|
||||
|
||||
//比较器特殊功能寄存器
|
||||
sfr CMPCR1 = 0xe6;
|
||||
#define CMPEN 0x80
|
||||
#define CMPIF 0x40
|
||||
#define PIE 0x20
|
||||
#define NIE 0x10
|
||||
#define PIS 0x08
|
||||
#define NIS 0x04
|
||||
#define CMPOE 0x02
|
||||
#define CMPRES 0x01
|
||||
sfr CMPCR2 = 0xe7;
|
||||
#define INVCMPO 0x80
|
||||
#define DISFLT 0x40
|
||||
|
||||
//PCA/PWM 特殊功能寄存器
|
||||
sfr CCON = 0xd8;
|
||||
sbit CF = CCON^7;
|
||||
sbit CR = CCON^6;
|
||||
sbit CCF3 = CCON^3;
|
||||
sbit CCF2 = CCON^2;
|
||||
sbit CCF1 = CCON^1;
|
||||
sbit CCF0 = CCON^0;
|
||||
sfr CMOD = 0xd9;
|
||||
#define CIDL 0x80
|
||||
#define ECF 0x01
|
||||
sfr CL = 0xe9;
|
||||
sfr CH = 0xf9;
|
||||
sfr CCAPM0 = 0xda;
|
||||
#define ECOM0 0x40
|
||||
#define CCAPP0 0x20
|
||||
#define CCAPN0 0x10
|
||||
#define MAT0 0x08
|
||||
#define TOG0 0x04
|
||||
#define PWM0 0x02
|
||||
#define ECCF0 0x01
|
||||
sfr CCAPM1 = 0xdb;
|
||||
#define ECOM1 0x40
|
||||
#define CCAPP1 0x20
|
||||
#define CCAPN1 0x10
|
||||
#define MAT1 0x08
|
||||
#define TOG1 0x04
|
||||
#define PWM1 0x02
|
||||
#define ECCF1 0x01
|
||||
sfr CCAPM2 = 0xdc;
|
||||
#define ECOM2 0x40
|
||||
#define CCAPP2 0x20
|
||||
#define CCAPN2 0x10
|
||||
#define MAT2 0x08
|
||||
#define TOG2 0x04
|
||||
#define PWM2 0x02
|
||||
#define ECCF2 0x01
|
||||
sfr CCAPM3 = 0xdd;
|
||||
#define ECOM3 0x40
|
||||
#define CCAPP3 0x20
|
||||
#define CCAPN3 0x10
|
||||
#define MAT3 0x08
|
||||
#define TOG3 0x04
|
||||
#define PWM3 0x02
|
||||
#define ECCF3 0x01
|
||||
sfr CCAP0L = 0xea;
|
||||
sfr CCAP1L = 0xeb;
|
||||
sfr CCAP2L = 0xec;
|
||||
sfr CCAP3L = 0xed;
|
||||
sfr CCAP0H = 0xfa;
|
||||
sfr CCAP1H = 0xfb;
|
||||
sfr CCAP2H = 0xfc;
|
||||
sfr CCAP3H = 0xfd;
|
||||
sfr PCA_PWM0 = 0xf2;
|
||||
sfr PCA_PWM1 = 0xf3;
|
||||
sfr PCA_PWM2 = 0xf4;
|
||||
sfr PCA_PWM3 = 0xf5;
|
||||
|
||||
//增强型PWM波形发生器特殊功能寄存器
|
||||
sfr PWMCFG = 0xf1;
|
||||
#define CBIF 0x80
|
||||
#define ETADC 0x40
|
||||
sfr PWMIF = 0xf6;
|
||||
#define C7IF 0x80
|
||||
#define C6IF 0x40
|
||||
#define C5IF 0x20
|
||||
#define C4IF 0x10
|
||||
#define C3IF 0x08
|
||||
#define C2IF 0x04
|
||||
#define C1IF 0x02
|
||||
#define C0IF 0x01
|
||||
sfr PWMFDCR = 0xf7;
|
||||
#define INVCMP 0x80
|
||||
#define INVIO 0x40
|
||||
#define ENFD 0x20
|
||||
#define FLTFLIO 0x10
|
||||
#define EFDI 0x08
|
||||
#define FDCMP 0x04
|
||||
#define FDIO 0x02
|
||||
#define FDIF 0x01
|
||||
sfr PWMCR = 0xfe;
|
||||
#define ENPWM 0x80
|
||||
#define ECBI 0x40
|
||||
|
||||
//如下特殊功能寄存器位于扩展RAM区域
|
||||
//访问这些寄存器,需先将P_SW2的BIT7设置为1,才可正常读写
|
||||
#define PWMC (*(unsigned int volatile xdata *)0xfff0)
|
||||
#define PWMCH (*(unsigned char volatile xdata *)0xfff0)
|
||||
#define PWMCL (*(unsigned char volatile xdata *)0xfff1)
|
||||
#define PWMCKS (*(unsigned char volatile xdata *)0xfff2)
|
||||
#define TADCP (*(unsigned char volatile xdata *)0xfff3)
|
||||
#define TADCPH (*(unsigned char volatile xdata *)0xfff3)
|
||||
#define TADCPL (*(unsigned char volatile xdata *)0xfff4)
|
||||
#define PWM0T1 (*(unsigned int volatile xdata *)0xff00)
|
||||
#define PWM0T1H (*(unsigned char volatile xdata *)0xff00)
|
||||
#define PWM0T1L (*(unsigned char volatile xdata *)0xff01)
|
||||
#define PWM0T2 (*(unsigned int volatile xdata *)0xff02)
|
||||
#define PWM0T2H (*(unsigned char volatile xdata *)0xff02)
|
||||
#define PWM0T2L (*(unsigned char volatile xdata *)0xff03)
|
||||
#define PWM0CR (*(unsigned char volatile xdata *)0xff04)
|
||||
#define PWM0HLD (*(unsigned char volatile xdata *)0xff05)
|
||||
#define PWM1T1 (*(unsigned int volatile xdata *)0xff10)
|
||||
#define PWM1T1H (*(unsigned char volatile xdata *)0xff10)
|
||||
#define PWM1T1L (*(unsigned char volatile xdata *)0xff11)
|
||||
#define PWM1T2 (*(unsigned int volatile xdata *)0xff12)
|
||||
#define PWM1T2H (*(unsigned char volatile xdata *)0xff12)
|
||||
#define PWM1T2L (*(unsigned char volatile xdata *)0xff13)
|
||||
#define PWM1CR (*(unsigned char volatile xdata *)0xff14)
|
||||
#define PWM1HLD (*(unsigned char volatile xdata *)0xff15)
|
||||
#define PWM2T1 (*(unsigned int volatile xdata *)0xff20)
|
||||
#define PWM2T1H (*(unsigned char volatile xdata *)0xff20)
|
||||
#define PWM2T1L (*(unsigned char volatile xdata *)0xff21)
|
||||
#define PWM2T2 (*(unsigned int volatile xdata *)0xff22)
|
||||
#define PWM2T2H (*(unsigned char volatile xdata *)0xff22)
|
||||
#define PWM2T2L (*(unsigned char volatile xdata *)0xff23)
|
||||
#define PWM2CR (*(unsigned char volatile xdata *)0xff24)
|
||||
#define PWM2HLD (*(unsigned char volatile xdata *)0xff25)
|
||||
#define PWM3T1 (*(unsigned int volatile xdata *)0xff30)
|
||||
#define PWM3T1H (*(unsigned char volatile xdata *)0xff30)
|
||||
#define PWM3T1L (*(unsigned char volatile xdata *)0xff31)
|
||||
#define PWM3T2 (*(unsigned int volatile xdata *)0xff32)
|
||||
#define PWM3T2H (*(unsigned char volatile xdata *)0xff32)
|
||||
#define PWM3T2L (*(unsigned char volatile xdata *)0xff33)
|
||||
#define PWM3CR (*(unsigned char volatile xdata *)0xff34)
|
||||
#define PWM3HLD (*(unsigned char volatile xdata *)0xff35)
|
||||
#define PWM4T1 (*(unsigned int volatile xdata *)0xff40)
|
||||
#define PWM4T1H (*(unsigned char volatile xdata *)0xff40)
|
||||
#define PWM4T1L (*(unsigned char volatile xdata *)0xff41)
|
||||
#define PWM4T2 (*(unsigned int volatile xdata *)0xff42)
|
||||
#define PWM4T2H (*(unsigned char volatile xdata *)0xff42)
|
||||
#define PWM4T2L (*(unsigned char volatile xdata *)0xff43)
|
||||
#define PWM4CR (*(unsigned char volatile xdata *)0xff44)
|
||||
#define PWM4HLD (*(unsigned char volatile xdata *)0xff45)
|
||||
#define PWM5T1 (*(unsigned int volatile xdata *)0xff50)
|
||||
#define PWM5T1H (*(unsigned char volatile xdata *)0xff50)
|
||||
#define PWM5T1L (*(unsigned char volatile xdata *)0xff51)
|
||||
#define PWM5T2 (*(unsigned int volatile xdata *)0xff52)
|
||||
#define PWM5T2H (*(unsigned char volatile xdata *)0xff52)
|
||||
#define PWM5T2L (*(unsigned char volatile xdata *)0xff53)
|
||||
#define PWM5CR (*(unsigned char volatile xdata *)0xff54)
|
||||
#define PWM5HLD (*(unsigned char volatile xdata *)0xff55)
|
||||
#define PWM6T1 (*(unsigned int volatile xdata *)0xff60)
|
||||
#define PWM6T1H (*(unsigned char volatile xdata *)0xff60)
|
||||
#define PWM6T1L (*(unsigned char volatile xdata *)0xff61)
|
||||
#define PWM6T2 (*(unsigned int volatile xdata *)0xff62)
|
||||
#define PWM6T2H (*(unsigned char volatile xdata *)0xff62)
|
||||
#define PWM6T2L (*(unsigned char volatile xdata *)0xff63)
|
||||
#define PWM6CR (*(unsigned char volatile xdata *)0xff64)
|
||||
#define PWM6HLD (*(unsigned char volatile xdata *)0xff65)
|
||||
#define PWM7T1 (*(unsigned int volatile xdata *)0xff70)
|
||||
#define PWM7T1H (*(unsigned char volatile xdata *)0xff70)
|
||||
#define PWM7T1L (*(unsigned char volatile xdata *)0xff71)
|
||||
#define PWM7T2 (*(unsigned int volatile xdata *)0xff72)
|
||||
#define PWM7T2H (*(unsigned char volatile xdata *)0xff72)
|
||||
#define PWM7T2L (*(unsigned char volatile xdata *)0xff73)
|
||||
#define PWM7CR (*(unsigned char volatile xdata *)0xff74)
|
||||
#define PWM7HLD (*(unsigned char volatile xdata *)0xff75)
|
||||
|
||||
//I2C特殊功能寄存器
|
||||
//如下特殊功能寄存器位于扩展RAM区域
|
||||
//访问这些寄存器,需先将P_SW2的BIT7设置为1,才可正常读写
|
||||
#define I2CCFG (*(unsigned char volatile xdata *)0xfe80)
|
||||
#define ENI2C 0x80
|
||||
#define MSSL 0x40
|
||||
#define I2CMSCR (*(unsigned char volatile xdata *)0xfe81)
|
||||
#define EMSI 0x80
|
||||
#define I2CMSST (*(unsigned char volatile xdata *)0xfe82)
|
||||
#define MSBUSY 0x80
|
||||
#define MSIF 0x40
|
||||
#define MSACKI 0x02
|
||||
#define MSACKO 0x01
|
||||
#define I2CSLCR (*(unsigned char volatile xdata *)0xfe83)
|
||||
#define ESTAI 0x40
|
||||
#define ERXI 0x20
|
||||
#define ETXI 0x10
|
||||
#define ESTOI 0x08
|
||||
#define SLRST 0x01
|
||||
#define I2CSLST (*(unsigned char volatile xdata *)0xfe84)
|
||||
#define SLBUSY 0x80
|
||||
#define STAIF 0x40
|
||||
#define RXIF 0x20
|
||||
#define TXIF 0x10
|
||||
#define STOIF 0x08
|
||||
#define TXING 0x04
|
||||
#define SLACKI 0x02
|
||||
#define SLACKO 0x01
|
||||
#define I2CSLADR (*(unsigned char volatile xdata *)0xfe85)
|
||||
#define I2CTXD (*(unsigned char volatile xdata *)0xfe86)
|
||||
#define I2CRXD (*(unsigned char volatile xdata *)0xfe87)
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,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);
|
||||
static void CRFS_Init(void);
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
/* ========================================================================
|
||||
* 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]);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
# 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);
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
# ifndef CONFIG
|
||||
# define CONFIG
|
||||
# include "CONFIG.h"
|
||||
# endif
|
||||
/**
|
||||
* NRF24L01+ 驱动头文件 (STC8H1K08 移植版, SDCC 兼容)
|
||||
* SPI 引脚: SCK=P1.5, CE=P1.6, IRQ=P1.7, CSN=P5.4, MISO=P1.3, MOSI=P1.4
|
||||
* 使用 STC8H 硬件 SPI (SPI 默认引脚)
|
||||
*/
|
||||
|
||||
/* SDCC mcs51 模式下缺少的标准类型 */
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned int uint16_t;
|
||||
typedef unsigned long uint32_t;
|
||||
|
||||
/* ========== 引脚定义 (SDCC 语法) ========== */
|
||||
__sbit __at(0x95) NRF_SCK; /* P1^5 */
|
||||
__sbit __at(0x96) NRF_CE; /* P1^6 */
|
||||
__sbit __at(0x97) NRF_IRQ; /* P1^7 */
|
||||
__sbit __at(0xCC) NRF_CSN; /* P5^4 */
|
||||
__sbit __at(0x93) NRF_MISO; /* P1^3 */
|
||||
__sbit __at(0x94) NRF_MOSI; /* P1^4 */
|
||||
|
||||
/* ========== 寄存器地址 ========== */
|
||||
#define NRF_CONFIG 0x00
|
||||
#define NRF_EN_AA 0x01
|
||||
#define NRF_EN_RXADDR 0x02
|
||||
#define NRF_SETUP_AW 0x03
|
||||
#define NRF_SETUP_RETR 0x04
|
||||
#define NRF_RF_CH 0x05
|
||||
#define NRF_RF_SETUP 0x06
|
||||
#define NRF_STATUS 0x07
|
||||
#define NRF_OBSERVE_TX 0x08
|
||||
#define NRF_RPD 0x09
|
||||
#define NRF_RX_ADDR_P0 0x0A
|
||||
#define NRF_RX_ADDR_P1 0x0B
|
||||
#define NRF_RX_ADDR_P2 0x0C
|
||||
#define NRF_RX_ADDR_P3 0x0D
|
||||
#define NRF_RX_ADDR_P4 0x0E
|
||||
#define NRF_RX_ADDR_P5 0x0F
|
||||
#define NRF_TX_ADDR 0x10
|
||||
#define NRF_RX_PW_P0 0x11
|
||||
#define NRF_RX_PW_P1 0x12
|
||||
#define NRF_RX_PW_P2 0x13
|
||||
#define NRF_RX_PW_P3 0x14
|
||||
#define NRF_RX_PW_P4 0x15
|
||||
#define NRF_RX_PW_P5 0x16
|
||||
#define NRF_FIFO_STATUS 0x17
|
||||
#define NRF_DYNPD 0x1C
|
||||
#define NRF_FEATURE 0x1D
|
||||
|
||||
/* ========== 命令 ========== */
|
||||
#define NRF_CMD_R_REGISTER 0x00
|
||||
#define NRF_CMD_W_REGISTER 0x20
|
||||
#define NRF_CMD_R_RX_PAYLOAD 0x61
|
||||
#define NRF_CMD_W_TX_PAYLOAD 0xA0
|
||||
#define NRF_CMD_FLUSH_TX 0xE1
|
||||
#define NRF_CMD_FLUSH_RX 0xE2
|
||||
#define NRF_CMD_REUSE_TX_PL 0xE3
|
||||
#define NRF_CMD_NOP 0xFF
|
||||
|
||||
/* ========== 状态标志 ========== */
|
||||
#define NRF_STATUS_RX_DR 0x40
|
||||
#define NRF_STATUS_TX_DS 0x20
|
||||
#define NRF_STATUS_MAX_RT 0x10
|
||||
|
||||
/* ========== 配置常量 ========== */
|
||||
#define NRF_RATE_250K 0x20
|
||||
#define NRF_RATE_1M 0x00
|
||||
#define NRF_RATE_2M 0x08
|
||||
|
||||
#define NRF_PA_MIN 0x00
|
||||
#define NRF_PA_LOW 0x02
|
||||
#define NRF_PA_HIGH 0x04
|
||||
#define NRF_PA_MAX 0x06
|
||||
|
||||
#define NRF_ADDR_WIDTH 5
|
||||
#define NRF_MAX_CHANNEL 125
|
||||
#define NRF_PAYLOAD_SIZE 32
|
||||
|
||||
/* ========== 函数声明 ========== */
|
||||
|
||||
/* 底层 SPI */
|
||||
uint8_t NRF_SPI_TransferByte(uint8_t dat);
|
||||
|
||||
/* 寄存器操作 */
|
||||
uint8_t NRF24L01_ReadReg(uint8_t reg);
|
||||
void NRF24L01_WriteReg(uint8_t reg, uint8_t value);
|
||||
void NRF24L01_ReadBuf(uint8_t reg, uint8_t *buf, uint8_t len);
|
||||
void NRF24L01_WriteBuf(uint8_t reg, const uint8_t *buf, uint8_t len);
|
||||
|
||||
/* 初始化与检测 */
|
||||
void NRF24L01_Init(void);
|
||||
uint8_t NRF24L01_Check(void);
|
||||
|
||||
/* 配置 */
|
||||
void NRF24L01_SetChannel(uint8_t ch);
|
||||
void NRF24L01_SetRXAddr(uint8_t pipe, const uint8_t *addr);
|
||||
|
||||
/* 模式切换 */
|
||||
void NRF24L01_RXMode(void);
|
||||
void NRF24L01_TXMode(void);
|
||||
|
||||
/* 数据收发 */
|
||||
uint8_t NRF24L01_RxPacket(uint8_t *data);
|
||||
uint8_t NRF24L01_IsDataReady(void);
|
||||
void NRF24L01_FlushRX(void);
|
||||
|
||||
#endif /* __NRF24_H__ */
|
||||
@@ -1,59 +0,0 @@
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/* ========================================================================
|
||||
* SBUS 输出 (100kbps 8E2, 与UART1共用TX)
|
||||
* ========================================================================
|
||||
*/
|
||||
|
||||
static void SBUS_Init(void);
|
||||
static void SBUS_SendFrame(void);
|
||||
static const uint8_t __code crsf_crc8_tab[256];
|
||||
@@ -1,83 +0,0 @@
|
||||
#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]);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# 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);
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
:03000000020006F5
|
||||
:03005F0002000399
|
||||
:0300030002006296
|
||||
:0700620075B20075B1002228
|
||||
:06003500E478FFF6D8FD9F
|
||||
:200013007900E94400601B7A0090006D780175A000E493F2A308B8000205A0D9F4DAF27526
|
||||
:02003300A0FF2C
|
||||
:20003B007800E84400600A790175A000E4F309D8FC7800E84400600C7900900001E4F0A3C3
|
||||
:04005B00D8FCD9FAFA
|
||||
:0D000600758107120069E5826003020003A6
|
||||
:04006900758200227A
|
||||
:00000001FF
|
||||
@@ -0,0 +1,255 @@
|
||||
#include "uart.h"
|
||||
|
||||
#define UART_Buf_Size 16
|
||||
|
||||
static char cmd[UART_Buf_Size];
|
||||
/* ========================================================================
|
||||
* UART1 - 串口通信 (使用Timer2做波特率发生器)
|
||||
* ========================================================================
|
||||
|
||||
# 串口驱动,需要包含以下内容
|
||||
* UART模式,波特率115200
|
||||
* 数据解析,命令表:
|
||||
模式切换 MODE(UART | SBUS | CRFS)
|
||||
模块地址 ADDR(0000000000)
|
||||
对频短语 PHRASE(xxxxxx)
|
||||
切换频道 TUN(040)
|
||||
清除信息 DEL(DATA)
|
||||
回传频率 TELEM(N) - 设置回传频率 1~10Hz
|
||||
* SBUS模式,波特率100000
|
||||
* CRFS模式,波特率420000,功能占位,暂不实现
|
||||
*/
|
||||
|
||||
static void UART_ParseCommand(void) {
|
||||
// 解析运行模式
|
||||
if (cmd[0] == 'M') {
|
||||
if (cmd_buf[5] == 'S'){
|
||||
Config.RunMode = UART_SBUS;
|
||||
SBUS_Init();
|
||||
UART_SendString(2, "OK");
|
||||
return;
|
||||
} else if (cmd_buf[5] == 'U') {
|
||||
Config.RunMode = UART_CMD;
|
||||
CMD_Init();
|
||||
UART_SendString(2, "OK");
|
||||
return;
|
||||
} else if (cmd_buf[5] == 'C') {
|
||||
CRFS_Init();
|
||||
Config.RunMode = UART_CRSF;
|
||||
UART_SendString(2, "OK");
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* ADDR(HHHHHHHHHH) - 切换NRF24L01地址 */
|
||||
else if (cmd[0] == 'A') {
|
||||
for (uint8_t i=0; i<5; i++) {
|
||||
uint8 h=0,l=0;
|
||||
/* 解析两位十六进制 */
|
||||
if (cmd_buf[6+i*2] >= '0' && cmd_buf[6+i*2] <= '9')
|
||||
h=cmd_buf[6+i*2]-'0';
|
||||
else if (cmd_buf[6+i*2] >= 'A' && cmd_buf[6+i*2] <= 'F')
|
||||
h=cmd_buf[6+i*2]-'A';
|
||||
else {
|
||||
UART_SendString(8, "ERR_ADDR");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_buf[7+i*2] >= '0' && cmd_buf[7+i*2] <= '9')
|
||||
h=cmd_buf[7+i*2]-'0';
|
||||
else if (cmd_buf[7+i*2] >= 'A' && cmd_buf[7+i*2] <= 'F')
|
||||
h=cmd_buf[7+i*2]-'A';
|
||||
else {
|
||||
UART_SendString(8, "ERR_ADDR");
|
||||
return;
|
||||
}
|
||||
|
||||
Config.RxAddr[i] = h | l;
|
||||
}
|
||||
// 应用
|
||||
WriteConfig();
|
||||
NRF24_SetAddr();
|
||||
return;
|
||||
}
|
||||
/* TUN(N) - 切换RF频道 */
|
||||
else if (cmd[0] == 'T' && cmd[1] == 'U') {
|
||||
uint8_t ch = 0;
|
||||
char *p = cmd + 4; /* 跳过 "TUN(" */
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
ch = ch * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
if (ch <= 125) {
|
||||
Config.RxAddr = ch
|
||||
NRF24L01_SetChannel();
|
||||
UART_SendString("OK");
|
||||
} else {
|
||||
UART_SendString("ERR_RANGE");
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* DEL(BIND) - 清除对频信息 */
|
||||
else if (cmd[0] == 'D') {
|
||||
/* 擦除EEPROM中的对频标志 */
|
||||
IAP_EraseALL();
|
||||
UART_SendString("OK");
|
||||
return;
|
||||
}
|
||||
/* PHRASE(xxxxxx) - 设置对频短语, 1~6位字母数字 */
|
||||
else if (cmd[0] == 'P') {
|
||||
uint8 i;
|
||||
char *p = cmd + 7; /* 跳过 "PHRASE(" */
|
||||
/* 计算短语长度 (直到 ')' 或结束) */
|
||||
uint8 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++)
|
||||
Config.BindPhr[i] = (uint8)p[i];
|
||||
/* 剩余部分用空格填充 */
|
||||
for (i = len; i < 6; i++)
|
||||
Config.BindPhr[i] = ' ';
|
||||
|
||||
IAP_WriteConfig();
|
||||
UART_SendString("OK");
|
||||
return;
|
||||
}
|
||||
/* TELEM(N) - 设置回传频率 1~9Hz */
|
||||
else if (cmd[0] == 'T' && cmd[1] == 'E') {
|
||||
uint8 hz = 0;
|
||||
char *p = cmd + 6; /* 跳过 "TELEM(" */
|
||||
if (*p > '0' && *p <= '9') {
|
||||
hz = *p - '0';
|
||||
} else {
|
||||
Cmd_Respond("ERR_RANGE");
|
||||
return;
|
||||
}
|
||||
Config.TelemRate = hz;
|
||||
return;
|
||||
}
|
||||
// 发送了识别不了的东西
|
||||
else {
|
||||
UART_SendString("UNK");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void UART_SendByte(uint8 dat) {
|
||||
SBUF = dat;
|
||||
while (!TI);
|
||||
TI = 0;
|
||||
}
|
||||
|
||||
static void UART_SendString(uint8 len, char *str) {
|
||||
for(uint8 i = 0, i++, i < len){
|
||||
UART_SendByte(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void SBUS_Init(void) {
|
||||
P_SW2 |= 0x80; /* 使能访问扩展SFR(若需访问T2相关XFR) */
|
||||
/* 1. 选择定时器2作为串口1的波特率发生器 */
|
||||
AUXR &= ~0x01; /* 先清除S1ST2,再置1 */
|
||||
AUXR |= 0x01; /* S1ST2 = 1 */
|
||||
/* 2. 定时器2配置为1T模式,启动 */
|
||||
AUXR |= (1 << 2); /* T2x12 = 1,不分频 */
|
||||
AUXR |= (1 << 4); /* T2R = 1,启动定时器2 */
|
||||
|
||||
/* 切换到 SBUS 波特率 100kbps */
|
||||
/* 3. 计算重载值:100kbps @ 40MHz,1T模式
|
||||
* Baud = SYSCLK / (4 * (65536 - reload))
|
||||
* reload = 65536 - SYSCLK / (4 * Baud)
|
||||
* = 65536 - 40000000 / (4 * 100000)
|
||||
* = 65536 - 100 = 65436 = 0xFF9C
|
||||
*/
|
||||
T2H = 0xFF;
|
||||
T2L = 0x9C;
|
||||
|
||||
/* 4. 串口模式:模式3(9位可变波特率),使能接收,REN=1 */
|
||||
SCON = 0xD0; /* SM0=1, SM1=1, SM2=0, REN=1, TB8=0 */
|
||||
|
||||
/* 5. 设置PCON:SMOD=0(无波特率加倍),SMOD0=1(启用帧错误检测,可选) */
|
||||
PCON &= ~0x80; /* SMOD = 0 */
|
||||
PCON |= 0x40; /* SMOD0 = 1 */
|
||||
|
||||
/* 6. 使能串口中断(根据需要) */
|
||||
ES = 1; /* 允许串口中断 */
|
||||
}
|
||||
|
||||
static void UART_Init(void) {
|
||||
P_SW2 |= 0x80; /* 使能访问扩展SFR(若需访问T2相关XFR) */
|
||||
|
||||
/* 1. 选择定时器2作为串口1的波特率发生器 */
|
||||
AUXR &= ~0x01; /* 先清除S1ST2,再置1 */
|
||||
AUXR |= 0x01; /* S1ST2 = 1 */
|
||||
|
||||
/* 2. 定时器2配置为1T模式,启动 */
|
||||
AUXR |= (1 << 2); /* T2x12 = 1,不分频 */
|
||||
AUXR |= (1 << 4); /* T2R = 1,启动定时器2 */
|
||||
|
||||
/* 3. 计算重载值:115200bps @ 40MHz,1T模式
|
||||
* Baud = SYSCLK / (4 * (65536 - reload))
|
||||
* reload = 65536 - SYSCLK / (4 * Baud)
|
||||
* = 65536 - 40000000 / (4 * 115200)
|
||||
* = 65536 - 86.805... ≈ 65536 - 87 = 65449 = 0xFFA9
|
||||
*/
|
||||
T2H = 0xFF;
|
||||
T2L = 0xA9;
|
||||
|
||||
/* 4. 串口模式:模式3(9位可变波特率),使能接收,REN=1 */
|
||||
SCON = 0xD0; /* SM0=1, SM1=1, SM2=0, REN=1, TB8=0 */
|
||||
|
||||
/* 5. 设置PCON:SMOD=0(无波特率加倍),SMOD0=1(启用帧错误检测) */
|
||||
PCON &= ~0x80; /* SMOD = 0 */
|
||||
PCON |= 0x40; /* SMOD0 = 1 */
|
||||
|
||||
/* 6. 使能串口中断(根据需要) */
|
||||
ES = 1; /* 允许串口中断 */ /* 允许串口中断 */
|
||||
}
|
||||
|
||||
void SBUS_Update(RFDATA dat){
|
||||
uint8 *p = &dat;
|
||||
for(i=0, i++, i<25){
|
||||
UART_SendByte(*p++);
|
||||
}
|
||||
}
|
||||
|
||||
/* UART1 中断服务 */
|
||||
void UART_Receive(void) __interrupt(4) {
|
||||
if (RI) {
|
||||
RI = 0;
|
||||
uint8 dat = SBUF;
|
||||
uint8 uart_rx_idx = 0;
|
||||
if (config.runModel == UART_CRFS) {
|
||||
/* CRFS 模式: 接收飞控发来的 CRSF 帧并缓存转发 */
|
||||
// 占位,暂不实现
|
||||
} else {
|
||||
/* 命令接收: 回车/换行结束 */
|
||||
if (dat == '\r' || dat == '\n') {
|
||||
if (uart_rx_idx > 0) {
|
||||
cmd_buf[uart_rx_idx] = '\0';
|
||||
UART_ParseCommand();
|
||||
}
|
||||
} else {
|
||||
if (uart_rx_idx < UART_Buff_Size - 1) {
|
||||
cmd_buff[uart_rx_idx++] = dat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TI) {
|
||||
TI = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
# ifndef CONFIG
|
||||
# define CONFIG
|
||||
# include "config.h"
|
||||
# endif
|
||||
|
||||
/* UART 接收缓冲 (放在 xdata) */
|
||||
static uint8 __xdata uart_rx_buf[UART_BUF_SIZE];
|
||||
|
||||
void UART_Init(void);
|
||||
void SBUS_Init(void);
|
||||
void CRFS_Init(void);
|
||||
|
||||
void UART_Receive(void) __interrupt(4);
|
||||
|
||||
void UART_SendByte(uint8 dat);
|
||||
void UART_SendString(uint8 size, char *str);
|
||||
void UART_ParseCommand(void);
|
||||
|
||||
/* 转换数据为sbus信号输出
|
||||
* sbus为25字节固定信号,数据结构如下:
|
||||
* Byte 1 | 帧头(固定为0x0F)
|
||||
* Byte 2-23 | 数据通道(16个11位数据)
|
||||
* Byte 24 | 标志位(包含帧丢失、故障保护等)
|
||||
* Byte 25 | 帧尾(固定为0x00)
|
||||
*/
|
||||
void SBUS_Update(RFDATA dat);
|
||||
Reference in New Issue
Block a user