2011年11月3日 星期四

int 2 ascii

之前寫了一個程式優化的文章


參考了BEE大大的建議,今天寫了一個int 2 ascii function


 


 


void int2ascii(BYTE *cp, WORD uquad)


{


    #define to_char(cp) (cp)+'0'


 


    memset(cp-5, '0', 5); // set all byte is ascii of '0'


   


    while (uquad >= 10) {


        *--cp = to_char(uquad % 10);


        uquad /= 10;


    }


    *--cp = to_char(uquad);


}


使用方式:


 




    BYTE CP[6]={0};


    WORD TEST = 4;


    int2ascii(&CP[5],TEST);


 


cool~  挺方便的


 


實在沒有多少時間寫文章,只能說抱歉了……


 


另外因為工作上的需求,要來做點工具了,又要停頓一陣子了,有空再來整理。



2011年11月2日 星期三

神奇的選單

如何寫一個容易維護的選單程式,當初只會寫了一堆if then else, 或者是switch case……


維護的好辛苦,今天寫了一個神奇的選單程式,維護上就簡單多了


VBITS_16 Menu_Flag_All,
         Menu_Flag_0,
         Menu_Flag_1,
         Menu_Flag_2,
         Menu_Flag_3,
         Menu_Flag_4;



void Null_Menu(void)
{
   ;
}


void Task_Menu_0(void)
{
    Menu_Flag_0.word = 0x0002;
    Menu_Service(&Menu_Flag_0, Menu_Table_0);
}


void Task_Menu_1(void)
{
    Menu_Flag_1.word = 0x0002;
    Menu_Service(&Menu_Flag_1, Menu_Table_1);
}


void Task_Menu_2(void)
{
    Menu_Flag_2.word = 0x0002;
    Menu_Service(&Menu_Flag_2, Menu_Table_2);
}


void Task_Menu_3(void)
{
    Menu_Flag_3.word = 0x0001;
    Menu_Service(&Menu_Flag_3, Menu_Table_3);
}


void Task_Menu_4(void)
{
    Menu_Flag_4.word = 0x0001;
    Menu_Service(&Menu_Flag_4, Menu_Table_4);
}


void test(void)
{
   ;
}


const FUNCT_PTR_V_V Menu_Table_0[16] =
{
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
};


const FUNCT_PTR_V_V Menu_Table_1[16] =
{
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
};
const FUNCT_PTR_V_V Menu_Table_2[16] =
{
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
};
const FUNCT_PTR_V_V Menu_Table_3[16] =
{
    test, //test
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
};
const FUNCT_PTR_V_V Menu_Table_4[16] =
{
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
};


const FUNCT_PTR_V_V Menu_Table_All[16] =
{
    Task_Menu_0,
    Task_Menu_1,
    Task_Menu_2,
    Task_Menu_3,
    Task_Menu_4,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
    Null_Menu,
};


 


void Menu_Service(VBITS_16 *service_flags, const FUNCT_PTR_V_V *service_table)
{


    WORD flags;
    int index = 0;
    if ( 0 == service_flags->word) return;
    flags = service_flags->word;
    while((flags & 1) == 0)
    {
       flags >>= 1;
       index++;
    }


    service_flags->word &= ~(1<<index);  /* Clear service request. */


    (*service_table[index])();              /* Dispatch to service handler. */


}


 


使用上也不複雜


  Menu_Flag_All.word = 0x0008;
  Menu_Service(&Menu_Flag_All, Menu_Table_All);


一樣也是call 副程式來使用,應該還可以寫得更好才對。


 


今天就先這樣吧!


PID 寫法

回想以前寫的程式,和現在在公司被訓練的結果,果然還是有差


今天播空寫一下PID 的寫法,功能可能不太正常,不過大至上應該是正常的


typedef enum _PIDType_e
{
    CTR_TYPE_PID = 0,
    CTR_TYPE_P,
    CTR_TYPE_PD,
    CTR_TYPE_PI,
} PIDType_e;


 


typedef struct _PIDStruct
{
PIDType_e Type;
    int Kp;
    int Ki;
    int Kd;
    long Error;
    long Error_Differential;
    long Error_Last;
    long Error_Accumulate;
    long Error_Saturation;
    long Output;
    long Output_Saturation;
   
}PIDStruct;


#define PIDStruct_Size sizeof(PIDStruct)


void PID_Control(PIDStruct *PID_ST)
{
    PID_ST->Error_Differential = PID_ST->Error - PID_ST->Error_Last;
    PID_ST->Error_Accumulate += PID_ST->Error;
    SATURATION(PID_ST->Error_Accumulate,
        PID_ST->Error_Saturation,
        -PID_ST->Error_Saturation);
    PID_ST->Error_Last = PID_ST->Error;


    switch (PID_ST->Type)
    {
    case CTR_TYPE_PID:
        PID_ST->Output = PID_ST->Kp * PID_ST->Error +
                         PID_ST->Ki * PID_ST->Error_Accumulate +
                         PID_ST->Kd * PID_ST->Error_Differential;      
        break;
    case CTR_TYPE_P:
        PID_ST->Output = PID_ST->Kp * PID_ST->Error;
    break;
    case CTR_TYPE_PD:
        PID_ST->Output = PID_ST->Kp * PID_ST->Error +
                         PID_ST->Kd * PID_ST->Error_Differential;      
    break;
    case CTR_TYPE_PI:
        PID_ST->Output = PID_ST->Kp * PID_ST->Error +
                         PID_ST->Ki * PID_ST->Error_Accumulate;
    break;


    default:
        // Error
        break;
    }
   
    if (0 != PID_ST->Output_Saturation)
    {
        // do not judgement if saturation is zero.
        SATURATION(PID_ST->Output,
        PID_ST->Output_Saturation,
        -PID_ST->Output_Saturation);
    }


}


這樣在做應用的時後,如果整支程式重複的地方,就不需要重複的貼上PID的寫法,只要CALL 這支副程式就可以搞定了


用之前先初始化變數


PIDStruct Motor_CTR_L;


void PID_Init(void)
{
    memset(&Motor_CTR_L, 0, PIDStruct_Size);
    Motor_CTR_L.Type = CTR_TYPE_PID;
    Motor_CTR_L.Kp = 10;
    Motor_CTR_L.Ki = 1;
    Motor_CTR_L.Kd = 2;
    Motor_CTR_L.Output_Saturation = -4000;
    Motor_CTR_L.Error_Saturation = -3000;
   
}


把誤差丟進去 Motor_CTR_L.Error = -1000;


最後CALL 副程式


PID_Control(&Motor_CTR_L);


我只有貼比較重要的片段,不過也差不多是所有的程式碼了。


 


忙裡偷閒的練習寫自己有興趣的程式,還滿爽的!