单片机mian主逻辑的写法

单片机mian主逻辑的写法


双while(1)写法

在嵌入式系统编程中,尤其是在使用C语言编写的程序中,while(1) 循环通常用于创建一个无限循环,这样程序就可以持续运行,不会自行终止。
这种结构在嵌入式应用程序中非常常见,因为它们通常需要不断地响应外部事件,如用户输入、传感器数据或其他设备通信。
在您提供的 MODE_2 函数中,也包含了一个 while(1) 循环。这是因为 MODE_2是一个特定的模式,它需要在自己的函数中持续运行,直到被外部事件(如用户按下特定的键)中断,通过retrun跳出mode_2()。即使这个函数被包含在主程序的while(1) 循环中调用,它仍然需要自己的循环来处理该模式下的所有逻辑。 这里的结构是这样的:
1.主程序的 while(1)循环:这是程序的最外层循环,它不断地检查当前的模式(由 MEMU 变量控制),并调用相应的模式处理函数(如 MODE_1, MODE_2,MODE_3, MODE_4 等)。
2.模式函数内的 while(1) 循环:每个模式函数(如 MODE_2)内部也有自己的 while(1)循环。这个循环负责处理该模式下的所有逻辑,如读取传感器数据、更新显示、处理用户输入等。当需要退出该模式时(例如用户按下了返回键),函数会设置MEMU 变量到一个特定的值,这样主程序的 while(1) 循环就会调用另一个模式处理函数或退出当前模式。

------------------------主程序部分main.py----------------------------------------
int main (void)
{
	RCC_Configuration(); //时钟设置
	NVIC_Configuration();	//NVIC设置
	//串口通信部分
	uart1_init(9600);//连接昆仑屏——485 
	uart2_init(115200);	//连接摄像头板
	uart3_init(9600);	//连接语音板
	uart4_init(9600);//连接电视板
  uart5_init(115200);//连接舵机板
	TIM3_Int_Init(3600-1,10000-1); //定时周期500ms,用于各种计时
	//RTC部分
	RTC_Config();//初始化RTC时钟
	BKP_Configuration();//初始化BKP
	RTC_Set(2023,9,26,10,30,20);	//设置当前时间
	//显示部分
	LCD_Init();//LCD初始化
	LCD_Clear();
	KEYPAD5x4_Init();	//矩阵键盘初始化
	EXTIX_Init();//外部中断 初始化
	Relay_Init();//继电器初始化
	//云台部分
	Store_Init();
	bsp_Coordinate_instructions((float)(0),(float)(-19.5));//舵机初始化——复位到指定位置
	 
	while(1)
	{ 
		switch(MEMU) //判断MEMU值,执行对应模式函数
	  {   				      	
				case 0:  LCD_Start();break;	//初始等待界面
        case 1:  LCD_Clear();MODE_1(); break;	//模式1			  				      
				case 2:  LCD_Clear();MODE_2(); break;	//模式2		
        case 3:  LCD_Clear();MODE_3(); break;	//模式3				  				      
				case 4:  LCD_Clear();MODE_4(); break;	//模式4		
				case 10: LCD_Clear();LCD_Main(); break;	//模式选择界面	
//				case 20: LCD_Clear();Position_Display();break;	//显示坐标函数,画圈功能(去掉该功能)
				case 30: LCD_Clear();Records_Display();break;	//显示记录函数
				case 40: LCD_Clear();Pages_Display();break;//翻页函数
				case 50: Scrolling_Display();break;//滚屏函数	
//				case 60: LCD_Clear();Parameter_Setting();break;//配置识别参数函数(去掉该功能)
				case 70: LCD_Clear();Servos_Adjust();break;//舵机校准界面
		}
	}
}
-------------------------------------------------------------------------
-----------------------control.py---------------------------------------
void MODE_1(void)
{
	/*
		单片机——摄像头协议:
			模式:01静止图片  02慢速视频  03快速视频
			颜色: 00无颜色要求 01红色 02绿色 03蓝色 04黄色 05紫红 
						06青色 07棕色 08深绿 09深蓝 0a褐色 0b紫色 0c深青 			
			形状:00无形状要求 01三角形 02正方形 03五边形 04六边形 05平行四边形 
						06三角星 07四角星 08五角星 09六角星 0a八角星 
						0b黑桃 0c红桃 0d方块 0e梅花 0f圆形
			背景:00无 01白色 02黑色
	*/
	// 单片机——摄像头协议数组:      帧头,命令,模式,颜色,形状,背景,帧尾
	u8 command_to_camera_start_1[7]={0xAA,0x01,0x01,0x00,0x00,0x00,0x55};//向摄像头发送的开始指令
	u8 command_to_camera_stop_1 [7]={0xAA,0x00,0x01,0x00,0x00,0x00,0x55};//向摄像头发送的停止指令
	
//	//将设置的参数写入协议数组:背景——颜色——形状
//	command_to_camera_start_1[5] =	setting_parameter/100;//背景
//	command_to_camera_start_1[3] = (setting_parameter/10)%10;//颜色
//	command_to_camera_start_1[4] = setting_parameter%10;//形状

	//LCD显示文字
	LCD_ShowChinese(0,0,"静态图片",RED,WHITE,32,0);
	LCD_ShowChinese(0,40,"计时:",RED,WHITE,32,0);
	LCD_ShowString(96,40,"   S",RED,WHITE,32,0);
	LCD_ShowChinese(0,80,"时间:",RED,WHITE,32,0);
 
	USART2_Send_Message(command_to_camera_start_1,7);//向摄像头发送开始识别指令
	delay_s(2);	//延时使摄像头初始化	
	USART4_Send_Message((u8*)"FJD01",6);//向电视板发送 播放指令
	MODE1.timer_flag = 1; //计时开启
		
	while(1)
	{
		RTC_Get();//读取RTC时钟
		sprintf((char*)time_buf,"%02d:%02d:%02d",rhour,rmin,rsec);//将时间放入要在LCD屏上显示的字符串
		LCD_ShowString(96,80,time_buf,RED,WHITE,32,0);		//显示当前时间
		LCD_ShowIntNum(96,40,MODE1.count,2,RED,WHITE,32);//显示计时时间
		if(KEYPAD5x4_Read() == KEYPAD_F1)//再按F1,退回到主界面
		{
			MEMU = 10; 
			MODE1.count = 0;			//定时器计时时间清0
			MODE1.timer_flag = 0;	//定时器计时停止
			//以下两个变量为防止视频卡死,退出时清0
			camera_timer_flag =0;//暂停定时标志位清0
			pause_count = 0;	//暂停定时计数清0,这个计时只有模式2,模式3有
			bsp_Coordinate_instructions((float)(0),(float)(-19.5));//舵机初始化——复位到指定位置
			USART4_Send_Message((u8*)"FJDSTOP",8);//向电视板发送 停止播放指令
			delay_ms(50);
			USART2_Send_Message(command_to_camera_stop_1,7);//通知摄像头停止识别
			return;//##检测到按键KEYPAD5x4_Read() == KEYPAD_F1,停止视频,如何跳出函数
		}

		//在这进行串口接收完成等待
		if(USART2_RX_STA) //接收到摄像头板发来的报文,进入坐标画圈模式,定时关闭,
		{
			USART2_RX_STA = 0;
			Usart2_process();//分析报文数据
			Usart2_ResetRXbuffer();
		}
	}	
}

------------------------------------------------------------------------

关于裸机调度的时间片

优点:针对不同的模块,调用时间间隔不同,合理利用系统资源。
视频教材:https://cloud.189.cn/t/2uIBrya2MnIj(访问码:2jic)

main.c


typedef struct
{
	uint8_t run;                // 调度标志,1:调度,0:挂起
	uint16_t timCount;          // 时间片计数值
	uint16_t timRload;          // 时间片重载值
	void (*pTaskFuncCb)(void);  // 函数指针变量,用来保存业务功能模块函数地址
} TaskComps_t;

static TaskComps_t g_taskComps[] = 
{
	{0, 5,    5,     HmiTask},
	{0, 10,   10,    WifiNetworkTask},
	{0, 100,  100,   SensorTask},
//	{0, 1000, 1000,  BatteryDrvTest},	
	{0, 1000, 1000,  BatteryTask},
	/* 添加业务功能模块 */
};

#define TASK_NUM_MAX   (sizeof(g_taskComps) / sizeof(g_taskComps[0]))

static void TaskHandler(void)
{
	for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
	{
		if (g_taskComps[i].run)                  // 判断时间片标志
		{
			g_taskComps[i].run = 0;              // 标志清零
			g_taskComps[i].pTaskFuncCb();        // 执行调度业务功能模块
		}
	}
}

/**
***********************************************************
* @brief 在定时器中断服务函数中被间接调用,设置时间片标记,
         需要定时器1ms产生1次中断
* @param
* @return 
***********************************************************
*/
static void TaskScheduleCb(void)
{
	for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
	{
		if (g_taskComps[i].timCount)
		{
			g_taskComps[i].timCount--;
			if (g_taskComps[i].timCount == 0)
			{
				g_taskComps[i].run = 1;
				g_taskComps[i].timCount = g_taskComps[i].timRload;
			}
		}
	}
}

static void DrvInit(void)
{
	DelayInit();
	LedDrvInit();
	KeyDrvInit();
	RtcDrvInit();
	SystickInit();

	WifiModuleDrvInit();
	LcdDrvInit();
	TempHumiDrvInit();
	Pm25DrvInit();
	BatteryDrvInit();
}
static void AppInit(void)
{
	TaskScheduleCbReg(TaskScheduleCb);
}

int main(void)
{	
	DrvInit();
	AppInit();
	DelayNms(1000);
	HmiTest();
//	RtcTime_t rtcTime = {2024, 4, 15, 16, 25, 30};
//	SetRtcTime(&rtcTime);
	while (1)
	{
		TaskHandler();//
	}
}

systick.c

#include <stdint.h>
#include <stdlib.h>
#include "gd32f30x.h"

static volatile uint64_t g_sysRunTime = 0;

static void (*g_pTaskScheduleFunc)(void);          // 函数指针变量,保存任务调度的函数地址

/**
***********************************************************
* @brief 注册任务调度回调函数
* @param pFunc, 传入回调函数地址
* @return 
***********************************************************
*/
void TaskScheduleCbReg(void (*pFunc)(void))
{
	g_pTaskScheduleFunc = pFunc;
}

/**
***********************************************************
* @brief systick初始化
* @param
* @return 
***********************************************************
*/
void SystickInit(void)
{
	/*1ms 产生一次定时中断*/
	if (SysTick_Config(rcu_clock_freq_get(CK_AHB) / 1000))
	{
		while (1);
	}
}

/**
***********************************************************
* @brief 定时中断服务函数,1ms产生一次中断
* @param
* @return 
***********************************************************
*/
void SysTick_Handler(void)
{
	g_sysRunTime++;
	if (g_pTaskScheduleFunc == NULL)
	{
		return;
	}
	g_pTaskScheduleFunc();
}

/**
***********************************************************
* @brief 获取系统运行时间
* @param
* @return 以1ms为单位
***********************************************************
*/
uint64_t GetSysRunTime(void)
{
	return g_sysRunTime;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值