打算设计一台单片机控制的红外线遥控前级 设计构想如下: 直流化的设计,完全没有交藕电容,即使音源带有数十毫伏的直流也能保证输出端直流电压接近零。 模拟开关芯片选择输入信号,最多八组二声道音源。 平衡或非平衡输入缓冲级。 音量控制采用12位元带反相功能的四象限乘法(four quadrant multiplication) 数字/模拟转换器 DAC。 可以用遥控以数码方式把信号反相来纠正一些错误的录音。 对不同平均幅度的音源进行数码自动音量调整(ALC),因为俺受够了不同电视节目音量忽大忽小的折腾,当然此功能在不需要时可以关闭。 开机延时和音源信号消失超于设定时间有自动关机功能(包括外接机器如功放,CD机,DVD 等)。 七画LED屏显示音源选择和音量位置,不需要时可以自动把扫描关闭以降低数码噪音。 有自学能力的红外线接收器,方便不同编码的各类型不同牌子的遥控器使用。 PWM 测试信号发生器,方便测试和观察放大器的输出波形。 使用ZILOG Encore!XP Z8F 单片机控制。 希望有兴趣跟帖的朋友可以从整个制作过程中学到一些新的知识,如 1. 模拟开关芯片的应用 2. 乘法数字/模拟转换器当音量调节使用(不是一般常用的数字电位器芯片如PGA2310, CS3310 等) 3. 数码自动音量调整 4. 信号消失自动关机功能 5. 自学功能的红外线接收 6. 用程序和PWM 当函数发生器 7. 单片机在音响的应用和如何编写单片机语言等等。 在未来几个月之内俺会依据进度把各部分已完成的程序发上来与各位共享。 图看不全的话清按着<Ctrl> 再用老鼠的滚轮 ![]() ![]() 因为手头上刚好有几个十多年前用剩的 AD 芯片,AD 芯片的最大好处是里面的电阻是薄膜的,质量应该比专用电子电位器里的半导体电阻优秀。 音源切换不用继电器因为担心在大音量超低音震动下会出现触点弹跳,用芯片切换另一好处是体积小而外部噪音干扰较低。 也考虑过用液晶显示,不过几米以外就看不清楚了,所以最后决定用LED。 俺是海外的,这个前级也是为上海的一个朋友设计的,开板子的事就由国内的朋友来办吧,俺会尽全力配合。 俺认为输入400欧姆的导通电阻影响是很微小的,假设它本身带给了0.01%的失真,但是在66K的总输入阻抗中只占有不到百分之一的比例,所以最后影响还不到0.0001%。它对输入阻抗和增益的影响也因为是平衡输入的切换而大部分被抵消了。 输入端的钳位二极管是必须的,否则芯片会轻易的被外面的静电或脉冲干扰所击毁,不过这二极管是钳位到正负15伏电源的,对峰值顶多是5伏的输入信号是不产生作用的,二极管几个pF的极电容还可以对射频过滤有一定的帮助。 开始动手在俺这儿开电路板需费一百多美金,这里又没有烧友同好分享,所以就找了一块两年前工程用剩的LED显示板,用洞洞板把主要元件焊了上去,再加上电源和外部接线就可以了。先写了LED屏的扫描部分,过些日子有空时再编写控制程序,然后就可以测试各种功能了。 ![]() ![]() ![]() 显示屏扫描子程序;每一毫秒调用一次 ;江文正,2007-08-15 .include "eZ8.inc" segment code xref _readbut ;读取按键 xref _DigCtr ;位数计 xref _DplDuty ;亮度占空比 xref _DplFlag ;bit0 = 闪烁, bit1 = 自动音量, bit2 = 切换, bit3 = 测试,bit4 = 设置遥控码 xref _FuncNr ;功能选择 xref _Volume ;音量 xref _ChNr ;输入切换号码 xdef _shiftdpl ;移位刷屏 ;================================================= ; 引脚定义 data1 equ PBOUT ![]() data1_0 equ 11111110B ![]() data1_1 equ 00000001B ![]() stb1 equ PBOUT ![]() stb1_0 equ 11111101B ![]() stb1_1 equ 00000010B ![]() clk1 equ PCOUT ![]() clk1_0 equ 01111111B ![]() clk1_1 equ 10000000B ![]() minus_0 equ 00010000B ;-0 minus_1 equ 00111000B ;-1 ;7 段显示笔画定仪表指针 seg_ptr:; FABGCD.E .BYTE 11101101B ;0 .BYTE 00101000B ;1 .BYTE 01110101B ;2 .BYTE 01111100B ;3 .BYTE 10111000B ;4 .BYTE 11011100B ;5 .BYTE 11011101B ;6 .BYTE 01101000B ;7 .BYTE 11111101B ;8 .BYTE 11111100B ;9 .BYTE 11111001B ;A .BYTE 11000101B ;C .BYTE 00111101B ;d .BYTE 10010101B ;t .BYTE 10101101B ;U .BYTE 10100100B ;V SegBuf equ R5 DigPos equ R4 ;====================================== _shiftdpl: CP _DigCtr,#05 JR ULT,$F inc _DplDuty cp _DplDuty,#4 ;此数用于调节亮度 JR ugt,$F ret#p#分页标题#e# $$: clr _DplDuty ; call __readbut push R0 ;如果只有 C 语言调用此子程序,进栈和退栈部分可以抹掉 push R1 ; push R2 ; push R3 push R4 push R5 ; LD DigPos,#00000001B CPX _DigCtr,#05 JR ULT,NX_DIG LDX _DigCtr,#0 NX_DIG ADDX _DigCtr,#1 LDX R0,_DigCtr $$: RR DigPos djnz R0,$B LDX SegBuf,_Volume cpx _DigCtr,#03 jr ult,$F LDX SegBuf,_ChNr $$: TMX _DigCtr,#1 JR NZ,LSD SWAP SegBuf ;若是偶数,左右四比特对换 LSD AND SegBuf,#0FH ;淹没左四比特 LD R0, #high(seg_ptr) ;画段指针 LD R1, #low(seg_ptr) ; ADD R1,SegBuf ;加上错位 ADC R0,#0 LDC SegBuf,@RR0 ;从画段表获取数据 cpx _FuncNr,#0 jr ne,$F cpx _DigCtr,#3 ;显示音量时第三位数空白 jr eq,blank $$: cpx _DigCtr,#05 jr ult,$F blank clr SegBuf ;灭显示 $$: LD R3,SegBuf ;输出画段 COM R3 ;低电平驱动 CALL OUT_BYTE LD R3,DigPos ;输出位数 CALL OUT_BYTE ORX stb1,#stb1_1 ;转移数据 NOP NOP NOP ANDX stb1,#stb1_0 ANDX data1,#data1_0 andx _DplFlag,#%FE ;标记处理完毕 pop R5 ;如果只有 C 语言调用此子程序,进栈和退栈部分可以抹掉 pop R4 pop R3 pop R2 pop R1 pop R0 RET OUT_BYTE ;串移数据 LD R2,#08 ;8 比特 SFT_LP ANDX data1,#data1_0 RL R3 JR NC,CLKING ORX data1,#data1_1 CLKING ;输出一个时钟脉冲 NOP NOP NOP ORX clk1,#clk1_1 NOP NOP NOP ANDX clk1,#clk1_0 DJNZ R2,SFT_LP RET ;-------------------------------------------- 刚完成了采用 NEC 波形的读码部分,改天再写飞利浦波形的。 ; 汇编部分,中断子程序 vector C3=_isr_C3; 红外线, 下降沿, _isr_C3: tmx PCIN,#%08 ; 只取下降沿 jr nz,c3_x ldx _width,T1H ; 一次 = 92.23uS#p#分页标题#e# ldx T1H,#%0 ; 定时器重新置零 orx _ir_flag,#1 ; 标记收到红外线信号 c3_x iret ;============================================================= vector TIMER1=_isr_T1 ;23.52mS _isr_T1: ; ldx _step_ctr,#0 ; 无红外线信号空挡,步骤置零 iret //C 语言部分 //////////////////////////////////////////////////////// // NEC uPD6121 波形 红外线读码 2007-08-23 江文正 // 方法 : 接收管输出下降沿触发中断子程序,读取下降沿之间的时间 width 后把定时器重新置零 // width 单位= 92.23uS, 前提是 定时器时钟 = 5.5296 MHz, prescale = 2 // 两个下降沿之间时段: 引导码, >11.81mS : width=128 // 重复码, >9mS : width=97 // >1.69mS : width=18 = 高电平数据, <1.69mS : width=18 = 低电平数据 IR_decode() { char rcv_8bit=0; int rcv_16bit=0; ir_flag &= 0xFE; //标记已处理 if (step_ctr ==0) { step_ctr=1; //开始 } else { if (width > 128) //引导码 { step_ctr=2; user_code=0; // 清0 cmd_code=0; // 清0 } else { if (width > 97) //重复码 { step_ctr=34; // } else { if (width > 18) //高电平 { rcv_8bit=1; rcv_16bit=1; } if (step_ctr<18) //用户码 { rcv_16bit = rcv_16bit << (step_ctr-1); user_code |= rcv_16bit; } else { if (step_ctr<26) //控制码 { rcv_8bit = rcv_8bit << (step_ctr-17); cmd_code |= rcv_8bit; } } if (step_ctr>25) //反码 { rcv_8bit = rcv_8bit << (step_ctr-25); comp_code |= rcv_8bit; } step_ctr++; if (step_ctr>33) //有效码 { comp_code ^= 0xFF; //2反位,2'complement comp_code--; if (cmd_code != comp_code) { step_ctr = 0; //错码,无效 } } } } } } 大部分国内生产的遥控器都使用NEC码,你先按照提示找出你手中遥控器的用户码,然后再找出你所想使用的那几个按键的功能码,再把这些码取代以下的部分 //所用遥控器的控制码, 不同遥控器的码会不一样 #define user 0xFF00;// 用户码 #define vol_up 0x58; // 增音量 <vol +> 按键 #define vol_dn 0x59; // 减音量 <vol -> 按键 #define ch_up 0x4A; // 下一个切换位置 <tune +> 按键 #define ch_dn 0x1E; // 前一个切换位置 <tune -> 按键 #define mute 0x46; // 静音 <mute> 按键 #define pwr 0x40; // 电源开关 <pwr> 按键#p#分页标题#e# #define anti 0x0E; // 左声道反相 <mode> 按键 #define agc 0x1C; // 自动音量 <audio> 按键 #define off_tmr 0x49; // 自动关机 <timer> 按键 请注意接收管输出必须接到有下降沿中断功能的 I/O 引脚, 附件是俺目前正在使用的源代码,有些部分俺同时写了C和汇编的,只需选用需要的部分就可以了,俺是使用荧光真空显示模块(VFD)的.LED显示部分的代码也有了,如果要使用LCD模块,俺可以替你们写,不过I/O接线会多一些,18 或 20 条腿的单片机也许不够用,要用28条腿以上的。 遥控前级.rar ![]() (责任编辑:admin) |