在网上看到一款DP666彩屏收音机,内核用的ESP32驱动的TEF6686芯片,且TEF6686这款芯片在收音机圈子里都反应不错,FM灵敏度高,还有场强数据,RDS数据等各项功能,那咱们也用51做一个。


先去闲鱼买个TEF6686收音机高频头,回来画板做个转接板带功放,用STC8051单片机做主控。加按键和EC11旋转编码器,最终数据先串口打印出来,后续再加彩屏显示信息。


程序用了DeepSeek V4 AI模型给我整改,下来体验还不错,串口信息输出偶尔会停止,不过不影响,反正以后还要改成彩屏显示的。
以下是源码:

#include <STC8051U.h>
#include <intrins.h>

#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
#define s8 signed char 	
/*----------------------------- I2C pins -------------------------------*/
sbit I2C_SDA = P1^1;
sbit I2C_SCL = P1^0;

/*----------------------------- I2C addresses -------------------------*/
#define I2C_ADDR_WRITE    0xC8
#define I2C_ADDR_READ     0xC9

/*----------------------------- modules --------------------------------*/
#define MODULE_FM         0x20
#define MODULE_AM         0x21
#define MODULE_AUDIO      0x30
#define MODULE_APPL       0x40

/*----------------------------- commands -------------------------------*/
#define CMD_TUNE_TO            0x01
#define CMD_SET_TUNE_OPTIONS   0x02
#define CMD_SET_BANDWIDTH      0x0A
#define CMD_SET_RFAGC          0x0B
#define CMD_SET_RDS            0x51
#define CMD_SET_QUALITY_STATUS 0x52
#define CMD_GET_QUALITY_DATA   0x81
#define CMD_GET_RDS_STATUS     0x82
#define CMD_GET_RDS_DATA       0x83
#define CMD_GET_SIGNAL_STATUS  0x85

#define CMD_SET_VOLUME         0x0A
#define CMD_SET_MUTE           0x0B

#define CMD_SET_REFERENCE_CLOCK 0x04
#define CMD_ACTIVATE           0x05

/*----------------------------- bands / frequency ----------------------*/
#define BAND_FM               0
#define BAND_AM               1

#define FM_FREQ_MIN           8750      /* 87.50 MHz, 10 kHz units */
#define FM_FREQ_MAX           10800     /* 108.00 MHz */
#define FM_FREQ_STEP          10

#define AM_FREQ_MIN           522       /* 522 kHz, 1 kHz units */
#define AM_FREQ_MAX           1620      /* 1620 kHz */
#define AM_FREQ_STEP          9         /* CHN MW step */

/*----------------------------- tuning action modes --------------------*/
#define TUNE_MODE_PRESET      1
#define TUNE_MODE_SEARCH      2
#define TUNE_MODE_END         7

/*----------------------------- RDS ------------------------------------*/
#define RDS_PS_LEN            8
#define RDS_BCD(v)            (unsigned char)((((v) >> 4) * 10) + ((v) & 0x0F))
/*----------------------------- keys ----------------------------------*/
sbit KEY_UP    = P2^2;
sbit KEY_DOWN  = P3^2;
sbit KEY_VOLUP = P2^1;
sbit KEY_VOLDN = P2^0;
sbit KEY_BAND  = P5^6;
sbit KEY_MUTE  = P5^7;
bit 
	KeySta0 = 1,  //KEY0当前按键状态
	KeySta1 = 1,  //KEY1当前按键状态
	KeySta2 = 1,  //KEY2当前按键状态
	KeySta3 = 1,  //KEY3当前按键状态
	KeySta4 = 1,  //KEY4当前按键状态
	KeySta5 = 1;  //KEY5当前按键状态
bit 
	backup0 = 1,  //KEY0按键值备份,保存前一次的扫描值
	backup1 = 1,  //KEY1按键值备份,保存前一次的扫描值
	backup2 = 1,  //KEY2按键值备份,保存前一次的扫描值
	backup3 = 1,  //KEY3按键值备份,保存前一次的扫描值
	backup4 = 1,  //KEY4按键值备份,保存前一次的扫描值
	backup5 = 1;  //KEY5按键值备份,保存前一次的扫描值

sbit EC11_A = P2^5;
sbit EC11_G = P2^6;
sbit EC11_B = P2^7;
u8 g_value = 0;       /* 被调节的数值 */
u8 last_state = 0;    /* 记录上一次的A、B相状态 */
void EC11_Scan(void);
s8 code EC11_Table[16] = {//EC11 状态转移表
     0, -1,  1,  0,  /* 上次状态 00 */
     1,  0,  0, -1,  /* 上次状态 01 */
    -1,  0,  0,  1,  /* 上次状态 10 */
     0,  1, -1,  0   /* 上次状态 11 */
};

unsigned int SysTick=0;
uchar TEF6686_DAT[16];


typedef struct {
    unsigned int  pi;                 /* PI 码(来自 RDS 块 A) */
    unsigned char ps[RDS_PS_LEN + 1]; /* 台名 PS,0 结尾 */
    unsigned char rt[65];             /* 广播文本 RT,0 结尾 */
    unsigned char ps_ready;           /* 1 = 已收满 8 字符 */
    unsigned char rt_ready;           /* 1 = 已收满 64 字符 */
    unsigned char pty;                /* 节目类型 0..31 */
    unsigned char ta;                 /* 交通公告标志 */
    unsigned char tp;                 /* 交通节目标志 */
    unsigned char ms;                 /* 音乐/语音(M=音乐 S=语音) */
    unsigned char sync;               /* RDS 同步锁定 */
    unsigned char ecc;                /* 扩展国家码(组 3A variant 0) */
    unsigned char lic;                /* 语言码低 2 位 */
    unsigned char eon_pi_valid;       /* EON 服务 PI 有效 */
    unsigned int  eon_pi;             /* EON 服务 PI */
    unsigned char af[16];             /* AF 频率码表(码 1..204) */
    unsigned char af_count;           /* AF 码数量 */
    unsigned char rt_plus_valid;      /* RT+ 信息有效 */
    unsigned char rt_plus_type;       /* RT+ 内容类型 0..63 */
    unsigned char rt_plus_start;      /* RT+ 起始位置(字符) */
    unsigned char rt_plus_len;        /* RT+ 长度(字符) */
    unsigned char rt_plus_running;    /* RT+ 运行标志 */
    unsigned char ct_valid;           /* 时钟时间有效 */
    unsigned char ct_hour;            /* 小时(BCD 已转十进制) */
    unsigned char ct_min;             /* 分钟 */
    unsigned char ct_day;             /* 日 */
    unsigned char ct_month;           /* 月 */
    unsigned char ct_year;            /* 年(低 2 位,非完整年份) */
    unsigned int  errA, errB, errC, errD;  /* A..D 块错误计数 */
    unsigned int  groups;             /* 收到的组数 */
} TEF6686_RDS;

/*------------------ 质量数据(0x81 返回 14 字节)---------------------*/
typedef struct {
    unsigned int  status;      /* 质量时间戳 0.1ms,>0 表示调谐完成 */
    int           level;       /* 场强 0.1 dBuV */
    unsigned int  usn;         /* 超声噪声 0.1 %(仅 FM) */
    unsigned int  wam;         /* 多径干扰 0.1 %(仅 FM) */
    int           offset;      /* 中频偏移 0.1 kHz(有符号) */
    unsigned int  bandwidth;   /* 中频带宽 0.1 kHz */
    unsigned int  modulation;  /* 调制度 0.1 % */
} TEF6686_Quality;

/*----------------------------- prototypes -----------------------------*/
unsigned char TEF6686_Init(void);
unsigned char TEF6686_SetBand(unsigned char band);
unsigned char TEF6686_Tune(unsigned char band, unsigned int freq);
unsigned char TEF6686_SetVolume(int vol);          /* dB, -60 .. +24 */
unsigned char TEF6686_Mute(unsigned char on);
unsigned char TEF6686_GetQualityData(unsigned char band, TEF6686_Quality *q);
unsigned char TEF6686_Seek(unsigned char band, unsigned char up);
unsigned char TEF6686_PollRDS(unsigned char band);
//TEF6686_RDS *TEF6686_GetRDS(void);
void I2C_Delay(void);
void TEF6686_DelayMs(unsigned int ms);	
unsigned char code TEF6686_PatchByteValues[] = {
  0xf0,0x00,0x38,0x2f,0xd0,0x80,0xf0,0x00,0x38,0x37,0xd0,0x80,0x43,0xb2,0x38,0x3a,
  0xd0,0x80,0xf0,0x00,0x70,0x00,0xc2,0xf7,0xf0,0x00,0x38,0x6b,0xd0,0x80,0x80,0xfc,
  0x39,0x0e,0xd0,0x80,0xf0,0x00,0x39,0x13,0xd0,0x80,0xf0,0x00,0x39,0x16,0xd0,0x80,
  0xf0,0x00,0x39,0xbc,0xd0,0x80,0xf0,0x00,0x39,0x32,0xd0,0x80,0xf0,0x00,0x39,0xbe,
  0xd0,0x80,0xc4,0xa2,0x02,0x11,0x60,0x04,0xf0,0x00,0x39,0x9a,0xd0,0x80,0x90,0x01,
  0x39,0x34,0xd0,0x80,0xf0,0x00,0x38,0xf0,0xd0,0x80,0xf0,0x00,0x39,0x3b,0xd2,0x80,
  0xf0,0x00,0x39,0x3f,0xd0,0x80,0xf0,0x00,0x39,0x49,0xd0,0x80,0xf0,0x00,0x39,0x4c,
  0xd0,0x80,0x9e,0x30,0x18,0xf9,0xd2,0x80,0xf0,0x00,0x39,0x51,0xd0,0x80,0xf0,0x00,
  0x39,0x54,0xd0,0x80,0xf0,0x00,0x39,0x57,0xd0,0x80,0x32,0x00,0x39,0x59,0xd0,0x80,
  0xf0,0x00,0x39,0x5b,0xd0,0x80,0xa8,0x01,0x39,0xaa,0xd0,0x80,0xf0,0x00,0x39,0xc3,
  0xd0,0x80,0xf0,0x00,0x39,0xc5,0xd0,0x80,0xf0,0x00,0x39,0xc7,0xd0,0x80,0xf0,0x00,
  0x39,0xda,0xd0,0x80,0xf0,0x00,0x39,0xdd,0xd0,0x80,0xf0,0x00,0x39,0xe0,0xd0,0x80,
  0xf0,0x00,0x39,0xe3,0xd0,0x80,0xf0,0x00,0x70,0x00,0xf0,0x00,0xf0,0x00,0x39,0xe8,
  0xd0,0x80,0xf0,0x00,0x39,0xb5,0xd2,0x80,0xf0,0x00,0x39,0xf6,0xd0,0x80,0x00,0x43,
  0x3a,0x05,0xd9,0x80,0xf0,0x00,0x3a,0x0f,0xd0,0x80,0xf0,0x00,0x3a,0x45,0xd0,0x80,
  0xf0,0x00,0x3a,0x48,0xd0,0x80,0xf0,0x00,0x3a,0x59,0xd0,0x80,0x2e,0x40,0x3a,0xf8,
  0xd0,0x80,0xf0,0x00,0x3b,0x02,0xd0,0x80,0xf0,0x00,0x0e,0x3f,0x60,0x00,0x50,0x10,
  0x28,0xd8,0xd2,0x80,0x91,0x01,0x01,0x36,0x60,0x00,0xf0,0x00,0x70,0x00,0xa0,0x18,
  0xf0,0x00,0x70,0x00,0xa0,0xd8,0xf0,0x00,0x70,0x00,0xa0,0xe8,0xf0,0x00,0x70,0x00,
  0xa1,0x6f,0xf0,0x00,0x70,0x00,0xa1,0x99,0xf0,0x00,0x70,0x00,0xa1,0xc4,0xf0,0x00,
  0x70,0x00,0xa1,0xdc,0xf0,0x00,0x20,0x31,0xd0,0x80,0xf0,0x00,0x04,0xc1,0x60,0x08,
  0xf0,0x00,0x01,0x01,0xd2,0x80,0xf0,0x00,0x00,0x30,0xd0,0x80,0x00,0x7f,0x60,0x02,
  0xe2,0x00,0xf0,0x00,0x0e,0x22,0x60,0x0a,0xf0,0x00,0x00,0xff,0x60,0x03,0xf0,0x00,
  0x01,0x42,0xd2,0x80,0x90,0x03,0x40,0x02,0xf0,0x00,0x90,0x43,0x01,0x70,0xd1,0x80,
  0xf0,0x00,0x01,0x69,0xd0,0x80,0x0e,0x69,0x60,0x0a,0xa2,0xc3,0x20,0x23,0x00,0x01,
  0x60,0x01,0xf0,0x00,0x70,0x00,0xf0,0x00,0xc4,0xcb,0x70,0x00,0xf0,0x00,0xca,0x09,
  0x30,0x23,0xf0,0x00,0xc2,0xcb,0x70,0x00,0xf0,0x00,0xf0,0x00,0x30,0x23,0xd0,0x08,
  0x82,0x00,0x0d,0x50,0x60,0x08,0xf0,0x00,0x0d,0x51,0x60,0x09,0x30,0x00,0x21,0x80,
  0x60,0x01,0xf0,0x00,0x40,0x32,0xf0,0x00,0x30,0x11,0x45,0xf3,0xf0,0x00,0x30,0x92,
  0x2d,0x30,0x60,0x04,0x31,0x13,0x2d,0x40,0x60,0x05,0x31,0x94,0x7f,0xff,0x60,0x06,
  0x32,0x15,0x0d,0x61,0x60,0x0a,0x32,0x96,0x0d,0x6b,0x60,0x0b,0x33,0x10,0x0d,0x50,
  0x60,0x01,0x33,0x90,0x0d,0x5c,0x60,0x02,0x30,0x21,0x0d,0x63,0x60,0x03,0x30,0x31,
  0x0d,0x75,0x60,0x0c,0x30,0xa2,0x8d,0x00,0x60,0x01,0x30,0xb3,0x01,0x73,0x60,0x02,
  0x30,0x41,0x00,0x25,0x60,0x03,0x30,0xc2,0x40,0x44,0xf0,0x00,0x31,0x43,0x40,0x35,
  0xf0,0x00,0x31,0xc4,0x64,0x00,0x60,0x06,0x32,0x45,0x1f,0x40,0x60,0x07,0x32,0xc6,
  0x70,0x00,0xf0,0x00,0x33,0x47,0x1e,0xbc,0x60,0x0d,0x33,0xc0,0x01,0x22,0x60,0x01,
  0x34,0x40,0xfd,0xee,0x60,0x02,0x30,0x51,0x7b,0x8f,0x60,0x03,0x30,0xd2,0xc4,0x29,
  0x60,0x04,0x31,0x51,0x1e,0xc2,0x60,0x0e,0x32,0x53,0xff,0x0d,0x60,0x02,0x32,0xd4,
  0x7d,0x2e,0x60,0x03,0x30,0x61,0xc1,0x9a,0x60,0x04,0x30,0xe2,0x70,0x00,0xf0,0x00,
  0x31,0x61,0x70,0x00,0xf0,0x00,0x32,0x63,0x70,0x00,0xf0,0x00,0x32,0xe4,0x70,0x00,
  0xd0,0x08,0xf0,0x00,0x03,0x70,0xd2,0x80,0xf0,0x00,0x70,0x00,0xa0,0x02,0xf0,0x00,
  0x70,0x00,0xa0,0x59,0xf0,0x00,0x02,0x15,0xd0,0x80,0xf0,0x00,0x0d,0x51,0x60,0x0f,
  0xf0,0x00,0x05,0x17,0x60,0x0e,0x23,0xf6,0x70,0x00,0xf0,0x00,0xf0,0x00,0x21,0x63,
  0x41,0xf5,0x91,0x8f,0x21,0xf8,0x40,0x74,0xc3,0xef,0x21,0xe0,0xf0,0x00,0xc3,0xa4,
  0x33,0xf7,0xf0,0x00,0xd8,0x5b,0x70,0x00,0xf0,0x00,0x82,0x18,0x70,0x00,0xf0,0x00,
  0x9f,0xaf,0x18,0x00,0xf0,0x00,0x9f,0x0f,0x31,0xf8,0x90,0x02,0xf0,0x00,0x70,0x00,
  0x90,0x28,0xf0,0x00,0x70,0x00,0xd0,0x08,0xf0,0x00,0x22,0x78,0xf0,0x00,0x16,0xd3,
  0x60,0x09,0xa0,0x7f,0x35,0xf0,0x1e,0xbc,0x60,0x0d,0xf0,0x00,0x0d,0x61,0x60,0x08,
  0xf0,0x00,0x03,0xa5,0xd2,0x80,0xf0,0x00,0x1e,0xc2,0x60,0x0d,0xf0,0x00,0x0d,0x6b,
  0x60,0x08,0xf0,0x00,0x03,0xa5,0xd2,0x80,0xf0,0x00,0x21,0x00,0xf0,0x00,0x83,0x6d,
  0x22,0xf1,0xf0,0x00,0xf0,0x00,0x23,0x77,0xf0,0x00,0x90,0x41,0x36,0x70,0xf0,0x00,
  0x9e,0x79,0x70,0x00,0x90,0x01,0xf0,0x00,0x32,0xf1,0xd0,0x08,0x91,0xc7,0x33,0x75,
  0xf0,0x00,0xf0,0x00,0x34,0x70,0xe6,0x00,0xf0,0x00,0x34,0xf0,0xe6,0x00,0xf0,0x00,
  0x24,0x74,0xf0,0x00,0xf0,0x00,0x24,0xf3,0xf0,0x00,0x8c,0x24,0x26,0xf2,0x40,0x16,
  0x8a,0x1b,0x34,0x74,0x4f,0xf5,0x82,0xb7,0x34,0xf3,0xf0,0x00,0xf0,0x00,0x20,0x71,
  0x90,0x05,0x83,0x04,0x70,0x00,0xf0,0x00,0x8e,0x67,0x70,0x00,0xf0,0x00,0xf0,0x00,
  0x70,0x00,0x90,0x02,0xf0,0x00,0x36,0xf6,0xf0,0x00,0xf0,0x00,0x34,0xf0,0x80,0x06,
  0x82,0xaf,0x70,0x00,0xf0,0x00,0x82,0x1b,0x70,0x00,0xd0,0x09,0x8e,0x5f,0x70,0x00,
  0xf0,0x00,0xf0,0x00,0x70,0x00,0xd0,0x09,0xf0,0x00,0x36,0xf5,0xf0,0x00,0xf0,0x00,
  0x34,0x70,0xf0,0x00,0x40,0x11,0x27,0x72,0xa2,0x66,0x90,0x8a,0x20,0xf3,0xa2,0x65,
  0x8e,0xd7,0x37,0x72,0xf0,0x00,0xf0,0x00,0x37,0xf1,0xe6,0x00,0xf0,0x00,0x70,0x00,
  0xd0,0x08,0xf0,0x00,0x22,0x7a,0xf0,0x00,0x16,0xc3,0x60,0x09,0xa0,0x58,0xf0,0x00,
  0x18,0x20,0xf0,0x00,0xf0,0x00,0x35,0x70,0xf0,0x00,0xf0,0x00,0x32,0x7a,0xd0,0x08,
  0x82,0x00,0x0d,0x51,0x60,0x08,0x40,0x03,0x70,0x00,0xf0,0x00,0x33,0x80,0x70,0x00,
  0xf0,0x00,0x21,0x06,0x70,0x00,0xf0,0x00,0x37,0x00,0x70,0x00,0xf0,0x00,0x37,0x80,
  0x40,0x15,0xf0,0x00,0x36,0x83,0x70,0x00,0xf0,0x00,0x33,0x05,0x0d,0x61,0x60,0x09,
  0x32,0x86,0x0d,0x6b,0x60,0x0a,0x32,0x10,0x70,0x00,0xf0,0x00,0x32,0x90,0x70,0x00,
  0xf0,0x00,0x33,0x10,0x70,0x00,0xf0,0x00,0x33,0x90,0x70,0x00,0xf0,0x00,0x34,0x10,
  0x70,0x00,0xf0,0x00,0x34,0x90,0x70,0x00,0xf0,0x00,0x31,0x10,0x70,0x00,0xf0,0x00,
  0x31,0x90,0x70,0x00,0xf0,0x00,0x32,0x20,0x70,0x00,0xf0,0x00,0x32,0xa0,0x70,0x00,
  0xf0,0x00,0x33,0x20,0x70,0x00,0xf0,0x00,0x33,0xa0,0x70,0x00,0xf0,0x00,0x34,0x20,
  0x70,0x00,0xf0,0x00,0x34,0xa0,0x70,0x00,0xf0,0x00,0x31,0x20,0x70,0x00,0xf0,0x00,
  0x31,0xa0,0x70,0x00,0xf0,0x00,0x82,0x00,0x0d,0x30,0x60,0x0a,0x0d,0x40,0x60,0x0b,
  0xc0,0x10,0xf0,0x00,0x10,0x20,0xf0,0x00,0x0d,0x51,0x60,0x0c,0xc0,0x10,0xf0,0x00,
  0x10,0x30,0xf0,0x00,0xf0,0x00,0x35,0xc0,0xd0,0x08,0xf0,0x00,0x0d,0x75,0x60,0x0f,
  0xf0,0x00,0x05,0x63,0x60,0x0e,0x24,0xf7,0x05,0x1d,0x60,0x0d,0x25,0x76,0x70,0x00,
  0xf0,0x00,0x91,0xc7,0x20,0xe8,0x40,0x15,0x91,0x8f,0x21,0xe9,0xd4,0x09,0xc3,0xef,
  0x20,0x00,0x40,0x12,0x9f,0xbe,0x20,0x11,0x58,0x03,0xa0,0x80,0x35,0x77,0x90,0x01,
  0xf0,0x00,0x70,0x00,0xd0,0x08,0xf0,0x00,0x21,0xf5,0xf0,0x00,0xa0,0xca,0x22,0x54,
  0xf0,0x00,0xcc,0x09,0x05,0x17,0x60,0x0c,0x83,0x2c,0x70,0x00,0xf0,0x00,0x8a,0x61,
  0x70,0x00,0xf0,0x00,0xae,0x48,0x22,0x45,0xa2,0x2e,0xa2,0x28,0x20,0x78,0xf0,0x00,
  0xf0,0x00,0x35,0xf0,0xf0,0x00,0xf0,0x00,0x18,0x00,0xf0,0x00,0xf0,0x00,0x30,0x78,
  0xf0,0x00,0x16,0xe3,0x60,0x09,0xa0,0x27,0x89,0x01,0x23,0xf4,0xf0,0x00,0xf0,0x00,
  0x20,0xf2,0xf0,0x00,0x82,0x61,0x21,0x73,0xf0,0x00,0xa0,0x50,0x36,0x70,0xf0,0x00,
  0xa0,0x58,0x23,0x72,0xe1,0x40,0xa8,0x01,0x22,0xf3,0xf0,0x00,0x90,0x49,0x22,0x75,
  0xe0,0x40,0x80,0x61,0x70,0x00,0xf0,0x00,0x8a,0x51,0x33,0xf1,0xf0,0x00,0xa0,0x58,
  0x70,0x00,0xf0,0x00,0xaf,0x48,0x70,0x00,0xf0,0x00,0xf0,0x00,0x34,0x70,0xd0,0x08,
  0x82,0x00,0x0d,0x75,0x60,0x08,0x90,0x09,0x0d,0x00,0x60,0x09,0xf0,0x00,0x35,0x00,
  0xf0,0x00,0xf0,0x00,0x33,0x80,0xc0,0x28,0xf0,0x00,0x10,0x10,0xf0,0x00,0xf0,0x00,
  0x34,0x81,0xd0,0x08,0x82,0x49,0x0d,0x75,0x60,0x08,0xf0,0x00,0x70,0x00,0x8f,0xfd,
  0x04,0x00,0x60,0x00,0xa2,0x14,0x8e,0xc0,0x40,0x00,0x60,0x05,0x60,0x00,0x60,0x05,
  0xe6,0x00,0xc8,0x1b,0x70,0x00,0xf0,0x00,0xd8,0xdb,0x0d,0x51,0x60,0x08,0x83,0x5b,
  0x70,0x00,0xf0,0x00,0x9e,0xba,0x30,0x03,0xf0,0x00,0xf0,0x00,0x30,0x84,0xd4,0x09,
  0xf0,0x00,0x70,0x00,0x8f,0xaf,0xf0,0x00,0x0d,0x75,0x60,0x08,0xf0,0x00,0x0d,0x51,
  0x60,0x09,0xf0,0x00,0x24,0x03,0xf0,0x00,0xf0,0x00,0x27,0x94,0xd0,0x08,0xa0,0x03,
  0x70,0x00,0xf0,0x00,0x00,0x11,0x08,0x00,0xf0,0x00,0x00,0x11,0x08,0x00,0xc0,0x0e,
  0xa0,0x09,0x00,0x11,0x08,0x00,0xa0,0x09,0x70,0x00,0xf0,0x00,0xa4,0x08,0x70,0x00,
  0xd0,0x08,0xa0,0x03,0x70,0x00,0xf0,0x00,0x00,0x11,0x08,0x00,0xf0,0x00,0x00,0x11,
  0x08,0x00,0xc0,0x26,0xa0,0x09,0x00,0x11,0x08,0x00,0xa0,0x09,0x70,0x00,0xf0,0x00,
  0xa4,0x08,0x70,0x00,0xd0,0x08,0xf0,0x00,0x1d,0x01,0x60,0x08,0xf0,0x00,0x0a,0x2c,
  0x60,0x00,0xf0,0x00,0x01,0x1a,0x60,0x01,0x31,0x00,0x70,0x00,0xf0,0x00,0x31,0x81,
  0x70,0x00,0xd0,0x08,0xa8,0x01,0x7f,0xff,0x60,0x06,0xcc,0x0a,0x70,0x00,0xf0,0x00,
  0x8e,0xa1,0x31,0x06,0xf0,0x00,0xf0,0x00,0x32,0x06,0xd4,0x09,0xae,0xe8,0x04,0xdf,
  0xd0,0x80,0x10,0x00,0x60,0x03,0xa1,0xf1,0x30,0x23,0x07,0x73,0xd2,0x80,0xf0,0x00,
  0x07,0xc6,0xd0,0x80,0x08,0x00,0x60,0x03,0xa0,0x02,0x0e,0x6f,0x60,0x09,0xf0,0x00,
  0x02,0x00,0x60,0x03,0x80,0x00,0xf0,0x00,0x07,0x73,0xd0,0x80,0x40,0xe0,0x00,0x1f,
  0x60,0x01,0x13,0xd5,0x60,0x07,0xa0,0x0b,0x90,0x40,0x70,0x00,0xf0,0x00,0x13,0xfb,
  0x60,0x06,0xa0,0x08,0x14,0x05,0x60,0x06,0xa0,0x07,0x14,0x0f,0x60,0x06,0xa0,0x06,
  0x45,0x60,0x00,0x3a,0x60,0x01,0x13,0xb6,0x60,0x07,0xa0,0x05,0x90,0x40,0x70,0x00,
  0xf0,0x00,0x13,0xf7,0x60,0x06,0xa0,0x02,0x14,0x01,0x60,0x06,0xa0,0x01,0x14,0x0b,
  0x60,0x06,0x80,0x00,0xf0,0x00,0x0d,0x28,0xd0,0x80,0xd7,0xca,0x00,0xff,0x60,0x04,
  0x81,0xd7,0x0c,0xf7,0x60,0x09,0xd0,0x56,0x70,0x00,0xf0,0x00,0x82,0x76,0x30,0x17,
  0xf0,0x00,0xd0,0xf6,0x40,0x83,0xf0,0x00,0xc1,0xa4,0x20,0x19,0xf0,0x00,0x82,0xf6,
  0x70,0x00,0xf0,0x00,0xc1,0x80,0x20,0x17,0xa1,0xd6,0xc3,0xe7,0x70,0x00,0xf0,0x00,
  0xc5,0xc7,0x70,0x00,0xf0,0x00,0xf0,0x00,0x30,0x17,0xd0,0x08,0xf0,0x00,0x70,0x00,
  0xa0,0xbf,0xf0,0x00,0x70,0x00,0x80,0x84,0x1e,0xc8,0x60,0x08,0xa1,0xd0,0xf0,0x00,
  0x20,0x00,0xa1,0xcf,0x90,0x00,0x70,0x00,0xf0,0x00,0xf0,0x00,0x70,0x00,0xd4,0x09,
  0xf0,0x00,0x70,0x00,0x8f,0xc0,0x1e,0xc8,0x60,0x08,0xa1,0xcb,0xf0,0x00,0x30,0x00,
  0xd0,0x08,0x00,0x28,0x60,0x00,0xa1,0xc9,0x9e,0x38,0x0e,0xf4,0x60,0x09,0x9e,0x38,
  0x70,0x00,0x9f,0xff,0xf0,0x00,0x70,0x00,0xd0,0x08,0x40,0x40,0x0c,0x8a,0xd5,0x80,
  0xf0,0x00,0x0c,0x8b,0xd2,0x80,0xf0,0x00,0x0f,0xb1,0xd2,0x80,0x9c,0x39,0x70,0x00,
  0xf0,0x00,0x9c,0x31,0x70,0x00,0x90,0x03,0xf0,0x00,0x70,0x00,0x90,0x02,0x40,0x10,
  0x70,0x00,0xaf,0xf3,0x41,0xf1,0x40,0x40,0x80,0x08,0x40,0x00,0x70,0x00,0xaf,0xf1,
  0x41,0xf1,0x40,0x40,0x80,0x07,0x40,0x71,0x40,0x20,0xa0,0x06,0x43,0xa1,0x40,0x30,
  0xa0,0x05,0xf0,0x00,0x10,0x75,0xd0,0x80,0x40,0x71,0x40,0x20,0xa0,0x03,0x43,0xa1,
  0x40,0x30,0xa0,0x01,0xf0,0x00,0x10,0x81,0xd0,0x80,0xf0,0x00,0x0c,0x92,0xd0,0x80,
  0xf0,0x00,0x0c,0x94,0xd0,0x80,0xf0,0x00,0x0b,0xc9,0x60,0x08,0xf0,0x00,0x1d,0x8d,
  0xd2,0x80,0xf0,0x00,0x16,0xd5,0xd0,0x80,0xf0,0x00,0x0b,0xc9,0x60,0x08,0xf0,0x00,
  0x1d,0x8f,0xd2,0x80,0xf0,0x00,0x16,0xda,0xd0,0x80,0x3e,0x91,0x1f,0x5f,0xd2,0x80,
  0xf0,0x00,0x23,0x8a,0xd0,0x80,0x0d,0x82,0x60,0x08,0xa1,0xab,0xf0,0x00,0x30,0x00,
  0xd0,0x08,0xf0,0x00,0x0f,0x88,0x60,0x0b,0xf0,0x00,0x02,0x30,0x60,0x03,0xf0,0x00,
  0x09,0x38,0x60,0x04,0x9f,0x98,0x01,0x2c,0x60,0x05,0xf0,0x00,0x2e,0xb3,0xee,0x00,
  0xf0,0x00,0x0f,0xb1,0xd2,0x80,0x9e,0x09,0x0d,0x84,0x60,0x0c,0x9f,0x90,0x70,0x00,
  0x90,0x02,0x9f,0x88,0x2f,0x34,0xee,0x00,0xf0,0x00,0x2f,0xb5,0xee,0x00,0x30,0x43,
  0x0b,0x42,0x60,0x08,0xf0,0x00,0x30,0xc4,0xf0,0x00,0xf0,0x00,0x31,0x45,0xf0,0x00,
  0xf0,0x00,0x2c,0xb1,0x40,0x17,0xf0,0x00,0x2d,0x32,0xf0,0x00,0xc6,0x79,0x22,0x05,
  0xf0,0x00,0xf0,0x00,0x3d,0x81,0xf0,0x00,0xf0,0x00,0x3d,0x01,0xf0,0x00,0xdd,0x6d,
  0x1b,0x93,0xd2,0x80,0x90,0x46,0x0d,0x82,0x60,0x0a,0x20,0x42,0x1b,0x93,0xd2,0x80,
  0xda,0xc9,0x20,0x25,0xa1,0x94,0x8c,0x69,0x2d,0xb3,0xf0,0x00,0xdd,0x49,0x32,0x01,
  0xf0,0x00,0x8d,0x89,0x70,0x00,0xf0,0x00,0x3c,0x81,0xfe,0x35,0x60,0x00,0x35,0x81,
  0x00,0x16,0x60,0x01,0xa0,0x18,0x21,0x46,0xf0,0x00,0xaa,0x07,0x01,0x2d,0x60,0x00,
  0x81,0xcf,0x70,0x00,0xf0,0x00,0x8f,0x80,0x70,0x00,0xf0,0x00,0xf0,0x00,0x70,0x00,
  0x94,0x02,0x40,0x45,0x57,0x4b,0x60,0x00,0xe0,0x00,0x60,0x01,0x80,0x02,0x40,0x65,
  0x40,0x00,0x60,0x00,0xc6,0x66,0x60,0x01,0x80,0x00,0xa0,0x30,0x40,0x00,0x60,0x04,
  0xaf,0x4e,0x00,0xa4,0x60,0x05,0x81,0x8e,0x0b,0x75,0x60,0x08,0xf0,0x00,0x14,0x74,
  0xd2,0x80,0xf0,0x00,0x1b,0x90,0xd2,0x80,0x2e,0x34,0x04,0x00,0x60,0x06,0x20,0xc2,
  0x1b,0x93,0xd2,0x80,0xd2,0xc9,0x03,0xe9,0x60,0x05,0x81,0x8e,0x0b,0x59,0x60,0x08,
  0x8f,0x2d,0x31,0xc6,0xf0,0x00,0xf0,0x00,0x70,0x00,0x94,0x02,0x40,0x45,0xb1,0x5c,
  0x60,0x03,0x46,0x66,0x60,0x07,0x80,0x02,0x40,0x65,0xaa,0xce,0x60,0x03,0xc6,0x66,
  0x60,0x07,0x80,0x00,0xa0,0xe0,0x00,0x38,0x60,0x04,0xaf,0x48,0x00,0x1d,0x60,0x05,
  0x81,0xc7,0x31,0x84,0xf0,0x00,0x31,0x05,0x14,0x74,0xd2,0x80,0xf0,0x00,0x1b,0x90,
  0xd2,0x80,0xf0,0x00,0xd8,0x00,0x60,0x00,0xf0,0x00,0x0b,0x67,0x60,0x08,0x21,0xc6,
  0x20,0x00,0x60,0x04,0xf0,0x00,0x13,0x33,0x60,0x05,0x81,0x86,0x31,0x84,0x40,0x07,
  0x31,0x05,0x14,0x74,0xd2,0x80,0xf0,0x00,0x1b,0x90,0xd0,0x80,0xf0,0x00,0x6e,0x6c,
  0x60,0x03,0x40,0x07,0x00,0xe5,0x60,0x05,0xa0,0x58,0xff,0xff,0x60,0x03,0xaa,0x24,
  0x0b,0x52,0x60,0x08,0x81,0x1c,0x70,0x00,0xf0,0x00,0x31,0x05,0x7f,0xdf,0x60,0x06,
  0x31,0x84,0x14,0x74,0xd2,0x80,0xf0,0x00,0x1b,0x90,0xd0,0x80,0xf0,0x00,0x0b,0x60,
  0x60,0x0e,0xf0,0x00,0x00,0x04,0x60,0x03,0x40,0xa7,0x3f,0xfc,0x60,0x04,0x32,0x63,
  0x80,0x08,0x60,0x05,0x32,0xe4,0x19,0x9a,0x60,0x06,0x33,0x65,0x0d,0x83,0x60,0x0f,
  0x31,0xe6,0x70,0x00,0xf0,0x00,0x30,0x77,0x70,0x00,0xd0,0x08,0x80,0xe5,0x7f,0xff,
  0x60,0x00,0xcc,0x0a,0x70,0x00,0xf0,0x00,0x8e,0xa9,0x33,0x70,0xf0,0x00,0xaf,0x20,
  0x34,0x70,0xd4,0x09,0xae,0xe8,0x70,0x00,0xf0,0x00,0xa8,0x05,0x00,0x80,0x60,0x07,
  0xa8,0xf6,0x33,0x75,0xf0,0x00,0xc3,0x86,0x70,0x00,0xf0,0x00,0x8f,0x7f,0x33,0xf6,
  0xf0,0x00,0xa8,0x85,0x1d,0xe4,0xd1,0x80,0xf0,0x00,0x34,0x75,0xd0,0x08,0x0d,0x83,
  0x60,0x09,0xa1,0x4f,0x20,0x12,0x1f,0x32,0xd2,0x80,0xf0,0x00,0x35,0x82,0xd0,0x08,
  0x90,0x82,0x0d,0x83,0x60,0x09,0x40,0xa7,0x40,0x77,0xe6,0x40,0xf0,0x00,0x70,0x00,
  0xf0,0x00,0xf0,0x00,0x30,0x17,0xd0,0x08,0x0b,0xb4,0x60,0x08,0xa1,0x48,0xf0,0x00,
  0x31,0x82,0xd0,0x08,0xf0,0x00,0x09,0x61,0x60,0x08,0xf0,0x00,0x09,0xc9,0x60,0x09,
  0xf0,0x00,0x21,0x80,0xf0,0x00,0xf0,0x00,0x20,0x91,0xa1,0x43,0xa2,0x08,0x70,0x00,
  0xd0,0x08,0x00,0xcf,0x60,0x00,0xa0,0x05,0x40,0x11,0x0c,0x14,0xd0,0x80,0x00,0xcf,
  0x60,0x00,0xa0,0x03,0xf0,0x00,0x20,0x22,0xd0,0x80,0x01,0x51,0x60,0x00,0xa0,0x01,
  0xf0,0x00,0x20,0x1e,0xd0,0x80,0xf0,0x00,0x0e,0x69,0x60,0x08,0xf0,0x00,0x01,0xd0,
  0x60,0x01,0xf0,0x00,0x30,0x80,0xf0,0x00,0xf0,0x00,0x30,0x01,0xd0,0x08,0x83,0x6d,
  0x0c,0x35,0x60,0x08,0x40,0x60,0x39,0xd8,0x60,0x01,0x41,0xe2,0x21,0x96,0x60,0x03,
  0x33,0x00,0x41,0x44,0xf0,0x00,0x33,0x81,0x70,0x00,0xf0,0x00,0x34,0x02,0x70,0x00,
  0xf0,0x00,0x34,0x83,0x0c,0x29,0x60,0x09,0x35,0x04,0x39,0xe6,0x60,0x00,0x35,0x85,
  0x39,0xeb,0x60,0x03,0x30,0x90,0x70,0x00,0xf0,0x00,0x33,0x93,0x70,0x00,0xd0,0x08,
  0xf0,0x00,0x70,0x00,0xae,0xcf,0xf0,0x00,0x70,0x00,0x8f,0x14,0xf0,0x00,0x70,0x00,
  0xaf,0x0d,0xf0,0x00,0x0c,0x51,0xd2,0x80,0xf0,0x00,0x21,0xa0,0xd0,0x80,0xf0,0x00,
  0x05,0x2e,0xd2,0x80,0xf0,0x00,0x70,0x00,0xa0,0x0e,0xf0,0x00,0x21,0xb7,0xd0,0x80,
  0xf0,0x00,0x1f,0x32,0xd2,0x80,0xf0,0x00,0x1e,0x84,0xd2,0x80,0xf0,0x00,0x21,0xe0,
  0xd0,0x80,0xf0,0x00,0x1e,0xa4,0xd2,0x80,0xf0,0x00,0x07,0xf7,0xd2,0x80,0xf0,0x00,
  0x22,0x15,0xd0,0x80,0xf0,0x00,0x07,0xfb,0xd2,0x80,0xf0,0x00,0x22,0x8f,0xd0,0x80,
  0x40,0x40,0x22,0xe1,0xd2,0x80,0x40,0x80,0x22,0xe2,0xd2,0x80,0xf0,0x00,0x22,0x9c,
  0xd0,0x80,0xf0,0x00,0x07,0xfb,0xd2,0x80,0xf0,0x00,0x22,0xb6,0xd0,0x80,0xf0,0x00,
  0x20,0xf0,0xd2,0x80,0x90,0x02,0x27,0xdf,0xd2,0x80,0x9e,0x69,0x70,0x00,0xf0,0x00,
  0xf0,0x00,0x07,0x00,0xd1,0x80,0xf0,0x00,0x23,0x20,0xd0,0x80,0x90,0x82,0x0c,0x29,
  0x60,0x09,0x40,0x17,0x40,0x67,0xe6,0x40,0xf0,0x00,0x70,0x00,0xf0,0x00,0xf0,0x00,
  0x32,0x17,0xd0,0x08,0xf0,0x00,0x07,0xf7,0xd2,0x80,0xf0,0x00,0x27,0xea,0xd2,0x80,
  0xf0,0x00,0x11,0xb5,0xd0,0x80,0x40,0x55,0x15,0x17,0x60,0x08,0xf0,0x00,0x1d,0x40,
  0x60,0x00,0x31,0x05,0x1e,0x60,0x60,0x01,0x31,0x85,0x70,0x00,0xf0,0x00,0x32,0x05,
  0x70,0x00,0xf0,0x00,0x32,0x85,0x70,0x00,0xf0,0x00,0x33,0x00,0x70,0x00,0xf0,0x00,
  0x33,0x81,0x0d,0x88,0x60,0x09,0x34,0x00,0x02,0x54,0x60,0x02,0x34,0x81,0x38,0x80,
  0x60,0x03,0x30,0x12,0x70,0x00,0xf0,0x00,0x30,0x93,0x70,0x00,0xd0,0x08,0x17,0x0b,
  0x60,0x0c,0xa0,0xff,0x00,0x40,0x40,0x05,0xf0,0x00,0x00,0x41,0x24,0x3f,0xd0,0x80,
  0xf0,0x00,0x0c,0x83,0x60,0x08,0x90,0x00,0x0c,0x6b,0x60,0x0b,0xf0,0x00,0x70,0x0c,
  0xe6,0x00,0xf0,0x00,0x20,0x03,0xf0,0x00,0xf0,0x00,0x22,0x04,0xf0,0x00,0xf0,0x00,
  0x3b,0xb3,0xf0,0x00,0xf0,0x00,0x3c,0x34,0xd0,0x08,0xf0,0x00,0x70,0x00,0xae,0x31,
  0xf0,0x00,0x0c,0x8d,0x60,0x08,0xf0,0x00,0x26,0x0a,0xd0,0x80,0x83,0xff,0x0d,0x95,
  0x60,0x08,0xf0,0x00,0x01,0xf4,0x60,0x00,0xf0,0x00,0x03,0xb1,0x60,0x01,0x10,0x00,
  0x03,0xb2,0x60,0x02,0x10,0x01,0x04,0x0e,0x60,0x00,0x10,0x02,0x04,0x0f,0x60,0x01,
  0x10,0x00,0x04,0x5c,0x60,0x02,0x10,0x01,0x04,0x5d,0x60,0x00,0x10,0x02,0x13,0x80,
  0x60,0x01,0x10,0x00,0x0d,0xa5,0x60,0x09,0x10,0x01,0x02,0xee,0x60,0x00,0x10,0x07,
  0x43,0x06,0x60,0x01,0x10,0x10,0x04,0x69,0x60,0x02,0x10,0x11,0x44,0x87,0x60,0x00,
  0x10,0x12,0x05,0xe3,0x60,0x01,0x10,0x10,0x46,0x08,0x60,0x02,0x10,0x11,0x06,0xae,
  0x60,0x00,0x10,0x12,0x0d,0x9e,0x60,0x08,0x10,0x10,0x9e,0x3c,0x60,0x00,0x10,0x17,
  0x0d,0xad,0x60,0x09,0x10,0x00,0x25,0xda,0x60,0x00,0x10,0x07,0xc0,0x41,0x60,0x01,
  0x10,0x10,0x28,0xa0,0x60,0x02,0x10,0x11,0x40,0x3c,0x60,0x00,0x10,0x12,0x29,0xcc,
  0x60,0x01,0x10,0x10,0x00,0x37,0x60,0x02,0x10,0x11,0x29,0xd1,0x60,0x00,0x10,0x12,
  0x00,0x37,0x60,0x01,0x10,0x10,0x29,0xd6,0x60,0x02,0x10,0x11,0x00,0x37,0x60,0x00,
  0x10,0x12,0x29,0xdb,0x60,0x01,0x10,0x10,0x00,0x37,0x60,0x02,0x10,0x11,0x0d,0xba,
  0x60,0x08,0x10,0x12,0x25,0xda,0x60,0x00,0x10,0x17,0xc0,0x40,0x60,0x01,0x10,0x00,
  0x27,0x15,0x60,0x02,0x10,0x01,0x40,0x3e,0x60,0x00,0x10,0x02,0x27,0x1a,0x60,0x01,
  0x10,0x00,0x80,0x3c,0x60,0x02,0x10,0x01,0x28,0x64,0x60,0x00,0x10,0x02,0x40,0x3c,
  0x60,0x01,0x10,0x00,0x28,0x69,0x60,0x02,0x10,0x01,0x40,0x3c,0x60,0x00,0x10,0x02,
  0x28,0x6e,0x60,0x01,0x10,0x00,0x80,0x3a,0x60,0x02,0x10,0x01,0x28,0x73,0x60,0x00,
  0x10,0x02,0x80,0x3a,0x60,0x01,0x10,0x00,0x0d,0xc9,0x60,0x09,0x10,0x01,0x70,0x00,
  0xf0,0x00,0x10,0x07,0x70,0x00,0xf0,0x00,0x10,0x17,0x70,0x00,0xd0,0x08,0x0c,0xdf,
  0x60,0x0b,0xa0,0xbf,0x30,0x30,0x23,0xd6,0xd2,0x80,0xf0,0x00,0x26,0xe8,0xd0,0x80,
  0x0d,0x95,0x60,0x08,0xa0,0xbc,0xf0,0x00,0x00,0x02,0xa0,0xbb,0x90,0x82,0x70,0x00,
  0xf0,0x00,0x82,0x8a,0x70,0x00,0x90,0x03,0x90,0x8a,0x70,0x00,0x90,0x01,0xf0,0x00,
  0x70,0x00,0x8f,0xfb,0x82,0xbf,0x70,0x00,0xf0,0x00,0xf0,0x00,0x01,0x99,0xd2,0x80,
  0xf0,0x00,0x0d,0x94,0x60,0x08,0xf0,0x00,0x26,0xc1,0xf0,0x00,0xf0,0x00,0x00,0x02,
  0xa0,0xb2,0x90,0x82,0x70,0x00,0xf0,0x00,0x82,0x8a,0x70,0x00,0x90,0x03,0x90,0x8a,
  0x70,0x00,0x90,0x01,0xf0,0x00,0x70,0x00,0x8f,0xfb,0x82,0x80,0x70,0x00,0xf0,0x00,
  0xf0,0x00,0x70,0x00,0xd0,0x08,0xf0,0x00,0x0d,0xa5,0x60,0x0d,0xf0,0x00,0x3f,0xff,
  0x60,0x02,0xf0,0x00,0x00,0x51,0xa0,0xa9,0xc2,0x53,0x70,0x00,0xf0,0x00,0x8e,0xc4,
  0x70,0x00,0x90,0x01,0xf0,0x00,0x70,0x00,0x97,0xfc,0xd4,0x8f,0x01,0x99,0xd2,0x80,
  0x40,0x05,0x0d,0x9e,0x60,0x0d,0x40,0x17,0x3f,0xff,0x60,0x02,0x9f,0x7d,0x00,0x51,
  0xa0,0xa2,0xc2,0x53,0x70,0x00,0xf0,0x00,0x82,0xc4,0x27,0x1c,0xd1,0x80,0xf0,0x00,
  0x70,0x00,0x97,0xfc,0x91,0x46,0x27,0x20,0xd0,0x80,0x40,0x07,0x01,0x99,0xd2,0x80,
  0xf0,0x00,0x0d,0x88,0x60,0x0e,0x40,0x07,0x25,0xc1,0xa0,0x9b,0x9e,0x79,0x2e,0x40,
  0x40,0x14,0x40,0x36,0x31,0x67,0x90,0x1e,0x2f,0x45,0x19,0x64,0x60,0x02,0x4f,0xf0,
  0x1a,0x5e,0x60,0x03,0x83,0x54,0x40,0x36,0xf0,0x00,0x83,0x5c,0x40,0x00,0xe2,0x00,
  0xf0,0x00,0x40,0x10,0xe2,0x00,0xf0,0x00,0x70,0x00,0xf0,0x00,0x90,0x00,0x70,0x00,
  0xf0,0x00,0xf0,0x00,0x70,0x00,0x9c,0x25,0x40,0x36,0x22,0xf0,0xd2,0x80,0x40,0x14,
  0x21,0x40,0x94,0x06,0x0d,0xba,0x60,0x0d,0xa0,0x8e,0xf0,0x00,0x20,0x51,0xa0,0x8d,
  0x90,0x41,0x70,0x00,0xf0,0x00,0x82,0x45,0x70,0x00,0x90,0x02,0xf0,0x00,0x70,0x00,
  0x90,0x07,0xf0,0x00,0x70,0xdc,0x8f,0xfb,0x0d,0xad,0x60,0x0d,0xa0,0x88,0xf0,0x00,
  0x20,0x51,0xa0,0x87,0x90,0x41,0x70,0x00,0xf0,0x00,0x82,0x45,0x70,0x00,0x90,0x19,
  0xf0,0x00,0x70,0x00,0x90,0x01,0xf0,0x00,0x70,0xdc,0x8f,0xfb,0x20,0xd1,0x3f,0xff,
  0x60,0x02,0xf0,0x00,0x0c,0xdf,0x60,0x0b,0xc2,0x53,0x31,0x61,0xf0,0x00,0xd4,0x8e,
  0x30,0x33,0xf0,0x00,0xd4,0x4a,0x37,0xc6,0xf0,0x00,0xc6,0xa2,0x70,0x00,0xf0,0x00,
  0xc3,0xa0,0x3d,0x42,0xf0,0x00,0xf0,0x00,0x31,0xe0,0xd0,0x08,0xc6,0x24,0x31,0xe0,
  0xf0,0x00,0x90,0x00,0x3d,0x44,0xf0,0x00,0x83,0xb6,0x70,0x00,0xe0,0x40,0xf0,0x00,
  0x37,0xc6,0xa0,0x4b,0x21,0x42,0x32,0x00,0x60,0x03,0xf0,0x00,0x22,0x60,0xf0,0x00,
  0xb0,0x98,0x22,0xe1,0xf0,0x00,0xf0,0x00,0x23,0xea,0xd2,0x80,0x40,0x16,0x23,0xde,
  0xd2,0x80,0xa9,0x83,0x70,0x00,0xf0,0x00,0xc2,0xf0,0x0c,0xdf,0x60,0x0b,0x80,0xc3,
  0x70,0x00,0xf0,0x00,0xf0,0x00,0x33,0x63,0xf0,0x00,0xf0,0x00,0x34,0xe3,0xf0,0x00,
  0xf0,0x00,0x30,0x33,0x80,0x12,0x40,0xd5,0x21,0x41,0xa0,0x6b,0xcc,0x0b,0x40,0x00,
  0xf0,0x00,0x80,0xed,0x23,0xea,0xd2,0x80,0xbf,0x60,0x20,0x60,0xf0,0x00,0xf0,0x00,
  0x20,0xe1,0xf0,0x00,0xf0,0x00,0x23,0xea,0xd2,0x80,0x90,0xc6,0x23,0xde,0xd2,0x80,
  0x4f,0x95,0x40,0x14,0xa0,0x64,0x81,0x75,0x70,0x00,0x40,0x06,0xaf,0x43,0x70,0x00,
  0xf0,0x00,0xc2,0xe0,0x0c,0xdf,0x60,0x0b,0xf0,0x00,0x31,0xe0,0xf0,0x00,0x80,0xc3,
  0x40,0x36,0xe6,0x00,0xc6,0x24,0x30,0x33,0xf0,0x00,0xf0,0x00,0x33,0x63,0xf0,0x00,
  0xf0,0x00,0x34,0xe3,0xf0,0x00,0xf0,0x00,0x3d,0x44,0xf0,0x00,0xf0,0x00,0x37,0xc6,
  0xa0,0x2e,0xf0,0x00,0x23,0x66,0xa0,0x31,0x82,0x92,0x0b,0xb8,0x60,0x03,0x47,0xf4,
  0x23,0xe0,0xd2,0x80,0x52,0x08,0x60,0x05,0x98,0x03,0x82,0x92,0x52,0x08,0x60,0x03,
  0x47,0xf4,0x23,0xe0,0xd2,0x80,0x52,0x08,0x60,0x05,0x98,0x23,0xf0,0x00,0x33,0xe4,
  0xf0,0x00,0xf0,0x00,0x34,0x65,0xf0,0x00,0xf0,0x00,0x35,0x64,0xf0,0x00,0xf0,0x00,
  0x35,0xe5,0xf0,0x00,0xf0,0x00,0x23,0x66,0xa0,0x4e,0x91,0x8e,0x70,0x00,0xf0,0x00,
  0xf0,0x00,0x33,0x66,0xa0,0x24,0x82,0x92,0x52,0x08,0x60,0x03,0xf0,0x00,0x23,0xe0,
  0xd2,0x80,0xf0,0x00,0x70,0x00,0x9c,0x05,0x82,0x92,0x0b,0xb8,0x60,0x03,0xf0,0x00,
  0x23,0xe0,0xd2,0x80,0xf0,0x00,0x70,0x00,0x9b,0xf7,0x0d,0x8e,0x60,0x0d,0xa0,0x2b,
  0xf0,0x00,0x70,0x00,0x8f,0xf5,0xf0,0x00,0x24,0xe6,0xa0,0x43,0x9f,0xbe,0x70,0x00,
  0xf0,0x00,0xf0,0x00,0x34,0xe6,0xa0,0x19,0x82,0x92,0x52,0x08,0x60,0x03,0xf0,0x00,
  0x23,0xe0,0xd2,0x80,0xf0,0x00,0x70,0x00,0x9c,0x05,0x82,0x92,0x0b,0xb8,0x60,0x03,
  0xf0,0x00,0x23,0xe0,0xd2,0x80,0xf0,0x00,0x70,0x00,0x9b,0xf7,0x0d,0x91,0x60,0x0d,
  0xa0,0x20,0xf0,0x00,0x70,0x00,0x8f,0xf5,0x40,0x14,0x23,0xe1,0xa0,0x38,0xc2,0x63,
  0x25,0x62,0xf0,0x00,0xf0,0x00,0x24,0x65,0x90,0x07,0xc2,0xa3,0x25,0xe6,0xf0,0x00,
  0x90,0x80,0x70,0x00,0x90,0x02,0x83,0x77,0x70,0x00,0xf0,0x00,0x25,0x60,0x23,0xe0,
  0xeb,0xc0,0x0c,0xdf,0x60,0x0b,0xa0,0x31,0xf0,0x00,0x30,0x30,0xf0,0x00,0xf0,0x00,
  0x21,0xe0,0xd0,0x08,0xc2,0xa3,0x25,0xe6,0xf0,0x00,0xf0,0x00,0x70,0x00,0x93,0xf9,
  0x90,0x40,0x70,0x00,0x8f,0xfa,0xf0,0x00,0x21,0xe0,0xaf,0x2e,0xf0,0x00,0x24,0x62,
  0xd2,0x80,0xf0,0x00,0x32,0x60,0xf0,0x00,0xf0,0x00,0x32,0xe1,0xd0,0x08,0xf0,0x00,
  0x23,0xed,0xd2,0x80,0xb8,0x68,0x22,0x60,0xf0,0x00,0xf0,0x00,0x22,0xe1,0xf0,0x00,
  0xf0,0x00,0x23,0xea,0xd2,0x80,0xf0,0x00,0x23,0xde,0xd2,0x80,0xa9,0x88,0x70,0x00,
  0xf0,0x00,0xab,0xf8,0x23,0xe4,0xd2,0x80,0x46,0x43,0x21,0x42,0xa0,0x20,0xa0,0x98,
  0x70,0x00,0xf0,0x00,0xf0,0x00,0x23,0xe7,0xd2,0x80,0xf0,0x00,0x23,0xc6,0xd2,0x80,
  0x90,0x00,0x70,0x00,0xf0,0x00,0xf0,0x00,0x70,0x00,0xdc,0x09,0xf0,0x00,0x23,0xce,
  0xd0,0x80,0x47,0xe5,0x70,0x00,0xf0,0x00,0x40,0x16,0x20,0xd3,0xa0,0x18,0x83,0x5d,
  0x20,0x52,0xf0,0x00,0xc2,0xf5,0x21,0x54,0x98,0x07,0xc2,0xb6,0x70,0x00,0x90,0x02,
  0xf0,0x00,0x70,0x00,0x90,0x05,0xf0,0x00,0x70,0x00,0x80,0x02,0xc2,0xb6,0x70,0x00,
  0xf0,0x00,0xf0,0x00,0x70,0x00,0xd4,0x09,0x82,0x64,0x70,0x00,0xf0,0x00,0xf0,0x00,
  0x70,0x00,0xdc,0x09,0xf0,0x00,0x31,0x51,0xf0,0x00,0xf0,0x00,0x30,0xd2,0xd0,0x08,
  0x0d,0xc9,0x60,0x0b,0xa0,0x0c,0x9e,0x79,0x20,0x36,0xf0,0x00,0xf0,0x00,0x20,0x45,
  0xf0,0x00,0x9f,0xbc,0x70,0x00,0xe0,0x40,0x91,0x45,0x70,0x00,0xd0,0x09,0x26,0x44,
  0x27,0x2d,0xd5,0x80,0x91,0x86,0x70,0x00,0xf0,0x00,0xf0,0x00,0x27,0x32,0xd5,0x80,
  0xf0,0x00,0x70,0x00,0xaf,0x66,0x2f,0x41,0x27,0x36,0xd0,0x80,0xf0,0x00,0x29,0x15,
  0xd2,0x80,0xf0,0x00,0x3b,0x06,0xd2,0x80,0xf0,0x00,0x28,0x88,0xd0,0x80,0xf0,0x00,
  0x70,0x00,0xd0,0x08,0xf0,0x00,0x16,0xc3,0x60,0x08,0xf0,0x00,0x00,0x9a,0x60,0x00,
  0xf0,0x00,0x02,0xe3,0x60,0x00,0x10,0x00,0x04,0xf4,0x60,0x00,0x10,0x00,0x06,0xff,
  0x60,0x00,0x10,0x00,0x09,0x07,0x60,0x00,0x10,0x00,0x0b,0x10,0x60,0x00,0x10,0x00,
  0x0d,0x1f,0x60,0x00,0x10,0x00,0x0f,0x65,0x60,0x00,0x10,0x00,0x0f,0x65,0x60,0x00,
  0x10,0x00,0x0d,0x1f,0x60,0x00,0x10,0x00,0x0b,0x10,0x60,0x00,0x10,0x00,0x09,0x07,
  0x60,0x00,0x10,0x00,0x06,0xff,0x60,0x00,0x10,0x00,0x04,0xf4,0x60,0x00,0x10,0x00,
  0x02,0xe3,0x60,0x00,0x10,0x00,0x00,0x9a,0x60,0x00,0xf0,0x00,0x10,0x00,0xf0,0x00,
  0xf0,0x00,0x10,0x00,0xf0,0x00,0xf0,0x00,0x16,0xd3,0x60,0x08,0xf0,0x00,0xff,0x93,
  0x60,0x00,0xf0,0x00,0xfe,0x37,0x60,0x00,0x10,0x00,0xfd,0xd9,0x60,0x00,0x10,0x00,
  0xfe,0x9f,0x60,0x00,0x10,0x00,0x03,0x85,0x60,0x00,0x10,0x00,0x0d,0x6b,0x60,0x00,
  0x10,0x00,0x16,0x84,0x60,0x00,0x10,0x00,0x1e,0x49,0x60,0x00,0x10,0x00,0x1e,0x49,
  0x60,0x00,0x10,0x00,0x16,0x84,0x60,0x00,0x10,0x00,0x0d,0x6b,0x60,0x00,0x10,0x00,
  0x03,0x85,0x60,0x00,0x10,0x00,0xfe,0x9f,0x60,0x00,0x10,0x00,0xfd,0xd9,0x60,0x00,
  0x10,0x00,0xfe,0x37,0x60,0x00,0x10,0x00,0xff,0x93,0x60,0x00,0xf0,0x00,0x10,0x00,
  0xf0,0x00,0xf0,0x00,0x10,0x00,0xf0,0x00,0xf0,0x00,0x16,0xe3,0x60,0x08,0xf0,0x00,
  0x00,0x64,0x60,0x00,0xf0,0x00,0xff,0xa8,0x60,0x00,0x10,0x00,0xff,0xa6,0x60,0x00,
  0x10,0x00,0xff,0xdf,0x60,0x00,0x10,0x00,0x00,0x01,0x60,0x00,0x10,0x00,0x01,0x28,
  0x60,0x00,0x10,0x00,0x01,0x2f,0x60,0x00,0x10,0x00,0xfd,0x23,0x60,0x00,0x10,0x00,
  0xfd,0xa1,0x60,0x00,0x10,0x00,0x03,0x89,0x60,0x00,0x10,0x00,0x02,0x54,0x60,0x00,
  0x10,0x00,0xfe,0x7d,0x60,0x00,0x10,0x00,0x00,0x8c,0x60,0x00,0x10,0x00,0xfb,0xe1,
  0x60,0x00,0x10,0x00,0xf9,0x42,0x60,0x00,0x10,0x00,0x0c,0x47,0x60,0x00,0x10,0x00,
  0x0e,0xa2,0x60,0x00,0x10,0x00,0xec,0x43,0x60,0x00,0x10,0x00,0xea,0xce,0x60,0x00,
  0x10,0x00,0x17,0x46,0x60,0x00,0x10,0x00,0x17,0x46,0x60,0x00,0x10,0x00,0xea,0xce,
  0x60,0x00,0x10,0x00,0xec,0x43,0x60,0x00,0x10,0x00,0x0e,0xa2,0x60,0x00,0x10,0x00,
  0x0c,0x47,0x60,0x00,0x10,0x00,0xf9,0x42,0x60,0x00,0x10,0x00,0xfb,0xe1,0x60,0x00,
  0x10,0x00,0x00,0x8c,0x60,0x00,0x10,0x00,0xfe,0x7d,0x60,0x00,0x10,0x00,0x02,0x54,
  0x60,0x00,0x10,0x00,0x03,0x89,0x60,0x00,0x10,0x00,0xfd,0xa1,0x60,0x00,0x10,0x00,
  0xfd,0x23,0x60,0x00,0x10,0x00,0x01,0x2f,0x60,0x00,0x10,0x00,0x01,0x28,0x60,0x00,
  0x10,0x00,0x00,0x01,0x60,0x00,0x10,0x00,0xff,0xdf,0x60,0x00,0x10,0x00,0xff,0xa6,
  0x60,0x00,0x10,0x00,0xff,0xa8,0x60,0x00,0x10,0x00,0x00,0x64,0x60,0x00,0xf0,0x00,
  0x10,0x00,0xf0,0x00,0xf0,0x00,0x10,0x00,0xf0,0x00,0xf0,0x00,0x17,0x0b,0x60,0x08,
  0xf0,0x00,0x00,0x03,0x60,0x00,0xf0,0x00,0x54,0xc0,0x60,0x00,0x10,0x00,0x00,0x05,
  0x60,0x00,0x10,0x00,0x00,0x05,0x60,0x00,0x10,0x00,0x00,0x0f,0x60,0x00,0x10,0x00,
  0x00,0x0f,0x60,0x00,0x10,0x00,0x09,0xc0,0x60,0x00,0x10,0x00,0x0a,0x20,0x60,0x00,
  0x10,0x00,0x1d,0x40,0x60,0x00,0x10,0x00,0x1e,0x60,0x60,0x00,0xf0,0x00,0x10,0x00,
  0xf0,0x00,0xf0,0x00,0x10,0x00,0xf0,0x00,0xf0,0x00,0x70,0x00,0xd0,0x08,
};

unsigned char code TEF6686_LutByteValues[] = {
  0x40,0x13,0x40,0x2f,0x41,0x68,0x41,0xc1,0x42,0x14,0x44,0xde,0x47,0xc5,0x47,0xfc,
  0x4e,0x56,0x4e,0x58,0x4e,0x5b,0x4d,0x83,0x4e,0x0a,0x4e,0x49,0x4e,0x53,0x4f,0x92,
  0x4f,0xea,0x50,0x74,0x50,0x80,0x56,0x60,0x56,0xd4,0x56,0xd9,0x59,0xb4,0x5a,0x3a,
  0x5b,0x79,0x5d,0xdc,0x60,0x67,0x60,0x88,0x60,0xa8,0x61,0x9f,0x61,0xb6,0x61,0xdf,
  0x62,0x14,0x62,0x59,0x62,0x9b,0x62,0xa1,0x63,0x69,0x64,0x3b,0x66,0x09,0x66,0xe7,
  0x67,0x0b,0x67,0x1a,0x67,0x29,0x68,0x87,0x68,0x99,0x68,0xa7,0x68,0xb2,
};

unsigned char code TEF6686_set_FM_command[] = {
  0x09,0x40,0x04,0x01,0x00,0x8c,0xa0,0x00,0x00,0x00,0x05,0x40,0x05,0x01,0x00,0x01,
  0x07,0x20,0x01,0x01,0x00,0x01,0x26,0x52,0x05,0x20,0x16,0x01,0x00,0x01,0x05,0x20,
  0x14,0x01,0x00,0x01,0x0b,0x20,0x28,0x01,0x00,0x78,0x01,0xf4,0x00,0x0a,0x00,0x14,
  0x09,0x20,0x2c,0x01,0x00,0x00,0x00,0xc8,0x03,0xe8,0x09,0x20,0x2b,0x01,0x00,0x00,
  0x00,0xc8,0x03,0xe8,0x0b,0x20,0x32,0x01,0x00,0xc8,0x07,0xd0,0x00,0x0a,0x00,0x50,
  0x09,0x20,0x36,0x01,0x00,0x03,0x00,0x78,0x00,0xa0,0x09,0x20,0x35,0x01,0x00,0x03,
  0x00,0x96,0x00,0xc8,0x07,0x20,0x37,0x01,0x00,0x01,0x09,0x60,0x07,0x20,0x39,0x01,
  0x00,0x01,0x00,0x64,0x0b,0x20,0x3c,0x01,0x00,0xc8,0x0f,0xa0,0x00,0x14,0x00,0x50,
  0x09,0x20,0x40,0x01,0x00,0x03,0x00,0x64,0x00,0x96,0x09,0x20,0x3f,0x01,0x00,0x03,
  0x00,0x78,0x00,0xa0,0x09,0x20,0x4a,0x01,0x00,0x03,0x00,0x50,0x00,0x8c,0x09,0x20,
  0x49,0x01,0x00,0x03,0x00,0x50,0x00,0x8c,0x09,0x40,0x03,0x01,0x00,0x00,0x00,0x21,
  0x00,0x03,0x09,0x40,0x03,0x01,0x00,0x01,0x00,0x21,0x00,0x00,0x09,0x40,0x03,0x01,
  0x00,0x02,0x00,0x21,0x00,0x00,0x09,0x40,0x03,0x01,0x00,0x00,0x00,0x20,0x00,0x03,
  0x09,0x40,0x03,0x01,0x00,0x01,0x00,0x20,0x00,0x00,0x09,0x40,0x03,0x01,0x00,0x02,
  0x00,0x20,0x00,0x00,0x0d,0x30,0x16,0x01,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,
  0x11,0x3a,0x0d,0x30,0x16,0x01,0x00,0x21,0x00,0x00,0x00,0x20,0x00,0x00,0x11,0x3a,
  0x05,0x30,0x0b,0x01,0x00,0x00,0x07,0x30,0x0d,0x01,0x00,0x80,0x00,0xe0,0x05,0x30,
  0x0a,0x01,0x00,0x32,
};

unsigned char code TEF6686_set_AM_command[] = {
  0x07,0x21,0x01,0x01,0x00,0x01,0x03,0xe7,0x07,0x21,0x52,0x01,0x00,0xc8,0x00,0x00,
  0x07,0x21,0x52,0x01,0x00,0x00,0x00,0x00,0x05,0x30,0x0a,0x01,0x00,0x32,
};
/*
 * tef6686.c - TEF6686 FM/AM tuner driver for 8051 (C89 / Keil C51)
 *
 * Soft-I2C bit-bang driver plus TEF6686 command layer.
 * Initialization order follows the reference Tuner_Interface.c:
 *   1C 00 00 / 1C 00 74  -> patch via 0x1B + 24-byte chunks
 *   1C 00 00 / 1C 00 75  -> LUT via 0x1B + 24-byte chunks
 *   1C 00 00 / 14 00 01  -> start firmware, wait 50 ms
 *   send band command table (contains ReferenceClock + Activate + config)
 *
 * 8051 memory map notes:
 *   - all tables live in CODE memory (const code unsigned char *)
 *   - I2C TX/RX buffers live in DATA/IDATA
 */

/*----------------------------- soft I2C ------------------------------*/
void Delay1us(uint time)	//@11.0592MHz
{
	unsigned long edata i;
	for(;time>0;time--)
	{
		_nop_();
		_nop_();
		i = 1UL;
		while (i) i--;
	}
}

void I2C_Delay(void) //5us
{
    	unsigned long edata i;

	_nop_();
	_nop_();
	i = 12UL;
	while (i) i--;
}

void I2C_Start(void)
{
    I2C_SDA = 1;
	I2C_Delay();
    I2C_SCL = 1;
    I2C_Delay();
    I2C_SDA = 0;
    I2C_Delay();
    I2C_SCL = 0;
	I2C_Delay();
}

void I2C_Stop(void)
{
    I2C_SDA = 0;
	I2C_Delay();
    I2C_SCL = 1;
    I2C_Delay();
    I2C_SDA = 1;
    I2C_Delay();
}

unsigned char I2C_WriteByte(unsigned char dat)
{
    unsigned char i;
    unsigned char ack;

    for (i = 0; i < 8; i++) {
        I2C_SDA = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
			I2C_Delay();
        I2C_SCL = 1;
        I2C_Delay();
        I2C_SCL = 0;
        I2C_Delay();
    }

    I2C_SDA = 1;               /* release line, read ACK */
		I2C_Delay();
    I2C_SCL = 1;
    I2C_Delay();
    ack = I2C_SDA;             /* 0 = ACK, 1 = NACK */
    I2C_SCL = 0;
    I2C_Delay();
    return ack;
}

unsigned char I2C_ReadByte(unsigned char ack)
{
    unsigned char i;
    unsigned char dat;

    dat = 0;
    I2C_SDA = 1;               /* release line */
	I2C_Delay();
    for (i = 0; i < 8; i++) {
        I2C_SCL = 1;
        I2C_Delay();
        dat <<= 1;
        if (I2C_SDA) dat |= 1;
        I2C_SCL = 0;
        I2C_Delay();
    }
    I2C_SDA = ack ? 1 : 0;     /* 1 = NACK (last byte), 0 = ACK */
		I2C_Delay();
    I2C_SCL = 1;
    I2C_Delay();
    I2C_SCL = 0;
		I2C_Delay();
    I2C_SDA = 1;
    I2C_Delay();
    return dat;
}

unsigned char I2C_WriteBuffer(const unsigned char *buf, unsigned char len)
{
    unsigned char i;

    I2C_Start();
    if (I2C_WriteByte(I2C_ADDR_WRITE) != 0) {
        I2C_Stop();
        return 0;
    }
    for (i = 0; i < len; i++) {
        if (I2C_WriteByte(buf[i]) != 0) {
            I2C_Stop();
            return 0;
        }
    }
    I2C_Stop();
    return 1;
}

unsigned char I2C_ReadBuffer(unsigned char *buf, unsigned char len)
{
    unsigned char i;

    I2C_Start();
    I2C_WriteByte(I2C_ADDR_READ);
    for (i = 0; i < len; i++) {
        buf[i] = I2C_ReadByte((i < (unsigned char)(len - 1)) ? 0 : 1);
    }
    I2C_Stop();
    return 1;
}

/*----------------------------- command layer --------------------------*/

unsigned char TEF6686_WriteCmd(unsigned char module, unsigned char cmd,unsigned char n, const unsigned int *p)
{
    unsigned char buf[19];
    unsigned char i;

    if (n > 8) return 0;
    buf[0] = module;
    buf[1] = cmd;
    buf[2] = 1;                        // index, always 1 
    for (i = 0; i < n; i++) {          // 16-bit big-endian parameters 
        buf[3 + 2 * i] = (unsigned char)(p[i] >> 8);
        buf[4 + 2 * i] = (unsigned char)p[i];
    }
    return I2C_WriteBuffer(buf, (unsigned char)(3 + 2 * n));
}

unsigned char TEF6686_GetCmd(unsigned char module, unsigned char cmd,unsigned char *rx, unsigned char len)
{
    unsigned char req[3];

    req[0] = module;
    req[1] = cmd;
    req[2] = 1;
    if (I2C_WriteBuffer(req, 3) != 1) return 0;
    return I2C_ReadBuffer(rx, len);
}

/*----------------------------- table / patch load --------------------*/

#define TEF6686_SPLIT_SIZE   24

unsigned char TEF6686_LoadData(const unsigned char code *dat,unsigned int sizee)
{
    unsigned char buf[TEF6686_SPLIT_SIZE + 1];
    unsigned char len, i;
    unsigned char r;

    buf[0] = 0x1B;
    while (sizee) {
        len = (sizee > TEF6686_SPLIT_SIZE) ? TEF6686_SPLIT_SIZE
                                          : (unsigned char)sizee;
        for (i = 0; i < len; i++) buf[1 + i] = dat[i];
        dat += len;
        sizee -= len;
        r = I2C_WriteBuffer(buf, (unsigned char)(len + 1));
        if (r != 1) return r;
    }
    return 1;
}

unsigned char TEF6686_SendTable(const unsigned char code *tab,
                                       unsigned int sizee)
{
    unsigned int i;
    unsigned char buf[24];
    unsigned char len, k;
    unsigned char r;

    i = 0;
    while (i < sizee) {
        len = tab[i];                  /* length-prefixed entry */
        for (k = 0; k < len; k++) buf[k] = tab[i + 1 + k];
        r = I2C_WriteBuffer(buf, len);
        if (r != 1) return r;
        i += (unsigned int)len + 1;
    }
    return 1;
}

/*----------------------------- public API ----------------------------*/

void TEF6686_DelayMs(unsigned int ms)
{
    unsigned long edata i;
	for(;ms>0;ms--)
	{
		_nop_();
		_nop_();
		i = 2763UL;
		while (i) i--;
	}
}

unsigned char TEF6686_Init(void)
{
    unsigned char ctrl[3];
    unsigned char r;
		unsigned char reset_dat[5]={0x1e,0x5a,0x01,0x5a,0x5a};//软复位数据
		unsigned char fre_dat[9]={0x40,0x04,0x01,0x00,0x8c,0xa0,0x00,0x00,0x00};//9.216M晶振频率数据
		unsigned char activate_dat[5]={0x40,0x05,0x01,0x00,0x01};//APPL_Activate数据
	
		r = I2C_WriteBuffer(reset_dat, 5);//软复位
    if (r != 1) return r;
		TEF6686_DelayMs(100);
		
    ctrl[0] = 0x1C;
    ctrl[1] = 0x00;
    ctrl[2] = 0x00;

    /* Clear Required Initialization Control */
    r = I2C_WriteBuffer(ctrl, 3);
    if (r != 1) return r;

    /* Set Required Initialization Control (1) */
    ctrl[2] = 0x74;
    r = I2C_WriteBuffer(ctrl, 3);
    if (r != 1) return r;

    /* Load Required Initialization(s): patch */
    r = TEF6686_LoadData(TEF6686_PatchByteValues,sizeof(TEF6686_PatchByteValues));
    if (r != 1) return r;

    /* Clear / Set Required Initialization Control (2) */
    ctrl[2] = 0x00;
    r = I2C_WriteBuffer(ctrl, 3);
    if (r != 1) return r;

    ctrl[2] = 0x75;
    r = I2C_WriteBuffer(ctrl, 3);
    if (r != 1) return r;

    /* Load Required Initialization(s): LUT */
    r = TEF6686_LoadData(TEF6686_LutByteValues,sizeof(TEF6686_LutByteValues));
    if (r != 1) return r;
		
    /* Clear Required Initialization Control, Start Firmware */
    ctrl[2] = 0x00;
    r = I2C_WriteBuffer(ctrl, 3);
    if (r != 1) return r;

    ctrl[0] = 0x14;
		ctrl[1] = 0x00;
    ctrl[2] = 0x01;
    r = I2C_WriteBuffer(ctrl, 3);
    if (r != 1) return r;

    /* Boot state -> Idle state */
    TEF6686_DelayMs(50);

		r=TEF6686_GetCmd(64,128,TEF6686_DAT,2);//读取 APPL module:64 cmd:128 寄存器数据
		if (r != 1) return r; 
		if (TEF6686_DAT[1]==0x00) return 0;//状态模式检测 0=boot state;no command support
		
		//型号版本检测 略
		r = I2C_WriteBuffer(fre_dat, 9);//写入晶振频率数据
    if (r != 1) return r;
		
		r = I2C_WriteBuffer(activate_dat, 5);//写入APPL_Activate数据
    if (r != 1) return r;
		
		TEF6686_DelayMs(100);
		
		r=TEF6686_GetCmd(64,128,TEF6686_DAT,2);//读取 APPL module:64 cmd:128 寄存器数据
		if (r != 1) return r; 
		if (TEF6686_DAT[1]!=0x02) return 0;//状态0x02模式检测
		
    /* FM table includes ReferenceClock + Activate + FM config + volume */
    r = TEF6686_SendTable(TEF6686_set_FM_command,sizeof(TEF6686_set_FM_command));
    if (r != 1) return r;

    /* Idle state -> Active state settle */
    TEF6686_DelayMs(100);

		r=TEF6686_GetCmd(64,128,TEF6686_DAT,2);//读取 APPL module:64 cmd:128 寄存器数据
		if (r != 1) return r; 
		
    return 1;
}

unsigned char TEF6686_SetBand(unsigned char band)
{
    if (band == BAND_FM) {
        return TEF6686_SendTable(TEF6686_set_FM_command,
                                 sizeof(TEF6686_set_FM_command));
    }
    return TEF6686_SendTable(TEF6686_set_AM_command,
                             sizeof(TEF6686_set_AM_command));
}

unsigned char TEF6686_Tune(unsigned char band, unsigned int freq)
{
    unsigned int p[2];

    p[0] = TUNE_MODE_PRESET;
    p[1] = freq;
    return TEF6686_WriteCmd((band == BAND_FM) ? MODULE_FM : MODULE_AM,
                            CMD_TUNE_TO, 2, p);
}

unsigned char TEF6686_SetVolume(int vol)
{
    unsigned int p[1];

    if (vol < -60) vol = -60;
    if (vol > 24) vol = 24;
    p[0] = (unsigned int)(vol * 10);   /* 0.1 dB units */
    return TEF6686_WriteCmd(MODULE_AUDIO, CMD_SET_VOLUME, 1, p);
}

unsigned char TEF6686_Mute(unsigned char on)
{
    unsigned int p[1];

    p[0] = on ? 1 : 0;
    return TEF6686_WriteCmd(MODULE_AUDIO, CMD_SET_MUTE, 1, p);
}

unsigned char TEF6686_GetQualityData(unsigned char band, TEF6686_Quality *q)
{
    unsigned char rx[14];
    unsigned char r;

    r = TEF6686_GetCmd((band == BAND_FM) ? MODULE_FM : MODULE_AM,
                       CMD_GET_QUALITY_DATA, rx, 14);
    if (r != 1) return 0;

    q->status     = ((unsigned int)rx[0] << 8) | rx[1];   /* 时间戳 0.1ms */
    q->level      = (int)(((int)rx[2] << 8) | rx[3]);     /* 0.1 dBuV 有符号 */
    q->usn        = ((unsigned int)rx[4] << 8) | rx[5];   /* 0.1 % */
    q->wam        = ((unsigned int)rx[6] << 8) | rx[7];   /* 0.1 % */
    q->offset     = (int)(((int)rx[8] << 8) | rx[9]);     /* 0.1 kHz 有符号 */
    q->bandwidth  = ((unsigned int)rx[10] << 8) | rx[11]; /* 0.1 kHz */
    q->modulation = ((unsigned int)rx[12] << 8) | rx[13]; /* 0.1 % */
    return 1;
}

/*==================== 软件自动搜台 ======================*/
/* 应用层全局变量前向声明(定义在文件下部) */
static unsigned char CurBand;
static unsigned int  CurFreq;
static unsigned int  FmFreq;
static unsigned int  AmFreq;
static unsigned char TuneMode;

/*
 * 搜台阈值(参考 Tuner_Api.h / Tuner_Api.c Radio_CheckStation):
 *   FM: 场强 level >= 25 dB(即 >=250, 0.1dBuV)
 *       usn < 27% (即 <270) 且 wam < 23% (即 <230)
 *       偏移 offset < 10kHz(|offset| < 100, 0.1kHz)
 *   AM: 仅要求偏移 offset < 1.5kHz(|offset| < 15, 0.1kHz)
 * 电平稳定时间: FM 4ms, AM 36ms(电平可用后再判 usn/wam)。
 */
#define FM_SCAN_LEVEL_100   250   /* 25.0 dBuV */
#define FM_SCAN_USN_100     270   /* 27.0 % */
#define FM_SCAN_WAM_100     230   /* 23.0 % */
#define FM_SCAN_OFFSET_100  100   /* 10.0 kHz */
#define AM_SCAN_OFFSET_100  15    /* 1.5 kHz */

/* 单步进频(带边界回绕),up=1 向上, up=0 向下 */
static unsigned int SeekStepFreq(unsigned char band, unsigned char up, unsigned int f)
{
    if (band == BAND_FM) {
        if (up) {
            if (f + FM_FREQ_STEP > FM_FREQ_MAX) f = FM_FREQ_MIN;
            else f += FM_FREQ_STEP;
        } else {
            if (f < FM_FREQ_MIN + FM_FREQ_STEP) f = FM_FREQ_MAX;
            else f -= FM_FREQ_STEP;
        }
    } else {
        if (up) {
            if (f + AM_FREQ_STEP > AM_FREQ_MAX) f = AM_FREQ_MIN;
            else f += AM_FREQ_STEP;
        } else {
            if (f < AM_FREQ_MIN + AM_FREQ_STEP) f = AM_FREQ_MAX;
            else f -= AM_FREQ_STEP;
        }
    }
    return f;
}

/* 软件搜台:从 CurFreq 起按方向逐步进频并检测;整圈未命中返回 0。
 * 命中后 CurFreq/FmFreq/AmFreq 同步更新并保持调在该台。 */
unsigned char TEF6686_Seek(unsigned char band, unsigned char up)
{
    unsigned int start, f, count;
    unsigned int maxsteps;
    TEF6686_Quality q;

    start = CurFreq;
    f     = CurFreq;
    if (band == BAND_FM)
        maxsteps = (FM_FREQ_MAX - FM_FREQ_MIN) / FM_FREQ_STEP + 2;
    else
        maxsteps = (AM_FREQ_MAX - AM_FREQ_MIN) / AM_FREQ_STEP + 2;

    for (count = 0; count < maxsteps; count++) {
        f = SeekStepFreq(band, up, f);

        TEF6686_Tune(band, f);
        if (band == BAND_FM) {
            TEF6686_DelayMs(34);           /* FM 电平+USN/WAM 稳定 */
            if (!TEF6686_GetQualityData(band, &q)) return 0;
            if (q.level >= FM_SCAN_LEVEL_100 &&
                q.usn   <  FM_SCAN_USN_100   &&
                q.wam   <  FM_SCAN_WAM_100   &&
                q.offset > -FM_SCAN_OFFSET_100 && q.offset < FM_SCAN_OFFSET_100) {
                break;                     /* 命中 */
            }
        } else {
            TEF6686_DelayMs(36);           /* AM 电平稳定 */
            if (!TEF6686_GetQualityData(band, &q)) return 0;
            if (q.offset > -AM_SCAN_OFFSET_100 && q.offset < AM_SCAN_OFFSET_100) {
                break;                     /* 命中 */
            }
        }
    }

    if (count >= maxsteps) {               /* 整圈未命中,回到起始频率 */
        TEF6686_Tune(band, start);
        return 0;
    }

    CurFreq = f;                           /* 停在命中的频率 */
    if (band == BAND_FM) FmFreq = f;
    else                 AmFreq = f;
    return 1;
}

/*----------------------------- RDS -----------------------------------*/

static TEF6686_RDS xdata Rds;   /* RDS 解码结果较大,放扩展 RAM */

TEF6686_RDS *TEF6686_GetRDS(void)
{
    return &Rds;
}

unsigned char TEF6686_PollRDS(unsigned char band)
{
    unsigned char st[2];
    unsigned char dat[12];
    unsigned char r;
    unsigned int status, a, b, c, d;
    unsigned int dec_err;
    unsigned int gt, ver, seg;
    unsigned char ch1, ch2;

    if (band != BAND_FM) return 0;

    r = TEF6686_GetCmd(MODULE_FM, CMD_GET_RDS_STATUS, st, 2);
    if (r != 1) return 0;

    status = ((unsigned int)st[0] << 8) | st[1];
    if ((status & 0x8000) == 0) return 0;   /* 无数据可用 */

    Rds.sync = (status & 0x0200) ? 1 : 0;   /* 位9 = RDS 同步 */

    r = TEF6686_GetCmd(MODULE_FM, CMD_GET_RDS_DATA, dat, 12);
    if (r != 1) return 0;

    a = ((unsigned int)dat[2] << 8) | dat[3];
    b = ((unsigned int)dat[4] << 8) | dat[5];
    c = ((unsigned int)dat[6] << 8) | dat[7];
    d = ((unsigned int)dat[8] << 8) | dat[9];
    dec_err = ((unsigned int)dat[10] << 8) | dat[11];

    /* 块错误计数:dec_error[15:14]=A,[13:12]=B,[11:10]=C,[9:8]=D */
    if (((dec_err >> 14) & 0x03) != 0) Rds.errA++;
    if (((dec_err >> 12) & 0x03) != 0) Rds.errB++;
    if (((dec_err >> 10) & 0x03) != 0) Rds.errC++;
    if (((dec_err >>  8) & 0x03) != 0) Rds.errD++;

    Rds.pi = a;                    /* PI 码在块 A */
    gt  = (b >> 11) & 0x0F;        /* 组类型 0..15(位 14..11) */
    ver = (b >> 15) & 0x01;        /* 0 = A 型, 1 = B 型 */
    Rds.tp  = (b & 0x0400) ? 1 : 0;       /* TP 位 10 */
    Rds.pty = (unsigned char)((b >> 5) & 0x1F); /* PTY 位 9..5 */

    if (gt == 0) {                 /* 组 0:PS 台名 */
        if (ver == 0) {            /* 0A */
            seg = (c >> 8) & 0x03; /* C1/C0 位 9..8 选择 PS 字符对 */
            ch1 = (unsigned char)(d & 0xFF);
            ch2 = (unsigned char)((d >> 8) & 0xFF);
            Rds.ps[seg * 2]     = (ch1 >= 0x20 && ch1 <= 0x7E) ? ch1 : ' ';
            Rds.ps[seg * 2 + 1] = (ch2 >= 0x20 && ch2 <= 0x7E) ? ch2 : ' ';
            Rds.ps[RDS_PS_LEN]  = 0;
            Rds.ta = (b & 0x0010) ? 1 : 0;   /* TA 位 4 */
            Rds.ms = (b & 0x0008) ? 1 : 0;   /* M/S 位 3 */
            if (seg == 3) Rds.ps_ready = 1;
        } else {                   /* 0B:PI 在块 C,段地址在块 B 位 1:0 */
            Rds.pi = c;
            seg = b & 0x03;
            ch1 = (unsigned char)(d & 0xFF);
            ch2 = (unsigned char)((d >> 8) & 0xFF);
            Rds.ps[seg * 2]     = (ch1 >= 0x20 && ch1 <= 0x7E) ? ch1 : ' ';
            Rds.ps[seg * 2 + 1] = (ch2 >= 0x20 && ch2 <= 0x7E) ? ch2 : ' ';
            Rds.ps[RDS_PS_LEN]  = 0;
            Rds.ta = (b & 0x0010) ? 1 : 0;
            Rds.ms = (b & 0x0008) ? 1 : 0;
            if (seg == 3) Rds.ps_ready = 1;
        }
    }
    else if (gt == 2) {            /* 组 2:RT 广播文本 */
        if (ver == 0) {            /* 2A */
            seg = b & 0x0F;
            Rds.rt[seg * 4]     = (unsigned char)(c & 0xFF);
            Rds.rt[seg * 4 + 1] = (unsigned char)((c >> 8) & 0xFF);
            Rds.rt[seg * 4 + 2] = (unsigned char)(d & 0xFF);
            Rds.rt[seg * 4 + 3] = (unsigned char)((d >> 8) & 0xFF);
            Rds.rt[64]          = 0;
            if (seg == 15) Rds.rt_ready = 1;
        } else {                   /* 2B:PI 在块 C */
            Rds.pi = c;
            seg = b & 0x0F;
            Rds.rt[seg * 2]     = (unsigned char)(d & 0xFF);
            Rds.rt[seg * 2 + 1] = (unsigned char)((d >> 8) & 0xFF);
            Rds.rt[64]          = 0;
            if (seg == 31) Rds.rt_ready = 1;
        }
    }
    else if (gt == 3) {            /* 组 3:AF / EON */
        if (ver == 0) {
            unsigned int variant = (c >> 12) & 0x07;  /* 位 14..12 */
            if (variant == 0) {
                /* variant 0:block C 高 8 位 = ECC;
                   block D 高 2 位 = LIC,block D 低字节 = 一个 AF 码 */
                Rds.ecc = (unsigned char)((c >> 8) & 0xFF);
                Rds.lic = (unsigned char)((d >> 14) & 0x03);
                Rds.af[0] = (unsigned char)(d & 0xFF);
                Rds.af_count = 1;
            } else {
                /* variant 1..4:EON 服务的 PI + 4 个 AF 码 */
                Rds.eon_pi = a;
                Rds.eon_pi_valid = 1;
                Rds.af[0] = (unsigned char)((c >> 8) & 0xFF);
                Rds.af[1] = (unsigned char)(c & 0xFF);
                Rds.af[2] = (unsigned char)((d >> 8) & 0xFF);
                Rds.af[3] = (unsigned char)(d & 0xFF);
                Rds.af_count = 4;
            }
        }
    }
    else if (gt == 4) {            /* 组 4:CT 时钟时间 */
        if (ver == 0) {
            Rds.ct_hour  = RDS_BCD((c >> 8) & 0xFF);
            Rds.ct_min   = RDS_BCD(c & 0xFF);
            Rds.ct_day   = RDS_BCD((d >> 6) & 0x3F);
            Rds.ct_month = RDS_BCD((d >> 2) & 0x0F);
            Rds.ct_year  = (unsigned char)(d & 0x03);  /* 仅低 2 位 */
            Rds.ct_valid = 1;
        }
    }
    else if (gt == 15) {           /* 组 15:RT+ */
        if (ver == 0) {
            Rds.rt_plus_type    = (unsigned char)((c >> 10) & 0x3F);
            Rds.rt_plus_start   = (unsigned char)((d >> 12) & 0x0F);
            Rds.rt_plus_len     = (unsigned char)((d >> 6) & 0x3F);
            Rds.rt_plus_running = (unsigned char)((d >> 5) & 0x01);
            Rds.rt_plus_valid   = 1;
        }
    }
    Rds.groups++;
    return 1;
}


/*----------------------------- application state ---------------------*/
/* CurBand/CurFreq/FmFreq/AmFreq/TuneMode 已在搜台段前向声明 */
static int           Volume;
static unsigned char Muted;
static unsigned char SqEnabled;   /* 静噪开关(映射为搜台电平门限) */

void TuneFreq(unsigned char up)
{
    TuneMode = 0;                        /* 手动步进 */
    if (CurBand == BAND_FM) {
        if (up) {
            if (CurFreq + FM_FREQ_STEP > FM_FREQ_MAX) CurFreq = FM_FREQ_MIN;
            else CurFreq += FM_FREQ_STEP;
        }
        else {
            if (CurFreq - FM_FREQ_STEP < FM_FREQ_MIN) CurFreq = FM_FREQ_MAX;
            else CurFreq -= FM_FREQ_STEP;
        }
        FmFreq = CurFreq;
    }
    else {
        if (up) {
            if (CurFreq + AM_FREQ_STEP > AM_FREQ_MAX) CurFreq = AM_FREQ_MIN;
            else CurFreq += AM_FREQ_STEP;
        }
        else {
            if (CurFreq - AM_FREQ_STEP < AM_FREQ_MIN) CurFreq = AM_FREQ_MAX;
            else CurFreq -= AM_FREQ_STEP;
        }
        AmFreq = CurFreq;
    }
    TEF6686_Tune(CurBand, CurFreq);
}

void SwitchBand(void)
{
    if (CurBand == BAND_FM) {
        CurBand = BAND_AM;
        if (AmFreq == 0) AmFreq = AM_FREQ_MIN;
        CurFreq = AmFreq;
    }
    else {
        CurBand = BAND_FM;
        if (FmFreq == 0) FmFreq = FM_FREQ_MIN;
        CurFreq = FmFreq;
    }
    TEF6686_SetBand(CurBand);
    TEF6686_Tune(CurBand, CurFreq);
}

void HandleKey()
{
//    static unsigned int pressTick0, pressTick1;  /* 按下时刻(10ms 单位) */
//   static unsigned char longDone0, longDone1;   /* 长按已触发标志 */

/*		// KEY_UP:短按手动上步进,长按向上自动搜台 
		if (KeySta0 != backup0)
		{  //当前值与前次值不相等说明此时KEY_UP按键有动作
				if(backup0==1)
				{	
					pressTick0 = SysTick;P00=!P00;
					longDone0  = 0;
					TuneFreq(1);//
				}
				else
				{	// 松开:清除长按标志 
					longDone0 = 1;
				}
	 	  	backup0 = KeySta0;//更新备份为当前值,以备进行下次比较
		}
		if (KeySta0 == 0 && !longDone0)
		{	// 长按 500ms(50 * 10ms)触发自动搜台 
			if ((unsigned int)(SysTick - pressTick0) >= 50)
			{
				longDone0 = 1;P01=!P01;
				TuneMode  = 1;
				TEF6686_Seek(CurBand, 1);
			}
		}

		// KEY_DOWN:短按手动下步进,长按向下自动搜台 
		if (KeySta1 != backup1)
		{  //当前值与前次值不相等说明此时KEY_DOWN按键有动作
	    	if(backup1==1)
				{	
					pressTick1 = SysTick;P02=!P02;
					longDone1  = 0;
					TuneFreq(0);
				}
				else
				{
					longDone1 = 1;
				}
	 	  	backup1 = KeySta1;//更新备份为当前值,以备进行下次比较
		}
		if (KeySta1 == 0 && !longDone1)
		{
			if ((unsigned int)(SysTick - pressTick1) >= 50)
			{
				longDone1 = 1;P03=!P03;
				TuneMode  = 1;
				TEF6686_Seek(CurBand, 0);
			}
		}*/
		
		// KEY_UP:短按自动搜台 
		if (KeySta0 != backup0)
		{  //当前值与前次值不相等说明此时KEY_UP按键有动作
				if(backup0==1)
				{	
					TEF6686_Seek(CurBand, 1);
				}
	 	  	backup0 = KeySta0;//更新备份为当前值,以备进行下次比较
		}

		// KEY_DOWN:短按向下自动搜台 
		if (KeySta1 != backup1)
		{  //当前值与前次值不相等说明此时KEY_DOWN按键有动作
	    	if(backup1==1)
				{	
					TEF6686_Seek(CurBand, 0);
				}
	 	  	backup1 = KeySta1;//更新备份为当前值,以备进行下次比较
		}
		
		if (KeySta2 != backup2)
		{  //当前值与前次值不相等说明此时KEY_VOLUP按键有动作
			if(backup2==1)
				{	
					Volume += 5;
					if (Volume > 24) Volume = 24;
					TEF6686_SetVolume(Volume);
				}
					backup2 = KeySta2;//更新备份为当前值,以备进行下次比较
		}
		if (KeySta3 != backup3)
		{  //当前值与前次值不相等说明此时KEY_VOLDN按键有动作
			if(backup3==1)
				{	
					Volume -= 5;
					if (Volume < -60) Volume = -60;
					TEF6686_SetVolume(Volume);
				}
				backup3 = KeySta3;//更新备份为当前值,以备进行下次比较
		}
		if (KeySta4 != backup4)
		{  //当前值与前次值不相等说明此时KEY_BAND按键有动作
			if(backup4==1)
				{	
					SwitchBand();
					TuneMode = 0;   /* 换波段回到手动 */
				}
	 	  	backup4 = KeySta4;//更新备份为当前值,以备进行下次比较
		}
		if (KeySta5 != backup5)
		{  //当前值与前次值不相等说明此时KEY_MUTE按键有动作
			if(backup5==1)
				{	
					Muted ^= 1;
					TEF6686_Mute(Muted);
				}
	 	  	backup5 = KeySta5;//更新备份为当前值,以备进行下次比较
		}
}

void Timer0_Init(void)//2ms
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0xCD;				//设置定时初始值
	TH0 = 0xF8;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;
  EA  = 1;
	
}

void Uart1_Init(void)	//115200bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器时钟1T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xE8;			//设置定时初始值
	TH1 = 0xFF;			//设置定时初始值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
}

void UART_Send_Byte(unsigned char mydata) //串口发送一字节
{
	SBUF=mydata;
	while(!TI);
	TI=0;
}
// 串口发送字符串
void UART_SendString(char *str) {
    while (*str) {
        UART_Send_Byte(*str++);
    }
}
/*==================== UART 状态输出(GBK 中文)=====================*/
/* 发送有符号十进制数 */
void UART_SendNum(int v)
{
    char buf[7];
    char i = 0;
    if (v < 0) { UART_Send_Byte('-'); v = -v; }
    do { buf[i++] = (char)('0' + (v % 10)); v /= 10; } while (v);
    while (i) UART_Send_Byte(buf[--i]);
}
/* 发送 0.1 单位值:v=425 -> "42.5" */
void UART_SendTenth(unsigned int v)
{
    UART_SendNum((int)(v / 10));
    UART_Send_Byte('.');
    UART_Send_Byte((char)('0' + (v % 10)));
}
/* 发送 16 位十六进制 */
void UART_SendHex(unsigned int v)
{
    char i;
    char c;
    for (i = 3; i >= 0; i--) {
        c = (char)((v >> (i * 4)) & 0x0F);
        UART_Send_Byte((c < 10) ? ('0' + c) : ('A' + c - 10));
    }
}
/* 发送 10 格柱条,val/max 比例填充 */
void UART_SendBar(unsigned int val, unsigned int max)
{
    char i;
    char n = 0;
    if (max) n = (char)((val * 10) / max);
    if (n > 10) n = 10;
    for (i = 0; i < 10; i++)
        UART_Send_Byte((i < n) ? '#' : '-');
}

/* 周期调用:输出一行完整状态(GBK 编码中文) */
void UART_SendStatus(void)
{
    TEF6686_Quality q;
    TEF6686_RDS *r;
    unsigned char i;

    if (!TEF6686_GetQualityData(CurBand, &q)) {
        UART_SendString("质量读取失败\r\n");
        return;
    }
    r = TEF6686_GetRDS();

    /* 波段 + 频率(0.01MHz 精度) */
    if (CurBand == BAND_FM) {
        UART_SendString("FM ");
        UART_SendNum((int)(CurFreq / 100));
        UART_Send_Byte('.');
        if ((CurFreq % 100) < 10) UART_Send_Byte('0');
        UART_SendNum((int)(CurFreq % 100));
        UART_SendString("MHz ");
    } else {
        UART_SendString("AM ");
        UART_SendNum((int)CurFreq);
        UART_SendString("kHz ");
    }
		UART_SendString("\r\n");//换行
		
    /* 调谐模式 MAN/AUTO */
    UART_SendString(TuneMode ? "AUTO " : "MAN  ");

    /* 场强 dBuV + 柱条(0..60 dBuV 满格) */
    UART_SendString("场强:");
    if (q.level < 0) {
        UART_Send_Byte('-');
        UART_SendTenth((unsigned int)(0 - q.level));
    } else {
        UART_SendTenth((unsigned int)q.level);
    }
    UART_SendString("dBuV[");
    UART_SendBar((unsigned int)(q.level < 0 ? 0 : q.level), 600);
    UART_Send_Byte(']');
		UART_SendString("\r\n");//换行

    /* 静噪 SQ */
    UART_SendString(" 静噪SQ:");
    UART_SendString(SqEnabled ? "开" : "关");

    if (CurBand == BAND_FM) {
        /* USN/WAM 干扰(0.1%) */
        UART_SendString(" 超声噪声USN:");
        UART_SendTenth(q.usn);
        UART_SendString("% 多径干扰WAM:");
        UART_SendTenth(q.wam);
        UART_SendString("%");
    }
		UART_SendString("\r\n");//换行

    /* 中频偏移(0.1kHz 有符号) */
    UART_SendString(" 偏移:");
    if (q.offset >= 0) UART_Send_Byte('+');
    UART_SendNum((int)q.offset / 10);
    UART_Send_Byte('.');
    UART_Send_Byte((char)('0' + ((q.offset < 0) ? (-q.offset) % 10 : q.offset % 10)));
    UART_SendString("kHz");

    /* 带宽(0.1kHz) */
    UART_SendString(" 带宽:");
    UART_SendNum((int)(q.bandwidth / 10));
    UART_SendString("kHz");
		UART_SendString("\r\n");//换行

    /* 调制度 S/M 双条(0..100% 满格) */
    UART_SendString(" 调制S:");
    UART_SendBar(q.modulation, 1000);
    UART_SendString(" M:");
    UART_SendBar(q.modulation, 1000);
		UART_SendString("\r\n");//换行

    /* RDS 状态(仅 FM) */
    if (CurBand == BAND_FM) {
        UART_SendString(" RDS:");
        UART_SendString(r->sync ? "已锁定" : "未锁定");
				UART_SendString("\r\n");//换行
			
        if (r->ps_ready) {
            UART_SendString(" 电台名PS=");
            UART_SendString((char *)r->ps);
        }
				
        UART_SendString(" 节目类型PTY=");
        UART_SendNum((int)r->pty);
				UART_SendString("\r\n");//换行
				
        UART_SendString(" 交通广播通告TP=");
        UART_SendNum((int)r->tp);
        UART_SendString(" TA=");
        UART_SendNum((int)r->ta);
				UART_SendString("\r\n");//换行
				
        UART_SendString(" 音乐/语音M/S=");
        UART_SendNum((int)r->ms);
				
        UART_SendString(" 节目识别码PI=");
        UART_SendHex(r->pi);
				UART_SendString("\r\n");//换行
				
        if (r->ct_valid) {
            UART_SendString(" 时间信息CT=");
            UART_SendNum((int)r->ct_hour);
            UART_Send_Byte(':');
            if (r->ct_min < 10) UART_Send_Byte('0');
            UART_SendNum((int)r->ct_min);
        }
				UART_SendString("\r\n");//换行
				
        if (r->af_count) {
            UART_SendString(" 电台备选频率AF=");
            for (i = 0; i < r->af_count; i++) {
                if (r->af[i] >= 1 && r->af[i] <= 204) {
                    UART_SendNum((int)(875 + r->af[i]) / 10);
                    UART_Send_Byte('.');
                    UART_Send_Byte((char)('0' + ((875 + r->af[i]) % 10)));
                    UART_SendString("MHz ");
                }
            }
        }
				UART_SendString("\r\n");//换行
				
        if (r->eon_pi_valid) {
            UART_SendString(" EON服务_PI=");
            UART_SendHex(r->eon_pi);
            UART_SendString(" ECC=");
            UART_SendNum((int)r->ecc);
        }
				UART_SendString("\r\n");//换行
				
        if (r->rt_plus_valid) {
            UART_SendString(" RT+[");
            UART_SendNum((int)r->rt_plus_start);
            UART_Send_Byte('+');
            UART_SendNum((int)r->rt_plus_len);
            UART_Send_Byte(']');
        }
				UART_SendString("\r\n");//换行
        if (r->rt_ready) {
            UART_SendString(" RT文本=");
            UART_SendString((char *)r->rt);
        }
				UART_SendString("\r\n");//换行
				
        UART_SendString(" 块错误A:");
        UART_SendNum((int)(r->errA & 0xFF));
        UART_SendString(" B:");
        UART_SendNum((int)(r->errB & 0xFF));
        UART_SendString(" C:");
        UART_SendNum((int)(r->errC & 0xFF));
        UART_SendString(" D:");
        UART_SendNum((int)(r->errD & 0xFF));
    }
    UART_SendString("\r\n");
}
void Timer0_ISR(void) interrupt 1
{
	static unsigned char keybuf [6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//按键扫描缓冲区,保存一段时间内的扫描值
	static cnt=0;
	cnt++;
	if(cnt>=5) //10ms
	{
		cnt=0;
		if(SysTick<65535) SysTick++;//防溢出自加
	}
	/*************************按键扫描***************************/
  keybuf[0] = (keybuf[0]<<1) | KEY_UP;//缓冲区左移一位,并将当前KEY_UP扫描值移入最低位
	keybuf[1] = (keybuf[1]<<1) | KEY_DOWN;//缓冲区左移一位,并将当前KEY_DOWN扫描值移入最低位
	keybuf[2] = (keybuf[2]<<1) | KEY_VOLUP;//缓冲区左移一位,并将当前KEY_VOLUP扫描值移入最低位
	keybuf[3] = (keybuf[3]<<1) | KEY_VOLDN;//缓冲区左移一位,并将当前KEY_VOLDN扫描值移入最低位
	keybuf[4] = (keybuf[4]<<1) | KEY_BAND;//缓冲区左移一位,并将当前KEY2扫描值移入最低位
	keybuf[5] = (keybuf[5]<<1) | KEY_MUTE;//缓冲区左移一位,并将当前KEY3扫描值移入最低位
	
	if 		(keybuf[0] == 0x00) KeySta0 = 0;//连续 8 次扫描值都为 0,即 16ms 内都只检测到按下状态时,可认为KEY_UP按键已按下
	else if (keybuf[0] == 0xFF) KeySta0 = 1;//连续 8 次扫描值都为 1,即 16ms 内都只检测到弹起状态时,可认为KEY_UP按键已弹起
	if 		(keybuf[1] == 0x00) KeySta1 = 0;//连续 8 次扫描值都为 0,即 16ms 内都只检测到按下状态时,可认为KEY_DOWN按键已按下
	else if (keybuf[1] == 0xFF) KeySta1 = 1;//连续 8 次扫描值都为 1,即 16ms 内都只检测到弹起状态时,可认为KEY_DOWN按键已弹起
	if 		(keybuf[2] == 0x00) KeySta2 = 0;//连续 8 次扫描值都为 0,即 16ms 内都只检测到按下状态时,可认为KEY_VOLUP按键已按下
	else if (keybuf[2] == 0xFF) KeySta2 = 1;//连续 8 次扫描值都为 1,即 16ms 内都只检测到弹起状态时,可认为KEY_VOLUP按键已弹起
	if 		(keybuf[3] == 0x00) KeySta3 = 0;//连续 8 次扫描值都为 0,即 16ms 内都只检测到按下状态时,可认为KEY_VOLDN按键已按下
	else if (keybuf[3] == 0xFF) KeySta3 = 1;//连续 8 次扫描值都为 1,即 16ms 内都只检测到弹起状态时,可认为KEY_VOLDN按键已弹起
	if 		(keybuf[4] == 0x00) KeySta4 = 0;//连续 8 次扫描值都为 0,即 16ms 内都只检测到按下状态时,可认为KEY_BAND按键已按下
	else if (keybuf[4] == 0xFF) KeySta4 = 1;//连续 8 次扫描值都为 1,即 16ms 内都只检测到弹起状态时,可认为KEY_BAND按键已弹起
	if 		(keybuf[5] == 0x00) KeySta5 = 0;//连续 8 次扫描值都为 0,即 16ms 内都只检测到按下状态时,可认为KEY_MUTE按键已按下
	else if (keybuf[5] == 0xFF) KeySta5 = 1;//连续 8 次扫描值都为 1,即 16ms 内都只检测到弹起状态时,可认为KEY_MUTE按键已弹起	

}
/* ==========================================
   EC11 编码器轮询扫描函数 (查表法)
   ========================================== */
void EC11_Scan(void)
{
    u8 current_state;
    s8 direction;

    /* 
     * 1. 读取当前A、B相的状态
     * 注意:必须先将 sbit 强转为 u8 才能进行位运算,
     * 否则 Keil C51 会报 invalid left operand type 错误。
     */
    current_state = ((u8)EC11_A << 1) | (u8)EC11_B;

    /* 2. 如果状态没有发生变化,直接返回,节省CPU时间 */
    if (current_state == last_state) 
    {
        return;
    }

    /* 3. 查表获取方向
     * 将上一次的状态左移2位作为高2位,当前状态作为低2位,
     * 组合成一个 0~15 的索引,直接查表。
     */
    direction = EC11_Table[(last_state << 2) | current_state];

    /* 4. 根据查表结果修改数值 */
    if (direction == 1)
    {
        g_value++;
			TuneFreq(1);
    }
    else if (direction == -1)
    {
        g_value--;
			TuneFreq(0);
    }

    /* 5. 更新上一次的状态 */
    last_state = current_state;
}

void IO_Init ()//IO初始化
{
		P0M0 = 0X00; P0M1 = 0X00;
    P1M0 = 0X00; P1M1 = 0X00;
    P2M0 = 0X00; P2M1 = 0X00;
    P3M0 = 0X00; P3M1 = 0X00;
    P4M0 = 0X00; P4M1 = 0X00;
    P5M0 = 0X00; P5M1 = 0X00;
		I2C_SDA = 1;
		I2C_SCL = 1;
		KEY_UP    = 1;
		KEY_DOWN  = 1;
		KEY_VOLUP = 1;
		KEY_VOLDN = 1;
		KEY_BAND  = 1;
		KEY_MUTE  = 1;
		EC11_A = 1;
		EC11_G = 0;
		EC11_B = 1;

}
/* ===================== 主函数 ===================== */
void main(void)
{
	unsigned int lastTick;
//    unsigned char ev;
	uchar i,j;
    WTST = 0;
    EAXFR = 1;
    CKCON = 0;
    IO_Init ();//IO初始化
		S1_S1=0;S1_S0=1;//串口1切换到3.6 3.7
		Uart1_Init();
		EA=1;
		
	/* 初始化:读取当前引脚状态作为初始状态 */
    last_state = ((u8)EC11_A << 1) | (u8)EC11_B;
	
		CurBand  = BAND_FM;
    CurFreq  = FM_FREQ_MIN;
    FmFreq   = FM_FREQ_MIN;
    AmFreq   = 0;
    Volume   = 0;
    Muted    = 0;
    TuneMode = 0;
    SqEnabled = 1;   /* 默认开启静噪(映射搜台电平门限) */

    lastTick = 0;

    Timer0_Init();
		for(i=0;i<16;i++)
		TEF6686_DAT[i]=0;
		
		TEF6686_DelayMs(200);
    TEF6686_Init();
    TEF6686_SetVolume(Volume);
    TEF6686_SetBand(CurBand);
    TEF6686_Tune(CurBand, CurFreq);
    UART_SendString("TEF6686 初始化完成\r\n");
    while(1)
    {
        /* 每 10ms 检查一次状态节拍 */
        if (SysTick != lastTick) {
            lastTick = SysTick;
            if ((SysTick % 10) == 0) {       //每 100ms 轮询一次 RDS
                TEF6686_PollRDS(CurBand);
            }
            if ((SysTick % 100) == 0) {      //每 1s 输出一行完整状态
                UART_SendStatus();
            }
        }

			HandleKey();
      EC11_Scan();//编码器扫描
//		P00=P25;
//		P01=P27;

    }
}


整个程序用到6个按键加一个EC11旋转编码器控制,按键控制上下自动搜台,音量加减,FM/AM中波转换,静音功能,旋转编码器控制0.1MHz步进微调。还没加彩屏驱动,RDS功能还没法验证,因为附近没有带RDS信息的广播台,用了自制的si4713发送rds信息,已确定能解码出电台名和PI码。
DIY爱好者可以拿去试用改编。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐