自定義方波波形發生器(代碼庫)

自定義方波波形發生器(代碼庫)

本文講述一個可以產生任意波形的波形發生器,可以適用於m433,紅外發射等需要自定義波形的場景。且本文的代碼是非阻塞的,在波形生成期間可以繼續執行其他代碼。具體代碼:https://github.com/zrw269113179/waveform.git
注意,本文使用的所有相關於GPIO的操作都使用我的另一個底層驅動,詳見
https://blog.csdn.net/u014723040/article/details/90715769

預覽

讓我們先來看看效果,首先我們先定義一個波形對象

static waveform wave1;

然後對他進行初始化

waveform_init(&wave1,27);//27爲我們綁定的引腳號,即通過27號引腳輸出波形

接着再定時器中斷中調用輪詢函數

 if (TIM2_GetITStatus(TIM2_IT_Update) == SET)    
 {
 	waveform_loop(); 
 	TIM2_ClearITPendingBit(TIM2_IT_Update); 
}

記得先把27號腳配置成輸出模式,然後我們就可以調用函數生成波形了

waveform_generate(&wave1,0,100);    
waveform_generate(&wave1,1,200);    
waveform_generate(&wave1,0,300);    
waveform_generate(&wave1,1,400);    
waveform_generate(&wave1,0,500);

這裏我們的定時器週期爲100us,所以上述代碼波形先輸出10ms的低電平,再20ms的高電平,再30ms的低電平,再40ms的高電平,最後50ms的低電平,後續沒有其他輸出,因此保持低電平。如下圖所示實際波形圖

代碼分析

結構體

我們先來看這個結構體

#define WAVE_DEEP_LEN       20
typedef struct
{    
	unsigned short tick;    // 輸出時間    
	unsigned char level:1;  // 輸出電平
}wave_queue_obj;
typedef struct waveform_t
{    
	unsigned char pin;          // 綁定引腳    
	unsigned char deep;         // 隊列深度    
	unsigned char front;        // 隊列頭    
	unsigned short tick_cnt;    // 計時時間    
	struct waveform_t* next;    // 鏈表    
	wave_queue_obj queue[WAVE_DEEP_LEN]; // 隊列數組
}waveform;

這裏我們可以看到定義了一個隊列,用隊列來記錄我們需要輸出的波形,因此我們可能需要更改WAVE_DEEP_LEN的值,使隊列不佔用過多的空間,推薦定義爲一個波形調waveform_generate函數的最大次數。即示例中的波形需要調用5次waveform_generate才能生成一次波形,那麼WAVE_DEEP_LEN就可以設置成5,這裏永遠取最大的值。

waveform_init

/**
 * @brief 波形對象初始化
 * 
 * @param wave 波形對象
 * @param pin 輸出引腳 
 */
 void waveform_init(waveform *wave, unsigned char pin)
 {    
	 wave->front = 0;    
	 wave->deep = 0;    
	 wave->pin = pin;    
	 wave->tick_cnt = 0;    
	 if (head == 0x00)    
	 {        
	 	head = wave;    
	 }    
	 else    
	 {        
		 wave->next = head;        
		 head = wave;    
	 }
}

初始化函數令波形對象*wave 綁定輸出引腳,並且將其編入鏈表,以便後續遍歷。

waveform_generate

/**
 * @brief 波形生成函數
 * 
 * @param wave 波形 
 * @param level 高低電平輸出 
 * @param tick 輸出時間 
 */
 void waveform_generate(waveform *wave, unsigned char level, unsigned short tick)
 {
	 if ((wave->deep + 1) % WAVE_DEEP_LEN != wave->front)   
	 {        
		wave->queue[wave->deep].tick = tick;
		wave->queue[wave->deep].level = level;
		wave->deep++;
		if (wave->deep >= WAVE_DEEP_LEN)        
		{            
		 wave->deep -= WAVE_DEEP_LEN;        
		}
	}
}

這裏我們看到,僅僅是將輸出屬性入隊,而沒有直接做輸出。

waveform_loop

要做到非阻塞,就必須使用到輪詢,我們定義一個定時器來進行輪詢,waveform_loop即爲其輪詢函數,在定時器中定期調用該函數。

void waveform_loop()
{    
	waveform *iterator = head;   
	while (iterator != 0)    
	{        
		if (iterator->deep != iterator->front)        
		{            
			wave_queue_obj *temp = &iterator->queue[iterator->front];            
			pin_write(iterator->pin,temp->level);            
			iterator->tick_cnt++;            
			if (iterator->tick_cnt > temp->tick)            
			{
				waveform_quit_queue(iterator);                
				iterator->tick_cnt=0;            
			}        
		}
		iterator = iterator->next;    
	}
}

這裏我們遍歷鏈表,當iterator->deep != iterator->front時,即該波形對象中輸出隊列不爲空時,我們輸出當前隊列需要輸出的電平,即pin_write(iterator->pin,temp->level);,然後疊加計時時間iterator->tick_cnt++;然後判斷輸出時間是否達到隊列中期望輸出的時間,如果大於該時間則隊列中當前對象出列,完成當前隊列的輸出。

總結

該代碼庫中我們通過對隊列和鏈表的運用,利用定時器的特點實現了非阻塞式的波形生成器,且調用簡單,適用於裸機或單線程生成自定義波形。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章