i2c矩阵按键

1.单片机型号:NUVOTON N76E003

2.工程代码:

#include "N76E003.h"

typedef bit bool;
enum{
  false = 0,
  true = 1,
};
#define uint8 unsigned char

#define SET_BIT0        0x01
#define SET_BIT1        0x02
#define SET_BIT2        0x04
#define SET_BIT3        0x08
#define SET_BIT4        0x10
#define SET_BIT5        0x20
#define SET_BIT6        0x40
#define SET_BIT7        0x80
uint8 setBit8(uint8 hexnum,bool a)
{
	hexnum = (hexnum & ~SET_BIT7);
	if(a==true)
	{
		hexnum |= SET_BIT7;
	}
	return hexnum;
}
uint8 setBitN(uint8 hexnum,uint8 N,bool B)//N between [0-7], B = true or false
{
	uint8 temp;
	switch(N)
	{
		case 0: temp=SET_BIT0; break;
		case 1: temp=SET_BIT1; break;
		case 2: temp=SET_BIT2; break;
		case 3: temp=SET_BIT3; break;
		case 4: temp=SET_BIT4; break;
		case 5: temp=SET_BIT5; break;
		case 6: temp=SET_BIT6; break;
		case 7: temp=SET_BIT7; break;
		default: break;
	}
	hexnum = (hexnum & ~temp);
	if(B==true)	{hexnum |= temp;}
	return hexnum;
}


#define G_COL 5
#define G_ROW 4
#define keyNum G_COL*G_ROW
#define Slave_address 0xF0

/**********************Custom instruction----high 4 bit************************/
#define GET_read_length  	0x10
#define READ_keyValue  		0x20
#define SET_DEBOUNCE_TIME 0x30
#define GET_DebounceTime 	0x40
#define INTO_LPM				 	0x50
/*----------------------------------------------------------------------------*/

------------------- Define Port as Quasi mode  -------------------
#define P00_Quasi_Mode				P0M1&=~SET_BIT0;P0M2&=~SET_BIT0
#define P01_Quasi_Mode				P0M1&=~SET_BIT1;P0M2&=~SET_BIT1
#define P02_Quasi_Mode				P0M1&=~SET_BIT2;P0M2&=~SET_BIT2
#define P03_Quasi_Mode				P0M1&=~SET_BIT3;P0M2&=~SET_BIT3
#define P04_Quasi_Mode				P0M1&=~SET_BIT4;P0M2&=~SET_BIT4
#define P05_Quasi_Mode				P0M1&=~SET_BIT5;P0M2&=~SET_BIT5
#define P06_Quasi_Mode				P0M1&=~SET_BIT6;P0M2&=~SET_BIT6
#define P07_Quasi_Mode				P0M1&=~SET_BIT7;P0M2&=~SET_BIT7
#define P10_Quasi_Mode				P1M1&=~SET_BIT0;P1M2&=~SET_BIT0
#define P11_Quasi_Mode				P1M1&=~SET_BIT1;P1M2&=~SET_BIT1
#define P12_Quasi_Mode				P1M1&=~SET_BIT2;P1M2&=~SET_BIT2
#define P13_Quasi_Mode				P1M1&=~SET_BIT3;P1M2&=~SET_BIT3
#define P14_Quasi_Mode				P1M1&=~SET_BIT4;P1M2&=~SET_BIT4
#define P15_Quasi_Mode				P1M1&=~SET_BIT5;P1M2&=~SET_BIT5
#define P16_Quasi_Mode				P1M1&=~SET_BIT6;P1M2&=~SET_BIT6
#define P17_Quasi_Mode				P1M1&=~SET_BIT7;P1M2&=~SET_BIT7
#define P20_Quasi_Mode				P2M1&=~SET_BIT0;P2M2&=~SET_BIT0
#define P30_Quasi_Mode				P3M1&=~SET_BIT0;P3M2&=~SET_BIT0
------------------- Define Port as Push Pull mode -------------------
#define P00_PushPull_Mode			P0M1|=SET_BIT0;P0M2&=~SET_BIT0
#define P01_PushPull_Mode			P0M1|=SET_BIT1;P0M2&=~SET_BIT1
#define P02_PushPull_Mode			P0M1&=~SET_BIT2;P0M2|=SET_BIT2
#define P03_PushPull_Mode			P0M1&=~SET_BIT3;P0M2|=SET_BIT3
#define P04_PushPull_Mode			P0M1&=~SET_BIT4;P0M2|=SET_BIT4
#define P05_PushPull_Mode			P0M1&=~SET_BIT5;P0M2|=SET_BIT5
#define P06_PushPull_Mode			P0M1&=~SET_BIT6;P0M2|=SET_BIT6
#define P07_PushPull_Mode			P0M1&=~SET_BIT7;P0M2|=SET_BIT7
#define P10_PushPull_Mode			P1M1&=~SET_BIT0;P1M2|=SET_BIT0
#define P11_PushPull_Mode			P1M1&=~SET_BIT1;P1M2|=SET_BIT1
#define P12_PushPull_Mode			P1M1&=~SET_BIT2;P1M2|=SET_BIT2
#define P13_PushPull_Mode			P1M1&=~SET_BIT3;P1M2|=SET_BIT3
#define P14_PushPull_Mode			P1M1&=~SET_BIT4;P1M2|=SET_BIT4
#define P15_PushPull_Mode			P1M1&=~SET_BIT5;P1M2|=SET_BIT5
#define P16_PushPull_Mode			P1M1&=~SET_BIT6;P1M2|=SET_BIT6
#define P17_PushPull_Mode			P1M1&=~SET_BIT7;P1M2|=SET_BIT7
#define P20_PushPull_Mode			P2M1&=~SET_BIT0;P2M2|=SET_BIT0
#define P30_PushPull_Mode			P3M1&=~SET_BIT0;P3M2|=SET_BIT0
------------------- Define Port as Input Only mode -------------------
#define P00_Input_Mode				P0M1|=SET_BIT0;P0M2&=~SET_BIT0
#define P01_Input_Mode				P0M1|=SET_BIT1;P0M2&=~SET_BIT1
#define P02_Input_Mode				P0M1|=SET_BIT2;P0M2&=~SET_BIT2
#define P03_Input_Mode				P0M1|=SET_BIT3;P0M2&=~SET_BIT3
#define P04_Input_Mode				P0M1|=SET_BIT4;P0M2&=~SET_BIT4
#define P05_Input_Mode				P0M1|=SET_BIT5;P0M2&=~SET_BIT5
#define P06_Input_Mode				P0M1|=SET_BIT6;P0M2&=~SET_BIT6
#define P07_Input_Mode				P0M1|=SET_BIT7;P0M2&=~SET_BIT7
#define P10_Input_Mode				P1M1|=SET_BIT0;P1M2&=~SET_BIT0
#define P11_Input_Mode				P1M1|=SET_BIT1;P1M2&=~SET_BIT1
#define P12_Input_Mode				P1M1|=SET_BIT2;P1M2&=~SET_BIT2
#define P13_Input_Mode				P1M1|=SET_BIT3;P1M2&=~SET_BIT3
#define P14_Input_Mode				P1M1|=SET_BIT4;P1M2&=~SET_BIT4
#define P15_Input_Mode				P1M1|=SET_BIT5;P1M2&=~SET_BIT5
#define P16_Input_Mode				P1M1|=SET_BIT6;P1M2&=~SET_BIT6
#define P17_Input_Mode				P1M1|=SET_BIT7;P1M2&=~SET_BIT7
#define P20_Input_Mode				P2M1|=SET_BIT0;P2M2&=~SET_BIT0
#define P30_Input_Mode				P3M1|=SET_BIT0;P3M2&=~SET_BIT0
-------------------Define Port as Open Drain mode -------------------
#define P00_OpenDrain_Mode		P0M1|=SET_BIT0;P0M2|=SET_BIT0
#define P01_OpenDrain_Mode		P0M1|=SET_BIT1;P0M2|=SET_BIT1
#define P02_OpenDrain_Mode		P0M1|=SET_BIT2;P0M2|=SET_BIT2
#define P03_OpenDrain_Mode		P0M1|=SET_BIT3;P0M2|=SET_BIT3
#define P04_OpenDrain_Mode		P0M1|=SET_BIT4;P0M2|=SET_BIT4
#define P05_OpenDrain_Mode		P0M1|=SET_BIT5;P0M2|=SET_BIT5
#define P06_OpenDrain_Mode		P0M1|=SET_BIT6;P0M2|=SET_BIT6
#define P07_OpenDrain_Mode		P0M1|=SET_BIT7;P0M2|=SET_BIT7
#define P10_OpenDrain_Mode		P1M1|=SET_BIT0;P1M2|=SET_BIT0
#define P11_OpenDrain_Mode		P1M1|=SET_BIT1;P1M2|=SET_BIT1
#define P12_OpenDrain_Mode		P1M1|=SET_BIT2;P1M2|=SET_BIT2
#define P13_OpenDrain_Mode		P1M1|=SET_BIT3;P1M2|=SET_BIT3
#define P14_OpenDrain_Mode		P1M1|=SET_BIT4;P1M2|=SET_BIT4
#define P15_OpenDrain_Mode		P1M1|=SET_BIT5;P1M2|=SET_BIT5
#define P16_OpenDrain_Mode		P1M1|=SET_BIT6;P1M2|=SET_BIT6
#define P17_OpenDrain_Mode		P1M1|=SET_BIT7;P1M2|=SET_BIT7
#define P20_OpenDrain_Mode		P2M1|=SET_BIT0;P2M2|=SET_BIT0
#define P30_OpenDrain_Mode		P3M1|=SET_BIT0;P3M2|=SET_BIT0

/************************pin definition********************************/
sbit C1=P1^7;
sbit C2=P3^0;
sbit C3=P0^7;
sbit C4=P0^6;
sbit C5=P0^5;

sbit D1=P0^1;
sbit D2=P0^2;
sbit D3=P0^3;
sbit D4=P0^4;

sbit led_red=P1^0;
sbit led_green=P1^5;
sbit led_blue=P0^0;

sbit i2c_SDA = P1^4;
sbit i2c_SCL = P1^3;
sbit i2c_INT = P1^2;

/************************************************************************/
code const uint8  scan_arr[]={0x10,0x08,0x04,0x02,0x01};//High level detection
uint8 data_received[2];
uint8 data_send[20];
uint8 col_buf[G_COL]={0x00,0x00,0x00,0x00,0x00};//Column value representation
uint8 last_col_buf[G_COL]={0x00,0x00,0x00,0x00,0x00};
uint8 ket[keyNum];//The point of time that marks a key event.
//Whether the time point of a key event marking a key can be changed
uint8 ket_en_recorded[G_COL]={0x00,0x00,0x00,0x00,0x00};
uint8 keyEventArray[keyNum];
uint8 total;//The number of key events
uint8 writeIndex=0,readIndex=0;
uint8 T0_cnt=0;
uint8 debounceTime=10;
//The following are the variables set relative to the I2C-Master
uint8 length_send;//byte length of master should to read
uint8 length_receive=1;//Assume that the i2c-master sends one byte to the slave
bool en_scan;
bit BIT_TMP;

void timer0_init()
{
	TMOD&=0xF0;TMOD|=0x01;//TIMER0_MODE1_ENABLE	16bit	
	CKCON   &= ~SET_BIT4;
	ET0 = 1;//enable Timer0 interrupt
	EA = 1;
	TR0 = 1;//Timer0 run
}

void port_init()
{
	//set all scan port to Input_Mode
	P17_Input_Mode;
	P30_Input_Mode;
	P07_Input_Mode;
	P06_Input_Mode;
	P05_Input_Mode;
	//set all data port to open-drain
	P01_OpenDrain_Mode;
	P02_OpenDrain_Mode;
	P03_OpenDrain_Mode;
	P04_OpenDrain_Mode;
	//set led port to push-pull mode
	P10_PushPull_Mode;
	P15_PushPull_Mode;
	
	//Initialize the scan pin
	C1=C2=C3=C4=C5=0;
}

void init_I2C()
{
	I2CPX=0;//set SCL=P1.3 SDA=P1.4
	//set SDA and SCL port to Quasi mode
	P14_Quasi_Mode;
	P13_Quasi_Mode;
	P12_Quasi_Mode;
	i2c_SDA=1;//set SDA and SCL pins high
	i2c_SCL=1;
	BIT_TMP=EA;
	TA=0xAA;TA=0x55;SFRS=0x01;P1SR|=SET_BIT2;TA=0xAA;TA=0x55;SFRS=0x00;
	EA=BIT_TMP;
	EIE |= SET_BIT0;//enable I2C interrupt by setting IE1 bit 0
	EA= 1;	
	I2ADDR=Slave_address;//define own slave address
	I2CEN		= 1; //enable I2C circuit
	AA=1;//the AA bit should be set to enable acknowledging its own slave address.
}

void setScanTTL(uint8 ttl)
{
	C1=(ttl & 0x10)>>4; C2=(ttl & 0x08)>>3; C3=(ttl & 0x04)>>2; C4=(ttl & 0x02)>>1; C5=(ttl & 0x01);
}

void keyScan()
{
	bool uncertain_changs=false;
	static uint8 scan_colIndex=0;
	uint8 col_diffPart=0;
	if(en_scan)
	{
		uint8 d1,d2,d3,d4;
		uint8 col_bit=0;
		d1=D1; d2=D2; d3=D3; d4=D4;
		setScanTTL(0x00);
		col_buf[scan_colIndex] = (d1 << 3)|(d2 << 2)|(d3 << 1)|d4;
		col_diffPart = col_buf[scan_colIndex] ^ last_col_buf[scan_colIndex];
		if(col_diffPart>0)
		{
			for(col_bit=0;col_bit < G_ROW; col_bit++)//
			{
				if((col_diffPart>>col_bit) & 0x01)//If the state of a key is changed
				{
					if(!(ket_en_recorded[scan_colIndex]>>col_bit & 0x01))//Prevent coverage record
					{
						ket[scan_colIndex*G_ROW+col_bit]=T0_cnt;//Record the moment of a key event
						ket_en_recorded[scan_colIndex] = setBitN(ket_en_recorded[scan_colIndex],col_bit,1);//
					}
					uncertain_changs=true;
				}
				else//If the state of a key is not changed,Allow to record the moment of this key event.
				{
					ket_en_recorded[scan_colIndex] = setBitN(ket_en_recorded[scan_colIndex],col_bit,0);
				}
			}
		}

		if(uncertain_changs)
		{
			uint8 j=0;
			for(j=0;j<G_ROW;j++)
			{
				if((col_diffPart>>j) & 0x01)//Find the button of the state change in column scan_colIndex.
				{
					if(T0_cnt-ket[scan_colIndex*G_ROW+j] >= debounceTime)//debounce
					{
						bool nowStat = (col_buf[scan_colIndex]>>j) & 0x01;
						bool lastStat = (last_col_buf[scan_colIndex]>>j) & 0x01;
						if(nowStat != lastStat)//只记录按键状态发生变化的事件
						{
								if((nowStat == 1) && (lastStat == 0))//pressed
									{keyEventArray[writeIndex%keyNum] = setBit8(scan_colIndex*G_ROW+j,1);}
								else if((nowStat == 0) && (lastStat == 1))//released
									{keyEventArray[writeIndex%keyNum] = setBit8(scan_colIndex*G_ROW+j,0);}
								writeIndex++;
								total++;
								last_col_buf[scan_colIndex] = col_buf[scan_colIndex];		//update last_col_buf[scan_colIndex]					
								i2c_INT=0;//send interrupt to i2c-master
						}// else do nothing						
						//Finish the key event processing,Allow to record the moment of this key event.
						ket_en_recorded[scan_colIndex] = setBitN(ket_en_recorded[scan_colIndex],j,0);
					}
				}//end if(col_diffPart>>j & 0x01)
			}// end for j
			uncertain_changs=false;//Only after each scan gets the variable is true to enter this statement.
		}// end if(uncertain_changes)
		scan_colIndex++;
		en_scan=false;
	}
	else
	{
		if(scan_colIndex >= G_COL)
		{
			scan_colIndex=0;
		}
		setScanTTL(scan_arr[scan_colIndex]);/*set scan TTL*/
		/*********Prevent short-circuit from combination key**********/
		switch(scan_colIndex)
		{
			case 0: P17_PushPull_Mode; P30_Input_Mode; P07_Input_Mode; P06_Input_Mode; P05_Input_Mode; break;
			case 1: P17_Input_Mode; P30_PushPull_Mode; P07_Input_Mode; P06_Input_Mode; P05_Input_Mode; break;
			case 2: P17_Input_Mode; P30_Input_Mode; P07_PushPull_Mode; P06_Input_Mode; P05_Input_Mode; break;
			case 3: P17_Input_Mode; P30_Input_Mode; P07_Input_Mode; P06_PushPull_Mode; P05_Input_Mode; break;
			case 4: P17_Input_Mode; P30_Input_Mode; P07_Input_Mode; P06_Input_Mode; P05_PushPull_Mode; break;
			default: break;
		}	
	}
}

void into_SleepMode_wait()
{

}
void execute_cmd(uint8 cmd)
{
	uint8 i=0;
	switch(cmd)
	{
		case GET_read_length:
			length_send=1;//此时回复给i2c-master一字节
			data_send[0]=total;
			break;

		case READ_keyValue:   //此时回复给i2c-master length_send个字节
		{
			length_send = total;//表示i2c-slave 要发送的字节数
			for(i=0;i<length_send;i++)
			{
				data_send[i] = keyEventArray[readIndex%keyNum];
				readIndex++;
				total--;
			}	
			i2c_INT=1;
			break;//
		}
		case SET_DEBOUNCE_TIME:
				debounceTime = (data_received[0] & 0x0f);
			break;
		case GET_DebounceTime:
			length_send=1;
			data_send[0]=debounceTime;
			break;
		case INTO_LPM:
			into_SleepMode_wait();
			break;

		default:
			break;
	}
}

void I2C_ISR(void) interrupt 6
{
		unsigned char i;
    switch (I2STAT)
    {
        case 0x00://bus error,always put in ISR for noise handling.
            STO = 1;//recover from bus error
            break;
        case 0x60: //从机收到自身的地址并应答  own SLA+W received, ACK returned.
            AA = 1;
            break;
	case 0x88://从机接收地址无应答----previous own SLA+W, data received,NACK returned. not address SLAVE mode entered.
            AA = 1;
            break;
	case 0x80://从机接收数据应答----previous own SLA+W, data received,ACK returned.
            data_received[0] = I2DAT;
	    AA = 1;
	    execute_cmd( data_received[0]);
	    break;
	case 0xA8://从机发送地址应答 own SLA+R received, ACK returned
            I2DAT = data_send[0];//告诉主机需要接收的长度
            AA = 1;
            break;
	case 0xB8://从机发送数据应答----previous own SLA+R, data reansmitted.
            //将变化的按键事件发送给i2c_master		 
	    for(i=0;i < length_send;i++)
	    {
	        I2DAT = data_send[i];
	        AA = 1;
	    }	
            break;
	case 0xC8://从机发送最后数据应答 ------previous own SLA+R, last data transmitted, ACK received, not addressed SLAVE.
            AA = 1;//mode entered
            break; 
        case 0xC0://从机发送数据无应答----previous own SLA+R, data reansmitted.NACK received. not address SLAVE.
            AA = 1;//mode entered
            break; 
				
        case 0x68://从机接收仲裁失败
	    P02 = 0;
            while(1);
            break;		 
        case 0xA0://从机发送重复开始或停止信号--STOP or repeated START received while still addressed SLAVE mode.
            //P3 = 0xA0;
            AA = 1;
            break;             
    }
    SI = 0;
    while(STO);
}


void main (void) 
{
	uint8 i=0;
	writeIndex=0;
	readIndex=0;
	total=0;
	i2c_INT=1;
	en_scan=false;
	port_init();
	init_I2C();
	timer0_init();

	
  while(1)
  {
		keyScan();
  }
}

void Timer0_ISR (void) interrupt 1  //interrupt address is 0x000B
{
    T0_cnt++;
    en_scan=true;
    //1.001ms
    TH0 = 0xfa;
    TL0 = 0xca;    
}




 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值