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;
}