微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 我的MIDI键盘程序

我的MIDI键盘程序

时间:11-29 来源:互联网 点击:
#include //89s52头文件
#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_DEFINEDvoid _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();      // 延时5usI2C_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设置成输入,必须先向端口写1I2C_SCL = 1;F0 = 0;if(I2C_SDA == 1)    // 若I2C_SDA=1表明非应答,置位非应答标志F0F0 = 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;    // 传送位1I2C_SCL = 1;delayNOP();I2C_SDA = 0;I2C_SCL = 0;}else{I2C_SDA = 0;    // 否则传送位0I2C_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,则数据的最后一位置1elsetdata = tdata&0xfe;    // 否则数据的最后一位置0I2C_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;}				   //--------------------------------------------------------------------------------------------------// 函数名称: 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; //开外部中断0iic_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; //开外部中断0EA=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 intuchar keytype=2;//#define keytype 2#define blacklist_time 240uchar kbtime=0; //记录时间,占2个字节uchar keynumber[2][7]; //记录键位,占14个字节uchar blacklist[7];//uchar code seg[]={"admin"};/*0->NoTouch Response1->Very Soft Touch Response2->Soft Touch Response3->Medium Touch Response4->Hard Touch Response5->Very Hard Touch Response*/uchar code vel[5][251]={{//Very Soft127,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},{//Soft127,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},{//Medium127,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},{//Hard100,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 Hard92,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_LOWSendData <= 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 0010if(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~874HC1652 BIT1~8 KB DATA 9~1674HC5952 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-7777-7F为通道模式信息控制器值C+ 通道号音色切换音色号 0-127无该字节数据D+ 通道号通道压力该通道全部键盘的触后压力无该字节数据E+ 通道号弯音轮弯音轮低位数据弯音轮高位数据F系统普通信息、实时信息、及高级信息代码忽略忽略*/				   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 00000010while (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所以用来做比较。有变化的就输出1keynumber[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=tempblacklist_time){//超时了temp=0x01;temp=tempblacklist_time){//超时了temp=0x1;temp=temp

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top