1. 程式人生 > >用於微控制器程式設計的一種簡單的主函式框架

用於微控制器程式設計的一種簡單的主函式框架

常見的微控制器最小系統(最小外圍電路)中,會帶有微控制器、晶振、LDO、按鍵、LED指示燈。假如是使用STM32,現在通常會配合STM32CubeMX,快速生成初始化程式碼和工程專案檔案。在生成了一套工程專案後,需要在檔案的特定位置加上使用者程式碼。

我對作業系統程式設計不熟悉,但需要把微控制器對外擴模組的操作程式編成任務,每個任務在一秒鐘內執行的次數不同。因此需要編個簡單的框架,控制每個任務的執行次數。

/* Private variables ---------------------------------------------------------*/
uint32_t counter_10ms, counter_50ms, counter_100ms, counter_500ms, counter_1000ms, counter_2000ms, counter_3s, counter_5s, counter_10s, counter_20s, counter_50s;
uint8_t flag_1ms, flag_10ms, flag_50ms, flag_100ms, flag_500ms, flag_1000ms, flag_2000ms, flag_3s, flag_5s, flag_10s, flag_20s, flag_50s;

int main(void)
{
  //這裡執行初始化程式碼
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)  {
    if(flag_1ms ==1)	{			
		LEDSoftTimer(b_LED1Freq, b_LED1Duty, b_LED2Freq, b_LED2Duty);
		flag_1ms = 0;		
		
		if(flag_ADCbusy==RESET)		{
			ADC_GetData();
			flag_ADCbusy = SET;
			if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)a_ADCxConvertedValues,   2) != HAL_OK)			{
				Error_Handler();
			}
		}		
	}
	if(flag_10ms==1)	{
		flag_10ms=0;
	}
	if(flag_50ms==1)	{
		flag_50ms=0;		
	}
	if(flag_100ms==1)	{
		flag_100ms=0;
		SerialDisplay();
	}
	if(flag_500ms==1)	{
		flag_500ms=0;		
	}
	if(flag_1000ms==1)	{
		flag_1000ms=0;	
		sec++;
		if(sec>0xff)
			sec = 0;
	}
	if(flag_2000ms==1)	{
		flag_2000ms=0;
	}	
	if(flag_3s==1)	{
		flag_3s=0;
	}
	if(flag_5s==1)	{      
		flag_5s=0;
	}	
	if(flag_10s==1)	{
		flag_10s=0;
	}	
	if(flag_20s==1)	{
		flag_20s=0;
	}	
	if(flag_50s==1)	{ 
		flag_50s=0;
	}	
  } 
  /* USER CODE END 3 */

}
//然後在systick中更新時間計數器和相關flag的值,systick中斷由CPU定時器生成,每1ms中斷一次
void HAL_SYSTICK_Callback(void)
{

	flag_1ms = 1;
	/*update counters*/
	if(counter_10ms<9) {
		counter_10ms++;
	}
	else {
		counter_10ms = 0;
		flag_10ms = 1;
	}
	
	if(counter_50ms<49)	{	
		counter_50ms++;
	} else {
		counter_50ms = 0;
		flag_50ms = 1;
	}
	
	if(counter_100ms<99) {
		counter_100ms++;
	}	else {
		counter_100ms = 0;
		flag_100ms = 1;
		if(counter_500ms<4)	{
			counter_500ms++;
		}	else {
			counter_500ms = 0;
			flag_500ms = 1;
		}
		if(counter_1000ms<9) {
			counter_1000ms++;
		}	else {
			counter_1000ms = 0;
			flag_1000ms = 1;			
			UpdateDateTime();
			if(counter_3s < 2) {
				counter_3s++;
			}	else {
				counter_3s = 0;
				flag_3s = 1;
			}
			if(counter_5s < 4) {
				counter_5s++;
			}	else {
				counter_5s = 0;
				flag_5s = 1;
			}
			if(counter_10s < 9)	{
				counter_10s++;
			}	else {
				counter_10s = 0;
				flag_10s = 1;
			}
		}
		if(counter_2000ms<19)	{
			counter_2000ms++;
		}	else {
			counter_2000ms = 0;
			flag_2000ms = 1;
		}
	}
}

上面的程式中,每1ms執行一次ADC取樣。還有每100ms執行一次程式把資料傳輸到上位機顯示。直接把上面的程式碼複製到STM32CubeMX生成的專案檔案,即可快速的分配CPU運算資源。

另外,最簡單的狀態機程式設計結構如下。

本例子用STM32和NodeMCU通訊,驅動NodeMCU和手機連線,並通過TCP協議把一句句的資訊傳輸到手機。

void Proc_NodeMCU(void)
{
	uint8_t CIPSEND_CustomSize[2];
	uint8_t NodeMCU_ACK_res;
	if(Status_NodeMCU == 1)
	{
		
		清空UART接收資料
		傳送AT指令
		採用阻塞,超時的方式檢查NodeMCU有沒回傳"OK\r\n"字元,
		如果收到"OK\r\n": Status_NodeMCU=2;且flag_ProcNodeMCUActive=1;代表NodeMCU程式有效
		否則無NodeMCU連線
	}
	else if(Status_NodeMCU == 2)
	{
		清空UART接收資料
		傳送AT指令配置成STATION模式
		採用阻塞,超時的方式檢查NodeMCU有沒回傳"OK\r\n"字元,
		如果收到"OK\r\n": Status_NodeMCU=3;
	}
	else if(Status_NodeMCU == 3)
	{
		清空UART接收資料
		傳送AT指令,控制NodeMCU連線AP
		採用阻塞,超時的方式檢查NodeMCU有沒回傳"OK\r\n"字元,
		如果收到"OK\r\n": Status_NodeMCU=4;
	}
	else if(Status_NodeMCU == 4)
	{
		清空UART接收資料
		傳送AT指令,NodeMCU和手機建立TCP連線
		處理回傳資料
		如果正常:Status_NodeMCU=10;
	}
	else if(Status_NodeMCU == 10)
	{
		清空UART接收資料
		傳送AT指令,控制NodeMCU進入資料透傳模式,併發送資訊包至手機
		處理回傳資料
		如果正常:Status_NodeMCU=11;
		如果不正常:Status_NodeMCU=4;將重新連線

	}
	else if(Status_NodeMCU == 11)
	{
		清空UART接收資料
		傳送AT指令控制NodeMCU進入低功率傳送模式,減少射頻干擾和功耗
		Status_NodeMCU = 10;下次執行本程式可省去連線部分,直接控制NodeMCU進入資料透傳模式
		本次傳送資料完成,flag_ProcNodeMCUActive=0;
	}
	else
	{
		Status_NodeMCU = 1;
	}

}

還有一種狀態機寫法,