1. 程式人生 > >基於C語言的編碼器(光耦)程式設計之C程式碼解析(二)

基於C語言的編碼器(光耦)程式設計之C程式碼解析(二)

程式碼需要一個.c文件和一個.h文件。

.h文件主要配置編碼器相關引數

#define OptoKnobNumber   2 /* 旋鈕個數配置 */

#define _01_SHIFT_BIT_  0x01  /* 移動位數值 */
#define _02_SHIFT_BIT_  0x02  /* 移動位數值 */
#define _01_GET_BIT_    0x01  /* 獲取位數值 */
#define _034b_OptoKnob_CW_WAVE_    0x034b   /*11 01 00 10 11 正向旋轉波形*/
#define _0387_OptoKnob_CCW_WAVE_   0x0387   /*11 10 00 01 11 反向旋轉波形*/
#define _3f_Knob_MaxValue_         0x3f     /* 最大檔位配置 */
#define _00_Knob_MinValue_         0x00     /* 最小檔位配置 */

/* 旋鈕名稱配置 */
enum Opto_name
{
	optoname_AC = 0,
	optoname_WIND = 1,
};

/* 旋鈕引數結構體配置 */
typedef struct
{
	enum  Opto_name  name;
	uint16                 OptoE1_Value;   		 /* E1腳電平快取位元組 */
	uint16                 OptoE2_Value; 		 /* E2腳電平快取位元組*/
	uint16                 OptoGroup_PreValue;   /* 當前E1、E2腳電平組合快取位元組*/
	uint16                 OptoGroup_OldValue;   /* 上一次E1、E2腳電平組合快取位元組*/
	uint16                 OptoShift_Value;      /* 多次E1、E2腳電平組合快取位元組 */
	sint8                  Opto_Value;           /* 旋鈕檔位位元組 */
	uint8                  Opto_Sync;            /* 旋鈕同步位元組 */
}Opto_Struct;

.c文件主要設計相關函式

1、初始化旋鈕結構體函式void OptoKnob_ParaInit(void);

void OptoKnob_ParaInit(void)
{
	enum Opto_name Opto_id;
	
	for(Opto_id = 0u; Opto_id < OptoKnobNumber; Opto_id++)
	{
		OptoKnob_Struct[Opto_id].name = Opto_id;
		OptoKnob_Struct[Opto_id].OptoE1_Value = 0x0000;
		OptoKnob_Struct[Opto_id].OptoE2_Value = 0x0000;
		OptoKnob_Struct[Opto_id].OptoGroup_PreValue = 0x0000;
		OptoKnob_Struct[Opto_id].OptoGroup_OldValue = 0x0000;
		OptoKnob_Struct[Opto_id].OptoShift_Value = 0x0000;
		OptoKnob_Struct[Opto_id].Opto_Value = 0x00;
		OptoKnob_Struct[Opto_id].Opto_Sync = 0x00;
	}
}

2、所有旋鈕服務函式void OptoKnob_ServiceAll(void); 

void OptoKnob_ServiceAll(void)
{
	enum Opto_name Opto_id;
	
	for(Opto_id = 0u; Opto_id < OptoKnobNumber; Opto_id++)
	{
		OptoKnob_Service(Opto_id);
	}
}

3、單個旋鈕處理函式static void OptoKnob_Service(enum Opto_name name)

static void OptoKnob_Service(enum Opto_name name)
{
	Opto_Struct*  StructP = &OptoKnob_Struct[name];
	
	StructP->OptoE1_Value <<= _01_SHIFT_BIT_;  /* 產生最低位快取當前E1電平 */
	StructP->OptoE2_Value <<= _01_SHIFT_BIT_;  /* 產生最低位快取當前E2電平 */
	
	OptoKnob_GetPort[StructP->name](StructP);  /* 獲取電平值*/

    /* 組合E1、E2電平      E1、E2的前後關係會影響旋鈕轉動的波形序列 這裡注意一下*/
	StructP->OptoGroup_PreValue =  ((StructP->OptoE1_Value&0x01)<<_01_GET_BIT_ ) | (StructP->OptoE2_Value&_01_GET_BIT_ );

	/* 電平組合發生改變 */
	if(StructP->OptoGroup_PreValue != StructP->OptoGroup_OldValue)
	{
                /* 上一次電平組合更新為當前的電平組合*/
		StructP->OptoGroup_OldValue = StructP->OptoGroup_PreValue; 
                /* 記錄電平組合序列   */
		StructP->OptoShift_Value |= StructP->OptoGroup_PreValue;  
		switch(StructP->OptoShift_Value & 0x03ff) /* 取10位資料 */
		{
			case _034b_OptoKnob_CW_WAVE_: 
				StructP->Opto_Value++;
				
				if(StructP->Opto_Value > _3f_Knob_MaxValue_ )
				{
					StructP->Opto_Value = _00_Knob_MinValue_;
				}
				
				StructP->Opto_Sync = 1;
				break;

			case _0387_OptoKnob_CCW_WAVE_: 
				StructP->Opto_Value--;
				
				if(StructP->Opto_Value < _00_Knob_MinValue_)
				{
					StructP->Opto_Value = _3f_Knob_MaxValue_;
				}
				
				StructP->Opto_Sync = 1;
				break;

			default:
				break;
		}
		/* 產生最低2位記錄下一次改變電平組合  */
		StructP->OptoShift_Value <<= _02_SHIFT_BIT_;  
	}
}

4、電平獲取函式 static void OptoKnob_AC(Opto_Struct* Knob); static void OptoKnob_WIND(Opto_Struct* Knob);


/*這段程式碼看不懂就算了,我為了方便才這麼做,這程式碼就是多個旋鈕時的選擇函式,總之這些函式功能就是獲取2個埠的電平值,你自己寫個可以返回埠電平的函式就可以了*/

static void OptoKnob_AC(Opto_Struct* Knob);
static void OptoKnob_WIND(Opto_Struct* Knob);

typedef void (*OptoKnob_getport)(Opto_Struct*);

OptoKnob_getport   OptoKnob_GetPort[]=
{
	OptoKnob_AC,
	OptoKnob_WIND,
};

static void OptoKnob_AC(Opto_Struct* StructP)
{
	if(((P1&BIT7) >> 7) != 0x00)
	{
		StructP->OptoE1_Value |= 0x01;
	}
	else
	{
		StructP->OptoE1_Value &= ~0x01;
	}
	
	if(((P1&BIT6) >> 6) != 0x00)
	{
		StructP->OptoE2_Value |= 0x01;
	}
	else
	{
		StructP->OptoE2_Value &= ~0x01;
	}
}

static void OptoKnob_WIND(Opto_Struct* StructP)
{
	if(((P9&BIT6) >> 6) != 0x00)
	{
		StructP->OptoE1_Value |= 0x01;
	}
	else
	{
		StructP->OptoE1_Value &= ~0x01;
	}
	
	if(((P9&BIT4) >> 4) != 0x00)
	{
		StructP->OptoE2_Value |= 0x01;
	}
	else
	{
		StructP->OptoE2_Value &= ~0x01;
	}
}

以上程式碼完成後,在main初始化階段呼叫void OptoKnob_ParaInit(void)函式,大概500us一次呼叫void OptoKnob_ServiceAll(void)就可以了,建議不要太久,500us到1ms之間差不多了。