前些天在自己的車上改裝了一個音頻切換電路,由于音頻信號是雙聲道,就必須要一個雙刀雙擲的開關來進行切換,但現在雙刀雙擲的開關已經很少了,再者安裝不方便于是就有了這個小電路。花了20分鐘寫了個小程序,測試了一下效果很不錯,價格也和好點的雙刀雙擲開關差不太多。
電路:
實際電路:
來個背面圖,簡潔小巧
功能:上電先調用上次單片機內部EEPROM中的數據控制繼電器是開或關,按鍵按下后把數據取反送入內部EEPROM進行保存,方便下次開機調用。
程序如下:
#include "reg51.h" #include "intrins.h" typedef unsigned char BYTE; typedef unsigned int WORD; /*---------------------------------------------------------------------*/ /*-- 端口定義 ---------------------------------------*/ /*---------------------------------------------------------------------*/ sbit SWITCH = P3^2; sbit LED = P3^4; /*---------------------------------------------------------------------*/ /*-- 變量定義 ---------------------------------------*/ /*---------------------------------------------------------------------*/ bit flag,BUTTON_TEMP; //----------------------------------------------- sfr IAP_DATA = 0xC2; //IAP數據寄存器 sfr IAP_ADDRH = 0xC3; //IAP地址寄存器高字節 sfr IAP_ADDRL = 0xC4; //IAP地址寄存器低字節 sfr IAP_CMD = 0xC5; //IAP命令寄存器 sfr IAP_TRIG = 0xC6; //IAP命令觸發寄存器 sfr IAP_CONTR = 0xC7; //IAP控制寄存器 sfr WDT_CONTR = 0xC1; //0000,0000 看門狗控制寄存器 #define CMD_IDLE 0 //空閑模式 #define CMD_READ 1 //IAP字節讀命令 #define CMD_PROGRAM 2 //IAP字節編程命令 #define CMD_ERASE 3 //IAP扇區擦除命令 #define ENABLE_IAP 0x83 //if SYSCLK<12MHz #define BUTTON_ADDRESS 0x0100 //測試地址 /*---------------------------- 關閉IAP ----------------------------*/ void IapIdle() { IAP_CONTR = 0; //關閉IAP功能 IAP_CMD = 0; //清除命令寄存器 IAP_TRIG = 0; //清除觸發寄存器 IAP_ADDRH = 0x80; //將地址設置到非IAP區域 IAP_ADDRL = 0; } /*---------------------------- 從ISP/IAP/EEPROM區域讀取一字節 ----------------------------*/ BYTE IapReadByte(WORD addr) { BYTE dat; //數據緩沖區 IAP_CONTR = ENABLE_IAP; //使能IAP IAP_CMD = CMD_READ; //設置IAP命令 IAP_ADDRL = addr; //設置IAP低地址 IAP_ADDRH = addr >> 8; //設置IAP高地址 IAP_TRIG = 0x5a; //寫觸發命令(0x5a) IAP_TRIG = 0xa5; //寫觸發命令(0xa5) _nop_(); //等待ISP/IAP/EEPROM操作完成 dat = IAP_DATA; //讀ISP/IAP/EEPROM數據 IapIdle(); //關閉IAP功能 return dat; //返回 } /*---------------------------- 寫一字節數據到ISP/IAP/EEPROM區域 ----------------------------*/ void IapProgramByte(WORD addr, BYTE dat) { IAP_CONTR = ENABLE_IAP; //使能IAP IAP_CMD = CMD_PROGRAM; //設置IAP命令 IAP_ADDRL = addr; //設置IAP低地址 IAP_ADDRH = addr >> 8; //設置IAP高地址 IAP_DATA = dat; //寫ISP/IAP/EEPROM數據 IAP_TRIG = 0x5a; //寫觸發命令(0x5a) IAP_TRIG = 0xa5; //寫觸發命令(0xa5) _nop_(); //等待ISP/IAP/EEPROM操作完成 IapIdle(); } /*---------------------------- 扇區擦除 ----------------------------*/ void IapEraseSector(WORD addr) { IAP_CONTR = ENABLE_IAP; //使能IAP IAP_CMD = CMD_ERASE; //設置IAP命令 IAP_ADDRL = addr; //設置IAP低地址 IAP_ADDRH = addr >> 8; //設置IAP高地址 IAP_TRIG = 0x5a; //寫觸發命令(0x5a) IAP_TRIG = 0xa5; //寫觸發命令(0xa5) _nop_(); //等待ISP/IAP/EEPROM操作完成 IapIdle(); } /*---------------------------------------------------------------------*/ /*-- 延時子程序 ---------------------------------------*/ /*---------------------------------------------------------------------*/ void DELAY_1MS(unsigned int z) { unsigned char i, j,k; for(k=z;k>0;k--) { _nop_(); _nop_(); _nop_(); i = 11; j = 190; do { while (--j); } while (--i); } } /*---------------------------------------------------------------------*/ /*-- 主程序 ---------------------------------------*/ /*---------------------------------------------------------------------*/ void main() { flag=0; WDT_CONTR = 0x35; //啟動看門狗 while (1) { WDT_CONTR = 0x35; //啟動看門狗 if(flag==0) { if(IapReadByte(BUTTON_ADDRESS)==0) { LED=1; } else if(IapReadByte(BUTTON_ADDRESS)==1) LED=0; else { IapEraseSector(BUTTON_ADDRESS); IapProgramByte(BUTTON_ADDRESS,BUTTON_TEMP); } flag=1; } if(SWITCH==0) { DELAY_1MS(20); if(SWITCH==0) { while(!SWITCH); flag=0; BUTTON_TEMP=!BUTTON_TEMP; IapEraseSector(BUTTON_ADDRESS); IapProgramByte(BUTTON_ADDRESS,BUTTON_TEMP); } } } }