#define io_74hc165_SH_LD P1_0 //硬件设置 #define io_74hc165_CLK P1_1 #define io_74hc165_SDA P1_2 #define io_74hc164_SCK P1_3 #define io_74hc164_SDA P1_4 #ifndef RW_DEFINED #define RW_DEFINED void _snop_() { } #endif //Crystal at 12.0MHz 1MIPS #define I2C_SDA P3_2 // 将p3.2口模拟数据口,必须要这样。中断接受数据 #ifdef I2C_SCL #else #define I2C_SCL P1_6 // 将p1.1口模拟时钟口,默认 #endif #ifdef SlaveAddress #else #define SlaveAddress 0x02 //地址 #endif #ifdef MasterAddress #else #define MasterAddress 0x01 //主机地址 #endif #define delayNOP(); {_snop_();_snop_();_snop_();_snop_();}; unsigned char s_control; unsigned char s_note; unsigned char s_svel; bit nm; bit SystemError; // 从机错误标志位 //-------------------------------------------------------------------------------------------------- // 函数名称: iic_start() // 函数功能: 启动I2C总线子程序 //-------------------------------------------------------------------------------------------------- void iic_start(void) { EA=0; //时钟保持高,数据线从高到低一次跳变,I2C通信开始 I2C_SDA = 1; I2C_SCL = 1; delayNOP(); // 延时5us I2C_SDA = 0; delayNOP(); I2C_SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: iic_stop() // 函数功能: 停止I2C总线数据传送子程序 //-------------------------------------------------------------------------------------------------- void iic_stop(void) { I2C_SDA = 0; //时钟保持高,数据线从低到高一次跳变,I2C通信停止 I2C_SCL = 1; delayNOP(); I2C_SDA = 1; delayNOP(); I2C_SCL = 0; EA=1; } //-------------------------------------------------------------------------------------------------- // 函数名称: slave_ACK // 函数功能: 从机发送应答位子程序 //-------------------------------------------------------------------------------------------------- void slave_ACK(void) { I2C_SDA = 0; I2C_SCL = 1; delayNOP(); I2C_SDA = 1; I2C_SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: slave_NOACK // 函数功能: 从机发送非应答位子程序,迫使数据传输过程结束 //-------------------------------------------------------------------------------------------------- void slave_NOACK(void) { I2C_SDA = 1; I2C_SCL = 1; delayNOP(); I2C_SDA = 0; I2C_SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: check_ACK // 函数功能: 主机应答位检查子程序,迫使数据传输过程结束 //-------------------------------------------------------------------------------------------------- void check_ACK(void) { I2C_SDA = 1; // 将p1.0设置成输入,必须先向端口写1 I2C_SCL = 1; F0 = 0; if(I2C_SDA == 1) // 若I2C_SDA=1表明非应答,置位非应答标志F0 F0 = 1; I2C_SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: IICSendByte // 入口参数: ch // 函数功能: 发送一个字节 //-------------------------------------------------------------------------------------------------- void IICSendByte(unsigned char ch) { unsigned char idata n=8; // 向I2C_SDA上发送一位数据字节,共八位 while(n--) { if((ch&0x80) == 0x80) // 若要发送的数据最高位为1则发送位1 { I2C_SDA = 1; // 传送位1 I2C_SCL = 1; delayNOP(); I2C_SDA = 0; I2C_SCL = 0; } else { I2C_SDA = 0; // 否则传送位0 I2C_SCL = 1; delayNOP(); I2C_SCL = 0; } ch = ch<<1; // 数据左移一位 } } //-------------------------------------------------------------------------------------------------- // 函数名称: IICreceiveByte // 返回接收的数据 // 函数功能: 接收一字节子程序 //-------------------------------------------------------------------------------------------------- unsigned char IICreceiveByte(void) { unsigned char idata n=8; // 从I2C_SDA线上读取一上数据字节,共八位 unsigned char tdata=0; while(n--) { I2C_SDA = 1; I2C_SCL = 1; tdata = tdata<<1; // 左移一位,或_crol_(temp,1) if(I2C_SDA == 1) tdata = tdata|0x01; // 若接收到的位为1,则数据的最后一位置1 else tdata = tdata&0xfe; // 否则数据的最后一位置0 I2C_SCL=0; } return(tdata); } bit IICwaitACK() { //10us不属于超时 unsigned char i=0; bit j=0; I2C_SDA=1;//输入状态 while (i!=10) { if (I2C_SCL==1) //先SCL=1 SDA=0后SCL=0 SDA=1 { j=1; break; } i++; } return j; }[page] //-------------------------------------------------------------------------------------------------- // 函数名称: slavesenddata // 入口参数: control,note and vel // 函数功能: 发送MIDI信息在IIC总线上 //-------------------------------------------------------------------------------------------------- //保证Simple.不使用标准I2C协议。 发送从机地址,等ACK,再发送发送3byte数据,等ACK.It 's very simple. void slavesenddata(unsigned char control,unsigned char note,unsigned char svel) { EA=0; IT0=0; //外中断0为 下降沿触发 设定成低电平出发的话 容易导致 误触发 EX0=0; //开外部中断0 iic_start(); SystemError=1; IICSendByte(SlaveAddress);//发送地址 if (IICwaitACK()) //等主机的回应 { IICSendByte(control); IICSendByte(note); IICSendByte(svel); if (IICwaitACK()) //等主机的回应 { SystemError=0; } } iic_stop(); IT0=1; //地址不对就不去管了 EX0=1; //开中断继续 EA=1; } void initial_i2c() { IT0=1; //外中断0为 下降沿触发 设定成低电平出发的话 容易导致 误触发 EX0=1; //开外部中断0 EA=1; } void recvint0() interrupt 0 using 2 { unsigned char mAddress=0; EA=0; IT0=0; // EX0=0; //关中断防止干扰 //slave_ACK(); mAddress=IICreceiveByte(); if (mAddress==MasterAddress) { slave_ACK(); s_control=IICreceiveByte(); s_note=IICreceiveByte(); s_svel=IICreceiveByte(); nm=1; //提示主程序有新的消息,请注意查收~ } else {//延时,不能这样退出去引发中断 //ACK占用两个周期,接受数据占用10个周期。延够时了就跑 delayNOP(); delayNOP(); delayNOP(); delayNOP(); delayNOP(); delayNOP(); delayNOP(); delayNOP(); } IT0=1; //地址不对就不去管了 EX0=1; //开中断继续 EA=1; } //下面是引脚的连接以及相关必要的宏定义 //Crystal at 12MHz #ifdef io_74hc165_SH_LD #else #define io_74hc165_SH_LD P1_0 //默认设置 #endif #ifdef io_74hc165_CLK #else #define io_74hc165_CLK P1_1 #endif #ifdef io_74hc165_SDA #else #define io_74hc165_SDA P1_2 #endif #define io_74hc165_SH_HIGH io_74hc165_SH_LD=1; #define io_74hc165_SH_LOW io_74hc165_SH_LD=1; #ifdef io_74hc164_SCK #else #define io_74hc164_SCK P1_3 #endif #ifdef io_74hc164_SDA #else #define io_74hc164_SDA P1_4 #endif #define IO_74HC164_SCK_HIGH io_74hc164_SCK = 1 ; #define IO_74HC164_SCK_LOW io_74hc164_SCK = 0 ; #define IO_74HC164_SDA_INPUT io_74hc164_SDA //使用165来接受键盘数据。两片作为164输出。 #define uint8 unsigned char #define uchar unsigned char #define uint unsigned int uchar keytype=2; //#define keytype 2 #define blacklist_time 240 uchar kbtime=0; //记录时间,占2个字节 uchar keynumber[2][7]; //记录键位,占14个字节 uchar blacklist[7]; //uchar code seg[]={"admin"}; /*0->NoTouch Response 1->Very Soft Touch Response 2->Soft Touch Response 3->Medium Touch Response 4->Hard Touch Response 5->Very Hard Touch Response */ uchar code vel[5][251]= { {//Very Soft 127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,126,126,125,124,124,123,122,122,121,120,120,119,118,118,117,116,116,115,114,114,113,112,112,111,110,110,109,108,108,107,106,106,105,104,104,103,102,102,101,100,100,99,98,98,97,96,96,95,94,94,93,92,92,91,90,90,89,88,88,87,86,86,85,84,84,83,82,82,81,80,80,79,78,78,77, 76,76,75,74,74,73,72,72,71,70,70,69, 68,68,67,66,66,65,64,64,63,62,62,61, 60,60,59,58,58,57,56,56,55,54,54,53, 52,52,51,50,50,49,48,48,47,46,46,45, 44,44,43,42,42,41,40,40,39,38,38,37, 36,36,35,34,34,33,32,32,31,30,30,29, 28,28,27,26,26,25,24,24,23,22,22,21, 20,20,19,18,18,17,16,16,15,14,14,13, 12,12,11,10,10,9,8,8,7,6,6,5, 4,4,3,2,2,1,0 } , {//Soft 127,127,127,127,127,127,127,127,127, 127,127,127,127,127,127,127,127,127, 127,127,127,127,127,127,127,127,127, 127,127,127,127,127,127,127,127,126, 125,125,124,124,123,122,122,121,121, 120,120,119,118,118,117,117,116,115, 115,114,114,113,112,112,111,111,110, 110,109,108,108,107,107,106,105,105, 104,104,103,102,102,101,101,100,100, 99,98,98,97,97,96,95,95,94,94,93,92, 92,91,91,90,90,89,88,88,87,87,86,85, 85,84,84,83,82,82,81,81,80,80,79,78, 78,77,77,76,75,75,74,74,73,72,72,71, 71,70,70,69,68,68,67,67,66,65,65,64, 64,63,62,62,61,61,60,60,59,58,58,57, 57,56,55,55,54, 54,53,52,52,51,51,50,50,49,48,48,47, 47,46,45,45,44,44,43,42,42,41,41,40, 40,39,38,38,37,37,36,35,35,34,34,33, 32,32,31,31,30,30,29,28,28,27,27,26, 25,25,24,24,23,22,22,21,21,20,20,19, 18,18,17,17,16,15,15,14,14,13,12,12, 11,11,10,10,9,8,8,7,7,6,5,5, 4,4,3,2,2,1,1,0 } , {//Medium 127,127,127,127,127,127,127,127,127, 126,126,125,125,124,124,123,123,122, 122,121,121,120,120,119,118,118,117, 117,116,116,115,115,114,114,113,113, 112,112,111,111,110,110,109,108,108, 107,107,106,106,105,105,104,104,103, 103,102,102,101,101,100,100,99,98,98, 97,97,96,96,95,95,94,94,93,93,92,92, 91,91,90,90,89,88,88,87,87,86,86,85, 85,84,84,83,83,82,82,81,81,80,80,79, 78,78,77,77,76,76,75,75,74,74,73,73, 72,72,71,71,70,70,69,68,68,67,67,66, 66,65,65,64,64,63,63,62,62,61,61,60, 60,59,58,58,57,57,56,56,55,55,54,54,53, 53,52,52,51,51,50,50,49,48,48,47,47, 46,46,45,45,44,44,43,43,42,42,41,41, 40,40,39,38,38,37,37,36,36,35,35,34, 34,33,33,32,32,31,31,30,30,29,28,28, 27,27,26,26,25,25,24,24,23,23,22,22, 21,21,20,20,19,18,18,17,17,16,16,15, 15,14,14,13,13,12,12,11,11,10,10,9, 8,8,7,7,6,6,5,5,4,4,3,3, 2,2,1,1,0 } , {//Hard 100,99,99,98,98,98,97,97,96,96,96,95, 95,94,94,94,93,93,92,92,92,91,91,90, 90,90,89,89,88,88,88,87,87,86,86,86, 85,85,84,84,84,83,83,82,82,82,81,81, 80,80,80,79,79,78,78,78,77,77,76,76, 76,75,75,74,74,74,73,73,72,72,72,71, 71,70,70,70,69,69,68,68,68,67,67,66, 66,66,65,65,64,64,64,63,63,62,62,62, 61,61,60,60,60,59,59,58,58,58,57,57, 56,56,56,55,55,54,54,54,53,53,52,52, 52,51,51,50,50,50,49,49,48,48,48,47, 47,46,46,46,45,45,44,44,44,43,43, 42,42,42,41,41,40,40,40,39,39,38,38, 38,37,37,36,36,36,35,35,34,34,34,33, 33,32,32,32,31,31,30,30,30,29,29,28, 28,28,27,27,26,26,26,25,25,24,24,24, 23,23,22,22,22,21,21,20,20,20,19,19, 18,18,18,17,17,16,16,16,15,15,14,14, 14,13,13,12,12,12,11,11,10,10,10,9, 9,8,8,8,7,7,6,6,6,5,5,4, 4,4,3,3,2,2,2,1,1,0,0 } , {//Very Hard 92,92,91,91,91,90,90,90,89,89,88,88, 88,87,87,87,86,86,85,85,85,84,84,84, 83,83,82,82,82,81,81,81,80,80,80,79, 79,78,78,78,77,77,77,76,76,75,75,75, 74,74,74,73,73,72,72,72,71,71,71,70, 70,70,69,69,68,68,68,67,67,67,66,66, 65,65,65,64,64,64,63,63,62,62,62,61, 61,61,60,60,59,59,59,58,58,58,57,57, 57,56,56,55,55,55,54,54,54,53,53,52, 52,52,51,51,51,50,50,50,49,49,48,48, 48,47,47,47,46,46,45,45,45,44,44,44, 43,43,42,42,42,41,41,41,40,40,40,39, 39,38,38,38,37,37,37,36,36,35, 35,35,34,34,34,33,33,32,32,32,31,31, 31,30,30,29,29,29,28,28,28,27,27,27, 26,26,25,25,25,24,24,24,23,23,22,22, 22,21,21,21,20,20,20,19,19,18,18,18, 17,17,17,16,16,15,15,15,14,14,14,13, 13,12,12,12,11,11,11,10,10,10,9,9, 8,8,8,7,7,7,6,6,5,5,5,4, 4,4,3,3,2,2,2,1,1,1,0,0 } }; uchar count_begin[7][7]; //记录按键时间,占49个字节 //在钢琴上压键时间大于500mS可以几乎认为是没有力度了啊 //VIO //VIO程序开始。 void v_74hc164WriteData_f( uint8 Dat ) //向74HC164写一个字节的内容 { //即可并行输出该字节 uint8 i = 0 ; uint8 SendData = Dat ; for( i = 8 ; i > 0 ; i-- ) { IO_74HC164_SCK_LOW SendData <<= 1 ; IO_74HC164_SDA_INPUT = CY ; IO_74HC164_SCK_HIGH } } uchar v_74hc165ReadData_f() { uchar i,c=0x00; for (i=0;i<8;i++) { c<=1; //0000 0010 if(io_74hc165_SDA) {c=c|0x01;} io_74hc165_CLK=0; //下降沿有效 io_74hc165_CLK=0; io_74hc165_CLK=1; //进位 } return c; } //VIO结束 /* 74HC1651 BIT1~8 KB DATA 1~8 74HC1652 BIT1~8 KB DATA 9~16 74HC5952 BIT1~8 KB CS 1~8 */ void initial_clock() { TMOD=0x00; TH0=0x10; TL0=0xC1; PCON=0x80; } /* MIDI命令简表 命令代码 (cc) 命令说明 数据kk含义及说明 数据vv含义及说明 8+ 通道号 关闭音符 对应的MIDI音符0-127 关闭音符的速度值 9+ 通道号 开启音符 对应的MIDI音符0-127 压下琴键的速度值(力度) A+ 通道号 触后压力 对应的MIDI音符0-127 对应音符的触后压力值 B+ 通道号 控制器 控制器号0-77 77-7F为通道模式信息 控制器值 C+ 通道号 音色切换 音色号 0-127 无该字节数据 D+ 通道号 通道压力 该通道全部键盘的触后压力 无该字节数据 E+ 通道号 弯音轮 弯音轮低位数据 弯音轮高位数据 F 系统普通信息、实时信息、及高级信息代码 忽略 忽略 */[page] void initial_keyboard() //初始化键盘 { v_74hc164WriteData_f(0x00);//关掉后排段选 v_74hc164WriteData_f(0x00);//关掉前排段选 } //keynumber[0]定义为第一排 //keynumber[1]定义为第二排 void scan_key() { uchar ts=0; //开始的时间 uchar kb_cs; // 段选 uchar i=0; uchar j=0; //循环变量 uchar outa=0; uchar outb=0; uchar csp; uchar lkb,hkb; uchar atime; uchar temp;//临时 kb_cs=0x01; //00000001 00000010 while (i!=8) { ts=kbtime; v_74hc164WriteData_f(0x00);//关掉前排段选 v_74hc164WriteData_f(kb_cs);//输出后排段选 //高在前,低在后 //以下代码输出下排力度检测的信号 io_74hc165_SH_HIGH //拉高并行置数 outa=v_74hc165ReadData_f(); //读入输出 io_74hc165_SH_LOW //拉低并行置数 //结束,以下代码输出前排检测开关的信号 initial_keyboard();//保险点 v_74hc164WriteData_f(kb_cs); //输出前排段选 v_74hc164WriteData_f(0x00); //关掉后排段选 csp=0x01;//初始化指针 io_74hc165_SH_HIGH //拉高并行置数 outb=v_74hc165ReadData_f(); //读入输出 io_74hc165_SH_LOW //拉低并行置数 initial_keyboard();//全部关掉 //与原来的键值进行比较~ lkb=outb^keynumber[0][i]; //前排与原来的键值比较 hkb=outa^keynumber[1][i]; //后排与原来的键值比较 // 1&1=1 1&0=0 0&1=0 0&0=0 // 1^1=0 1^0=0 0^1=0 0^0=0所以用来做比较。有变化的就输出1 keynumber[0][i]=outb; //前排,记录下新的键值 keynumber[1][i]=outa; //后排 //原理:在琴键下面有两个开关,顺序为K1,K2。按照顺序接通。只能两个全导通/两个全关断,或者只有K1导通。在K1导通的时候lkb&csp发生变化并且在前排键上也发生变化 //所以程序会在一个2维数组中记录闭合的时间,然后继续扫过去。等到第二次扫到这组键的话 while(j!=8) { if ((lkb&csp)!=0) // 前排触点是否有变化 { if ((outb&csp)!=0) { //前排的按键按下了 count_begin[i][j]=ts; } else {//前排键松开了就复原黑名单 temp=0x01; temp=temp<blacklist_time) { //超时了 temp=0x01; temp=temp< blacklist_time) { //超时了 temp=0x1; temp=temp< 全部源码下载地址:http://www.51hei.com/f/mdid.rar
编译后约占用1K ROM。效率够高~
不过这个最后还要和主控ATmega8通信。
还是半成品。
做键盘也是要技术的。做电子琴更要技术。哇哈哈哈! 本程序的正式版本请看:http://www.51hei.com/mcu/1636.html
89S52单片机的Flash ROM为8KByte.内存为256Byte.
PS:程序本来是分块设计的。为了发上网就用cpp处理了下。include 全部被替换掉了。
上一篇:用电脑远距离控制的开关制作
下一篇:利用PLL(LM567)做频率解调的实例
推荐阅读最新更新时间:2024-03-16 14:25
设计资源 培训 开发板 精华推荐
- 逛安富利新能源技术创新云会展 赢好礼!
- ST有奖直播 | 75V降压控制器和隔离降压方案
- 造个车,一起驶向诗和远方!学习 TI 汽车参考设计,参加技能小测试赢好礼!
- 直播已结束【大唐恩智浦具有阻抗检测功能的新能源锂电芯电池管理方案】
- nanoPower技术:延长电池寿命,提升传感器性能 2021年1月20日 上午10:00在线研讨会
- 第三代半导体如何测试 进阶技能备好了!收集能量抽好礼!
- TI模拟博文深度阅读季,赢小米盒子!
- 福禄克专家级热像仪震撼上市,参与问答赢精美好礼!
- 【1月14日 技术直播】工程师请就位,Keysight计量专家开讲啦 ~电子仪器计量校准基础知识与校准周期探讨
- 万用表,红外测温仪等你来拆!—— EEWorld拆你来玩拆解(第二期)