用于单片机编程的一种简单的主函数框架

常见的单片机最小系统(最小外围电路)中,会带有单片机、晶振、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;
	}

}

还有一种状态机写法,

状态机的两种写法对比

TI官方代码中的任务状态机

猜你喜欢

转载自blog.csdn.net/qq_27158179/article/details/82865051