⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pub_func.c

📁 NEC527多功能电表完整源代码,包括LCD驱动,显示,计量,存储,整个527驱动程序!
💻 C
📖 第 1 页 / 共 2 页
字号:
            year_days += 365;
        }
    }

    temp = Bcd2HexChar(mon);
    temp--;
    if( temp >= 12 )
    {
        temp = 0;
    }
    
    if( ( ( temp1 & 0x03 ) == 0 ) && ( temp == 1 ) )
    {
        leap = 1;
    }        
    else 
    {
        leap = 0;
    }
    
    days = days_per_month[temp];
    temp1 = days_every_month[temp]+leap;
    temp = Bcd2HexChar(day);
    temp--;
    if( temp > temp1 )
    {
        temp = 0;
    }
    days += temp;
    year_days += days;
    days = (unsigned short)( (unsigned long)year_days % MAX_REC_DAY_CNT );

    return(DAY_BASE+DAY_OFFSET*days);
}

unsigned char GetPrevMonIdx(unsigned char item)
{
    unsigned short temp;

    temp=(_SysPotInfo.last_balance_year%10)*12+_SysPotInfo.last_balance_mon+1;
    return((unsigned char)((temp+(ushort)item*119)%120));
}

unsigned long GetPrevMonAddr(unsigned char item)
{
    if(item==0)
    {
        return(BASE_CUR+4);
    }
    else if(item==0xFF)
    {
        return(BASE_CURS+4);
    }
    else
    {
        return(YEAR_BASE+(ulong)GetPrevMonIdx(item)*MON_OFFSET+4);
    }
}

void SaveCurrMd2Flash( void )
{
    unsigned long tmp1[2];
    unsigned long tmp2[2];
    unsigned short ii;
    
    MemSetZero((unsigned char*)(&tmp1[0]), SIZE_PER_MD_REC);    
    for( ii = 0; ii < TOTAL_MD_REC_NUM; ii++ )
    {
        FramRead( ADDR_OF_CUR_MD_START+ii*SIZE_PER_MD_REC, (unsigned char*)(&tmp1[0]), SIZE_PER_MD_REC );
        DataflashWriteByBuffer1( (BASE_CUR+MON_MD_REC+ii*MON_MD_REC_OFFSET), (unsigned char*)(&tmp1[0]), SIZE_PER_MD_REC );
        DataflashReadByBuffer1( BASE_CURS+MON_MD_REC+ii*MON_MD_REC_OFFSET,(unsigned char*)(&tmp2[0]), SIZE_PER_MD_REC);
        if( tmp1[0] > tmp2[0] )
        {
            DataflashWriteByBuffer1( BASE_CURS+MON_MD_REC+ii*MON_MD_REC_OFFSET,(unsigned char*)(&tmp1[0]), SIZE_PER_MD_REC);
        }
    }   
}

void ClearCurrMd( void )
{
    unsigned short ii;
    unsigned char tmp[SIZE_PER_MD_REC];
    
    MemSetZero(&tmp[0], SIZE_PER_MD_REC);
    
    for( ii = 0; ii < TOTAL_MD_REC_NUM; ii++ )
    {
        FramWrite( ADDR_OF_CUR_MD_START+ii*SIZE_PER_MD_REC, &tmp[0], SIZE_PER_MD_REC );
    }	
}

const unsigned long _Evt_Rec_Address[]={
    EVT_VOL_SEQERR_BASE,
    EVT_CUR_SEQERR_BASE,
    EVT_WATT_OVER_BASE,
    EVT_REQ_OVER_BASE,
    EVT_CURRENT_IMBA_BASE,
    EVT_WATT_REVERSE_BASE
}; 

const unsigned short _Evt_Save_Address[]={
    ADDR_OF_VOL_SEQERR_REC,
    ADDR_OF_CUR_SEQERR_REC,
    ADDR_OF_WATT_OVER_REC,
    ADDR_OF_REQ_OVER_REC,
    ADDR_OF_CURRENT_IMBA_REC,
    ADDR_OF_WATT_REVERSE_REC
};    

const unsigned short _Evt_Backup_Address[] = {
    ADDR_OF_VOL_SEQERR_TIME_BACKUP,
    ADDR_OF_CUR_SEQERR_TIME_BACKUP,
    ADDR_OF_WATT_OVER_TIME_BACKUP,
    ADDR_OF_REQ_OVER_TIME_BACKUP,
    ADDR_OF_CURRENT_IMBA_TIME_BACKUP,
    ADDR_OF_WATT_REVERSE_TIME_BACKUP    
};    
   
const unsigned char _Evt_Rec_Len[]={
    EVT_VOL_SEQERR_OFFSET,
    EVT_CUR_SEQERR_OFFSET,
    EVT_WATT_OVER_OFFSET,
    EVT_REQ_OVER_OFFSET,
    EVT_CURRENT_IMBA_OFFSET,
    EVT_WATT_REVERSE_OFFSET
};    
	
void SaveEvtStartInfo(unsigned char item)
{
    unsigned long temp[4];
    unsigned short addr,count;
    unsigned char i=9,len;
	
    addr = _Evt_Save_Address[item];
    WriteAddShortToFram( addr );
   
    addr = _Evt_Backup_Address[item];
    SaveTmpTime( addr );
    count = (ushort)(_Evt_Rec_Address[item]/DF_PAGE_LEN);
    len = _Evt_Rec_Len[item];
    if( DataflashMainToBuffer1(count) == OK )
    {
        i = 9;
        do
        {
            DataflashBuffer1Read( (unsigned short)(i-1)*len, (unsigned char *)&pub_data.pub_data_buff3[0], len );
            DataflashBuffer1Write( (unsigned short)i*len, (unsigned char *)&pub_data.pub_data_buff3[0], len );
        }while(--i);
		
        MemSetZero( (unsigned char *)&pub_data.pub_data_buff3[0], 20 );
        pub_data.pub_data_buff3[0] = SystemTime[SPACE_OF_MINUTE];
        pub_data.pub_data_buff3[1] = SystemTime[SPACE_OF_HOUR];
        pub_data.pub_data_buff3[2] = SystemTime[SPACE_OF_DAY];
        pub_data.pub_data_buff3[3] = SystemTime[SPACE_OF_MONTH];
        pub_data.pub_data_buff3[4] = SystemTime[SPACE_OF_YEAR];
        if( item <= 3 )
        {            
            for( i = 0; i < 3; i++ )
            {
                temp[i] = (unsigned long)CurrentVI[i]*CurrentVI[3+i];
            }
            temp[0] += ( temp[1]+temp[2] );
            temp[0] /=100;			
            temp[0] = Hex2BcdLong(temp[0]);
            memcpy( (unsigned char *)&pub_data.pub_data_buff3[10], (unsigned char *)&temp[0], 3 );
        }
        else if( item == 4 )
        {
            for( i = 0; i < 3; i++ )
            {
                temp[0] = (unsigned long)CurrentVI[3+i]*10;
                temp[0] = Hex2BcdLong( temp[0] );
                memcpy( (unsigned char *)&pub_data.pub_data_buff3[10+i*3], (unsigned char *)&temp[0], 3 );
            }
        }
        else if( item == 5 )
        {
            for( i = 0; i < 4; i++ )
            {
                CalcInstantPower( (unsigned char *)&temp[i], i );
                memcpy( (unsigned char *)&pub_data.pub_data_buff3[10+i*3], (unsigned char *)&temp[i], 3 );
            }
            pub_data.pub_data_buff3[22] = ( PhaseActive & 0x07 );
        }
        DataflashBuffer1Write( 0, (unsigned char *)&pub_data.pub_data_buff3[0], len );
        DataflashBuffer1ToMain(count);
    }    	
}

void SaveEvtStopInfo(unsigned char item)
{
    unsigned long temp = 0;
    unsigned short addr;
    unsigned char rec[5];

    addr = _Evt_Backup_Address[item];
    temp = CalcPastTime(addr);
	
    addr = _Evt_Save_Address[item]+2;
    CalcTotalTime( addr, temp );
        	
    temp = _Evt_Rec_Address[item]/DF_PAGE_LEN;	
    if( DataflashMainToBuffer1((ushort)temp) == OK )
    {
        rec[0] = SystemTime[SPACE_OF_MINUTE];
        rec[1] = SystemTime[SPACE_OF_HOUR];
        rec[2] = SystemTime[SPACE_OF_DAY];
        rec[3] = SystemTime[SPACE_OF_MONTH];            
        rec[4] = SystemTime[SPACE_OF_YEAR];	
        DataflashBuffer1Write( 5, &rec[0], 5 );
        DataflashBuffer1ToMain( (ushort)temp );
    }    		
}

void SaveEvtSetSysClock(unsigned char port)
{
    unsigned short temp,count,ii=9;
	
    temp = EVT_REC_SET_TIME_BASE/DF_PAGE_LEN;
    if( DataflashMainToBuffer1( temp ) == OK )
    {
        DataflashBuffer1Read( 0, (unsigned char *)&count, 2 );
        count = __bcd_add_short( count, 1 );
        DataflashBuffer1Write( 0, (unsigned char *)&count, 2 );
		
        do{
            DataflashBuffer1Read( (ushort)(EVT_REC_SET_TIME_OFFSET*(ii-1)+2), (unsigned char *)&pub_data.pub_data_buff3[0], (ushort)EVT_REC_SET_TIME_OFFSET );
            DataflashBuffer1Write( (ushort)(EVT_REC_SET_TIME_OFFSET*ii+2), (unsigned char *)&pub_data.pub_data_buff3[0], (ushort)EVT_REC_SET_TIME_OFFSET );
        }while(--ii);
		        
        pub_data.pub_data_buff3[0] = port;
        pub_data.pub_data_buff3[1] = FrameBuffer[FRM_DATA+2];
        FramRead( ADDR_OF_SET_TIME_BACKUP, (unsigned char *)&pub_data.pub_data_buff3[10], 7 );
        pub_data.pub_data_buff3[17] = 0x20;
        memcpy( (unsigned char *)&pub_data.pub_data_buff3[2], &SystemTime[0], 7 );
        pub_data.pub_data_buff3[9] = 0x20;
        DataflashBuffer1Write( (ushort)(EVT_REC_SET_TIME_PORT), (unsigned char *)&pub_data.pub_data_buff3[0], (ushort)EVT_REC_SET_TIME_OFFSET );
        DataflashBuffer1ToMain( temp );
    }
}

void SaveEvtClrMeterData(unsigned char port)
{
    unsigned short count;
    unsigned char i;

    count = WriteAddShortToFram( ADDR_OF_CLR_POWERDATA_COUNT );
    MemSetZero( (unsigned char *)&pub_data.pub_data_buff3[0], EVT_REC_DATA_CLR_OFFSET );
    pub_data.pub_data_buff3[EVT_REC_DATA_CLR_COMMPORT] = port;
    pub_data.pub_data_buff3[EVT_REC_DATA_CLR_PASSWORD] = FrameBuffer[FRM_DATA+2];
    memcpy( (unsigned char *)&pub_data.pub_data_buff3[EVT_REC_DATA_CLR_TIME], &SystemTime[0], 7 );
    pub_data.pub_data_buff3[9] = 0x20;
    for( i = 0; i < 20; i++ )
    {
        LoadEnergy( (unsigned char *)&pub_data.pub_data_buff3[EVT_REC_DATA_CLR_POWER+i*4], 0xFF, i+5+(i/10)*5  );
    }

    DI1DI0 = EVT_REC_DATA_CLR_BASE+DF_PAGE_LEN*(count/5)+EVT_REC_DATA_CLR_OFFSET*(count%5);
    DataflashWriteByBuffer1( DI1DI0, (unsigned char *)&pub_data.pub_data_buff3[0], EVT_REC_DATA_CLR_OFFSET );
}

void SaveEvtClrReqPwrData(unsigned char mode, unsigned char flag)
{
    unsigned short page, ii=9;
	
    WriteAddShortToFram( ADDR_OF_REQ_CLR_COUNT );
    page = EVT_REC_REQ_CLR_BASE/DF_PAGE_LEN;	
    if( DataflashMainToBuffer1( page ) == OK )
    {
        do{
            DataflashBuffer1Read( (ii-1)*(ushort)EVT_REC_REQ_CLR_OFFSET, (unsigned char *)&pub_data.pub_data_buff3[0], (ushort)EVT_REC_REQ_CLR_OFFSET );
            DataflashBuffer1Write( ii*(ushort)EVT_REC_REQ_CLR_OFFSET, (unsigned char *)&pub_data.pub_data_buff3[0], (ushort)EVT_REC_REQ_CLR_OFFSET );
        }while(--ii);
		
        pub_data.pub_data_buff3[0] = mode;
        if( mode == 5 ) 
        {
            pub_data.pub_data_buff3[1] = 0;
        }			
        else 
        {
            if( flag == 0 )
            {
                pub_data.pub_data_buff3[1] = FrameBuffer[FRM_DATA];        
            }				
            else
            {
                pub_data.pub_data_buff3[1] = FrameBuffer[FRM_DATA+2];
            }
        }
		
        memcpy( (unsigned char *)&pub_data.pub_data_buff3[2], &SystemTime[0], 7 );
        pub_data.pub_data_buff3[9] = 0x20;
        LoadMaxDemandInfo( (unsigned char *)&pub_data.pub_data_buff3[10], 0xFF, 55 );
        LoadMaxDemandInfo( (unsigned char *)&pub_data.pub_data_buff3[13], 0xFF, 60 );
        LoadMaxDemandInfo( (unsigned char *)&pub_data.pub_data_buff3[16], 0xFF, 70 );
        LoadMaxDemandInfo( (unsigned char *)&pub_data.pub_data_buff3[19], 0xFF, 75 );
        DataflashBuffer1Write( 0, (unsigned char *)&pub_data.pub_data_buff3[0], (ushort)EVT_REC_REQ_CLR_OFFSET );
        DataflashBuffer1ToMain( page );
    }        	
}

void SaveEvtProgram(void)
{
    unsigned short page;
    unsigned char rec[EVT_REC_PROG_OFFSET], ii = 9;

    WriteAddShortToFram( ADDR_OF_PROG_COUNT );
    page = EVT_REC_PROG_BASE/DF_PAGE_LEN;
    if( DataflashMainToBuffer1( page ) == OK )
    {
        do{
            DataflashBuffer1Read( (ushort)EVT_REC_PROG_OFFSET*(ii-1), rec, EVT_REC_PROG_OFFSET );
            DataflashBuffer1Write( (ushort)EVT_REC_PROG_OFFSET*ii, rec, EVT_REC_PROG_OFFSET );
        }while(--ii);
		
        for( ii = 0; ii < 3; ii++ )
        {
            if( CommPortBak & ( BIT0 << ii ) ) break;
        }		
        rec[0] = ii;
        rec[1] = FrameBuffer[FRM_DATA+2];
        memcpy( (unsigned char *)&rec[2], &SystemTime[0], 7 );
        rec[9] = 0x20;
        memcpy( (unsigned char *)&rec[10], &FrameBuffer[FRM_DATA], 2 );
        DataflashBuffer1Write( 0, (unsigned char *)&rec[0], EVT_REC_PROG_OFFSET);
        DataflashBuffer1ToMain( page );
    }	
}

void SaveEvtPowerDownUp(unsigned char item)
{
    unsigned short addr,count;
    unsigned char rec[16], ii = 9;
	
    FramRead( ADDR_OF_PD_COUNT, (unsigned char *)&count, 2 );
    if( item != 0 )
    {
        count = __bcd_add_short( count, 1 );
        FramWrite( ADDR_OF_PD_COUNT, (unsigned char *)&count, 2 );
        do{
            FramRead( ADDR_OF_PD_TIME+PD_TIME_OFFSET*(ii-1), &rec[0], PD_TIME_OFFSET );
            FramWrite( ADDR_OF_PD_TIME+PD_TIME_OFFSET*ii, &rec[0], PD_TIME_OFFSET );
        }while(--ii);
    }
	
    addr = ADDR_OF_PD_TIME+item*8;
    memcpy( (unsigned char *)&rec[0], &SystemTime[0], 7 );
    rec[7] = 0x20;
    FramWrite( addr, (unsigned char *)&rec[0], 8 );
}

void SaveEvtClrPowerMeter(void)
{
    unsigned short count;
    unsigned char ii;

    DataflashReadByBuffer1( EVT_REC_PM_CLR_BASE, (unsigned char *)&count, 2 );
    count = __bcd_add_short( count, 1 );
    DataflashWriteByBuffer1( EVT_REC_PM_CLR_BASE, (unsigned char *)&count, 2 );

    count = Bcd2HexShort( count );
    count = ( count-1)%10;
    DI1DI0 = EVT_REC_PM_CLR_BASE+DF_PAGE_LEN*count+2;

    for( ii = 0; ii < 3; ii++ )
    {
        if( CommPortBak & ( BIT0 << ii ) ) break;
    }
    
    pub_data.pub_data_buff3[EVT_REC_PM_CLR_COMMPORT] = ii;
    pub_data.pub_data_buff3[EVT_REC_PM_CLR_PASSWORD] = FrameBuffer[FRM_DATA];
    memcpy( (unsigned char *)&pub_data.pub_data_buff3[EVT_REC_PM_CLR_TIME], &SystemTime[0], 7 );
    pub_data.pub_data_buff3[9] = 0x20;    
    FramRead( ADDR_OF_PROG_REC, (unsigned char *)&pub_data.pub_data_buff3[EVT_REC_PM_CLR_PROG_COUNT], 2 );
    FramRead( ADDR_OF_COVER_UP_OPEN, (unsigned char *)&pub_data.pub_data_buff3[EVT_REC_PM_CLR_COVERUP_COUNT], 2 );
    FramRead( ADDR_OF_COVER_DOWN_OPEN, (unsigned char *)&pub_data.pub_data_buff3[EVT_REC_PM_CLR_COVERDOWN_COUNT], 2 );
    
    for( ii = 0; ii < 20; ii++ )
    {
        LoadEnergy( (unsigned char *)&pub_data.pub_data_buff3[EVT_REC_PM_CLR_POWER+ii*4], 0xFF, ii+5+(ii/10)*5  );
    }    	
    DataflashWriteByBuffer1( DI1DI0, (unsigned char *)&pub_data.pub_data_buff3[0], EVT_REC_PM_CLR_OFFSET );
}

const unsigned short _shift_evt_data_addr[]={
    ADDR_OF_LOST_REC,
    ADDR_OF_VOLTAGE_OVER,
    ADDR_OF_CURRENT_OVER,
    ADDR_OF_LOWI_REC,
    ADDR_OF_LOWV_REC,
    ADDR_OF_CURRENT_IMBA_REC,
    ADDR_OF_CUR_SEQERR_REC,    
    ADDR_OF_WATT_OVER_REC,
    ADDR_OF_REQ_OVER_REC,
    ADDR_OF_VOL_SEQERR_REC,
    ADDR_OF_REQ_CLR_COUNT,
    ADDR_OF_PROG_COUNT,
    ADDR_OF_PD_COUNT,
    ADDR_OF_VOLTAGE_INFO,
    ADDR_OF_WATT_REVERSE_REC
};

const unsigned short _shift_evt_data_len[]={
    LOST_REC_OFFSET,
    VOLTAGE_OVER_OFFSET,	    
    CURRENT_OVER_OFFSET,
    LOWI_REC_OFFSET,
    LOWV_REC_OFFSET,
    CURRENT_IMBA_REC_OFFSET,
    CUR_SEQERR_REC_OFFSET,    
    WATT_OVER_REC_OFFSET,
    REQ_OVER_REC_OFFSET,    
    VOL_SEQERR_REC_OFFSET,    
    REQ_CLR_COUNT_OFFSET,
    PROG_COUNT_OFFSET,
    PD_COUNT_OFFSET,
    VOLTAGE_INFO_OFFSET,
    WATT_REVERSE_REC_OFFSET
};	
void SaveEvtDataShift(void)
{
    unsigned short addr, t_addr, count, count2;
    unsigned char ii, jj, flag;
	
    for( ii = 0; ii < 3; ii++ )
    {
        ClrWdt();
        if( VStateWord & ( PS_LVDO_PHA << ii ) )
        {
            t_addr = TMPT_LVDO_PHA+TMPT_OFFSET * ii;
            addr = ADDR_OF_VOLTAGE_INFO+VOLTAGE_LVDO_POSITION;
            SavePastTime( addr, t_addr, 3 );
            addr = ADDR_OF_VOLTAGE_INFO+VOLTAGE_LVDO_POSITION+3+ii*3;
            SavePastTime( addr, t_addr, 3 );
            t_addr = TMPT_BASE+TMPT_LVDO_PHA+TMPT_OFFSET*ii;
            SaveTmpTime( t_addr );
        }
        else if( VStateWord & ( PS_OVUP_PHA << ii ) )
        {            
            t_addr = TMPT_OVUP_PHA+TMPT_OFFSET*ii;
            addr = ADDR_OF_VOLTAGE_INFO;
            SavePastTime( addr, t_addr, 3 );
            addr = ADDR_OF_VOLTAGE_INFO+3+ii*3;
            SavePastTime( addr, t_addr, 3 );
            SaveTmpTime( TMPT_BASE+TMPT_OVUP_PHA+TMPT_OFFSET*ii );	
        }
        else
        {            
            t_addr = TMPT_VOK_PHA+TMPT_OFFSET*ii;
            addr = ADDR_OF_VOLTAGE_INFO+VOLTAGE_VOK_POSITION+ii*3;
            SavePastTime( addr, t_addr, 3 );
            SaveTmpTime( TMPT_BASE+TMPT_VOK_PHA+TMPT_OFFSET*ii );
        }
    }

    SaveEvtOnBalance();
	
    for( jj = 0; jj < 15; jj++ )
    {        
        ii = 4;
        do
        {
            addr = _shift_evt_data_addr[jj]+_shift_evt_data_len[jj]*(ii-1);
            FramRead( addr, (unsigned char *)&pub_data.pub_data_buff3[0], (unsigned char)_shift_evt_data_len[jj] );
            addr = _shift_evt_data_addr[jj]+_shift_evt_data_len[jj]*ii;
            FramWrite( addr, (unsigned char *)&pub_data.pub_data_buff3[0], (unsigned char)_shift_evt_data_len[jj] );
        }while(--ii);
        MemSetoWriteE2prom( _shift_evt_data_addr[jj], (unsigned char)_shift_evt_data_len[jj] );
    }
	
    for( ii = 0; ii < 11; ii++ )
    {
        count = 0;
        if( ii <= 4 )
        {
            for( jj = 0; jj < 3; jj++ )
            {
                addr = ADDR_OF_EVT_FLAG_ON_BALANCE+ii*3+jj;
                FramRead( addr, &flag, 1 );
                if( flag != 0 )
                {                
                    count++;
                    count2 = 1;
                    addr = _shift_evt_data_addr[ii]+2+jj*2;
                    FramWrite( addr, (unsigned char *)&count2, 2 );
                }
            }
        }
        else 
        {
            addr = ADDR_OF_EVT_FLAG_ON_BALANCE+FLAG_CUR_IMBA+(ii-5);
            FramRead( addr, &flag, 1 );
            if( flag != 0 ) count = 1;
        }
        FramWrite( _shift_evt_data_addr[ii], (unsigned char *)&count, 2 );
    }	
    MemSetoWriteE2prom( ADDR_OF_EVT_FLAG_ON_BALANCE, SIZE_OF_EVT_FLAG_ON_BALANCE );
}

void SaveZeroFreezePower(void)
{
    unsigned short page,ii;
    unsigned char rec[OFFSET_ZERO_FREEZE_POWER];

    for( ii = 0; ii < 10; ii++ )
    {
        LoadEnergy( (unsigned char *)&pub_data.pub_data_buff3[ii*4], 0xFF, (uchar)(ii+5) );
    }

    ii = 7;
    page = ZERO_FREEZE_POWER_BASE/DF_PAGE_LEN;
    if( DataflashMainToBuffer1(page) == OK )
    {
        do{
            DataflashBuffer1Read( (ii-1)*(ushort)OFFSET_ZERO_FREEZE_POWER, rec, (ushort)OFFSET_ZERO_FREEZE_POWER );
            DataflashBuffer1Write( ii*(ushort)OFFSET_ZERO_FREEZE_POWER, rec, (ushort)OFFSET_ZERO_FREEZE_POWER );
        }while(--ii);

        DataflashBuffer1Write( 0, (unsigned char *)&pub_data.pub_data_buff3[0], (ushort)OFFSET_ZERO_FREEZE_POWER );
        DataflashBuffer1ToMain( page );
    }			
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -